createExpr translates a Go SSA expression to LLVM IR. This can be zero, one, or multiple LLVM IR instructions and/or runtime calls.
(expr ssa.Value)
| 2157 | // createExpr translates a Go SSA expression to LLVM IR. This can be zero, one, |
| 2158 | // or multiple LLVM IR instructions and/or runtime calls. |
| 2159 | func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) { |
| 2160 | if _, ok := b.locals[expr]; ok { |
| 2161 | // sanity check |
| 2162 | panic("instruction has already been created: " + expr.String()) |
| 2163 | } |
| 2164 | |
| 2165 | switch expr := expr.(type) { |
| 2166 | case *ssa.Alloc: |
| 2167 | typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem()) |
| 2168 | size := b.targetData.TypeAllocSize(typ) |
| 2169 | // Move all "large" allocations to the heap. |
| 2170 | if expr.Heap || size > b.MaxStackAlloc { |
| 2171 | // Calculate ^uintptr(0) |
| 2172 | maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue() |
| 2173 | if size > maxSize { |
| 2174 | // Size would be truncated if truncated to uintptr. |
| 2175 | return llvm.Value{}, b.makeError(expr.Pos(), fmt.Sprintf("value is too big (%v bytes)", size)) |
| 2176 | } |
| 2177 | sizeValue := llvm.ConstInt(b.uintptrType, size, false) |
| 2178 | layoutValue := b.createObjectLayout(typ, expr.Pos()) |
| 2179 | buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment) |
| 2180 | align := b.targetData.ABITypeAlignment(typ) |
| 2181 | buf.AddCallSiteAttribute(0, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(align))) |
| 2182 | return buf, nil |
| 2183 | } else { |
| 2184 | buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment) |
| 2185 | if b.targetData.TypeAllocSize(typ) != 0 { |
| 2186 | b.CreateStore(llvm.ConstNull(typ), buf) // zero-initialize var |
| 2187 | } |
| 2188 | return buf, nil |
| 2189 | } |
| 2190 | case *ssa.BinOp: |
| 2191 | x := b.getValue(expr.X, getPos(expr)) |
| 2192 | y := b.getValue(expr.Y, getPos(expr)) |
| 2193 | return b.createBinOp(expr.Op, expr.X.Type(), expr.Y.Type(), x, y, expr.Pos()) |
| 2194 | case *ssa.Call: |
| 2195 | return b.createFunctionCall(expr.Common()) |
| 2196 | case *ssa.ChangeInterface: |
| 2197 | // Do not change between interface types: always use the underlying |
| 2198 | // (concrete) type in the type number of the interface. Every method |
| 2199 | // call on an interface will do a lookup which method to call. |
| 2200 | // This is different from how the official Go compiler works, because of |
| 2201 | // heap allocation and because it's easier to implement, see: |
| 2202 | // https://research.swtch.com/interfaces |
| 2203 | return b.getValue(expr.X, getPos(expr)), nil |
| 2204 | case *ssa.ChangeType: |
| 2205 | // This instruction changes the type, but the underlying value remains |
| 2206 | // the same. This is often a no-op, but sometimes we have to change the |
| 2207 | // LLVM type as well. |
| 2208 | x := b.getValue(expr.X, getPos(expr)) |
| 2209 | llvmType := b.getLLVMType(expr.Type()) |
| 2210 | if x.Type() == llvmType { |
| 2211 | // Different Go type but same LLVM type (for example, named int). |
| 2212 | // This is the common case. |
| 2213 | return x, nil |
| 2214 | } |
| 2215 | // Figure out what kind of type we need to cast. |
| 2216 | switch llvmType.TypeKind() { |
no test coverage detected