github.com/llir/llvm@v0.3.6/ir/evaluator_test.go (about) 1 // This example program parses testdata/eval.ll, evaluates the return value of 2 // the @main function and prints the result to standard output. The result 3 // should be 42. 4 package ir_test 5 6 import ( 7 "fmt" 8 "log" 9 10 "github.com/llir/llvm/asm" 11 "github.com/llir/llvm/ir" 12 "github.com/llir/llvm/ir/constant" 13 "github.com/llir/llvm/ir/types" 14 "github.com/llir/llvm/ir/value" 15 ) 16 17 func Example_evaluator() { 18 // Parse the LLVM IR assembly file `eval.ll`. 19 m, err := asm.ParseFile("testdata/eval.ll") 20 if err != nil { 21 log.Fatalf("%+v", err) 22 } 23 // Evalute and print the return value of the `@main` function. 24 for _, f := range m.Funcs { 25 if f.Name() == "main" { 26 e := newEvaluator(f) 27 fmt.Println("result:", e.eval()) 28 break 29 } 30 } 31 32 // Output: 33 // 34 // result: 42 35 } 36 37 // evaluator is a function evaluator. 38 type evaluator struct { 39 // Function being evaluated. 40 f *ir.Func 41 // Function arguments. 42 args []value.Value 43 } 44 45 // newEvaluator returns a new function evaluator, for evaluating the result of 46 // invoking f with args. 47 func newEvaluator(f *ir.Func, args ...value.Value) *evaluator { 48 return &evaluator{f: f, args: args} 49 } 50 51 // eval evalutes f and returns the corresponding 32-bit integer. 52 func (e *evaluator) eval() uint32 { 53 f := e.f 54 if !types.Equal(f.Sig.RetType, types.I32) { 55 panic(fmt.Errorf("support for function return type %s not yet implemented", f.Sig.RetType)) 56 } 57 for _, block := range f.Blocks { 58 switch term := block.Term.(type) { 59 case *ir.TermRet: 60 // Note: support for functions with more than one ret terminator not 61 // yet implemented. 62 if term.X != nil { 63 // The result of the first return value of a function is evaluated. 64 return e.evalValue(term.X) 65 } 66 } 67 } 68 panic(fmt.Errorf("unable to locate ret terminator in function %q", f.Ident())) 69 } 70 71 // evalInst evaluates inst and returns the corresponding 32-bit integer. 72 func (e *evaluator) evalInst(inst ir.Instruction) uint32 { 73 switch inst := inst.(type) { 74 // Binary instructions. 75 case *ir.InstAdd: 76 return e.evalValue(inst.X) + e.evalValue(inst.Y) 77 case *ir.InstSub: 78 return e.evalValue(inst.X) - e.evalValue(inst.Y) 79 case *ir.InstMul: 80 return e.evalValue(inst.X) * e.evalValue(inst.Y) 81 case *ir.InstUDiv: 82 return e.evalValue(inst.X) / e.evalValue(inst.Y) 83 case *ir.InstSDiv: 84 return e.evalValue(inst.X) / e.evalValue(inst.Y) 85 case *ir.InstURem: 86 return e.evalValue(inst.X) % e.evalValue(inst.Y) 87 case *ir.InstSRem: 88 return e.evalValue(inst.X) % e.evalValue(inst.Y) 89 // Bitwise instructions. 90 case *ir.InstShl: 91 return e.evalValue(inst.X) << e.evalValue(inst.Y) 92 case *ir.InstLShr: 93 return e.evalValue(inst.X) >> e.evalValue(inst.Y) 94 case *ir.InstAShr: 95 x, y := e.evalValue(inst.X), e.evalValue(inst.Y) 96 result := x >> y 97 // sign extend. 98 if x&0x80000000 != 0 { 99 result = signExt(result) 100 } 101 return result 102 case *ir.InstAnd: 103 return e.evalValue(inst.X) & e.evalValue(inst.Y) 104 case *ir.InstOr: 105 return e.evalValue(inst.X) | e.evalValue(inst.Y) 106 case *ir.InstXor: 107 return e.evalValue(inst.X) ^ e.evalValue(inst.Y) 108 // Other instructions. 109 case *ir.InstCall: 110 callee, ok := inst.Callee.(*ir.Func) 111 if !ok { 112 panic(fmt.Errorf("support for callee type %T not yet implemented", inst.Callee)) 113 } 114 ee := newEvaluator(callee, inst.Args...) 115 return ee.eval() 116 default: 117 panic(fmt.Errorf("support for instruction type %T not yet implemented", inst)) 118 } 119 } 120 121 // evalValue evalutes v and returns the corresponding 32-bit integer. 122 func (e *evaluator) evalValue(v value.Value) uint32 { 123 switch v := v.(type) { 124 case ir.Instruction: 125 return e.evalInst(v) 126 case *constant.Int: 127 return uint32(v.X.Int64()) 128 case *ir.Param: 129 f := e.f 130 for i, param := range f.Params { 131 if v.Ident() == param.Ident() { 132 return e.evalValue(e.args[i]) 133 } 134 } 135 panic(fmt.Errorf("unable to locate paramater %q of function %q", v.Ident(), f.Ident())) 136 default: 137 panic(fmt.Errorf("support for value type %T not yet implemented", v)) 138 } 139 } 140 141 // signExt sign extends x. 142 func signExt(x uint32) uint32 { 143 for i := uint32(31); i >= 0; i-- { 144 mask := uint32(1 << i) 145 if x&mask != 0 { 146 break 147 } 148 x |= mask 149 } 150 return x 151 }