1 module samples.fibonacci; 2 3 import std.conv : to; 4 import std.stdio : writefln, writeln; 5 import std.string : toStringz, fromStringz; 6 7 import llvm.c; 8 9 int main(string[] args) 10 { 11 LLVM.load(); 12 13 char* error; 14 15 LLVMInitializeNativeTarget(); 16 LLVMInitializeNativeAsmPrinter(); 17 LLVMInitializeNativeAsmParser(); 18 19 auto _module = LLVMModuleCreateWithName("fibonacci".toStringz()); 20 auto f_args = [ LLVMInt32Type() ]; 21 auto f = LLVMAddFunction( 22 _module, 23 "fib", 24 LLVMFunctionType(LLVMInt32Type(), f_args.ptr, 1, cast(LLVMBool) false)); 25 LLVMSetFunctionCallConv(f, LLVMCCallConv); 26 27 auto n = LLVMGetParam(f, 0); 28 29 auto entry = LLVMAppendBasicBlock(f, "entry".toStringz()); 30 auto case_base0 = LLVMAppendBasicBlock(f, "case_base0".toStringz()); 31 auto case_base1 = LLVMAppendBasicBlock(f, "case_base1".toStringz()); 32 auto case_default = LLVMAppendBasicBlock(f, "case_default".toStringz()); 33 auto end = LLVMAppendBasicBlock(f, "end".toStringz()); 34 auto builder = LLVMCreateBuilder(); 35 36 /+ Entry basic block +/ 37 LLVMPositionBuilderAtEnd(builder, entry); 38 auto Switch = LLVMBuildSwitch( 39 builder, 40 n, 41 case_default, 42 2); 43 LLVMAddCase(Switch, LLVMConstInt(LLVMInt32Type(), 0, cast(LLVMBool) false), case_base0); 44 LLVMAddCase(Switch, LLVMConstInt(LLVMInt32Type(), 1, cast(LLVMBool) false), case_base1); 45 46 /+ Basic block for n = 0: fib(n) = 0 +/ 47 LLVMPositionBuilderAtEnd(builder, case_base0); 48 auto res_base0 = LLVMConstInt(LLVMInt32Type(), 0, cast(LLVMBool) false); 49 LLVMBuildBr(builder, end); 50 51 /+ Basic block for n = 1: fib(n) = 1 +/ 52 LLVMPositionBuilderAtEnd(builder, case_base1); 53 auto res_base1 = LLVMConstInt(LLVMInt32Type(), 1, cast(LLVMBool) false); 54 LLVMBuildBr(builder, end); 55 56 /+ Basic block for n > 1: fib(n) = fib(n - 1) + fib(n - 2) +/ 57 LLVMPositionBuilderAtEnd(builder, case_default); 58 59 auto n_minus_1 = LLVMBuildSub( 60 builder, 61 n, 62 LLVMConstInt(LLVMInt32Type(), 1, cast(LLVMBool) false), 63 "n - 1".toStringz()); 64 auto call_f_1_args = [ n_minus_1 ]; 65 auto call_f_1 = LLVMBuildCall(builder, f, call_f_1_args.ptr, 1, "fib(n - 1)".toStringz()); 66 67 auto n_minus_2 = LLVMBuildSub( 68 builder, 69 n, 70 LLVMConstInt(LLVMInt32Type(), 2, cast(LLVMBool) false), 71 "n - 2".toStringz()); 72 auto call_f_2_args = [ n_minus_2 ]; 73 auto call_f_2 = LLVMBuildCall(builder, f, call_f_2_args.ptr, 1, "fib(n - 2)".toStringz()); 74 75 auto res_default = LLVMBuildAdd(builder, call_f_1, call_f_2, "fib(n - 1) + fib(n - 2)".toStringz()); 76 LLVMBuildBr(builder, end); 77 78 /+ Basic block for collecting the result +/ 79 LLVMPositionBuilderAtEnd(builder, end); 80 auto res = LLVMBuildPhi(builder, LLVMInt32Type(), "result".toStringz()); 81 auto phi_vals = [ res_base0, res_base1, res_default ]; 82 auto phi_blocks = [ case_base0, case_base1, case_default ]; 83 LLVMAddIncoming(res, phi_vals.ptr, phi_blocks.ptr, 3); 84 LLVMBuildRet(builder, res); 85 86 LLVMVerifyModule(_module, LLVMAbortProcessAction, &error); 87 LLVMDisposeMessage(error); 88 89 LLVMExecutionEngineRef engine; 90 error = null; 91 92 version(Windows) 93 { 94 /+ On Windows, we can only use the old JIT for now +/ 95 LLVMCreateJITCompilerForModule(&engine, _module, 2, &error); 96 } 97 else 98 { 99 // Ran into some issues under Arch, so comment the new MVJIT out for now 100 /+static if(LLVM_Version >= 3.3) 101 { 102 /+ On other systems we should be able to use the newer 103 + MCJIT instead - if we have a high enough LLVM version +/ 104 LLVMMCJITCompilerOptions options; 105 LLVMInitializeMCJITCompilerOptions(&options, options.sizeof); 106 107 LLVMCreateMCJITCompilerForModule(&engine, _module, &options, options.sizeof, &error); 108 } 109 else 110 {+/ 111 LLVMCreateJITCompilerForModule(&engine, _module, 2, &error); 112 //} 113 } 114 115 if(error !is null) 116 { 117 writefln("%s", error.fromStringz()); 118 LLVMDisposeMessage(error); 119 return 1; 120 } 121 122 auto pass = LLVMCreatePassManager(); 123 LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass); 124 LLVMAddConstantPropagationPass(pass); 125 LLVMAddInstructionCombiningPass(pass); 126 LLVMAddPromoteMemoryToRegisterPass(pass); 127 LLVMAddGVNPass(pass); 128 LLVMAddCFGSimplificationPass(pass); 129 LLVMRunPassManager(pass, _module); 130 131 writefln("The following module has been generated for the fibonacci series:\n"); 132 LLVMDumpModule(_module); 133 134 writeln(); 135 136 int n_exec= 10; 137 if(args.length > 1) 138 { 139 n_exec = to!int(args[1]); 140 } 141 else 142 { 143 writefln("; Argument for fib missing on command line, using default: \"%d\"", n_exec); 144 } 145 146 auto exec_args = [ LLVMCreateGenericValueOfInt(LLVMInt32Type(), n_exec, cast(LLVMBool) 0) ]; 147 writefln("; Running (jit-compiled) fib(%d)...", n_exec); 148 auto exec_res = LLVMRunFunction(engine, f, 1, exec_args.ptr); 149 writefln("; fib(%d) = %d", n_exec, LLVMGenericValueToInt(exec_res, 0)); 150 151 LLVMDisposePassManager(pass); 152 LLVMDisposeBuilder(builder); 153 LLVMDisposeExecutionEngine(engine); 154 return 0; 155 }