// makeMapLiteral makes a map with the specified keys and values. func (c *compiler) makeMapLiteral(typ types.Type, keys, values []Value) *LLVMValue { var count, keysptr, valuesptr llvm.Value dyntyp := c.types.ToRuntime(typ) dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "") if len(keys) == 0 { count = llvm.ConstNull(c.types.inttype) keysptr = llvm.ConstNull(c.target.IntPtrType()) valuesptr = keysptr } else { maptyp := typ.Underlying().(*types.Map) keytyp := maptyp.Key() valtyp := maptyp.Elem() count = llvm.ConstInt(c.types.inttype, uint64(len(keys)), false) keysptr = c.builder.CreateArrayAlloca(c.types.ToLLVM(keytyp), count, "") valuesptr = c.builder.CreateArrayAlloca(c.types.ToLLVM(valtyp), count, "") for i := range keys { gepindices := []llvm.Value{llvm.ConstInt(c.types.inttype, uint64(i), false)} key := keys[i].Convert(keytyp).LLVMValue() ptr := c.builder.CreateGEP(keysptr, gepindices, "") c.builder.CreateStore(key, ptr) value := values[i].Convert(valtyp).LLVMValue() ptr = c.builder.CreateGEP(valuesptr, gepindices, "") c.builder.CreateStore(value, ptr) } keysptr = c.builder.CreatePtrToInt(keysptr, c.target.IntPtrType(), "") valuesptr = c.builder.CreatePtrToInt(valuesptr, c.target.IntPtrType(), "") } f := c.NamedFunction("runtime.makemap", "func(t uintptr, n int, keys, values uintptr) uintptr") mapval := c.builder.CreateCall(f, []llvm.Value{dyntyp, count, keysptr, valuesptr}, "") return c.NewValue(mapval, typ) }
func (tm *TypeMap) interfaceRuntimeType(tstr string, i *types.Interface) (global, ptr llvm.Value) { rtype := tm.makeRtype(i, reflect.Interface) interfaceType := llvm.ConstNull(tm.runtimeInterfaceType) global, ptr = tm.makeRuntimeTypeGlobal(interfaceType) tm.types.record(tstr, global, ptr) interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0}) methodset := i.MethodSet() imethods := make([]llvm.Value, methodset.Len()) for index := 0; index < methodset.Len(); index++ { method := methodset.At(index).Obj() imethod := llvm.ConstNull(tm.runtimeImethod) name := tm.globalStringPtr(method.Name()) name = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[0]) //pkgpath := tm.globalStringPtr(tm.functions.objectdata[method].Package.Path()) //pkgpath = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[1]) mtyp := tm.ToRuntime(method.Type()) imethod = llvm.ConstInsertValue(imethod, name, []uint32{0}) //imethod = llvm.ConstInsertValue(imethod, pkgpath, []uint32{1}) imethod = llvm.ConstInsertValue(imethod, mtyp, []uint32{2}) imethods[index] = imethod } imethodsSliceType := tm.runtimeInterfaceType.StructElementTypes()[1] imethodsSlice := tm.makeSlice(imethods, imethodsSliceType) interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1}) global.SetInitializer(interfaceType) return global, ptr }
func (tm *TypeMap) uncommonType(n *types.Named, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj().Name()) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) _, path := tm.qualifiedName(n) pkgpathPtr := tm.globalStringPtr(path) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) methodset := tm.functions.methods(n) methodfuncs := methodset.nonptr if ptr { methodfuncs = methodset.ptr } // Store methods. methods := make([]llvm.Value, len(methodfuncs)) for i, mfunc := range methodfuncs { ftyp := mfunc.Type().(*types.Signature) method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(mfunc.Name()) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { ftyp := types.NewSignature(nil, nil, ftyp.Params(), ftyp.Results(), ftyp.IsVariadic()) mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() tfn = llvm.ConstExtractValue(tfn, []uint32{0}) tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn if !ptr && tm.Sizeof(ftyp.Recv().Type()) > int64(tm.target.PointerSize()) { mfunc := methodset.lookup(mfunc.Name(), true) ifn = tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() ifn = llvm.ConstExtractValue(ifn, []uint32{0}) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[i] = method } methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := tm.makeSlice(methods, methodsSliceType) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) const eqalgsig = "func(uintptr, unsafe.Pointer, unsafe.Pointer) bool" var equalAlg llvm.Value switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: equalAlg = tm.functions.NamedFunction("runtime.streqalg", eqalgsig) case types.Float32: equalAlg = tm.functions.NamedFunction("runtime.f32eqalg", eqalgsig) case types.Float64: equalAlg = tm.functions.NamedFunction("runtime.f64eqalg", eqalgsig) case types.Complex64: equalAlg = tm.functions.NamedFunction("runtime.c64eqalg", eqalgsig) case types.Complex128: equalAlg = tm.functions.NamedFunction("runtime.c128eqalg", eqalgsig) } } if equalAlg.IsNil() { equalAlg = tm.functions.NamedFunction("runtime.memequal", eqalgsig) } elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
// 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 (tm *TypeMap) interfaceRuntimeType(i *types.Interface) (global, ptr llvm.Value) { rtype := tm.makeRtype(i, reflect.Interface) interfaceType := llvm.ConstNull(tm.runtime.interfaceType.llvm) global, ptr = tm.makeRuntimeTypeGlobal(interfaceType, typeString(i)) tm.types.Set(i, runtimeTypeInfo{global, ptr}) interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0}) methodset := tm.MethodSet(i) imethods := make([]llvm.Value, methodset.Len()) for index := 0; index < methodset.Len(); index++ { method := methodset.At(index).Obj() imethod := llvm.ConstNull(tm.runtime.imethod.llvm) name := tm.globalStringPtr(method.Name()) name = llvm.ConstBitCast(name, tm.runtime.imethod.llvm.StructElementTypes()[0]) mtyp := tm.ToRuntime(method.Type()) imethod = llvm.ConstInsertValue(imethod, name, []uint32{0}) if !ast.IsExported(method.Name()) { pkgpath := tm.globalStringPtr(method.Pkg().Path()) pkgpath = llvm.ConstBitCast(pkgpath, tm.runtime.imethod.llvm.StructElementTypes()[1]) imethod = llvm.ConstInsertValue(imethod, pkgpath, []uint32{1}) } imethod = llvm.ConstInsertValue(imethod, mtyp, []uint32{2}) imethods[index] = imethod } imethodsSliceType := tm.runtime.interfaceType.llvm.StructElementTypes()[1] imethodsSlice := tm.makeSlice(imethods, imethodsSliceType) interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1}) global.SetInitializer(interfaceType) return global, ptr }
// 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 }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) equalAlg := llvm.ConstNull(llvm.PointerType(tm.equalAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) equalAlg := tm.functions.NamedFunction("runtime.memequal", "func f(uintptr, unsafe.Pointer, unsafe.Pointer) bool") elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
func (d *LocalVariableDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false), info.MDNode(d.Context), llvm.MDString(d.Name), info.mdFileNode(d.File), llvm.ConstInt(llvm.Int32Type(), uint64(d.Line)|(uint64(d.Argument)<<24), false), info.MDNode(d.Type), llvm.ConstNull(llvm.Int32Type()), // flags llvm.ConstNull(llvm.Int32Type()), // optional reference to inline location }) }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.alg.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.alg.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.alg.copyAlgFunctionType, 0)) equalAlg := tm.alg.eqalg(t) elems := []llvm.Value{ AlgorithmHash: hashAlg, AlgorithmEqual: equalAlg, AlgorithmPrint: printAlg, AlgorithmCopy: copyAlg, } return llvm.ConstStruct(elems, false) }
func (tm *TypeMap) pointerRuntimeType(p *types.Pointer) (global, ptr llvm.Value) { // Is the base type a named type from another package? If so, we'll // create a reference to the externally defined symbol. var globalname string if n, ok := p.Base.(*types.Name); ok { pkgpath := n.Package if pkgpath == "" { pkgpath = "runtime" } globalname = "__llgo.type.*" + n.String() if pkgpath != tm.pkgpath { global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname) global.SetInitializer(llvm.ConstNull(tm.runtimeType)) global.SetLinkage(llvm.CommonLinkage) return global, global } } commonType := tm.makeCommonType(p, reflect.Ptr) if n, ok := p.Base.(*types.Name); ok { uncommonTypeInit := tm.uncommonType(n, true) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{9}) } baseTypeGlobal, baseTypePtr := tm.toRuntime(p.Base) ptrType := llvm.ConstNull(tm.runtimePtrType) ptrType = llvm.ConstInsertValue(ptrType, commonType, []uint32{0}) ptrType = llvm.ConstInsertValue(ptrType, baseTypePtr, []uint32{1}) global, ptr = tm.makeRuntimeTypeGlobal(ptrType) global.SetName(globalname) // Set ptrToThis in the base type's commonType. baseRuntimeType := baseTypeGlobal.Initializer() baseType := llvm.ConstExtractValue(baseRuntimeType, []uint32{1}) if baseType.Type() == tm.runtimeCommonType { baseType = llvm.ConstInsertValue(baseType, ptr, []uint32{10}) } else { commonType := llvm.ConstExtractValue(baseType, []uint32{0}) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{10}) baseType = llvm.ConstInsertValue(baseType, commonType, []uint32{0}) } baseRuntimeType = llvm.ConstInsertValue(baseRuntimeType, baseType, []uint32{1}) baseTypeGlobal.SetInitializer(baseRuntimeType) return global, ptr }
func (c *compiler) makeInterface(v *LLVMValue, iface types.Type) *LLVMValue { llv := v.LLVMValue() lltyp := llv.Type() i8ptr := llvm.PointerType(llvm.Int8Type(), 0) if lltyp.TypeKind() == llvm.PointerTypeKind { llv = c.builder.CreateBitCast(llv, i8ptr, "") } else { // If the value fits exactly in a pointer, then we can just // bitcast it. Otherwise we need to malloc. if c.target.TypeStoreSize(lltyp) <= uint64(c.target.PointerSize()) { bits := c.target.TypeSizeInBits(lltyp) if bits > 0 { llv = coerce(c.builder, llv, llvm.IntType(int(bits))) llv = c.builder.CreateIntToPtr(llv, i8ptr, "") } else { llv = llvm.ConstNull(i8ptr) } } else { ptr := c.createTypeMalloc(lltyp) c.builder.CreateStore(llv, ptr) llv = c.builder.CreateBitCast(ptr, i8ptr, "") } } value := llvm.Undef(c.types.ToLLVM(iface)) rtype := c.types.ToRuntime(v.Type()) rtype = c.builder.CreateBitCast(rtype, llvm.PointerType(llvm.Int8Type(), 0), "") value = c.builder.CreateInsertValue(value, rtype, 0, "") value = c.builder.CreateInsertValue(value, llv, 1, "") if iface.Underlying().(*types.Interface).NumMethods() > 0 { result := c.NewValue(value, types.NewInterface(nil, nil)) result, _ = result.convertE2I(iface) return result } return c.NewValue(value, iface) }
func (c *compiler) compareStrings(lhs, rhs *LLVMValue, op token.Token) *LLVMValue { strcmp := c.NamedFunction("runtime.strcmp", "func(a, b _string) int32") _string := strcmp.Type().ElementType().ParamTypes()[0] lhsstr := c.coerceString(lhs.LLVMValue(), _string) rhsstr := c.coerceString(rhs.LLVMValue(), _string) args := []llvm.Value{lhsstr, rhsstr} result := c.builder.CreateCall(strcmp, args, "") zero := llvm.ConstNull(llvm.Int32Type()) var pred llvm.IntPredicate switch op { case token.EQL: pred = llvm.IntEQ case token.LSS: pred = llvm.IntSLT case token.GTR: pred = llvm.IntSGT case token.LEQ: pred = llvm.IntSLE case token.GEQ: pred = llvm.IntSGE case token.NEQ: panic("NEQ is handled in LLVMValue.BinaryOp") default: panic("unreachable") } result = c.builder.CreateICmp(pred, result, zero, "") return c.NewValue(result, types.Typ[types.Bool]) }
// makeSlice allocates a new slice with the optional length and capacity, // initialising its contents to their zero values. func (c *compiler) makeSlice(elttyp types.Type, length, capacity Value) llvm.Value { var lengthValue llvm.Value if length != nil { lengthValue = length.Convert(types.Int32).LLVMValue() } else { lengthValue = llvm.ConstNull(llvm.Int32Type()) } // TODO check capacity >= length capacityValue := lengthValue if capacity != nil { capacityValue = capacity.Convert(types.Int32).LLVMValue() } llvmelttyp := c.types.ToLLVM(elttyp) mem := c.builder.CreateArrayMalloc(llvmelttyp, capacityValue, "") sizeof := llvm.ConstTrunc(llvm.SizeOf(llvmelttyp), llvm.Int32Type()) size := c.builder.CreateMul(capacityValue, sizeof, "") c.memsetZero(mem, size) slicetyp := types.Slice{Elt: elttyp} struct_ := llvm.Undef(c.types.ToLLVM(&slicetyp)) struct_ = c.builder.CreateInsertValue(struct_, mem, 0, "") struct_ = c.builder.CreateInsertValue(struct_, lengthValue, 1, "") struct_ = c.builder.CreateInsertValue(struct_, capacityValue, 2, "") return struct_ }
func (tm *TypeMap) mapRuntimeType(m *types.Map) (global, ptr llvm.Value) { commonType := tm.makeCommonType(m, reflect.Map) mapType := llvm.ConstNull(tm.runtimeMapType) mapType = llvm.ConstInsertValue(mapType, commonType, []uint32{0}) // TODO set key, elem return tm.makeRuntimeTypeGlobal(mapType) }
func (tm *TypeMap) nameRuntimeType(n *types.Name) (global, ptr llvm.Value) { global, ptr = tm.makeRuntimeType(n.Underlying) globalInit := global.Initializer() // Locate the common type. underlyingRuntimeType := llvm.ConstExtractValue(globalInit, []uint32{1}) commonType := underlyingRuntimeType if _, ok := n.Underlying.(*types.Basic); !ok { commonType = llvm.ConstExtractValue(commonType, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{8}) // Update the global's initialiser. if _, ok := n.Underlying.(*types.Basic); !ok { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, commonType, []uint32{0}) } else { underlyingRuntimeType = commonType } globalInit = llvm.ConstInsertValue(globalInit, underlyingRuntimeType, []uint32{1}) global.SetName("__llgo.reflect." + n.Obj.Name) return global, ptr }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) equalAlgName := "runtime.memequal" equalAlg := tm.module.NamedFunction(equalAlgName) if equalAlg.IsNil() { equalAlg = llvm.AddFunction( tm.module, equalAlgName, tm.equalAlgFunctionType) } elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
func (tm *TypeMap) structRuntimeType(s *types.Struct) (global, ptr llvm.Value) { commonType := tm.makeCommonType(s, reflect.Struct) structType := llvm.ConstNull(tm.runtimeStructType) structType = llvm.ConstInsertValue(structType, commonType, []uint32{0}) // TODO set fields return tm.makeRuntimeTypeGlobal(structType) }
func (c *compiler) compareStrings(lhs, rhs *LLVMValue, op token.Token) *LLVMValue { strcmp := c.module.Module.NamedFunction("runtime.strcmp") if strcmp.IsNil() { string_type := c.types.ToLLVM(types.String) param_types := []llvm.Type{string_type, string_type} func_type := llvm.FunctionType(llvm.Int32Type(), param_types, false) strcmp = llvm.AddFunction(c.module.Module, "runtime.strcmp", func_type) } args := []llvm.Value{lhs.LLVMValue(), rhs.LLVMValue()} result := c.builder.CreateCall(strcmp, args, "") zero := llvm.ConstNull(llvm.Int32Type()) var pred llvm.IntPredicate switch op { case token.EQL: pred = llvm.IntEQ case token.LSS: pred = llvm.IntSLT case token.GTR: pred = llvm.IntSGT case token.LEQ: pred = llvm.IntSLE case token.GEQ: pred = llvm.IntSGE case token.NEQ: panic("NEQ is handled in LLVMValue.BinaryOp") default: panic("unreachable") } result = c.builder.CreateICmp(pred, result, zero, "") return c.NewLLVMValue(result, types.Bool) }
func (tm *TypeMap) pointerRuntimeType(p *types.Pointer) (global, ptr llvm.Value) { commonType := tm.makeCommonType(p, reflect.Map) ptrType := llvm.ConstNull(tm.runtimePtrType) ptrType = llvm.ConstInsertValue(ptrType, commonType, []uint32{0}) ptrType = llvm.ConstInsertValue(ptrType, tm.ToRuntime(p.Base), []uint32{1}) return tm.makeRuntimeTypeGlobal(ptrType) }
// stringIterNext advances the iterator, and returns the tuple (ok, k, v). func (c *compiler) stringIterNext(str *LLVMValue, preds []llvm.BasicBlock) *LLVMValue { // While Range/Next expresses a mutating operation, we represent them using // a Phi node where the first incoming branch (before the loop), and all // others take the previous value plus one. // // See ssa.go for comments on (and assertions of) our assumptions. index := c.builder.CreatePHI(c.types.inttype, "index") strnext := c.runtime.strnext.LLVMValue() args := []llvm.Value{ c.coerceString(str.LLVMValue(), strnext.Type().ElementType().ParamTypes()[0]), index, } result := c.builder.CreateCall(strnext, args, "") nextindex := c.builder.CreateExtractValue(result, 0, "") runeval := c.builder.CreateExtractValue(result, 1, "") values := make([]llvm.Value, len(preds)) values[0] = llvm.ConstNull(index.Type()) for i, _ := range preds[1:] { values[i+1] = nextindex } index.AddIncoming(values, preds) // Create an (ok, index, rune) tuple. ok := c.builder.CreateIsNotNull(nextindex, "") typ := tupleType(types.Typ[types.Bool], types.Typ[types.Int], types.Typ[types.Rune]) tuple := llvm.Undef(c.types.ToLLVM(typ)) tuple = c.builder.CreateInsertValue(tuple, ok, 0, "") tuple = c.builder.CreateInsertValue(tuple, index, 1, "") tuple = c.builder.CreateInsertValue(tuple, runeval, 2, "") return c.NewValue(tuple, typ) }
func (c *compiler) VisitMake(expr *ast.CallExpr) Value { typ := c.typeinfo.Types[expr] switch utyp := typ.Underlying().(type) { case *types.Slice: var length, capacity Value switch len(expr.Args) { case 3: capacity = c.VisitExpr(expr.Args[2]) fallthrough case 2: length = c.VisitExpr(expr.Args[1]) } slice := c.makeSlice(utyp.Elem(), length, capacity) return c.NewValue(slice, typ) case *types.Chan: f := c.NamedFunction("runtime.makechan", "func(t uintptr, cap int) uintptr") dyntyp := c.types.ToRuntime(typ) dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "") var cap_ llvm.Value if len(expr.Args) > 1 { cap_ = c.VisitExpr(expr.Args[1]).LLVMValue() } else { cap_ = llvm.ConstNull(c.types.inttype) } args := []llvm.Value{dyntyp, cap_} ptr := c.builder.CreateCall(f, args, "") return c.NewValue(ptr, typ) case *types.Map: return c.makeMapLiteral(typ, nil, nil) } panic(fmt.Sprintf("unhandled type: %s", typ)) }
func (v *LLVMValue) UnaryOp(op token.Token) Value { b := v.compiler.builder switch op { case token.SUB: var value llvm.Value isfp := types.Identical(types.Underlying(v.typ), types.Float32) || types.Identical(types.Underlying(v.typ), types.Float64) if isfp { zero := llvm.ConstNull(v.compiler.types.ToLLVM(v.Type())) value = b.CreateFSub(zero, v.LLVMValue(), "") } else { value = b.CreateNeg(v.LLVMValue(), "") } return v.compiler.NewLLVMValue(value, v.typ) case token.ADD: return v // No-op case token.AND: return v.pointer case token.NOT: value := b.CreateNot(v.LLVMValue(), "") return v.compiler.NewLLVMValue(value, v.typ) case token.XOR: lhs := v.LLVMValue() rhs := llvm.ConstAllOnes(lhs.Type()) value := b.CreateXor(lhs, rhs, "") return v.compiler.NewLLVMValue(value, v.typ) default: panic("Unhandled operator: ") // + expr.Op) } panic("unreachable") }
func (v *LLVMValue) UnaryOp(op token.Token) Value { b := v.compiler.builder switch op { case token.SUB: var value llvm.Value if isFloat(v.typ) { zero := llvm.ConstNull(v.compiler.types.ToLLVM(v.Type())) value = b.CreateFSub(zero, v.LLVMValue(), "") } else { value = b.CreateNeg(v.LLVMValue(), "") } return v.compiler.NewValue(value, v.typ) case token.ADD: return v // No-op case token.NOT: value := b.CreateNot(v.LLVMValue(), "") return v.compiler.NewValue(value, v.typ) case token.XOR: lhs := v.LLVMValue() rhs := llvm.ConstAllOnes(lhs.Type()) value := b.CreateXor(lhs, rhs, "") return v.compiler.NewValue(value, v.typ) default: panic(fmt.Sprintf("Unhandled operator: %s", op)) } panic("unreachable") }
// basicRuntimeType creates the runtime type structure for // a basic type. If underlying is true, then a new global // is always created. func (tm *TypeMap) basicRuntimeType(b *types.Basic, underlying bool) (global, ptr llvm.Value) { b = types.Typ[b.Kind()] // unalias var name string if !underlying { name = typeString(b) if tm.pkgpath != "runtime" { global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(name)) global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm)) global.SetLinkage(llvm.CommonLinkage) return global, global } } rtype := tm.makeRtype(b, basicReflectKinds[b.Kind()]) global, ptr = tm.makeRuntimeTypeGlobal(rtype, name) global.SetLinkage(llvm.ExternalLinkage) if !underlying { switch b.Kind() { case types.Int32: llvm.AddAlias(tm.module, global.Type(), global, typeSymbol("rune")) case types.Uint8: llvm.AddAlias(tm.module, global.Type(), global, typeSymbol("byte")) } } return global, ptr }
// 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 (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]) }
// makeSlice allocates a new slice with the optional length and capacity, // initialising its contents to their zero values. func (c *compiler) makeSlice(elttyp types.Type, length, capacity Value) llvm.Value { var lengthValue llvm.Value if length != nil { lengthValue = length.Convert(types.Typ[types.Int]).LLVMValue() } else { lengthValue = llvm.ConstNull(c.llvmtypes.inttype) } // TODO check capacity >= length capacityValue := lengthValue if capacity != nil { capacityValue = capacity.Convert(types.Typ[types.Int]).LLVMValue() } eltType := c.types.ToLLVM(elttyp) sizeof := llvm.ConstTruncOrBitCast(llvm.SizeOf(eltType), c.types.inttype) size := c.builder.CreateMul(capacityValue, sizeof, "") mem := c.createMalloc(size) mem = c.builder.CreateIntToPtr(mem, llvm.PointerType(eltType, 0), "") c.memsetZero(mem, size) slicetyp := types.NewSlice(elttyp) struct_ := llvm.Undef(c.types.ToLLVM(slicetyp)) struct_ = c.builder.CreateInsertValue(struct_, mem, 0, "") struct_ = c.builder.CreateInsertValue(struct_, lengthValue, 1, "") struct_ = c.builder.CreateInsertValue(struct_, capacityValue, 2, "") return struct_ }
func (tm *TypeMap) nameRuntimeType(n *types.Named) (global, ptr llvm.Value) { name := typeString(n) path := "runtime" if pkg := n.Obj().Pkg(); pkg != nil { path = pkg.Path() } if path != tm.pkgpath { // We're not compiling the package from whence the type came, // so we'll just create a pointer to it here. global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(name)) global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm)) global.SetLinkage(llvm.CommonLinkage) return global, global } // If the underlying type is Basic, then we always create // a new global. Otherwise, we clone the value returned // from toRuntime in case it is cached and reused. underlying := n.Underlying() if basic, ok := underlying.(*types.Basic); ok { global, ptr = tm.basicRuntimeType(basic, true) global.SetName(typeSymbol(name)) } else { global, ptr = tm.toRuntime(underlying) clone := llvm.AddGlobal(tm.module, global.Type().ElementType(), typeSymbol(name)) clone.SetInitializer(global.Initializer()) global = clone ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0)) } global.SetLinkage(llvm.ExternalLinkage) // Locate the rtype. underlyingRuntimeType := global.Initializer() rtype := underlyingRuntimeType if rtype.Type() != tm.runtime.rtype.llvm { rtype = llvm.ConstExtractValue(rtype, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := tm.uncommonType(n, nil) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9}) // Replace the rtype's string representation with the one from // uncommonType. XXX should we have the package name prepended? Probably. namePtr := llvm.ConstExtractValue(uncommonTypeInit, []uint32{0}) rtype = llvm.ConstInsertValue(rtype, namePtr, []uint32{8}) // Update the global's initialiser. Note that we take a copy // of the underlying type; we're not updating a shared type. if underlyingRuntimeType.Type() != tm.runtime.rtype.llvm { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, rtype, []uint32{0}) } else { underlyingRuntimeType = rtype } global.SetInitializer(underlyingRuntimeType) return global, ptr }