diff -r 1378060fadd6 -r feabf14b6c1d LLVMExamples.st --- a/LLVMExamples.st Mon Aug 17 09:16:53 2015 +0100 +++ b/LLVMExamples.st Mon Aug 17 08:53:26 2015 +0100 @@ -18,7 +18,7 @@ TestCase subclass:#LLVMExamples instanceVariableNames:'' classVariableNames:'' - poolDictionaries:'LLVMIntPredicate' + poolDictionaries:'LLVMIntPredicate LLVMDWARFEncoding LLVMDWARFLamguage' category:'LLVM-S-Core-Examples' ! @@ -231,19 +231,15 @@ ! example5_factorial - " - S simple factorial using recursive algorithm. - No negative argument or overflow checks" + "A simple factorial using recursive algorithm. + No overflow or negative value checks" - | module functionType function asm "Variables" - result i "Blocks" - entry loop loopBody exit jit externalFunction | + | module functionType function asm + "Variables" result i + "Blocks" entry loop loopBody exit jit externalFunction | module := LLVMModule newWithName:testSelector. - functionType := LLVMType function:{ - LLVMType intptr - } - returning:LLVMType intptr. + functionType := LLVMType function:{ LLVMType intptr } returning:LLVMType intptr. function := module addFunctionNamed:'factorial' type:functionType. asm := LLVMIRBuilder new. entry := function entry. @@ -253,25 +249,25 @@ "/ Generate function setup "/ - "/ function f(v) { - "/ var result; - "/ var i; - "/ result = 0; - "/ i := v; + "/ 03 function f(v) { + "/ 04 var result; + "/ 05 var i; + "/ 06 result = 0; + "/ 07 i := v; asm block:entry. result := asm alloca:LLVMType intptr as:'result'. i := asm alloca:LLVMType intptr as:'i'. asm store:(function parameterAt:1) _:i. - asm store:(function parameterAt:1) _:result. + asm store:(LLVMConstant sintptr: 1) _:result. asm br:loop. "/ Generate loop that computes the factorial "/ - "/ while ( i > 1 ) { - "/ result = result * i; - "/ i = i - 1. - "/ } + "/ 08 while ( i > 1 ) { + "/ 09 result = result * i; + "/ 10 i = i - 1. + "/ 11 } "/ "/ Note, that unlike 'traditional' assemblers, there's no "/ fall-through instruction, so we have to introduce a block @@ -293,7 +289,8 @@ "/ Generate return from function "/ - "/ return result; + "/ 12 return result; + "/ 13 } "/ asm block:exit. @@ -304,11 +301,14 @@ self assert:(externalFunction callWith:1) == 1. " - LLVMExamples example3_cond" + LLVMExamples run: example5_factorial_with_debug_info + " + "Created: / 10-08-2015 / 09:46:29 / Jan Vrany " + "Modified: / 17-08-2015 / 07:39:41 / Jan Vrany " ! -example5_factorial_with_overflow +example6_factorial_with_overflow " Simple factorial using recursive algorithm. This one checks for overflow, if overflow happens, @@ -344,7 +344,7 @@ result := asm alloca:LLVMType intptr as:'result'. i := asm alloca:LLVMType intptr as:'i'. asm store:(function parameterAt:1) _:i. - asm store:(function parameterAt:1) _:result. + asm store:(LLVMConstant sintptr: 1) _:result. asm br:loop. "/ Generate loop that computes the factorial @@ -408,7 +408,163 @@ self assert:(externalFunction callWith:120) == -1. "sly LLVMExamples example3_cond" - "Created: / 10-08-2015 / 17:12:00 / Jan Vrany " - "Modified: / 10-08-2015 / 18:58:51 / Jan Vrany " + + "Created: / 14-08-2015 / 06:46:31 / Jan Vrany " + "Modified: / 17-08-2015 / 07:40:02 / Jan Vrany " +! + +example7_factorial_with_debug_info + "A simple factorial using recursive algorithm + with debug info attached. + + + + " + + | module functionType function asm + "Variables" result i + "Blocks" entry loop loopBody exit + "Debug Info Metadata" dib diFile compilationUnitDI functionTypeDI functionDI intptrDI resultDI iDI + jit externalFunction | + + module := LLVMModule newWithName:testSelector. + dib := module debugInfoBuilder. + + diFile := dib createFile: Filename currentDirectory / 'factorial.lang'. + compilationUnitDI := dib createCompilationUnit: Filename currentDirectory / 'factorial.lang' language: LLVM_DW_LANG_lo_user + 10 producer: self class name. + + functionType := LLVMType function:{ LLVMType intptr } returning:LLVMType intptr. + intptrDI := dib createTypeScalar: 'intptr' type: LLVMType intptr encoding: LLVM_DW_ATE_signed. + functionTypeDI := dib createTypeFunctionIn: compilationUnitDI + parameterTypes: { intptrDI }. + function := module addFunctionNamed:'factorial' type:functionType. + functionDI := dib createFunction: 'factorial' in: compilationUnitDI file: diFile line: 03 type: functionTypeDI function: function local: false definition: true optimized: false. + dib createParameterVariable: 'v' in: functionDI file: diFile line: 03 type: intptrDI flags: 0 index: 1. + asm := LLVMIRBuilder new. + entry := function entry. + loop := function addBasicBlockNamed:'loop'. + loopBody := function addBasicBlockNamed:'loopBody'. + exit := function addBasicBlockNamed:'exit'. + + "/ Generate function setup + "/ + "/ 03 function f(v) { + "/ 04 var result; + "/ 05 var i; + "/ 06 result = 0; + "/ 07 i := v; + + asm block:entry. + asm line: 4 column: 3 scope: functionDI. + result := asm alloca:LLVMType intptr as:'result'. + resultDI := dib createAutomaticVariable: 'result' in: functionDI file: diFile line: 4 type: intptrDI. + dib insertDeclare: result variable: resultDI expression: dib createExpression location: asm location atEndOf: entry. + + asm line: 5 column: 3 scope: functionDI. + i := asm alloca:LLVMType intptr as:'i'. + iDI := dib createAutomaticVariable: 'i' in: functionDI file: diFile line: 4 type: intptrDI. + dib insertDeclare: i variable: iDI expression: dib createExpression location: asm location atEndOf: entry. + + asm line: 6 column: 3 scope: functionDI. + asm store:(function parameterAt:1) _:i. + + asm line: 7 column: 3 scope: functionDI. + asm store:(LLVMConstant sintptr: 1) _:result. + asm br:loop. + + "/ Generate loop that computes the factorial + "/ + "/ 08 while ( i > 1 ) { + "/ 09 result = result * i; + "/ 10 i = i - 1. + "/ 11 } + "/ + "/ Note, that unlike 'traditional' assemblers, there's no + "/ fall-through instruction, so we have to introduce a block + "/ loop's body which will become a target for conditional's + "/ then-branch. + + asm block:loop. + asm line: 8 column: 3 scope: functionDI. + asm + if:(asm + icmp:(asm load:i) + _:(LLVMConstant sintptr:1) + cond:LLVMIntSGT) + then:loopBody + else:exit. + asm block:loopBody. + asm line: 9 column: 3 scope: functionDI. + asm store:(asm mul:(asm load:result) _:(asm load:i)) _:result. + asm line: 10 column: 3 scope: functionDI. + asm store:(asm sub:(asm load:i) _:(LLVMConstant sintptr:1)) _:i. + asm line: 11 column: 3 scope: functionDI. + asm br:loop. + + "/ Generate return from function + "/ + "/ 12 return result; + "/ 13 } + "/ + + asm block:exit. + asm line: 12 column: 3 scope: functionDI. + asm ret:(asm load:result). + + dib finish. + self halt. + " + To generate stand-alone executable do the following: + + 1) Execute following to write LLVM IR to /tmp/factorial.ll + + module writeBitcodeToFile: '/tmp/factorial.bc' + + 2) Compile it into an object file + + llc-3.8 --filetype=obj factorial.bc + + 3) Write a simple main.c to call factorial(): + + '/tmp/main.c' asFilename writingFileDo:[:f | f nextPutAll: 'int main(int argc, char **argv) { factorial(5); exit(0); }' ]. + + 4) Compile main.c and link it with factorial.o + + gcc -o main main.c factorial.o + + To actually debug it, first write the pseudo-code for the factorial: + + '/tmp/factorial.lang' asFilename writingFileDo:[ :f| + f nextPutLine: ''. + f nextPutLine: ''. + f nextPutLine: 'function factorial(v) {'. + f nextPutLine: ' var result;'. + f nextPutLine: ' var i;'. + f nextPutLine: ' result = 0;'. + f nextPutLine: ' i := v;'. + f nextPutLine: ' while ( i > 1 ) {'. + f nextPutLine: ' result = result * i;'. + f nextPutLine: ' i = i - 1.'. + f nextPutLine: ' }'. + f nextPutLine: ' return result;'. + f nextPutLine: '}'. + ] + + Then debug it using gdb: + + gdb main + " + + + jit := LLVMExecutionEngine newForModule:module. + externalFunction := jit externalOfFunction:function. + self assert:(externalFunction callWith:5) == 120. + self assert:(externalFunction callWith:1) == 1. + + " + LLVMExamples example7_factorial_with_debug_info" + + "Created: / 14-08-2015 / 06:46:39 / Jan Vrany " + "Modified (comment): / 17-08-2015 / 08:52:28 / Jan Vrany " ! !