github.com/llir/llvm@v0.3.6/asm/local.go (about) 1 // Problems to solve. 2 // 3 // phi instructions can reference local variables defined in basic blocks not 4 // yet visited when translating basic blocks in linear order. 5 // 6 // Terminator instructions can reference basic blocks not yet visited when 7 // translating basic blocks in linear order. 8 // 9 // The function parameters, basic blocks and local variables (produced by the 10 // result of instructions) of a function may be unnamed. They are assigned the 11 // first unused local ID (e.g. %42) when traversing the body of the function in 12 // linear order; where function parameters are assigned first, then for each 13 // basic block, assign an ID to the basic block and then to the result of its 14 // instructions. Note, instructions that produce void results are ignored. 15 // Non-value instructions (e.g. store) are always ignored. Notably, the call 16 // instruction may be ignored if the callee has a void return. 17 18 // TODO: make concurrent :) 19 20 package asm 21 22 import ( 23 "github.com/llir/ll/ast" 24 "github.com/llir/llvm/ir" 25 "github.com/llir/llvm/ir/types" 26 "github.com/llir/llvm/ir/value" 27 "github.com/pkg/errors" 28 ) 29 30 // funcGen is a generator for a given IR function. 31 type funcGen struct { 32 // Module generator. 33 gen *generator 34 // LLVM IR function being generated. 35 f *ir.Func 36 // locals maps from local identifier (without '%' prefix) to corresponding IR 37 // value. 38 locals map[ir.LocalIdent]value.Value 39 } 40 41 // newFuncGen returns a new generator for the given IR function. 42 func newFuncGen(gen *generator, f *ir.Func) *funcGen { 43 return &funcGen{ 44 gen: gen, 45 f: f, 46 locals: make(map[ir.LocalIdent]value.Value), 47 } 48 } 49 50 // resolveLocals resolves the local variables (function parameters, basic 51 // blocks, results of instructions and terminators) of the given function body. 52 func (fgen *funcGen) resolveLocals(old ast.FuncBody) error { 53 // Index local identifiers and create scaffolding IR local variables (without 54 // bodies but with types). 55 oldBlocks := old.Blocks() 56 if err := fgen.createLocals(oldBlocks); err != nil { 57 return errors.WithStack(err) 58 } 59 // Translate AST instructions to IR. 60 if err := fgen.translateInsts(oldBlocks); err != nil { 61 return errors.WithStack(err) 62 } 63 // Translate AST terminators to IR. 64 return fgen.translateTerms(oldBlocks) 65 } 66 67 // === [ Create and index IR ] ================================================= 68 69 // local is a local variable. 70 type local interface { 71 value.Named 72 // ID returns the ID of the local identifier. 73 ID() int64 74 // SetID sets the ID of the local identifier. 75 SetID(id int64) 76 // IsUnnamed reports whether the local identifier is unnamed. 77 IsUnnamed() bool 78 } 79 80 // createLocals indexes local identifiers and creates scaffolding IR local 81 // variables (without bodies but with types) of the given function. 82 // 83 // post-condition: fgen.locals maps from local identifier (without '%' prefix) 84 // to corresponding skeleton IR value. 85 func (fgen *funcGen) createLocals(oldBlocks []ast.BasicBlock) error { 86 // Create local variable skeletons (without bodies but with types). 87 if err := fgen.newLocals(oldBlocks); err != nil { 88 return errors.WithStack(err) 89 } 90 // Assign local IDs. 91 // 92 // Note: the type of call instructions and invoke terminators must be 93 // determined before assigning local IDs, as they may be values or non-values 94 // based on return type. This is done by fgen.newLocals. 95 if err := fgen.f.AssignIDs(); err != nil { 96 return errors.WithStack(err) 97 } 98 // Index local identifiers. 99 return fgen.indexLocals() 100 } 101 102 // newLocals creates scaffolding IR local variables (without bodies but with 103 // types) of the given function. 104 func (fgen *funcGen) newLocals(oldBlocks []ast.BasicBlock) error { 105 // Note: function parameters are already translated in gen.irFuncHeader. 106 f := fgen.f 107 f.Blocks = make([]*ir.Block, len(oldBlocks)) 108 for i, oldBlock := range oldBlocks { 109 block := &ir.Block{} 110 if n, ok := oldBlock.Name(); ok { 111 block.LocalIdent = labelIdent(n) 112 } 113 if oldInsts := oldBlock.Insts(); len(oldInsts) > 0 { 114 block.Insts = make([]ir.Instruction, len(oldInsts)) 115 for j, oldInst := range oldInsts { 116 inst, err := fgen.newInst(oldInst) 117 if err != nil { 118 return errors.WithStack(err) 119 } 120 block.Insts[j] = inst 121 } 122 } 123 term, err := fgen.newTerm(oldBlock.Term()) 124 if err != nil { 125 return errors.WithStack(err) 126 } 127 block.Term = term 128 block.Parent = f 129 f.Blocks[i] = block 130 } 131 return nil 132 } 133 134 // indexLocals indexes local identifiers of the given function. 135 func (fgen *funcGen) indexLocals() error { 136 // Index function parameters. 137 f := fgen.f 138 for _, param := range f.Params { 139 if err := fgen.addLocal(param.LocalIdent, param); err != nil { 140 return errors.WithStack(err) 141 } 142 } 143 // Index basic blocks. 144 for _, block := range f.Blocks { 145 if err := fgen.addLocal(block.LocalIdent, block); err != nil { 146 return errors.WithStack(err) 147 } 148 // Index instructions. 149 for _, inst := range block.Insts { 150 v, ok := inst.(local) 151 if !ok || v.Type().Equal(types.Void) { 152 // Skip non-value instructions. 153 continue 154 } 155 ident := localIdentOfValue(v) 156 if err := fgen.addLocal(ident, v); err != nil { 157 return errors.WithStack(err) 158 } 159 } 160 // Index terminator. 161 v, ok := block.Term.(local) 162 if !ok || v.Type().Equal(types.Void) { 163 // Skip non-value terminators. 164 continue 165 } 166 ident := localIdentOfValue(v) 167 if err := fgen.addLocal(ident, v); err != nil { 168 return errors.WithStack(err) 169 } 170 } 171 return nil 172 } 173 174 // ### [ Helper functions ] #################################################### 175 176 // addLocal adds the local variable with the given local identifier to the map 177 // of local variables of the function. 178 func (fgen *funcGen) addLocal(ident ir.LocalIdent, v value.Value) error { 179 if prev, ok := fgen.locals[ident]; ok { 180 return errors.Errorf("local identifier %q already present; prev `%s`, new `%s`", ident.Ident(), prev, v) 181 } 182 fgen.locals[ident] = v 183 return nil 184 } 185 186 // localIdentOfValue returns the local identifier of the given local variable. 187 func localIdentOfValue(v local) ir.LocalIdent { 188 if v.IsUnnamed() { 189 return ir.LocalIdent{LocalID: v.ID()} 190 } 191 return ir.LocalIdent{LocalName: v.Name()} 192 }