// mapLookup searches a map for a specified key, returning a pointer to the // memory location for the value. If insert is given as true, and the key // does not exist in the map, it will be added with an uninitialised value. func (c *compiler) mapLookup(m *LLVMValue, key Value, insert bool) (elem *LLVMValue, notnull *LLVMValue) { mapType := m.Type().Underlying().(*types.Map) maplookup := c.NamedFunction("runtime.maplookup", "func f(t, m, k uintptr, insert bool) uintptr") ptrType := c.target.IntPtrType() args := make([]llvm.Value, 4) args[0] = llvm.ConstPtrToInt(c.types.ToRuntime(mapType), ptrType) args[1] = c.builder.CreatePtrToInt(m.LLVMValue(), ptrType, "") if insert { args[3] = llvm.ConstAllOnes(llvm.Int1Type()) } else { args[3] = llvm.ConstNull(llvm.Int1Type()) } if lv, islv := key.(*LLVMValue); islv && lv.pointer != nil { args[2] = c.builder.CreatePtrToInt(lv.pointer.LLVMValue(), ptrType, "") } if args[2].IsNil() { stackval := c.builder.CreateAlloca(c.types.ToLLVM(key.Type()), "") c.builder.CreateStore(key.LLVMValue(), stackval) args[2] = c.builder.CreatePtrToInt(stackval, ptrType, "") } eltPtrType := types.NewPointer(mapType.Elem()) llvmtyp := c.types.ToLLVM(eltPtrType) zeroglobal := llvm.AddGlobal(c.module.Module, llvmtyp.ElementType(), "") zeroglobal.SetInitializer(llvm.ConstNull(llvmtyp.ElementType())) result := c.builder.CreateCall(maplookup, args, "") result = c.builder.CreateIntToPtr(result, llvmtyp, "") notnull_ := c.builder.CreateIsNotNull(result, "") result = c.builder.CreateSelect(notnull_, result, zeroglobal, "") value := c.NewValue(result, eltPtrType) return value.makePointee(), c.NewValue(notnull_, types.Typ[types.Bool]) }
func (c *compiler) defineMemcpyFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) dst, src, size := fn.Param(0), fn.Param(1), fn.Param(2) pint8 := llvm.PointerType(llvm.Int8Type(), 0) dst = c.builder.CreateIntToPtr(dst, pint8, "") src = c.builder.CreateIntToPtr(src, pint8, "") sizeType := size.Type() sizeBits := sizeType.IntTypeWidth() memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(sizeBits) memcpy := c.module.NamedFunction(memcpyName) if memcpy.IsNil() { paramtypes := []llvm.Type{ pint8, pint8, size.Type(), llvm.Int32Type(), llvm.Int1Type()} memcpyType := llvm.FunctionType(llvm.VoidType(), paramtypes, false) memcpy = llvm.AddFunction(c.module.Module, memcpyName, memcpyType) } args := []llvm.Value{ dst, src, size, llvm.ConstInt(llvm.Int32Type(), 1, false), // single byte alignment llvm.ConstInt(llvm.Int1Type(), 0, false), // not volatile } c.builder.CreateCall(memcpy, args, "") c.builder.CreateRetVoid() }
// convertI2V converts an interface to a value. func (v *LLVMValue) convertI2V(typ types.Type) (result, success Value) { builder := v.compiler.builder predicate := v.interfaceTypeEquals(typ).LLVMValue() // If result is zero, then we've got a match. end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end") end.MoveAfter(builder.GetInsertBlock()) nonmatch := llvm.InsertBasicBlock(end, "nonmatch") match := llvm.InsertBasicBlock(nonmatch, "match") builder.CreateCondBr(predicate, match, nonmatch) builder.SetInsertPointAtEnd(match) matchResultValue := v.loadI2V(typ).LLVMValue() builder.CreateBr(end) builder.SetInsertPointAtEnd(nonmatch) nonmatchResultValue := llvm.ConstNull(matchResultValue.Type()) builder.CreateBr(end) builder.SetInsertPointAtEnd(end) successValue := builder.CreatePHI(llvm.Int1Type(), "") resultValue := builder.CreatePHI(matchResultValue.Type(), "") successValues := []llvm.Value{llvm.ConstAllOnes(llvm.Int1Type()), llvm.ConstNull(llvm.Int1Type())} successBlocks := []llvm.BasicBlock{match, nonmatch} successValue.AddIncoming(successValues, successBlocks) success = v.compiler.NewValue(successValue, types.Typ[types.Bool]) resultValues := []llvm.Value{matchResultValue, nonmatchResultValue} resultBlocks := []llvm.BasicBlock{match, nonmatch} resultValue.AddIncoming(resultValues, resultBlocks) result = v.compiler.NewValue(resultValue, typ) return result, success }
// Binary logical operators are handled specially, outside of the Value // type, because of the need to perform lazy evaluation. // // Binary logical operators are implemented using a Phi node, which takes // on the appropriate value depending on which basic blocks branch to it. func (c *compiler) compileLogicalOp(op token.Token, lhs Value, rhsFunc func() Value) Value { lhsBlock := c.builder.GetInsertBlock() resultBlock := llvm.AddBasicBlock(lhsBlock.Parent(), "") resultBlock.MoveAfter(lhsBlock) rhsBlock := llvm.InsertBasicBlock(resultBlock, "") falseBlock := llvm.InsertBasicBlock(resultBlock, "") if op == token.LOR { c.builder.CreateCondBr(lhs.LLVMValue(), resultBlock, rhsBlock) } else { c.builder.CreateCondBr(lhs.LLVMValue(), rhsBlock, falseBlock) } c.builder.SetInsertPointAtEnd(rhsBlock) rhs := rhsFunc() rhsBlock = c.builder.GetInsertBlock() // rhsFunc may create blocks c.builder.CreateCondBr(rhs.LLVMValue(), resultBlock, falseBlock) c.builder.SetInsertPointAtEnd(falseBlock) c.builder.CreateBr(resultBlock) c.builder.SetInsertPointAtEnd(resultBlock) result := c.builder.CreatePHI(llvm.Int1Type(), "") trueValue := llvm.ConstAllOnes(llvm.Int1Type()) falseValue := llvm.ConstNull(llvm.Int1Type()) var values []llvm.Value var blocks []llvm.BasicBlock if op == token.LOR { values = []llvm.Value{trueValue, trueValue, falseValue} blocks = []llvm.BasicBlock{lhsBlock, rhsBlock, falseBlock} } else { values = []llvm.Value{trueValue, falseValue} blocks = []llvm.BasicBlock{rhsBlock, falseBlock} } result.AddIncoming(values, blocks) return c.NewLLVMValue(result, types.Bool) }
func boolLLVMValue(v bool) (lv llvm.Value) { if v { lv = llvm.ConstAllOnes(llvm.Int1Type()) } else { lv = llvm.ConstNull(llvm.Int1Type()) } return lv }
func (v ConstValue) LLVMValue() llvm.Value { typ := types.Underlying(v.Type()) switch typ { case types.Int, types.Uint: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) // TODO 32/64bit (probably wait for gc) //int_val := v.Val.(*big.Int) //if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 { // panic(fmt.Sprint("const ", int_val, " overflows int")) //} //return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true) case types.Uint: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int8: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true) case types.Uint8, types.Byte: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false) case types.Int16: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true) case types.Uint16: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false) case types.Int32, types.Rune: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) case types.Uint32: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int64: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Uint64: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Float32: return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64())) case types.Float64: return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64())) case types.UnsafePointer, types.Uintptr: inttype := v.compiler.target.IntPtrType() return llvm.ConstInt(inttype, uint64(v.Int64()), false) case types.String: strval := (v.Val).(string) ptr := v.compiler.builder.CreateGlobalStringPtr(strval, "") len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(strval)), false) return llvm.ConstStruct([]llvm.Value{ptr, len_}, false) case types.Bool: if v := v.Val.(bool); v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) } panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind)) }
func (tm *TypeMap) basicLLVMType(b *types.Basic) llvm.Type { switch b.Kind { case types.BoolKind: return llvm.Int1Type() case types.Int8Kind, types.Uint8Kind: return llvm.Int8Type() case types.Int16Kind, types.Uint16Kind: return llvm.Int16Type() case types.Int32Kind, types.Uint32Kind: return llvm.Int32Type() case types.Int64Kind, types.Uint64Kind: return llvm.Int64Type() case types.Float32Kind: return llvm.FloatType() case types.Float64Kind: return llvm.DoubleType() case types.UnsafePointerKind, types.UintptrKind, types.UintKind, types.IntKind: return tm.target.IntPtrType() //case Complex64: TODO //case Complex128: //case UntypedInt: //case UntypedFloat: //case UntypedComplex: case types.StringKind: i8ptr := llvm.PointerType(llvm.Int8Type(), 0) elements := []llvm.Type{i8ptr, llvm.Int32Type()} return llvm.StructType(elements, false) } panic(fmt.Sprint("unhandled kind: ", b.Kind)) }
func (tm *llvmTypeMap) basicLLVMType(b *types.Basic) llvm.Type { switch b.Kind() { case types.Bool: return llvm.Int1Type() case types.Int8, types.Uint8: return llvm.Int8Type() case types.Int16, types.Uint16: return llvm.Int16Type() case types.Int32, types.Uint32: return llvm.Int32Type() case types.Uint, types.Int: return tm.inttype case types.Int64, types.Uint64: return llvm.Int64Type() case types.Float32: return llvm.FloatType() case types.Float64: return llvm.DoubleType() case types.UnsafePointer, types.Uintptr: return tm.target.IntPtrType() case types.Complex64: f32 := llvm.FloatType() elements := []llvm.Type{f32, f32} return llvm.StructType(elements, false) case types.Complex128: f64 := llvm.DoubleType() elements := []llvm.Type{f64, f64} return llvm.StructType(elements, false) case types.String: i8ptr := llvm.PointerType(llvm.Int8Type(), 0) elements := []llvm.Type{i8ptr, tm.inttype} return llvm.StructType(elements, false) } panic(fmt.Sprint("unhandled kind: ", b.Kind)) }
func (lhs *LLVMValue) compareI2V(rhs *LLVMValue) Value { c := lhs.compiler predicate := lhs.interfaceTypeEquals(rhs.typ).LLVMValue() end := llvm.InsertBasicBlock(c.builder.GetInsertBlock(), "end") end.MoveAfter(c.builder.GetInsertBlock()) nonmatch := llvm.InsertBasicBlock(end, "nonmatch") match := llvm.InsertBasicBlock(nonmatch, "match") c.builder.CreateCondBr(predicate, match, nonmatch) c.builder.SetInsertPointAtEnd(match) lhsValue := lhs.loadI2V(rhs.typ) matchResultValue := lhsValue.BinaryOp(token.EQL, rhs).LLVMValue() c.builder.CreateBr(end) c.builder.SetInsertPointAtEnd(nonmatch) nonmatchResultValue := llvm.ConstNull(llvm.Int1Type()) c.builder.CreateBr(end) c.builder.SetInsertPointAtEnd(end) resultValue := c.builder.CreatePHI(matchResultValue.Type(), "") resultValues := []llvm.Value{matchResultValue, nonmatchResultValue} resultBlocks := []llvm.BasicBlock{match, nonmatch} resultValue.AddIncoming(resultValues, resultBlocks) return c.NewValue(resultValue, types.Typ[types.Bool]) }
// interfacesEqual compares two interfaces for equality, returning // a dynamic boolean value. func (lhs *LLVMValue) compareI2I(rhs *LLVMValue) Value { c := lhs.compiler b := c.builder lhsValue := b.CreateExtractValue(lhs.LLVMValue(), 0, "") rhsValue := b.CreateExtractValue(rhs.LLVMValue(), 0, "") lhsType := b.CreateExtractValue(lhs.LLVMValue(), 1, "") rhsType := b.CreateExtractValue(rhs.LLVMValue(), 1, "") llvmUintptr := c.target.IntPtrType() runtimeCompareI2I := c.module.Module.NamedFunction("runtime.compareI2I") if runtimeCompareI2I.IsNil() { args := []llvm.Type{llvmUintptr, llvmUintptr, llvmUintptr, llvmUintptr} functype := llvm.FunctionType(llvm.Int1Type(), args, false) runtimeCompareI2I = llvm.AddFunction( c.module.Module, "runtime.compareI2I", functype) } args := []llvm.Value{ c.builder.CreatePtrToInt(lhsType, llvmUintptr, ""), c.builder.CreatePtrToInt(rhsType, llvmUintptr, ""), c.builder.CreatePtrToInt(lhsValue, llvmUintptr, ""), c.builder.CreatePtrToInt(rhsValue, llvmUintptr, ""), } result := c.builder.CreateCall(runtimeCompareI2I, args, "") return c.NewLLVMValue(result, types.Bool) }
func NewTypeMap(llvmtm *LLVMTypeMap, module llvm.Module, pkgpath string, exprTypes map[ast.Expr]types.Type, c *FunctionCache, r Resolver) *TypeMap { tm := &TypeMap{ LLVMTypeMap: llvmtm, module: module, pkgpath: pkgpath, types: make(map[string]runtimeTypeInfo), expr: exprTypes, functions: c, resolver: r, } // Load runtime/reflect types, and generate LLVM types for // the structures we need to populate runtime type information. pkg, err := c.compiler.parseReflect() if err != nil { panic(err) // FIXME return err } reflectLLVMType := func(name string) llvm.Type { obj := pkg.Scope.Lookup(name) if obj == nil { panic(fmt.Errorf("Failed to find type: %s", name)) } return tm.ToLLVM(obj.Type.(types.Type)) } tm.runtimeType = reflectLLVMType("runtimeType") tm.runtimeCommonType = reflectLLVMType("commonType") tm.runtimeUncommonType = reflectLLVMType("uncommonType") tm.runtimeArrayType = reflectLLVMType("arrayType") tm.runtimeChanType = reflectLLVMType("chanType") tm.runtimeFuncType = reflectLLVMType("funcType") tm.runtimeMethod = reflectLLVMType("method") tm.runtimeImethod = reflectLLVMType("imethod") tm.runtimeInterfaceType = reflectLLVMType("interfaceType") tm.runtimeMapType = reflectLLVMType("mapType") tm.runtimePtrType = reflectLLVMType("ptrType") tm.runtimeSliceType = reflectLLVMType("sliceType") tm.runtimeStructType = reflectLLVMType("structType") tm.commonType = pkg.Scope.Lookup("commonType").Type.(*types.Name) // Types for algorithms. See 'runtime/runtime.h'. uintptrType := tm.target.IntPtrType() voidPtrType := llvm.PointerType(llvm.Int8Type(), 0) boolType := llvm.Int1Type() // Create runtime algorithm function types. params := []llvm.Type{uintptrType, voidPtrType} tm.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false) params = []llvm.Type{uintptrType, uintptrType, uintptrType} tm.equalAlgFunctionType = llvm.FunctionType(boolType, params, false) params = []llvm.Type{uintptrType, voidPtrType} tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType, voidPtrType} tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) return tm }
// convertI2V converts an interface to a value. func (v *LLVMValue) convertI2V(typ types.Type) (result, success Value) { typptrType := llvm.PointerType(llvm.Int8Type(), 0) runtimeType := v.compiler.types.ToRuntime(typ) runtimeType = llvm.ConstBitCast(runtimeType, typptrType) vval := v.LLVMValue() builder := v.compiler.builder ifaceType := builder.CreateExtractValue(vval, 0, "") diff := builder.CreatePtrDiff(runtimeType, ifaceType, "") zero := llvm.ConstNull(diff.Type()) predicate := builder.CreateICmp(llvm.IntEQ, diff, zero, "") // If result is zero, then we've got a match. end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end") end.MoveAfter(builder.GetInsertBlock()) nonmatch := llvm.InsertBasicBlock(end, "nonmatch") match := llvm.InsertBasicBlock(nonmatch, "match") builder.CreateCondBr(predicate, match, nonmatch) builder.SetInsertPointAtEnd(match) matchResultValue := v.loadI2V(typ).LLVMValue() builder.CreateBr(end) builder.SetInsertPointAtEnd(nonmatch) nonmatchResultValue := llvm.ConstNull(matchResultValue.Type()) builder.CreateBr(end) builder.SetInsertPointAtEnd(end) successValue := builder.CreatePHI(llvm.Int1Type(), "") resultValue := builder.CreatePHI(matchResultValue.Type(), "") successValues := []llvm.Value{llvm.ConstAllOnes(llvm.Int1Type()), llvm.ConstNull(llvm.Int1Type())} successBlocks := []llvm.BasicBlock{match, nonmatch} successValue.AddIncoming(successValues, successBlocks) success = v.compiler.NewLLVMValue(successValue, types.Bool) resultValues := []llvm.Value{matchResultValue, nonmatchResultValue} resultBlocks := []llvm.BasicBlock{match, nonmatch} resultValue.AddIncoming(resultValues, resultBlocks) result = v.compiler.NewLLVMValue(resultValue, typ) return result, success }
func NewTypeMap(llvmtm *LLVMTypeMap, pkgpath string, exprTypes map[ast.Expr]types.Type, c *FunctionCache, p map[*ast.Object]string, r Resolver) *TypeMap { tm := &TypeMap{ LLVMTypeMap: llvmtm, pkgpath: pkgpath, types: make(map[types.Type]llvm.Value), expr: exprTypes, pkgmap: p, functions: c, resolver: r, } // Load "reflect.go", and generate LLVM types for the runtime type // structures. pkg, err := parseReflect() if err != nil { panic(err) // FIXME return err } objToLLVMType := func(name string) llvm.Type { obj := pkg.Scope.Lookup(name) return tm.ToLLVM(obj.Type.(types.Type)) } tm.runtimeType = objToLLVMType("runtimeType") tm.runtimeCommonType = objToLLVMType("commonType") tm.runtimeUncommonType = objToLLVMType("uncommonType") tm.runtimeArrayType = objToLLVMType("arrayType") tm.runtimeChanType = objToLLVMType("chanType") tm.runtimeFuncType = objToLLVMType("funcType") tm.runtimeMethod = objToLLVMType("method") tm.runtimeImethod = objToLLVMType("imethod") tm.runtimeInterfaceType = objToLLVMType("interfaceType") tm.runtimeMapType = objToLLVMType("mapType") tm.runtimePtrType = objToLLVMType("ptrType") tm.runtimeSliceType = objToLLVMType("sliceType") tm.runtimeStructType = objToLLVMType("structType") // Types for algorithms. See 'runtime/runtime.h'. uintptrType := tm.target.IntPtrType() voidPtrType := llvm.PointerType(llvm.Int8Type(), 0) boolType := llvm.Int1Type() // Create runtime algorithm function types. params := []llvm.Type{uintptrType, voidPtrType} tm.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false) params = []llvm.Type{uintptrType, uintptrType, uintptrType} tm.equalAlgFunctionType = llvm.FunctionType(boolType, params, false) params = []llvm.Type{uintptrType, voidPtrType} tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType, voidPtrType} tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) return tm }
func (tm *TypeMap) funcRuntimeType(f *types.Signature) (global, ptr llvm.Value) { rtype := tm.makeRtype(f, reflect.Func) funcType := llvm.ConstNull(tm.runtimeFuncType) funcType = llvm.ConstInsertValue(funcType, rtype, []uint32{0}) // dotdotdot if f.IsVariadic() { variadic := llvm.ConstInt(llvm.Int1Type(), 1, false) funcType = llvm.ConstInsertValue(funcType, variadic, []uint32{1}) } // TODO in //funcType = llvm.ConstInsertValue(funcType, tm.ToRuntime(p.Elt()), []uint32{2}) // TODO out //funcType = llvm.ConstInsertValue(funcType, tm.ToRuntime(p.Elt()), []uint32{3}) return tm.makeRuntimeTypeGlobal(funcType) }
func (d *SubprogramDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false), FileDescriptor(d.File).path(), info.MDNode(d.Context), llvm.MDString(d.Name), llvm.MDString(d.DisplayName), llvm.MDString(""), // mips linkage name llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false), info.MDNode(d.Type), llvm.ConstNull(llvm.Int1Type()), // not static llvm.ConstAllOnes(llvm.Int1Type()), // locally defined (not extern) llvm.ConstNull(llvm.Int32Type()), // virtuality llvm.ConstNull(llvm.Int32Type()), // index into a virtual function info.MDNode(nil), // basetype containing the vtable pointer llvm.ConstInt(llvm.Int32Type(), 0, false), // flags llvm.ConstNull(llvm.Int1Type()), // not optimised d.Function, info.MDNode(nil), // Template parameters info.MDNode(nil), // function declaration descriptor llvm.MDNode(nil), // function variables llvm.ConstInt(llvm.Int32Type(), uint64(d.ScopeLine), false), // Line number where the scope of the subprogram begins }) }
func NewTypeMap(module llvm.Module, target llvm.TargetData, exprTypes map[ast.Expr]types.Type) *TypeMap { tm := &TypeMap{module: module, target: target, expr: exprTypes} tm.types = make(map[types.Type]llvm.Type) tm.runtime = make(map[types.Type]llvm.Value) // Load "reflect.go", and generate LLVM types for the runtime type // structures. pkg, err := parseReflect() if err != nil { panic(err) // FIXME return err } objToLLVMType := func(name string) llvm.Type { obj := pkg.Scope.Lookup(name) return tm.ToLLVM(obj.Type.(types.Type)) } tm.runtimeCommonType = objToLLVMType("commonType") tm.runtimeUncommonType = objToLLVMType("uncommonType") tm.runtimeArrayType = objToLLVMType("arrayType") tm.runtimeChanType = objToLLVMType("chanType") tm.runtimeFuncType = objToLLVMType("funcType") tm.runtimeInterfaceType = objToLLVMType("interfaceType") tm.runtimeMapType = objToLLVMType("mapType") tm.runtimePtrType = objToLLVMType("ptrType") tm.runtimeSliceType = objToLLVMType("sliceType") tm.runtimeStructType = objToLLVMType("structType") // Types for algorithms. See 'runtime/runtime.h'. uintptrType := tm.target.IntPtrType() voidPtrType := llvm.PointerType(llvm.Int8Type(), 0) boolType := llvm.Int1Type() // Create runtime algorithm function types. params := []llvm.Type{ llvm.PointerType(uintptrType, 0), uintptrType, voidPtrType} tm.hashAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{ llvm.PointerType(boolType, 0), uintptrType, voidPtrType, voidPtrType} tm.equalAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType} tm.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType, voidPtrType} tm.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) return tm }
func (c *compiler) defineMemsetFunction(fn llvm.Value) { entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) dst, fill, size := fn.Param(0), fn.Param(1), fn.Param(2) sizeType := size.Type() sizeBits := sizeType.IntTypeWidth() memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(sizeBits) memset := c.NamedFunction(memsetName, "func f(dst *int8, fill byte, size uintptr, align int32, volatile bool)") pint8 := memset.Type().ElementType().ParamTypes()[0] dst = c.builder.CreateIntToPtr(dst, pint8, "") args := []llvm.Value{ dst, fill, size, llvm.ConstInt(llvm.Int32Type(), 1, false), // single byte alignment llvm.ConstInt(llvm.Int1Type(), 0, false), // not volatile } c.builder.CreateCall(memset, args, "") c.builder.CreateRetVoid() }
func newAlgorithmMap(m llvm.Module, runtime *runtimeInterface, target llvm.TargetData) *algorithmMap { am := &algorithmMap{ module: m, runtime: runtime, } uintptrType := target.IntPtrType() voidPtrType := llvm.PointerType(llvm.Int8Type(), 0) boolType := llvm.Int1Type() params := []llvm.Type{uintptrType, voidPtrType} am.hashAlgFunctionType = llvm.FunctionType(uintptrType, params, false) params = []llvm.Type{uintptrType, uintptrType, uintptrType} am.equalAlgFunctionType = llvm.FunctionType(boolType, params, false) params = []llvm.Type{uintptrType, voidPtrType} am.printAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) params = []llvm.Type{uintptrType, voidPtrType, voidPtrType} am.copyAlgFunctionType = llvm.FunctionType(llvm.VoidType(), params, false) return am }
func (tm *TypeMap) funcRuntimeType(f *types.Signature) (global, ptr llvm.Value) { rtype := tm.makeRtype(f, reflect.Func) funcType := llvm.ConstNull(tm.runtime.funcType.llvm) global, ptr = tm.makeRuntimeTypeGlobal(funcType, typeString(f)) tm.types.Set(f, runtimeTypeInfo{global, ptr}) funcType = llvm.ConstInsertValue(funcType, rtype, []uint32{0}) // dotdotdot if f.Variadic() { variadic := llvm.ConstInt(llvm.Int1Type(), 1, false) funcType = llvm.ConstInsertValue(funcType, variadic, []uint32{1}) } // in intypes := tm.rtypeSlice(f.Params()) funcType = llvm.ConstInsertValue(funcType, intypes, []uint32{2}) // out outtypes := tm.rtypeSlice(f.Results()) funcType = llvm.ConstInsertValue(funcType, outtypes, []uint32{3}) global.SetInitializer(funcType) return global, ptr }
func (v ConstValue) LLVMValue() llvm.Value { typ := types.Underlying(v.Type()) if name, ok := typ.(*types.Name); ok { typ = name.Underlying } switch typ.(*types.Basic).Kind { case types.IntKind, types.UintKind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) // TODO 32/64bit (probably wait for gc) //int_val := v.Val.(*big.Int) //if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 { // panic(fmt.Sprint("const ", int_val, " overflows int")) //} //return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true) case types.Int8Kind: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true) case types.Uint8Kind: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false) case types.Int16Kind: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true) case types.Uint16Kind: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false) case types.Int32Kind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) case types.Uint32Kind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int64Kind: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Uint64Kind: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), false) case types.Float32Kind: return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64())) case types.Float64Kind: return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64())) case types.Complex64Kind: r_, i_ := v.Complex() r := llvm.ConstFloat(llvm.FloatType(), r_) i := llvm.ConstFloat(llvm.FloatType(), i_) return llvm.ConstStruct([]llvm.Value{r, i}, false) case types.Complex128Kind: r_, i_ := v.Complex() r := llvm.ConstFloat(llvm.DoubleType(), r_) i := llvm.ConstFloat(llvm.DoubleType(), i_) return llvm.ConstStruct([]llvm.Value{r, i}, false) case types.UnsafePointerKind, types.UintptrKind: inttype := v.compiler.target.IntPtrType() return llvm.ConstInt(inttype, uint64(v.Int64()), false) case types.StringKind: strval := (v.Val).(string) strlen := len(strval) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var ptr llvm.Value if strlen > 0 { ptr = v.compiler.builder.CreateGlobalStringPtr(strval, "") ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(strlen), false) return llvm.ConstStruct([]llvm.Value{ptr, len_}, false) case types.BoolKind: if v := v.Val.(bool); v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) } panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind)) }
// convertI2I converts an interface to another interface. func (v *LLVMValue) convertI2I(iface *types.Interface) (result *LLVMValue, success *LLVMValue) { c := v.compiler builder := v.compiler.builder src_typ := v.Type().Underlying() val := v.LLVMValue() zero_iface_struct := llvm.ConstNull(c.types.ToLLVM(iface)) iface_struct := zero_iface_struct dynamicType := builder.CreateExtractValue(val, 0, "") receiver := builder.CreateExtractValue(val, 1, "") // TODO check whether the functions in the struct take // value or pointer receivers. // TODO handle dynamic interface conversion (non-subset). srciface := src_typ.(*types.Interface) for i := 0; i < iface.NumMethods(); i++ { m := iface.Method(i) // FIXME sort methods somewhere, make loop linear. var mi int for ; mi < srciface.NumMethods(); mi++ { if srciface.Method(i).Name() == m.Name() { break } } if mi >= srciface.NumMethods() { goto check_dynamic } else { fptr := builder.CreateExtractValue(val, mi+2, "") iface_struct = builder.CreateInsertValue(iface_struct, fptr, i+2, "") } } iface_struct = builder.CreateInsertValue(iface_struct, dynamicType, 0, "") iface_struct = builder.CreateInsertValue(iface_struct, receiver, 1, "") result = c.NewValue(iface_struct, iface) success = c.NewValue(llvm.ConstAllOnes(llvm.Int1Type()), types.Typ[types.Bool]) return result, success check_dynamic: runtimeConvertI2I := c.NamedFunction("runtime.convertI2I", "func f(typ, from, to uintptr) bool") llvmUintptr := runtimeConvertI2I.Type().ElementType().ParamTypes()[0] var vptr llvm.Value if v.pointer != nil { vptr = v.pointer.LLVMValue() } else { vptr = c.builder.CreateAlloca(val.Type(), "") c.builder.CreateStore(val, vptr) } runtimeType := c.builder.CreatePtrToInt(c.types.ToRuntime(iface), llvmUintptr, "") from := c.builder.CreatePtrToInt(vptr, llvmUintptr, "") to := c.builder.CreateAlloca(iface_struct.Type(), "") c.builder.CreateStore(iface_struct, to) toUintptr := c.builder.CreatePtrToInt(to, llvmUintptr, "") args := []llvm.Value{runtimeType, from, toUintptr} ok := c.builder.CreateCall(runtimeConvertI2I, args, "") value := c.builder.CreateLoad(to, "") value = c.builder.CreateSelect(ok, value, zero_iface_struct, "") result = c.NewValue(value, iface) success = c.NewValue(ok, types.Typ[types.Bool]) return result, success }
func constInt1(v bool) llvm.Value { if v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) }
func (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue { switch { case v.Kind() == exact.Unknown: // TODO nil literals should be represented more appropriately once the exact-package supports it. llvmtyp := c.types.ToLLVM(typ) return c.NewValue(llvm.ConstNull(llvmtyp), typ) case isString(typ): if isUntyped(typ) { typ = types.Typ[types.String] } llvmtyp := c.types.ToLLVM(typ) strval := exact.StringVal(v) strlen := len(strval) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var ptr llvm.Value if strlen > 0 { init := llvm.ConstString(strval, false) ptr = llvm.AddGlobal(c.module.Module, init.Type(), "") ptr.SetInitializer(init) ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(c.types.inttype, uint64(strlen), false) llvmvalue := llvm.Undef(llvmtyp) llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1}) return c.NewValue(llvmvalue, typ) case isInteger(typ): if isUntyped(typ) { typ = types.Typ[types.Int] } llvmtyp := c.types.ToLLVM(typ) var llvmvalue llvm.Value if isUnsigned(typ) { v, _ := exact.Uint64Val(v) llvmvalue = llvm.ConstInt(llvmtyp, v, false) } else { v, _ := exact.Int64Val(v) llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true) } return c.NewValue(llvmvalue, typ) case isBoolean(typ): if isUntyped(typ) { typ = types.Typ[types.Bool] } var llvmvalue llvm.Value if exact.BoolVal(v) { llvmvalue = llvm.ConstAllOnes(llvm.Int1Type()) } else { llvmvalue = llvm.ConstNull(llvm.Int1Type()) } return c.NewValue(llvmvalue, typ) case isFloat(typ): if isUntyped(typ) { typ = types.Typ[types.Float64] } llvmtyp := c.types.ToLLVM(typ) floatval, _ := exact.Float64Val(v) llvmvalue := llvm.ConstFloat(llvmtyp, floatval) return c.NewValue(llvmvalue, typ) case typ == types.Typ[types.UnsafePointer]: llvmtyp := c.types.ToLLVM(typ) v, _ := exact.Uint64Val(v) llvmvalue := llvm.ConstInt(llvmtyp, v, false) return c.NewValue(llvmvalue, typ) case isComplex(typ): if isUntyped(typ) { typ = types.Typ[types.Complex128] } llvmtyp := c.types.ToLLVM(typ) floattyp := llvmtyp.StructElementTypes()[0] llvmvalue := llvm.ConstNull(llvmtyp) realv := exact.Real(v) imagv := exact.Imag(v) realfloatval, _ := exact.Float64Val(realv) imagfloatval, _ := exact.Float64Val(imagv) llvmre := llvm.ConstFloat(floattyp, realfloatval) llvmim := llvm.ConstFloat(floattyp, imagfloatval) llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1}) return c.NewValue(llvmvalue, typ) } // Special case for string -> [](byte|rune) if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) { if v.Kind() == exact.String { strval := c.NewConstValue(v, types.Typ[types.String]) return strval.Convert(typ).(*LLVMValue) } } panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", c.types.TypeString(typ), typ, v, v)) }
// phiValue returns a new value with the same value and type as the given Phi. // This is used for go.tools/ssa instructions that introduce new ssa.Values, // but would otherwise not generate a new LLVM value. func phiValue(c *compiler, v *LLVMValue) *LLVMValue { llv := v.LLVMValue() llv = c.builder.CreateSelect(llvm.ConstAllOnes(llvm.Int1Type()), llv, llv, "") return c.NewValue(llv, v.Type()) }