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 |
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 |