56
きつねさんでもわかる LLVM読書会 第2回 2013/7/6 cuzic

きつねさんでもわかるLlvm読書会 第2回

Embed Size (px)

DESCRIPTION

参考:  https://github.com/ruby-llvm/ruby-llvm/tree/master/samples  https://github.com/Kmotiko/DummyCCompiler  http://kschiess.github.io/parslet/  https://github.com/ruby-llvm/ruby-llvm   https://github.com/cuzic/llvm-kitsunesan

Citation preview

  • 1. LLVM 2013/7/6 cuzic

2. 2013/7/6 2 LLVM Ruby TRICK TRICK: Ruby IOCCC Ruby amagasakirb 10 Land of Lisp 1 3. 2013/7/6 2 LLVM LLVM Ruby-LLVM LLVM LLVM Ruby-LLVM Hello, World Parslet Ruby-LLVM PEG Parslet Parslet LLVM Pass Pass Pass Pass 2 4. 2013/7/6 2 LLVM LLVM Ruby-LLVM 3 5. 2013/7/6 2 LLVM LLVM LLVM BSD C++ LLVM CoreClang etc LLVM Core LLVM IR LLVM IR C++ Clang LLVM 4 6. 2013/7/6 2 LLVM Debian 7.0 (Wheezy) aptitude aptitude install llvm 3.0 llvm-3.1 -3.1 suffix llvm-config llvm-config-3.1 PATH alias 5 sudo aptitude install llvm-3.1 llvm-3.1-dev llvm-3.1-doc llvm-3.1-examples llvm-3.1-runtime llvm-3.1-source $ export PATH=/usr/lib/llvm-3.1/bin:$PATH ### LLVM $ sudo cat >> /etc/apt/sources.list deb http://llvm.org/apt/wheezy/ llvm-toolchain-wheezy main deb-src http://llvm.org/apt/wheezy/ llvm-toolchain-wheezy main ^D $ sudo aptitude install llvm-3.3 sudo aptitude install llvm-3.1 llvm-3.1-dev llvm-3.1-doc llvm-3.1-examples llvm-3.1-runtime llvm-3.1-source $ export PATH=/usr/lib/llvm-3.1/bin:$PATH ### LLVM $ sudo cat >> /etc/apt/sources.list deb http://llvm.org/apt/wheezy/ llvm-toolchain-wheezy main deb-src http://llvm.org/apt/wheezy/ llvm-toolchain-wheezy main ^D $ sudo aptitude install llvm-3.3 7. 2013/7/6 2 LLVM Ruby-LLVM Ruby LLVM LLVM IR LLVM JIT Compiler treetopcitrusrsecparslet Ruby-LLVM 6 ### Ruby-LLVM $ export PATH=/usr/lib/llvm-3.1/bin:$PATH $ gem install ruby-llvm ### Ruby-LLVM $ export PATH=/usr/lib/llvm-3.1/bin:$PATH $ gem install ruby-llvm 8. 2013/7/6 2 LLVM LLVM IR http://www.aosabook.org/en/llvm.html 7 define i32 @add1(i32 %a, i32 %b) { entry: %tmp1 = add i32 %a, %b ret i32 %tmp1 } define i32 @add2(i32 %a, i32 %b) { entry: %tmp1 = icmp eq i32 %a, 0 br i1 %tmp1, label %done, label %recurse recurse: %tmp2 = sub i32 %a, 1 %tmp3 = add i32 %b, 1 %tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3) ret i32 %tmp4 done: ret i32 %b } define i32 @add1(i32 %a, i32 %b) { entry: %tmp1 = add i32 %a, %b ret i32 %tmp1 } define i32 @add2(i32 %a, i32 %b) { entry: %tmp1 = icmp eq i32 %a, 0 br i1 %tmp1, label %done, label %recurse recurse: %tmp2 = sub i32 %a, 1 %tmp3 = add i32 %b, 1 %tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3) ret i32 %tmp4 done: ret i32 %b } unsigned add1(unsigned a, unsigned b) { return a+b; } // not efficient way to add two numbers. unsigned add2(unsigned a, unsigned b) { if (a == 0) return b; return add2(a-1, b+1); } 9. 2013/7/6 2 LLVM Module, Function, Basic Block, Instruction 8 define i32 @add1(i32 %a, i32 %b) { entry: %tmp1 = add i32 %a, %b ret i32 %tmp1 } define i32 @add2(i32 %a, i32 %b) { entry: %tmp1 = icmp eq i32 %a, 0 br i1 %tmp1, label %done, label %recurse recurse: %tmp2 = sub i32 %a, 1 %tmp3 = add i32 %b, 1 %tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3) ret i32 %tmp4 done: ret i32 %b } define i32 @add1(i32 %a, i32 %b) { entry: %tmp1 = add i32 %a, %b ret i32 %tmp1 } define i32 @add2(i32 %a, i32 %b) { entry: %tmp1 = icmp eq i32 %a, 0 br i1 %tmp1, label %done, label %recurse recurse: %tmp2 = sub i32 %a, 1 %tmp3 = add i32 %b, 1 %tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3) ret i32 %tmp4 done: ret i32 %b } ModuleFunction Basic Block Instruction 10. 2013/7/6 2 LLVM Module, Function, Basic Block, Instruction LLVM IR Module Module Function GlobalVariable Function or Basic Block Basic Block retbrswitch Basic Block Basic Block Basic Block Instruction Instruction 9 11. 2013/7/6 2 LLVM Ruby-LLVM LLVM IR LLVM::Module Module Module Function Module#functions.add Function Function BasicBlock Function#basic_blocks.append BasicBlock build Builder Instruction Instruction return JIT LLVM.init_x86 ; JITCompiler.new(m).run_function(func, args) args m func 10 12. 2013/7/6 2 LLVM LLVM Hello, World Hello, World Ruby-LLVM http://llvm.org/docs/LangRef.html#module-structure 11 ; Declare the string constant as a global constant. @.str = private unnamed_addr constant [13 x i8] c"hello world0A00" ; External declaration of the puts function declare i32 @puts(i8* nocapture) nounwind ; Definition of main function define i32 @main() { ; i32()* ; Convert [13 x i8]* to i8 *... %cast210 = getelementptr [13 x i8]* @.str, i64 0, i64 0 ; Call puts function to write out the string to stdout. call i32 @puts(i8* %cast210) ret i32 0 } ; Named metadata !1 = metadata !{i32 42} !foo = !{!1, null} ; Declare the string constant as a global constant. @.str = private unnamed_addr constant [13 x i8] c"hello world0A00" ; External declaration of the puts function declare i32 @puts(i8* nocapture) nounwind ; Definition of main function define i32 @main() { ; i32()* ; Convert [13 x i8]* to i8 *... %cast210 = getelementptr [13 x i8]* @.str, i64 0, i64 0 ; Call puts function to write out the string to stdout. call i32 @puts(i8* %cast210) ret i32 0 } ; Named metadata !1 = metadata !{i32 42} !foo = !{!1, null} 13. 2013/7/6 2 LLVM Ruby-LLVM Hello, World 12 gem 'ruby-llvm' require 'llvm/core' require 'llvm/execution_engine' m = LLVM::Module.new('hello') str = "Hello, World!" llvm_str_type = LLVM.Array(LLVM::Int8, str.size + 1) llvm_g_str = m.globals.add(llvm_str_type, ".str") llvm_g_str.initializer = LLVM::ConstantArray.string(str) arg_types = [LLVM.Pointer(LLVM::Int8)] cputs = m.functions.add('puts', arg_types, LLVM::Int32) # Definition of main function main = m.functions.add('main', [], LLVM::Int32) do |function| entryBB = function.basic_blocks.append entryBB.build do |builder| zero = LLVM.Int(0) # GetElementPointer(gep) cast210 = builder.gep llvm_g_str, [zero, zero], 'cast210' builder.call cputs, cast210 builder.ret zero end end m.verify m.dump puts "-----------------------------------------------------" LLVM.init_x86 LLVM::JITCompiler.new(m).run_function(m.functions["main"], *[]) gem 'ruby-llvm' require 'llvm/core' require 'llvm/execution_engine' m = LLVM::Module.new('hello') str = "Hello, World!" llvm_str_type = LLVM.Array(LLVM::Int8, str.size + 1) llvm_g_str = m.globals.add(llvm_str_type, ".str") llvm_g_str.initializer = LLVM::ConstantArray.string(str) arg_types = [LLVM.Pointer(LLVM::Int8)] cputs = m.functions.add('puts', arg_types, LLVM::Int32) # Definition of main function main = m.functions.add('main', [], LLVM::Int32) do |function| entryBB = function.basic_blocks.append entryBB.build do |builder| zero = LLVM.Int(0) # GetElementPointer(gep) cast210 = builder.gep llvm_g_str, [zero, zero], 'cast210' builder.call cputs, cast210 builder.ret zero end end m.verify m.dump puts "-----------------------------------------------------" LLVM.init_x86 LLVM::JITCompiler.new(m).run_function(m.functions["main"], *[]) 14. 2013/7/6 2 LLVM 13 15. 2013/7/6 2 LLVM Ruby-LLVM Hello, World m LLVM Module 14 gem 'ruby-llvm' require 'llvm/core' require 'llvm/execution_engine' m = LLVM::Module.new('hello') gem 'ruby-llvm' require 'llvm/core' require 'llvm/execution_engine' m = LLVM::Module.new('hello') 16. 2013/7/6 2 LLVM Ruby-LLVM Hello, World hello Module LLVM LLVM.Array(LLVM::Int8, str.size + 1) m.globals.add ".str" ".str" "Hello, World!" 15 # generate global string "Hello, World!" str = "Hello, World!" llvm_str_type = LLVM.Array(LLVM::Int8, str.size + 1) llvm_g_str = m.globals.add(llvm_str_type, ".str") llvm_g_str.initializer = LLVM::ConstantArray.String(str) # generate global string "Hello, World!" str = "Hello, World!" llvm_str_type = LLVM.Array(LLVM::Int8, str.size + 1) llvm_g_str = m.globals.add(llvm_str_type, ".str") llvm_g_str.initializer = LLVM::ConstantArray.String(str) 17. 2013/7/6 2 LLVM Ruby-LLVM Hello, World puts m.functions LLVM::Module::FunctionCollection FunctionCollection#add LLVM LLVM LLVM::Function 16 # External Declaration of the `puts` function arg_types = [LLVM.Pointer(LLVM::Int8)] cputs = m.functions.add('puts', arg_types, LLVM::Int32) # External Declaration of the `puts` function arg_types = [LLVM.Pointer(LLVM::Int8)] cputs = m.functions.add('puts', arg_types, LLVM::Int32) extern int puts(const char *s);extern int puts(const char *s); 18. 2013/7/6 2 LLVM Ruby-LLVM Hello, World function.basic_blocks : LLVM::Function::BasicBlockCollection BasicBlock#build : LLVM::Builder builder.gep 17 # Definition of main function main = m.functions.add('main', [], LLVM::Int32) do |function| entryBB = function.basic_blocks.append entryBB.build do |builder| zero = LLVM.Int(0) # GetElementPointer(gep) cast210 = builder.gep llvm_g_str, [zero, zero], 'cast210' builder.call cputs, cast210 builder.ret zero end end # Definition of main function main = m.functions.add('main', [], LLVM::Int32) do |function| entryBB = function.basic_blocks.append entryBB.build do |builder| zero = LLVM.Int(0) # GetElementPointer(gep) cast210 = builder.gep llvm_g_str, [zero, zero], 'cast210' builder.call cputs, cast210 builder.ret zero end end 19. 2013/7/6 2 LLVM Ruby-LLVM Hello, World LLVM::Module#verify Module valid LLVM::Module#dump Module IR 18 m.verify m.dump m.verify m.dump 20. 2013/7/6 2 LLVM Ruby-LLVM Hello, World LLVM.init_x86 JITCompiler.new(m).run_function(main, args) main 19 LLVM.init_x86 LLVM::JITCompiler.new(m).run_function(m.functions["main"], *[]) LLVM.init_x86 LLVM::JITCompiler.new(m).run_function(m.functions["main"], *[]) 21. 2013/7/6 2 LLVM Ruby-LLVM Hello, World 20 gem 'ruby-llvm' require 'llvm/core' require 'llvm/execution_engine' m = LLVM::Module.new('hello') str = "Hello, World!" llvm_str_type = LLVM.Array(LLVM::Int8, str.size + 1) llvm_g_str = m.globals.add(llvm_str_type, ".str") llvm_g_str.initializer = LLVM::ConstantArray.string(str) arg_types = [LLVM.Pointer(LLVM::Int8)] cputs = m.functions.add('puts', arg_types, LLVM::Int32) # Definition of main function main = m.functions.add('main', [], LLVM::Int32) do |function| entryBB = function.basic_blocks.append entryBB.build do |builder| zero = LLVM.Int(0) # GetElementPointer(gep) cast210 = builder.gep llvm_g_str, [zero, zero], 'cast210' builder.call cputs, cast210 builder.ret zero end end m.verify m.dump puts "-----------------------------------------------------" LLVM.init_x86 LLVM::JITCompiler.new(m).run_function(m.functions["main"], *[]) gem 'ruby-llvm' require 'llvm/core' require 'llvm/execution_engine' m = LLVM::Module.new('hello') str = "Hello, World!" llvm_str_type = LLVM.Array(LLVM::Int8, str.size + 1) llvm_g_str = m.globals.add(llvm_str_type, ".str") llvm_g_str.initializer = LLVM::ConstantArray.string(str) arg_types = [LLVM.Pointer(LLVM::Int8)] cputs = m.functions.add('puts', arg_types, LLVM::Int32) # Definition of main function main = m.functions.add('main', [], LLVM::Int32) do |function| entryBB = function.basic_blocks.append entryBB.build do |builder| zero = LLVM.Int(0) # GetElementPointer(gep) cast210 = builder.gep llvm_g_str, [zero, zero], 'cast210' builder.call cputs, cast210 builder.ret zero end end m.verify m.dump puts "-----------------------------------------------------" LLVM.init_x86 LLVM::JITCompiler.new(m).run_function(m.functions["main"], *[]) 22. 2013/7/6 2 LLVM Ruby-LLVM Hello, World Ruby-LLVM LLVM IR 21 ; ModuleID = 'hello' @.str = global [14 x i8] c"Hello, World!00" declare i32 @puts(i8*) define i32 @main() { %1 = call i32 @puts(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ret i32 0 } ----------------------------------------------------- Hello, World! ; ModuleID = 'hello' @.str = global [14 x i8] c"Hello, World!00" declare i32 @puts(i8*) define i32 @main() { %1 = call i32 @puts(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ret i32 0 } ----------------------------------------------------- Hello, World! 23. 2013/7/6 2 LLVM LLVM LLVM IR br Basic Block phi Basic Block 22 ; ModuleID = 'Factorial' define i32 @fac(i32 %n) { entry: %test = icmp eq i32 %n, 1 br i1 %test, label %result, label %recur recur: ; preds = %entry %n-1 = sub i32 %n, 1 %"fac(n-1)" = call i32 @fac(i32 %n-1) %"n*fac(n-1)" = mul i32 %n, %"fac(n-1)" br label %result result: ; preds = %recur, %entry %fac = phi i32 [ 1, %entry ], [ %"n*fac(n-1)", %recur ] ret i32 %fac } ; ModuleID = 'Factorial' define i32 @fac(i32 %n) { entry: %test = icmp eq i32 %n, 1 br i1 %test, label %result, label %recur recur: ; preds = %entry %n-1 = sub i32 %n, 1 %"fac(n-1)" = call i32 @fac(i32 %n-1) %"n*fac(n-1)" = mul i32 %n, %"fac(n-1)" br label %result result: ; preds = %recur, %entry %fac = phi i32 [ 1, %entry ], [ %"n*fac(n-1)", %recur ] ret i32 %fac } int factorial(int n) { if (n == 0) return 1; return n*factorial(n-1); } 24. 2013/7/6 2 LLVM Ruby LLVM 23 m = LLVM::Module.new("Factorial") m.functions.add("fac", [LLVM::Int], LLVM::Int) do |fac, n| n.name = "n" bb = fac.basic_blocks entryBB = bb.append("entry") recurBB = bb.append("recur") resultBB = bb.append("result") n_fac_n_1 = nil entryBB.build do |builder| test = builder.icmp(:eq, n, LLVM::Int(1), "test") builder.cond(test, result, recur) end recurBB.build do |builder| n_1 = builder.sub(n, LLVM::Int(1), "n-1") fac_n_1 = builder.call(fac, n_1, "fac(n-1)") n_fac_n_1 = builder.mul(n, fac_n_1, "n*fac(n-1)") builder.br(result) end resultBB.build do |builder| fac = builder.phi(LLVM::Int, {entry => LLVM::Int(1), recur => n_fac_n_1 }, "fac") builder.ret(fac) end end m = LLVM::Module.new("Factorial") m.functions.add("fac", [LLVM::Int], LLVM::Int) do |fac, n| n.name = "n" bb = fac.basic_blocks entryBB = bb.append("entry") recurBB = bb.append("recur") resultBB = bb.append("result") n_fac_n_1 = nil entryBB.build do |builder| test = builder.icmp(:eq, n, LLVM::Int(1), "test") builder.cond(test, result, recur) end recurBB.build do |builder| n_1 = builder.sub(n, LLVM::Int(1), "n-1") fac_n_1 = builder.call(fac, n_1, "fac(n-1)") n_fac_n_1 = builder.mul(n, fac_n_1, "n*fac(n-1)") builder.br(result) end resultBB.build do |builder| fac = builder.phi(LLVM::Int, {entry => LLVM::Int(1), recur => n_fac_n_1 }, "fac") builder.ret(fac) end end 25. 2013/7/6 2 LLVM LLVM LLVM::Builder#br( basic_block) basic_block LLVM::Builder#cond( test, result, recur) test true result, false recur LLVM::Builder#phi(type, params, name) basic block 24 builder.cond(test, result, recur)builder.cond(test, result, recur) builder.br(result)builder.br(result) fac = builder.phi(LLVM::Int, {entry => LLVM::Int(1), recur => n_fac_n_1 }, "fac") fac = builder.phi(LLVM::Int, {entry => LLVM::Int(1), recur => n_fac_n_1 }, "fac") 26. 2013/7/6 2 LLVM 25 27. 2013/7/6 2 LLVM LLVM Ruby-LLVM LLVM LLVM IR ModuleFunctionBasic Block Module Function Function Basic Block Basic Block Instruction Ruby-LLVM LLVM LLVM IR JIT LLVM Ruby-LLVM LLVM IR LLVM IR br Ruby-LLVM cond phi 2 26 28. 2013/7/6 2 LLVM Parslet Ruby-LLVM 27 29. 2013/7/6 2 LLVM Parslet Parslet PEG (Parsing Expression Grammer) Ruby DSL PEG TreeTop: Ruby citrus: Ruby rsecRubyDSL parser transformer Ruby 28 30. 2013/7/6 2 LLVM Parslet Int +-*/ Int */ +- Ruby-LLVM LLVM BasicBlock#build LLVM Transformer rule BasicBlock#build Fiber 29 31. 2013/7/6 2 LLVM Parser 30 class Parser < Parslet::Parser rule(:space) { match('s').repeat(1) } rule(:sp) { space.maybe } rule(:integer) { match('[0-9]').repeat(1).as(:int) } rule(:mul) { integer.as(:left) >> sp >> match('[*/]').as(:op) >> sp >> multiplication.as(:right) } rule(:add) { multiplication.as(:left) >> sp >> match('[+-]').as(:op) >> sp >> addition.as(:right) } rule(:multiplication) { mul | integer } rule(:addition) { add | multiplication } rule(:expression) { addition.as(:expr) } root :expression end class Parser < Parslet::Parser rule(:space) { match('s').repeat(1) } rule(:sp) { space.maybe } rule(:integer) { match('[0-9]').repeat(1).as(:int) } rule(:mul) { integer.as(:left) >> sp >> match('[*/]').as(:op) >> sp >> multiplication.as(:right) } rule(:add) { multiplication.as(:left) >> sp >> match('[+-]').as(:op) >> sp >> addition.as(:right) } rule(:multiplication) { mul | integer } rule(:addition) { add | multiplication } rule(:expression) { addition.as(:expr) } root :expression end 32. 2013/7/6 2 LLVM Transformer LLVM LLVMBuilder rule 31 class LLVMTransformer simple(:n)){ b.int n } rule(:left => simple(:l), :right => simple(:r), :op => simple(:op)){ b.calc op, l, r } rule(:expr => simple(x)){ b.ret x } def do(tree) apply(tree) @@builder.dump end end class LLVMTransformer simple(:n)){ b.int n } rule(:left => simple(:l), :right => simple(:r), :op => simple(:op)){ b.calc op, l, r } rule(:expr => simple(x)){ b.ret x } def do(tree) apply(tree) @@builder.dump end end "int" LLVM "left" "right" "op" LLVM 33. 2013/7/6 2 LLVM LLVMBuilder LLVMBuilder LLVM building_loop rule 32 class LLVMBuilder def initialize @fiber = Fiber.new do @module = LLVM::Module.new("calculator") @module.functions.add("add", [], LLVM::Int) do |f,| bb = f.basic_blocks.append("entry") bb.build do |builder| building_loop builder end end end @fiber.resume end ... end class LLVMBuilder def initialize @fiber = Fiber.new do @module = LLVM::Module.new("calculator") @module.functions.add("add", [], LLVM::Int) do |f,| bb = f.basic_blocks.append("entry") bb.build do |builder| building_loop builder end end end @fiber.resume end ... end Fiber 1. Module 2. Function 3. Basic Block 4. Builder LLVM building_loop Fiber 34. 2013/7/6 2 LLVM LLVMBuilder 33 def building_loop builder llvm_ir = nil loop do op, l, r = Fiber.yield llvm_ir case op when "+" llvm_ir = builder.add l, r when "-" llvm_ir = builder.sub l, r when '*' llvm_ir = builder.mul l, r when "/" llvm_ir = builder.sdiv l, r when :exit llvm_ir = builder.ret l break end end end def building_loop builder llvm_ir = nil loop do op, l, r = Fiber.yield llvm_ir case op when "+" llvm_ir = builder.add l, r when "-" llvm_ir = builder.sub l, r when '*' llvm_ir = builder.mul l, r when "/" llvm_ir = builder.sdiv l, r when :exit llvm_ir = builder.ret l break end end end Fiber Fiber Fiber.yield Fiber Fiber.yield LLVM return LLVM 35. 2013/7/6 2 LLVM LLVMBuilder Fiber calc ret calc LLVM ret LLVM 34 def int n LLVM.Int n.to_i end def calc op, l, r @fiber.resume op, l, r end def ret x @fiber.resume :exit, x end def dump @module.dump end def int n LLVM.Int n.to_i end def calc op, l, r @fiber.resume op, l, r end def ret x @fiber.resume :exit, x end def dump @module.dump end Fiber Fiber Fiber LLVM Ruby LLVM 36. 2013/7/6 2 LLVM 35 37. 2013/7/6 2 LLVM Parslet Ruby-LLVM Parslet Ruby PEG DSL Ruby Hash Ruby-LLVM Basic Block Parslet DSL Fiber 36 38. 2013/7/6 2 LLVM LLVM Pass 37 39. 2013/7/6 2 LLVM Pass Pass LLVM IR Pass Immutable Pass LLVM IR Pass Module Pass PassFunction Function Pass Function Pass Loop Pass Function Loop Pass Region Pass Function Region Pass BasicBlockPass BasicBlock() Pass 38 40. 2013/7/6 2 LLVM easypass.hpp FunctionPass EasyPass runOnFunction Function 39 #include #include #include using namespace llvm; class EasyPass : public FunctionPass{ public: static char ID; EasyPass() : FunctionPass(ID){} ~EasyPass(){} virtual bool runOnFunction(Function &F); }; #include #include #include using namespace llvm; class EasyPass : public FunctionPass{ public: static char ID; EasyPass() : FunctionPass(ID){} ~EasyPass(){} virtual bool runOnFunction(Function &F); }; FunctionPass Pass Function Function EasyPass FunctionPass llvm 41. 2013/7/6 2 LLVM easypass.cpp Function RegisterPass EasyPass EasyPass 40 #include "easypass.hpp" bool EasyPass::runOnFunction(Function &F){ fprintf(stderr, "Function Name : %sn", F.getName().str().c_str()); return false; } // char EasyPass::ID=0; static RegisterPass X("easypass", "easy pass:only print function name", false , false); #include "easypass.hpp" bool EasyPass::runOnFunction(Function &F){ fprintf(stderr, "Function Name : %sn", F.getName().str().c_str()); return false; } // char EasyPass::ID=0; static RegisterPass X("easypass", "easy pass:only print function name", false , false); easypass.hpp RegisterPass EasyPass Pass help CFG true true ID 42. 2013/7/6 2 LLVM easypass 41 $ LLVM_DIR=/usr/lib/llvm-3.1 $ CXXFLAGS=`${LLVM_DIR}/bin/llvm-config --cxxflags` $ g++ -g ./src/easypass.cpp I./inc ${CXXFLAGS} c o ./obj/easypass.o $ g++ -g shared o ./bin/easypass.so ./obj/easypass.o $ LLVM_DIR=/usr/lib/llvm-3.1 $ CXXFLAGS=`${LLVM_DIR}/bin/llvm-config --cxxflags` $ g++ -g ./src/easypass.cpp I./inc ${CXXFLAGS} c o ./obj/easypass.o $ g++ -g shared o ./bin/easypass.so ./obj/easypass.o $ ${LLVM_DIR}/bin/opt load ./bin/easypass.so easypass debug-pass=Structure ./sample/test.ll S > /dev/null $ ${LLVM_DIR}/bin/opt load ./bin/easypass.so easypass debug-pass=Structure ./sample/test.ll S > /dev/null Pass Arguments: -targetlibinfo -easypass -preverify -domtree -verify -print-module Target Library Information ModulePass Manager FunctionPass Manager easy pass:only print function name Preliminary module verification Dominator Tree Construction Module Verifier Print module to stderr Function Name : test Function Name : main Pass Arguments: -targetlibinfo -easypass -preverify -domtree -verify -print-module Target Library Information ModulePass Manager FunctionPass Manager easy pass:only print function name Preliminary module verification Dominator Tree Construction Module Verifier Print module to stderr Function Name : test Function Name : main -shared -load so -easypass -debug-pass=Structure easypass Function Pass easypass 43. 2013/7/6 2 LLVM 42 44. 2013/7/6 2 LLVM ModulePass ModulePass Function Function ModulePass runOnModule Module true runOnXX 43 namespace llvm{ class ModulePass{ virtual bool runOnModule(Module &M) = 0; } } namespace llvm{ class ModulePass{ virtual bool runOnModule(Module &M) = 0; } } 45. 2013/7/6 2 LLVM FunctionPass FunctionPass Function Pass Function Function Module Function Module runOnFunction runOnFunction Function Function true 44 namespace llvm{ class FunctionPass{ virtual bool doInitialization(Module &M); virtual bool runOnFunction(Function &F) = 0; virtual bool doFinalization(Module &M); } } namespace llvm{ class FunctionPass{ virtual bool doInitialization(Module &M); virtual bool runOnFunction(Function &F) = 0; virtual bool doFinalization(Module &M); } } 46. 2013/7/6 2 LLVM LoopPass LoopPass Function Loop LPPassManager Loop Function Module runOnLoop Function Loop true 45 namespace llvm{ class LoopPass{ virtual bool doInitialization(Loop *, LPPassManager &LPM); virtual bool runOnLoop(Loop *, LPPassManager &LPM) = 0; virtual bool doFinalization(); } } namespace llvm{ class LoopPass{ virtual bool doInitialization(Loop *, LPPassManager &LPM); virtual bool runOnLoop(Loop *, LPPassManager &LPM) = 0; virtual bool doFinalization(); } } 47. 2013/7/6 2 LLVM RegionPass RegionPass LoopPass Region RGPassManager RegionTree Function Module runOnRegion Function Loop true 46 namespace llvm{ class RegionPass{ virtual bool doInitialization(Region *R, RGPassManager &RGM); virtual bool runOnRegion(Region *R, RGPassManager &RGM) = 0; virtual bool doFinalization(); } } namespace llvm{ class RegionPass{ virtual bool doInitialization(Region *R, RGPassManager &RGM); virtual bool runOnRegion(Region *R, RGPassManager &RGM) = 0; virtual bool doFinalization(); } } 48. 2013/7/6 2 LLVM BasicBlockPass BasicBlockPass FunctionPass BasicBlock BasicBlock runOnBasicBlock BasicBlock true 47 namespace llvm{ class BasicBlockPass{ virtual bool doInitialization(Function &F); virtual bool runOnBasicBlock(BasicBlock &BB) = 0; virtual bool doFinalization(Function &F); } } namespace llvm{ class BasicBlockPass{ virtual bool doInitialization(Function &F); virtual bool runOnBasicBlock(BasicBlock &BB) = 0; virtual bool doFinalization(Function &F); } } 49. 2013/7/6 2 LLVM Pass Pass::getAnalysisUsage Pass Pass Pass AnalysisUsage::addRequired Pass Pass AnalysisUsage::addRequiredTransive Pass Pass AnalysisUsage::addPreserved Pass Pass::getAnalysis addRequired Pass RegisterPass Pass 48 50. 2013/7/6 2 LLVM Pass opt Pass 49 $ llvm-as < /dev/null | opt -std-compile-opts -disable-output -debug-pass=Arguments Pass Arguments: -targetlibinfo -no-aa -tbaa -basicaa -preverify - domtree -verify -globalopt -ipsccp -deadargelim -instcombine - simplifycfg -basiccg -prune-eh -inline -functionattrs -argpromotion -scalarrepl-ssa -domtree -early-cse -simplify-libcalls -lazy-value- info -jump-threading -correlated-propagation -simplifycfg - instcombine -tailcallelim -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch - instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop- idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt - sccp -instcombine -lazy-value-info -jump-threading -correlated- propagation -domtree -memdep -dse -adce -simplifycfg -instcombine - strip-dead-prototypes -globaldce -constmerge -preverify -domtree - verify $ llvm-as < /dev/null | opt -std-compile-opts -disable-output -debug-pass=Arguments Pass Arguments: -targetlibinfo -no-aa -tbaa -basicaa -preverify - domtree -verify -globalopt -ipsccp -deadargelim -instcombine - simplifycfg -basiccg -prune-eh -inline -functionattrs -argpromotion -scalarrepl-ssa -domtree -early-cse -simplify-libcalls -lazy-value- info -jump-threading -correlated-propagation -simplifycfg - instcombine -tailcallelim -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch - instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop- idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt - sccp -instcombine -lazy-value-info -jump-threading -correlated- propagation -domtree -memdep -dse -adce -simplifycfg -instcombine - strip-dead-prototypes -globaldce -constmerge -preverify -domtree - verify 51. 2013/7/6 2 LLVM Pass -instcombine 2 +1 +2 -simplifycfg Call Flow Graph Basic Block Basic Block -inline caller -jump-threading if(true){ X=4; } if( X < 3 ){ } -indvars for(i=7; i*I < 1000; ++i) for(i=0; i < 25; ++i) -licm for( ){ x = y + z; } x = y + z; for( ){ } -loop-unswitch for( ){ A; if(test) B; C} if(test){for() {A; B; C;}} else{for() {A; C}} -loop-unroll http://ja.wikipedia.org/wiki/ 50 52. 2013/7/6 2 LLVM instcombine 1 + 1 2 51 int two(void){ int one = 1; return one + 1; } int two(void){ int one = 1; return one + 1; } ; (snip) define i32 @two() nounwind { %one = alloca i32, align 4 store i32 1, i32* %one, align 4 %1 = load i32* %one, align 4 %2 = add nsw i32 %1, 1 ret i32 %2 } ; (snip) define i32 @two() nounwind { %one = alloca i32, align 4 store i32 1, i32* %one, align 4 %1 = load i32* %one, align 4 %2 = add nsw i32 %1, 1 ret i32 %2 }; (snip) define i32 @two() nounwind { ret i32 2 } ; (snip) define i32 @two() nounwind { ret i32 2 } clang cc1 instcombine.c emit-llvm opt instcombine instcombine.ll | llvm-dis 53. 2013/7/6 2 LLVM inline one() 52 static int one(void){ return 1; } int two(void){ return one() + 1; } static int one(void){ return 1; } int two(void){ return one() + 1; } ModuleID = 'inline.c' target datalayout = "(snip)" target triple = "x86_64-pc-linux-gnu" define i32 @two() nounwind { %1 = call i32 @one() %2 = add nsw i32 %1, 1 ret i32 %2 } define internal i32 @one() nounwind { ret i32 1 } ModuleID = 'inline.c' target datalayout = "(snip)" target triple = "x86_64-pc-linux-gnu" define i32 @two() nounwind { %1 = call i32 @one() %2 = add nsw i32 %1, 1 ret i32 %2 } define internal i32 @one() nounwind { ret i32 1 } ; (snip) define i32 @two() nounwind { %1 = add nsw i32 1, 1 ret i32 %1 } ; (snip) define i32 @two() nounwind { %1 = add nsw i32 1, 1 ret i32 %1 } opt inline inline.ll | llvm-dis 54. 2013/7/6 2 LLVM simplifycfg return 2 Basic Block 53 int two(void){ int one = 1; if(one) return 2; else return 2; } int two(void){ int one = 1; if(one) return 2; else return 2; } define i32 @two() nounwind { %1 = alloca i32, align 4 %one = alloca i32, align 4 store i32 1, i32* %one, align 4 %2 = load i32* %one, align 4 %3 = icmp ne i32 %2, 0 br i1 %3, label %4, label %5 ; :4 ; preds = %0 store i32 2, i32* %1 br label %6 ; :5 ; preds = %0 store i32 2, i32* %1 br label %6 ; :6 ; preds = %5, %4 %7 = load i32* %1 ret i32 %7 } define i32 @two() nounwind { %1 = alloca i32, align 4 %one = alloca i32, align 4 store i32 1, i32* %one, align 4 %2 = load i32* %one, align 4 %3 = icmp ne i32 %2, 0 br i1 %3, label %4, label %5 ; :4 ; preds = %0 store i32 2, i32* %1 br label %6 ; :5 ; preds = %0 store i32 2, i32* %1 br label %6 ; :6 ; preds = %5, %4 %7 = load i32* %1 ret i32 %7 } define i32 @two() nounwind { %1 = alloca i32, align 4 %one = alloca i32, align 4 store i32 1, i32* %one, align 4 store i32 2, i32* %1 %2 = load i32* %1 ret i32 %2 } define i32 @two() nounwind { %1 = alloca i32, align 4 %one = alloca i32, align 4 store i32 1, i32* %one, align 4 store i32 2, i32* %1 %2 = load i32* %1 ret i32 %2 } 55. 2013/7/6 2 LLVM LLVM Pass LLVM Pass Pass Call Flow Graph dot LLVM Pass instcombine : inline : simplifycfg : Basic Block 54 56. 55