LLVMExamples.st
changeset 33 feabf14b6c1d
parent 28 97013ae2abae
child 42 23ae490859cd
equal deleted inserted replaced
32:1378060fadd6 33:feabf14b6c1d
    16 "{ NameSpace: Smalltalk }"
    16 "{ NameSpace: Smalltalk }"
    17 
    17 
    18 TestCase subclass:#LLVMExamples
    18 TestCase subclass:#LLVMExamples
    19 	instanceVariableNames:''
    19 	instanceVariableNames:''
    20 	classVariableNames:''
    20 	classVariableNames:''
    21 	poolDictionaries:'LLVMIntPredicate'
    21 	poolDictionaries:'LLVMIntPredicate LLVMDWARFEncoding LLVMDWARFLamguage'
    22 	category:'LLVM-S-Core-Examples'
    22 	category:'LLVM-S-Core-Examples'
    23 !
    23 !
    24 
    24 
    25 !LLVMExamples class methodsFor:'documentation'!
    25 !LLVMExamples class methodsFor:'documentation'!
    26 
    26 
   229 
   229 
   230     "Created: / 08-08-2015 / 04:16:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   230     "Created: / 08-08-2015 / 04:16:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   231 !
   231 !
   232 
   232 
   233 example5_factorial
   233 example5_factorial
   234     "
   234     "A simple factorial using recursive algorithm.
   235      S simple factorial using recursive algorithm.
   235      No overflow or negative value checks"
   236      No negative argument or overflow checks"
   236     
   237     
   237     | module functionType function asm  
   238     | module  functionType  function  asm  "Variables"
   238     "Variables" result  i  
   239     result  i  "Blocks"
   239     "Blocks" entry loop loopBody exit jit externalFunction |
   240     entry  loop  loopBody  exit  jit  externalFunction |
       
   241 
   240 
   242     module := LLVMModule newWithName:testSelector.
   241     module := LLVMModule newWithName:testSelector.
   243     functionType := LLVMType function:{
   242     functionType := LLVMType function:{ LLVMType intptr } returning:LLVMType intptr.
   244                     LLVMType intptr
       
   245                 }
       
   246             returning:LLVMType intptr.
       
   247     function := module addFunctionNamed:'factorial' type:functionType.
   243     function := module addFunctionNamed:'factorial' type:functionType.
   248     asm := LLVMIRBuilder new.
   244     asm := LLVMIRBuilder new.
   249     entry := function entry.
   245     entry := function entry.
   250     loop := function addBasicBlockNamed:'loop'.
   246     loop := function addBasicBlockNamed:'loop'.
   251     loopBody := function addBasicBlockNamed:'loopBody'.
   247     loopBody := function addBasicBlockNamed:'loopBody'.
   252     exit := function addBasicBlockNamed:'exit'.
   248     exit := function addBasicBlockNamed:'exit'.
   253      
   249      
   254     "/ Generate function setup
   250     "/ Generate function setup
   255     "/ 
   251     "/ 
   256     "/   function f(v) {
   252     "/ 03   function f(v) {
   257     "/     var result;
   253     "/ 04    var result;
   258     "/     var i;
   254     "/ 05    var i;
   259     "/     result = 0;
   255     "/ 06    result = 0;
   260     "/     i := v;
   256     "/ 07    i := v;
   261     
   257     
   262     asm block:entry.
   258     asm block:entry.
   263     result := asm alloca:LLVMType intptr as:'result'.
   259     result := asm alloca:LLVMType intptr as:'result'.
   264     i := asm alloca:LLVMType intptr as:'i'.
   260     i := asm alloca:LLVMType intptr as:'i'.
   265     asm store:(function parameterAt:1) _:i.
   261     asm store:(function parameterAt:1) _:i.
   266     asm store:(function parameterAt:1) _:result.
   262     asm store:(LLVMConstant sintptr: 1) _:result.
   267     asm br:loop.
   263     asm br:loop.
   268      
   264      
   269     "/ Generate loop that computes the factorial
   265     "/ Generate loop that computes the factorial
   270     "/ 
   266     "/ 
   271     "/     while ( i > 1 ) {
   267     "/ 08    while ( i > 1 ) {
   272     "/       result = result * i;
   268     "/ 09      result = result * i;
   273     "/       i = i - 1.
   269     "/ 10      i = i - 1.
   274     "/     }
   270     "/ 11    }
   275     "/ 
   271     "/ 
   276     "/ Note, that unlike 'traditional' assemblers, there's no
   272     "/ Note, that unlike 'traditional' assemblers, there's no
   277     "/ fall-through instruction, so we have to introduce a block 
   273     "/ fall-through instruction, so we have to introduce a block 
   278     "/ loop's body which will become a target for conditional's
   274     "/ loop's body which will become a target for conditional's
   279     "/ then-branch.
   275     "/ then-branch.
   291     asm store:(asm sub:(asm load:i) _:(LLVMConstant sintptr:1)) _:i.
   287     asm store:(asm sub:(asm load:i) _:(LLVMConstant sintptr:1)) _:i.
   292     asm br:loop.
   288     asm br:loop.
   293      
   289      
   294     "/ Generate return from function
   290     "/ Generate return from function
   295     "/ 
   291     "/ 
   296     "/     return result;
   292     "/ 12    return result;
       
   293     "/ 13 }
   297     "/ 
   294     "/ 
   298     
   295     
   299     asm block:exit.
   296     asm block:exit.
   300     asm ret:(asm load:result).
   297     asm ret:(asm load:result).
   301     jit := LLVMExecutionEngine newForModule:module.
   298     jit := LLVMExecutionEngine newForModule:module.
   302     externalFunction := jit externalOfFunction:function.
   299     externalFunction := jit externalOfFunction:function.
   303     self assert:(externalFunction callWith:5) == 120.
   300     self assert:(externalFunction callWith:5) == 120.
   304     self assert:(externalFunction callWith:1) == 1.
   301     self assert:(externalFunction callWith:1) == 1.
   305 
   302 
   306     "
   303     "
   307      LLVMExamples example3_cond"
   304         LLVMExamples run: example5_factorial_with_debug_info
       
   305     "
       
   306 
   308     "Created: / 10-08-2015 / 09:46:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   307     "Created: / 10-08-2015 / 09:46:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   309 !
   308     "Modified: / 17-08-2015 / 07:39:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   310 
   309 !
   311 example5_factorial_with_overflow
   310 
       
   311 example6_factorial_with_overflow
   312     "
   312     "
   313      Simple factorial using recursive algorithm.
   313      Simple factorial using recursive algorithm.
   314      This one checks for overflow, if overflow happens,
   314      This one checks for overflow, if overflow happens,
   315      return -1"
   315      return -1"
   316     
   316     
   342     
   342     
   343     asm block:entry.
   343     asm block:entry.
   344     result := asm alloca:LLVMType intptr as:'result'.
   344     result := asm alloca:LLVMType intptr as:'result'.
   345     i := asm alloca:LLVMType intptr as:'i'.
   345     i := asm alloca:LLVMType intptr as:'i'.
   346     asm store:(function parameterAt:1) _:i.
   346     asm store:(function parameterAt:1) _:i.
   347     asm store:(function parameterAt:1) _:result.
   347     asm store:(LLVMConstant sintptr: 1) _:result.
   348     asm br:loop.
   348     asm br:loop.
   349      
   349      
   350     "/ Generate loop that computes the factorial
   350     "/ Generate loop that computes the factorial
   351     "/ 
   351     "/ 
   352     "/     while ( i > 1 ) {
   352     "/     while ( i > 1 ) {
   406     self assert:(externalFunction callWith:5) == 120.
   406     self assert:(externalFunction callWith:5) == 120.
   407     self assert:(externalFunction callWith:1) == 1.
   407     self assert:(externalFunction callWith:1) == 1.
   408     self assert:(externalFunction callWith:120) == -1.
   408     self assert:(externalFunction callWith:120) == -1.
   409 
   409 
   410     "sly    LLVMExamples example3_cond"
   410     "sly    LLVMExamples example3_cond"
   411     "Created: / 10-08-2015 / 17:12:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   411 
   412     "Modified: / 10-08-2015 / 18:58:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   412     "Created: / 14-08-2015 / 06:46:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   413     "Modified: / 17-08-2015 / 07:40:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   414 !
       
   415 
       
   416 example7_factorial_with_debug_info
       
   417     "A simple factorial using recursive algorithm
       
   418      with debug info attached. 
       
   419 
       
   420 
       
   421 
       
   422     "     
       
   423 
       
   424     | module functionType function asm   
       
   425     "Variables" result  i  
       
   426     "Blocks" entry loop loopBody exit 
       
   427     "Debug Info Metadata" dib diFile compilationUnitDI functionTypeDI functionDI intptrDI resultDI iDI
       
   428     jit externalFunction |
       
   429 
       
   430     module := LLVMModule newWithName:testSelector.
       
   431     dib := module debugInfoBuilder.
       
   432 
       
   433     diFile := dib createFile: Filename currentDirectory / 'factorial.lang'.
       
   434     compilationUnitDI := dib createCompilationUnit: Filename currentDirectory / 'factorial.lang' language: LLVM_DW_LANG_lo_user + 10 producer: self class name.
       
   435 
       
   436     functionType := LLVMType function:{ LLVMType intptr } returning:LLVMType intptr.
       
   437     intptrDI := dib createTypeScalar: 'intptr' type: LLVMType intptr encoding: LLVM_DW_ATE_signed.
       
   438     functionTypeDI := dib createTypeFunctionIn: compilationUnitDI 
       
   439                                 parameterTypes: { intptrDI }.
       
   440     function := module addFunctionNamed:'factorial' type:functionType.
       
   441     functionDI := dib createFunction: 'factorial' in: compilationUnitDI file: diFile line: 03 type: functionTypeDI function: function local: false definition: true optimized: false.
       
   442     dib createParameterVariable: 'v' in: functionDI file: diFile line: 03 type: intptrDI flags: 0 index: 1.
       
   443     asm := LLVMIRBuilder new.
       
   444     entry := function entry.
       
   445     loop := function addBasicBlockNamed:'loop'.
       
   446     loopBody := function addBasicBlockNamed:'loopBody'.
       
   447     exit := function addBasicBlockNamed:'exit'.
       
   448      
       
   449     "/ Generate function setup
       
   450     "/ 
       
   451     "/ 03  function f(v) {
       
   452     "/ 04    var result;
       
   453     "/ 05    var i;
       
   454     "/ 06    result = 0;
       
   455     "/ 07    i := v;
       
   456     
       
   457     asm block:entry.
       
   458     asm line: 4 column: 3 scope: functionDI.
       
   459     result := asm alloca:LLVMType intptr as:'result'.
       
   460     resultDI := dib createAutomaticVariable: 'result' in: functionDI file: diFile line: 4 type: intptrDI.
       
   461     dib insertDeclare: result variable: resultDI expression: dib createExpression location: asm location atEndOf: entry.
       
   462 
       
   463     asm line: 5 column: 3 scope: functionDI.
       
   464     i := asm alloca:LLVMType intptr as:'i'.
       
   465     iDI := dib createAutomaticVariable: 'i' in: functionDI file: diFile line: 4 type: intptrDI.
       
   466     dib insertDeclare: i variable: iDI expression: dib createExpression location: asm location atEndOf: entry.
       
   467 
       
   468     asm line: 6 column: 3 scope: functionDI.
       
   469     asm store:(function parameterAt:1) _:i.
       
   470 
       
   471     asm line: 7 column: 3 scope: functionDI.
       
   472     asm store:(LLVMConstant sintptr: 1) _:result.
       
   473     asm br:loop.
       
   474      
       
   475     "/ Generate loop that computes the factorial
       
   476     "/ 
       
   477     "/   08  while ( i > 1 ) {
       
   478     "/   09    result = result * i;
       
   479     "/   10    i = i - 1.
       
   480     "/   11  }
       
   481     "/ 
       
   482     "/ Note, that unlike 'traditional' assemblers, there's no
       
   483     "/ fall-through instruction, so we have to introduce a block 
       
   484     "/ loop's body which will become a target for conditional's
       
   485     "/ then-branch.
       
   486     
       
   487     asm block:loop.
       
   488     asm line: 8 column: 3 scope: functionDI.
       
   489     asm 
       
   490         if:(asm 
       
   491                 icmp:(asm load:i)
       
   492                 _:(LLVMConstant sintptr:1)
       
   493                 cond:LLVMIntSGT)
       
   494         then:loopBody
       
   495         else:exit.
       
   496     asm block:loopBody.
       
   497     asm line: 9 column: 3 scope: functionDI.
       
   498     asm store:(asm mul:(asm load:result) _:(asm load:i)) _:result.
       
   499     asm line: 10 column: 3 scope: functionDI.
       
   500     asm store:(asm sub:(asm load:i) _:(LLVMConstant sintptr:1)) _:i.
       
   501     asm line: 11 column: 3 scope: functionDI.
       
   502     asm br:loop.
       
   503      
       
   504     "/ Generate return from function
       
   505     "/ 
       
   506     "/ 12    return result;
       
   507     "/ 13  }
       
   508     "/ 
       
   509 
       
   510     asm block:exit.
       
   511     asm line: 12 column: 3 scope: functionDI.
       
   512     asm ret:(asm load:result).
       
   513 
       
   514     dib finish.
       
   515     self halt.
       
   516     "
       
   517     To generate stand-alone executable do the following:
       
   518 
       
   519     1) Execute following to write LLVM IR to /tmp/factorial.ll
       
   520 
       
   521         module writeBitcodeToFile: '/tmp/factorial.bc'
       
   522 
       
   523     2) Compile it into an object file
       
   524 
       
   525         llc-3.8 --filetype=obj factorial.bc
       
   526 
       
   527     3) Write a simple main.c to call factorial():
       
   528 
       
   529         '/tmp/main.c' asFilename writingFileDo:[:f | f nextPutAll: 'int main(int argc, char **argv) { factorial(5); exit(0); }' ].
       
   530 
       
   531     4) Compile main.c and link it with factorial.o
       
   532 
       
   533         gcc -o main main.c factorial.o
       
   534 
       
   535     To actually debug it, first write the pseudo-code for the factorial:
       
   536 
       
   537         '/tmp/factorial.lang' asFilename writingFileDo:[ :f|
       
   538             f nextPutLine: ''.
       
   539             f nextPutLine: ''.
       
   540             f nextPutLine: 'function factorial(v) {'.
       
   541             f nextPutLine: '  var result;'.
       
   542             f nextPutLine: '  var i;'.
       
   543             f nextPutLine: '  result = 0;'.
       
   544             f nextPutLine: '  i := v;'.
       
   545             f nextPutLine: '  while ( i > 1 ) {'.
       
   546             f nextPutLine: '    result = result * i;'.
       
   547             f nextPutLine: '    i = i - 1.'.
       
   548             f nextPutLine: '  }'.
       
   549             f nextPutLine: '  return result;'.
       
   550             f nextPutLine: '}'.
       
   551         ]
       
   552 
       
   553     Then debug it using gdb:
       
   554 
       
   555             gdb main
       
   556     "
       
   557 
       
   558 
       
   559     jit := LLVMExecutionEngine newForModule:module.
       
   560     externalFunction := jit externalOfFunction:function.
       
   561     self assert:(externalFunction callWith:5) == 120.
       
   562     self assert:(externalFunction callWith:1) == 1.
       
   563 
       
   564     "
       
   565      LLVMExamples example7_factorial_with_debug_info"
       
   566 
       
   567     "Created: / 14-08-2015 / 06:46:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   568     "Modified (comment): / 17-08-2015 / 08:52:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   413 ! !
   569 ! !
   414 
   570