--- a/LLVMExamples.st Tue Aug 04 07:21:26 2015 +0100
+++ b/LLVMExamples.st Mon Aug 03 18:08:14 2015 +0100
@@ -15,7 +15,7 @@
"{ NameSpace: Smalltalk }"
-Object subclass:#LLVMExamples
+TestCase subclass:#LLVMExamples
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
@@ -40,38 +40,85 @@
"
! !
-!LLVMExamples class methodsFor:'examples'!
+!LLVMExamples class methodsFor:'accessing'!
+
+isTestSelector:aSelector
+ ^ (super isTestSelector:aSelector) or:[ aSelector startsWith: 'example' ]
+
+ "Created: / 03-08-2015 / 09:25:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!LLVMExamples methodsFor:'examples'!
example1_sum
+ "
+ Creates a simple function taking two arguments (as intptr_t) and returning
+ their sum (as intptr_t).
+ "
+
| module functionType function functionEntry asm jit externalFunction |
- module := LLVMModule newWithName: thisContext selector.
+ "/ 1) create a module to which the function would belong. A module is
+ "/ a set of functions and globals that are compiled at once by the MCJIT. Once
+ "/ module is compiled, no more methods or clobals can be added.
+
+ module := LLVMModule newWithName: testSelector.
+
+ "/ 2) Define a function within the module with type (intptr_t, intptr_t) -> intptr_t
functionType := LLVMType function: { LLVMType intptr . LLVMType intptr } returning: LLVMType intptr.
function := module addFunctionNamed: 'sum' type: functionType.
+ "/ 3) Generate function code. LLVM IR does not work with
+ "/ labels / jumps to labels but rather the user is responsible
+ "/ for creating basic blocks and adding them to the function.
+ "/ Hence, create a basic block named 'entry'
functionEntry := function addBasicBlockNamed: 'entry'.
+
+ "/ 4) To emit LLVM IR, create an IR builder and position it
+ "/ to the end of just created basic block.
asm := LLVMBuilder new.
asm positionAtEnd: functionEntry.
asm ret: (asm add: (function parameterAt: 1) and: (function parameterAt: 2)).
+ "/ Now, the module should look like
+ self assert: (module dumpString =
+'; ModuleID = ''example1_sum''
+define i64 @sum(i64, i64) {
+entry:
+ %2 = add i64 %0, %1
+ ret i64 %2
+}
+').
+
+
+ "/ 5) To compile a function (strictly speaking, whole module) at runtime,
+ "/ create a jit object (called ExecutionEngine in LLVM)
jit := LLVMExecutionEngine newForModule: module.
+
+ "/ 6) Finally, obtain a reference to the function. This cause
+ "/ the module to be closed and compiled to machine code.
externalFunction := jit externalOfFunction: function.
- ^ externalFunction callWith: 3 with: 4.
+ self assert: (externalFunction callWith: 3 with: 4) == 7
"
LLVMExamples example1_sum
"
"Created: / 17-07-2015 / 11:47:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 03-08-2015 / 10:29:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
example2_function_call
+ "
+ Creates a module with two functions, @sum and @sum_caller. The latter
+ calls the former.
+ "
| module calleeFunctionType calleeFunction calleFunctionEntry
callerFunctionType callerFunction callerFunctionEntry
asm jit externalFunction |
- module := LLVMModule newWithName: thisContext selector.
+ module := LLVMModule newWithName: testSelector.
calleeFunctionType := LLVMType function: { LLVMType intptr . LLVMType intptr } returning: LLVMType intptr.
calleeFunction := module addFunctionNamed: 'sum' type: calleeFunctionType.
@@ -88,49 +135,73 @@
asm := LLVMBuilder new.
asm positionAtEnd: callerFunctionEntry.
asm ret: (asm call: calleeFunction with: (callerFunction parameterAt: 1) with: (callerFunction parameterAt: 2)).
+ self assert: (module dumpString =
+'; ModuleID = ''example2_function_call''
+define i64 @sum(i64, i64) {
+entry:
+ %2 = add i64 %0, %1
+ ret i64 %2
+}
+
+define i64 @sum_caller(i64, i64) {
+entry:
+ %2 = call i64 @sum(i64 %0, i64 %1)
+ ret i64 %2
+}
+').
jit := LLVMExecutionEngine newForModule: module.
externalFunction := jit externalOfFunction: callerFunction.
- ^ externalFunction callWith: 3 with: 4.
+ self assert: (externalFunction callWith: 3 with: 4) == 7.
"
LLVMExamples example2_function_call
"
"Created: / 17-07-2015 / 12:45:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
- "Modified: / 17-07-2015 / 17:18:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 03-08-2015 / 10:29:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
-example3_function_call
+example3_hello_world
+ "
+ Creates a function @main() which calls @printf() to print
+ a famous 'Hello World!!' message on stdout
+ "
+
| module printfFunctionType printfFunction
- callerFunctionType callerFunction callerFunctionEntry
- asm jit externalFunction |
+ helloWorldString
+ mainFunctionType mainFunction mainFunctionEntry
+ asm jit externalFunction |
- module := LLVMModule newWithName: thisContext selector.
+ module := LLVMModule newWithName: testSelector.
- printfFunctionType := LLVMType function: { LLVMType intptr . LLVMType intptr } returning: LLVMType intptr.
- printfFunction := module addFunctionNamed: 'sum' type: printfFunctionType.
+ printfFunctionType := LLVMType function: #() returning: LLVMType int32.
+ printfFunction := module addFunctionNamed: 'printf' type: printfFunctionType.
- callerFunctionType := LLVMType function: { LLVMType intptr . LLVMType intptr } returning: LLVMType intptr.
- callerFunction := module addFunctionNamed: 'sum_caller' type: callerFunctionType.
+ helloWorldString := module addGlobalNamed: '.str' value: (LLVMConstant string: 'Hello World!!\n').
- callerFunctionEntry := callerFunction addBasicBlockNamed: 'entry'.
+ mainFunctionType := LLVMType function: #() returning: LLVMType intptr.
+ mainFunction := module addFunctionNamed: 'main' type: mainFunctionType.
+
+ mainFunctionEntry := mainFunction addBasicBlockNamed: 'entry'.
asm := LLVMBuilder new.
- asm positionAtEnd: callerFunctionEntry.
- asm ret: (asm call: printfFunction with: (callerFunction parameterAt: 1) with: (callerFunction parameterAt: 2)).
-
+ asm positionAtEnd: mainFunctionEntry.
+ asm call: printfFunction with: helloWorldString.
+ asm ret: (LLVMConstant sint32: 0).
jit := LLVMExecutionEngine newForModule: module.
- externalFunction := jit externalOfFunction: callerFunction.
+ externalFunction := jit externalOfFunction: mainFunction.
- ^ externalFunction callWith: 3 with: 4.
+ externalFunction call.
+ Stdout flush
"
- LLVMExamples example2_function_call
+ LLVMExamples example3_hello_world
"
- "Created: / 17-07-2015 / 17:21:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Created: / 03-08-2015 / 10:28:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 03-08-2015 / 18:00:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !