github.com/goplus/llgo@v0.8.3/ssa/stmt_builder.go (about) 1 /* 2 * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ssa 18 19 import ( 20 "bytes" 21 "fmt" 22 "go/types" 23 "log" 24 "strings" 25 26 "github.com/goplus/llvm" 27 ) 28 29 // ----------------------------------------------------------------------------- 30 31 type aBasicBlock struct { 32 impl llvm.BasicBlock 33 fn Function 34 idx int 35 } 36 37 // BasicBlock represents a basic block in a function. 38 type BasicBlock = *aBasicBlock 39 40 // Parent returns the function to which the basic block belongs. 41 func (p BasicBlock) Parent() Function { 42 return p.fn 43 } 44 45 // Index returns the index of the basic block in the parent function. 46 func (p BasicBlock) Index() int { 47 return p.idx 48 } 49 50 // ----------------------------------------------------------------------------- 51 52 type aBuilder struct { 53 impl llvm.Builder 54 Func Function 55 Prog Program 56 } 57 58 // Builder represents a builder for creating instructions in a function. 59 type Builder = *aBuilder 60 61 // Dispose disposes of the builder. 62 func (b Builder) Dispose() { 63 b.impl.Dispose() 64 } 65 66 // SetBlock means SetBlockEx(blk, AtEnd). 67 func (b Builder) SetBlock(blk BasicBlock) Builder { 68 if debugInstr { 69 log.Printf("Block _llgo_%v:\n", blk.idx) 70 } 71 b.SetBlockEx(blk, AtEnd) 72 return b 73 } 74 75 type InsertPoint int 76 77 const ( 78 AtEnd InsertPoint = iota 79 AtStart 80 AfterInit 81 ) 82 83 // SetBlockEx sets blk as current basic block and pos as its insert point. 84 func (b Builder) SetBlockEx(blk BasicBlock, pos InsertPoint) Builder { 85 if b.Func != blk.fn { 86 panic("mismatched function") 87 } 88 switch pos { 89 case AtEnd: 90 b.impl.SetInsertPointAtEnd(blk.impl) 91 case AtStart: 92 b.impl.SetInsertPointBefore(blk.impl.FirstInstruction()) 93 case AfterInit: 94 b.impl.SetInsertPointBefore(instrAfterInit(blk.impl)) 95 default: 96 panic("SetBlockEx: invalid pos") 97 } 98 return b 99 } 100 101 func instrAfterInit(blk llvm.BasicBlock) llvm.Value { 102 instr := blk.FirstInstruction() 103 for { 104 instr = llvm.NextInstruction(instr) 105 if notInit(instr) { 106 return instr 107 } 108 } 109 } 110 111 func notInit(instr llvm.Value) bool { 112 switch op := instr.InstructionOpcode(); op { 113 case llvm.Call: 114 if n := instr.OperandsCount(); n == 1 { 115 fn := instr.Operand(0) 116 return !strings.HasSuffix(fn.Name(), ".init") 117 } 118 } 119 return true 120 } 121 122 // Panic emits a panic instruction. 123 func (b Builder) Panic(v Expr) { 124 if debugInstr { 125 log.Printf("Panic %v\n", v.impl) 126 } 127 pkg := b.Func.Pkg 128 b.Call(pkg.rtFunc("TracePanic"), v) 129 b.impl.CreateUnreachable() 130 } 131 132 // Unreachable emits an unreachable instruction. 133 func (b Builder) Unreachable() { 134 b.impl.CreateUnreachable() 135 } 136 137 // Return emits a return instruction. 138 func (b Builder) Return(results ...Expr) { 139 if debugInstr { 140 var b bytes.Buffer 141 fmt.Fprint(&b, "Return ") 142 for i, arg := range results { 143 if i > 0 { 144 fmt.Fprint(&b, ", ") 145 } 146 fmt.Fprint(&b, arg.impl) 147 } 148 log.Println(b.String()) 149 } 150 switch n := len(results); n { 151 case 0: 152 b.impl.CreateRetVoid() 153 case 1: 154 raw := b.Func.raw.Type.(*types.Signature).Results().At(0).Type() 155 ret := checkExpr(results[0], raw, b) 156 b.impl.CreateRet(ret.impl) 157 default: 158 tret := b.Func.raw.Type.(*types.Signature).Results() 159 b.impl.CreateAggregateRet(llvmParams(0, results, tret, b)) 160 } 161 } 162 163 // Jump emits a jump instruction. 164 func (b Builder) Jump(jmpb BasicBlock) { 165 if b.Func != jmpb.fn { 166 panic("mismatched function") 167 } 168 if debugInstr { 169 log.Printf("Jump _llgo_%v\n", jmpb.idx) 170 } 171 b.impl.CreateBr(jmpb.impl) 172 } 173 174 // If emits an if instruction. 175 func (b Builder) If(cond Expr, thenb, elseb BasicBlock) { 176 if b.Func != thenb.fn || b.Func != elseb.fn { 177 panic("mismatched function") 178 } 179 if debugInstr { 180 log.Printf("If %v, _llgo_%v, _llgo_%v\n", cond.impl, thenb.idx, elseb.idx) 181 } 182 b.impl.CreateCondBr(cond.impl, thenb.impl, elseb.impl) 183 } 184 185 // The MapUpdate instruction updates the association of Map[Key] to 186 // Value. 187 // 188 // Pos() returns the ast.KeyValueExpr.Colon or ast.IndexExpr.Lbrack, 189 // if explicit in the source. 190 // 191 // Example printed form: 192 // 193 // t0[t1] = t2 194 func (b Builder) MapUpdate(m, k, v Expr) { 195 if debugInstr { 196 log.Printf("MapUpdate %v[%v] = %v\n", m.impl, k.impl, v.impl) 197 } 198 // TODO(xsw) 199 // panic("todo") 200 } 201 202 // -----------------------------------------------------------------------------