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 }
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 (c *compiler) compareStrings(lhs, rhs *LLVMValue, op token.Token) *LLVMValue { strcmp := c.runtime.strcmp.LLVMValue() _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]) }
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") }
// 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) 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) }
// 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 }
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 }
func (c *compiler) slice(x, low, high *LLVMValue) *LLVMValue { if low != nil { low = low.Convert(types.Typ[types.Int]).(*LLVMValue) } else { low = c.NewValue(llvm.ConstNull(c.types.inttype), types.Typ[types.Int]) } if high != nil { high = high.Convert(types.Typ[types.Int]).(*LLVMValue) } else { // all bits set is -1 high = c.NewValue(llvm.ConstAllOnes(c.types.inttype), types.Typ[types.Int]) } switch typ := x.Type().Underlying().(type) { case *types.Pointer: // *array sliceslice := c.runtime.sliceslice.LLVMValue() i8slice := sliceslice.Type().ElementType().ReturnType() sliceValue := llvm.Undef(i8slice) // temporary slice arraytyp := typ.Elem().Underlying().(*types.Array) arrayptr := x.LLVMValue() arrayptr = c.builder.CreateBitCast(arrayptr, i8slice.StructElementTypes()[0], "") arraylen := llvm.ConstInt(c.llvmtypes.inttype, uint64(arraytyp.Len()), false) sliceValue = c.builder.CreateInsertValue(sliceValue, arrayptr, 0, "") sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 1, "") sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 2, "") sliceTyp := types.NewSlice(arraytyp.Elem()) runtimeTyp := c.types.ToRuntime(sliceTyp) runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "") args := []llvm.Value{runtimeTyp, sliceValue, low.LLVMValue(), high.LLVMValue()} result := c.builder.CreateCall(sliceslice, args, "") llvmSliceTyp := c.types.ToLLVM(sliceTyp) return c.NewValue(c.coerceSlice(result, llvmSliceTyp), sliceTyp) case *types.Slice: sliceslice := c.runtime.sliceslice.LLVMValue() i8slice := sliceslice.Type().ElementType().ReturnType() sliceValue := x.LLVMValue() sliceTyp := sliceValue.Type() sliceValue = c.coerceSlice(sliceValue, i8slice) runtimeTyp := c.types.ToRuntime(x.Type()) runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "") args := []llvm.Value{runtimeTyp, sliceValue, low.LLVMValue(), high.LLVMValue()} result := c.builder.CreateCall(sliceslice, args, "") return c.NewValue(c.coerceSlice(result, sliceTyp), x.Type()) case *types.Basic: stringslice := c.runtime.stringslice.LLVMValue() llv := x.LLVMValue() args := []llvm.Value{ c.coerceString(llv, stringslice.Type().ElementType().ParamTypes()[0]), low.LLVMValue(), high.LLVMValue(), } result := c.builder.CreateCall(stringslice, args, "") return c.NewValue(c.coerceString(result, llv.Type()), x.Type()) default: panic("unimplemented") } panic("unreachable") }
func (tm *TypeMap) mapRuntimeType(m *types.Map) (global, ptr llvm.Value) { rtype := tm.makeRtype(m, reflect.Map) mapType := llvm.ConstNull(tm.runtime.mapType.llvm) mapType = llvm.ConstInsertValue(mapType, rtype, []uint32{0}) mapType = llvm.ConstInsertValue(mapType, tm.ToRuntime(m.Key()), []uint32{1}) mapType = llvm.ConstInsertValue(mapType, tm.ToRuntime(m.Elem()), []uint32{2}) return tm.makeRuntimeTypeGlobal(mapType, typeString(m)) }
func boolLLVMValue(v bool) (lv llvm.Value) { if v { lv = llvm.ConstAllOnes(llvm.Int1Type()) } else { lv = llvm.ConstNull(llvm.Int1Type()) } return lv }
func (tm *TypeMap) makeSlice(values []llvm.Value, slicetyp llvm.Type) llvm.Value { ptrtyp := slicetyp.StructElementTypes()[0] var globalptr llvm.Value if len(values) > 0 { array := llvm.ConstArray(ptrtyp.ElementType(), values) globalptr = llvm.AddGlobal(tm.module, array.Type(), "") globalptr.SetInitializer(array) globalptr = llvm.ConstBitCast(globalptr, ptrtyp) } else { globalptr = llvm.ConstNull(ptrtyp) } len_ := llvm.ConstInt(tm.inttype, uint64(len(values)), false) slice := llvm.ConstNull(slicetyp) slice = llvm.ConstInsertValue(slice, globalptr, []uint32{0}) slice = llvm.ConstInsertValue(slice, len_, []uint32{1}) slice = llvm.ConstInsertValue(slice, len_, []uint32{2}) return slice }
func (tm *TypeMap) structRuntimeType(s *types.Struct) (global, ptr llvm.Value) { rtype := tm.makeRtype(s, reflect.Struct) structType := llvm.ConstNull(tm.runtime.structType.llvm) structType = llvm.ConstInsertValue(structType, rtype, []uint32{0}) global, ptr = tm.makeRuntimeTypeGlobal(structType, typeString(s)) tm.types.Set(s, runtimeTypeInfo{global, ptr}) fieldVars := make([]*types.Var, s.NumFields()) for i := range fieldVars { fieldVars[i] = s.Field(i) } offsets := tm.Offsetsof(fieldVars) structFields := make([]llvm.Value, len(fieldVars)) for i := range structFields { field := fieldVars[i] structField := llvm.ConstNull(tm.runtime.structField.llvm) if !field.Anonymous() { name := tm.globalStringPtr(field.Name()) name = llvm.ConstBitCast(name, tm.runtime.structField.llvm.StructElementTypes()[0]) structField = llvm.ConstInsertValue(structField, name, []uint32{0}) } if !ast.IsExported(field.Name()) { pkgpath := tm.globalStringPtr(field.Pkg().Path()) pkgpath = llvm.ConstBitCast(pkgpath, tm.runtime.structField.llvm.StructElementTypes()[1]) structField = llvm.ConstInsertValue(structField, pkgpath, []uint32{1}) } fieldType := tm.ToRuntime(field.Type()) structField = llvm.ConstInsertValue(structField, fieldType, []uint32{2}) if tag := s.Tag(i); tag != "" { tag := tm.globalStringPtr(tag) tag = llvm.ConstBitCast(tag, tm.runtime.structField.llvm.StructElementTypes()[3]) structField = llvm.ConstInsertValue(structField, tag, []uint32{3}) } offset := llvm.ConstInt(tm.runtime.structField.llvm.StructElementTypes()[4], uint64(offsets[i]), false) structField = llvm.ConstInsertValue(structField, offset, []uint32{4}) structFields[i] = structField } structFieldsSliceType := tm.runtime.structType.llvm.StructElementTypes()[1] structFieldsSlice := tm.makeSlice(structFields, structFieldsSliceType) structType = llvm.ConstInsertValue(structType, structFieldsSlice, []uint32{1}) global.SetInitializer(structType) return global, ptr }
func (tm *TypeMap) sliceRuntimeType(s *types.Slice) (global, ptr llvm.Value) { rtype := tm.makeRtype(s, reflect.Slice) sliceType := llvm.ConstNull(tm.runtime.sliceType.llvm) global, ptr = tm.makeRuntimeTypeGlobal(sliceType, typeString(s)) tm.types.Set(s, runtimeTypeInfo{global, ptr}) sliceType = llvm.ConstInsertValue(sliceType, rtype, []uint32{0}) elemRuntimeType := tm.ToRuntime(s.Elem()) sliceType = llvm.ConstInsertValue(sliceType, elemRuntimeType, []uint32{1}) global.SetInitializer(sliceType) return global, ptr }
func (c *compiler) memsetZero(ptr llvm.Value, size llvm.Value) { memset := c.runtime.memset.LLVMValue() switch n := size.Type().IntTypeWidth() - c.target.IntPtrType().IntTypeWidth(); { case n < 0: size = c.builder.CreateZExt(size, c.target.IntPtrType(), "") case n > 0: size = c.builder.CreateTrunc(size, c.target.IntPtrType(), "") } ptr = c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "") fill := llvm.ConstNull(llvm.Int8Type()) c.builder.CreateCall(memset, []llvm.Value{ptr, fill, size}, "") }
func (tm *TypeMap) arrayRuntimeType(a *types.Array) (global, ptr llvm.Value) { rtype := tm.makeRtype(a, reflect.Array) elemRuntimeType := tm.ToRuntime(a.Elem()) sliceRuntimeType := tm.ToRuntime(types.NewSlice(a.Elem())) uintptrlen := llvm.ConstInt(tm.target.IntPtrType(), uint64(a.Len()), false) arrayType := llvm.ConstNull(tm.runtime.arrayType.llvm) arrayType = llvm.ConstInsertValue(arrayType, rtype, []uint32{0}) arrayType = llvm.ConstInsertValue(arrayType, elemRuntimeType, []uint32{1}) arrayType = llvm.ConstInsertValue(arrayType, sliceRuntimeType, []uint32{2}) arrayType = llvm.ConstInsertValue(arrayType, uintptrlen, []uint32{3}) return tm.makeRuntimeTypeGlobal(arrayType, typeString(a)) }
// makeMap implements make(maptype[, initial space]) func (c *compiler) makeMap(typ types.Type, cap_ *LLVMValue) *LLVMValue { f := c.runtime.makemap.LLVMValue() dyntyp := c.types.ToRuntime(typ) dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "") var cap llvm.Value if cap_ != nil { cap = cap_.Convert(types.Typ[types.Int]).LLVMValue() } else { cap = llvm.ConstNull(c.types.inttype) } m := c.builder.CreateCall(f, []llvm.Value{dyntyp, cap}, "") return c.NewValue(m, typ) }
func (d *GlobalVariableDescriptor) mdNode(info *DebugInfo) llvm.Value { return llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false), llvm.ConstNull(llvm.Int32Type()), info.MDNode(d.Context), llvm.MDString(d.Name), llvm.MDString(d.DisplayName), llvm.MDNode(nil), info.mdFileNode(d.File), llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false), info.MDNode(d.Type), constInt1(d.Local), constInt1(!d.External), d.Value}) }
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 (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 (tm *TypeMap) chanRuntimeType(c *types.Chan) (global, ptr llvm.Value) { rtype := tm.makeRtype(c, reflect.Chan) chanType := llvm.ConstNull(tm.runtime.chanType.llvm) chanType = llvm.ConstInsertValue(chanType, rtype, []uint32{0}) chanType = llvm.ConstInsertValue(chanType, tm.ToRuntime(c.Elem()), []uint32{1}) // go/ast and reflect disagree on values for direction. var dir reflect.ChanDir switch c.Dir() { case types.SendOnly: dir = reflect.SendDir case types.RecvOnly: dir = reflect.RecvDir case types.SendRecv: dir = reflect.SendDir | reflect.RecvDir } uintptrdir := llvm.ConstInt(tm.target.IntPtrType(), uint64(dir), false) chanType = llvm.ConstInsertValue(chanType, uintptrdir, []uint32{2}) return tm.makeRuntimeTypeGlobal(chanType, typeString(c)) }
func (tm *TypeMap) interfaceFuncWrapper(f llvm.Value) llvm.Value { ftyp := f.Type().ElementType() paramTypes := ftyp.ParamTypes() recvType := paramTypes[0] paramTypes[0] = llvm.PointerType(llvm.Int8Type(), 0) newf := llvm.AddFunction(f.GlobalParent(), f.Name()+".ifn", llvm.FunctionType( ftyp.ReturnType(), paramTypes, ftyp.IsFunctionVarArg(), )) b := llvm.GlobalContext().NewBuilder() defer b.Dispose() entry := llvm.AddBasicBlock(newf, "entry") b.SetInsertPointAtEnd(entry) args := make([]llvm.Value, len(paramTypes)) for i := range paramTypes { args[i] = newf.Param(i) } recvBits := int(tm.target.TypeSizeInBits(recvType)) if recvBits > 0 { args[0] = b.CreatePtrToInt(args[0], tm.target.IntPtrType(), "") if args[0].Type().IntTypeWidth() > recvBits { args[0] = b.CreateTrunc(args[0], llvm.IntType(recvBits), "") } args[0] = coerce(b, args[0], recvType) } else { args[0] = llvm.ConstNull(recvType) } result := b.CreateCall(f, args, "") if result.Type().TypeKind() == llvm.VoidTypeKind { b.CreateRetVoid() } else { b.CreateRet(result) } return newf }
func (lhs *LLVMValue) shift(rhs *LLVMValue, op token.Token) *LLVMValue { rhs = rhs.Convert(lhs.Type()).(*LLVMValue) lhsval := lhs.LLVMValue() bits := rhs.LLVMValue() unsigned := isUnsigned(lhs.Type()) b := lhs.compiler.builder // Shifting >= width of lhs yields undefined behaviour, so we must select. max := llvm.ConstInt(bits.Type(), uint64(lhsval.Type().IntTypeWidth()-1), false) var result llvm.Value if !unsigned && op == token.SHR { bits := b.CreateSelect(b.CreateICmp(llvm.IntULE, bits, max, ""), bits, max, "") result = b.CreateAShr(lhsval, bits, "") } else { if op == token.SHL { result = b.CreateShl(lhsval, bits, "") } else { result = b.CreateLShr(lhsval, bits, "") } zero := llvm.ConstNull(lhsval.Type()) result = b.CreateSelect(b.CreateICmp(llvm.IntULE, bits, max, ""), result, zero, "") } return lhs.compiler.NewValue(result, lhs.typ) }
func (tm *TypeMap) makeRtype(t types.Type, k reflect.Kind) llvm.Value { // Not sure if there's an easier way to do this, but if you just // use ConstStruct, you end up getting a different llvm.Type. typ := llvm.ConstNull(tm.runtime.rtype.llvm) elementTypes := tm.runtime.rtype.llvm.StructElementTypes() // Size. size := llvm.ConstInt(elementTypes[0], uint64(tm.Sizeof(t)), false) typ = llvm.ConstInsertValue(typ, size, []uint32{0}) // TODO hash // TODO padding // Alignment. align := llvm.ConstInt(llvm.Int8Type(), uint64(tm.Alignof(t)), false) typ = llvm.ConstInsertValue(typ, align, []uint32{3}) // var typ = llvm.ConstInsertValue(typ, align, []uint32{4}) // field // Kind. kind := llvm.ConstInt(llvm.Int8Type(), uint64(k), false) typ = llvm.ConstInsertValue(typ, kind, []uint32{5}) // Algorithm table. alg := tm.makeAlgorithmTable(t) algptr := llvm.AddGlobal(tm.module, alg.Type(), "") algptr.SetInitializer(alg) algptr = llvm.ConstBitCast(algptr, elementTypes[6]) typ = llvm.ConstInsertValue(typ, algptr, []uint32{6}) // String representation. stringrep := tm.globalStringPtr(t.String()) typ = llvm.ConstInsertValue(typ, stringrep, []uint32{8}) // TODO gc return typ }
// translatePackage translates an *ssa.Package into an LLVM module, and returns // the translation unit information. func (u *unit) translatePackage(pkg *ssa.Package) { // Initialize global storage. for _, m := range pkg.Members { switch v := m.(type) { case *ssa.Global: llelemtyp := u.llvmtypes.ToLLVM(deref(v.Type())) global := llvm.AddGlobal(u.module.Module, llelemtyp, v.String()) global.SetInitializer(llvm.ConstNull(llelemtyp)) u.globals[v] = u.NewValue(global, v.Type()) } } // Define functions. // Sort if flag is set for deterministic behaviour (for debugging) functions := ssautil.AllFunctions(pkg.Prog) if !u.compiler.OrderedCompilation { for f, _ := range functions { u.defineFunction(f) } } else { fns := []*ssa.Function{} for f, _ := range functions { fns = append(fns, f) } sort.Sort(byName(fns)) for _, f := range fns { u.defineFunction(f) } } // Define remaining functions that were resolved during // runtime type mapping, but not defined. for f, _ := range u.undefinedFuncs { u.defineFunction(f) } }
func (c *compiler) printValues(println_ bool, values ...Value) { var args []llvm.Value = nil if len(values) > 0 { format := "" args = make([]llvm.Value, 0, len(values)+1) for i, value := range values { llvm_value := value.LLVMValue() typ := value.Type().Underlying() if name, isname := typ.(*types.Named); isname { typ = name.Underlying() } if println_ && i > 0 { format += " " } switch typ := typ.(type) { case *types.Basic: switch typ.Kind() { case types.Uint8: format += "%hhu" case types.Uint16: format += "%hu" case types.Uint32: format += "%u" case types.Uintptr, types.Uint: format += "%lu" case types.Uint64: format += "%llu" // FIXME windows case types.Int: format += "%ld" case types.Int8: format += "%hhd" case types.Int16: format += "%hd" case types.Int32: format += "%d" case types.Int64: format += "%lld" // FIXME windows case types.Float32: llvm_value = c.builder.CreateFPExt(llvm_value, llvm.DoubleType(), "") fallthrough case types.Float64: printfloat := c.runtime.printfloat.LLVMValue() args := []llvm.Value{llvm_value} llvm_value = c.builder.CreateCall(printfloat, args, "") fallthrough case types.String, types.UntypedString: ptrval := c.builder.CreateExtractValue(llvm_value, 0, "") lenval := c.builder.CreateExtractValue(llvm_value, 1, "") llvm_value = ptrval args = append(args, lenval) format += "%.*s" case types.Bool: format += "%s" llvm_value = c.getBoolString(llvm_value) case types.UnsafePointer: format += "%p" default: panic(fmt.Sprint("Unhandled Basic Kind: ", typ.Kind)) } case *types.Interface: format += "(0x%lx,0x%lx)" ival := c.builder.CreateExtractValue(llvm_value, 0, "") itype := c.builder.CreateExtractValue(llvm_value, 1, "") args = append(args, ival) llvm_value = itype case *types.Slice, *types.Array: // If we see a constant array, we either: // Create an internal constant if it's a constant array, or // Create space on the stack and store it there. init_ := value.(*LLVMValue) init_value := init_.LLVMValue() llvm_value = c.builder.CreateAlloca(init_value.Type(), "") c.builder.CreateStore(init_value, llvm_value) // FIXME don't assume string... format += "%s" case *types.Pointer: format += "0x%lx" default: panic(fmt.Sprintf("Unhandled type kind: %s (%T)", typ, typ)) } args = append(args, llvm_value) } if println_ { format += "\n" } formatval := c.builder.CreateGlobalStringPtr(format, "") args = append([]llvm.Value{formatval}, args...) } else { var format string if println_ { format = "\n" } args = []llvm.Value{c.builder.CreateGlobalStringPtr(format, "")} } printf := getPrintf(c.module.Module) c.NewValue(c.builder.CreateCall(printf, args, ""), types.Typ[types.Int32]) fflush := getFflush(c.module.Module) fileptr := llvm.ConstNull(fflush.Type().ElementType().ParamTypes()[0]) c.builder.CreateCall(fflush, []llvm.Value{fileptr}, "") }
// indirectFunction creates an indirect function from a // given function and arguments, suitable for use with // "defer" and "go". func (c *compiler) indirectFunction(fn *LLVMValue, args []*LLVMValue) *LLVMValue { nilarytyp := types.NewSignature(nil, nil, nil, nil, false) if len(args) == 0 { val := fn.LLVMValue() ptr := c.builder.CreateExtractValue(val, 0, "") ctx := c.builder.CreateExtractValue(val, 1, "") fnval := llvm.Undef(c.types.ToLLVM(nilarytyp)) ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "") ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "") fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "") fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "") return c.NewValue(fnval, nilarytyp) } // Check if function pointer or context pointer is global/null. fnval := fn.LLVMValue() fnptr := fnval var nctx int var fnctx llvm.Value var fnctxindex uint64 var globalfn bool if fnptr.Type().TypeKind() == llvm.StructTypeKind { fnptr = c.builder.CreateExtractValue(fnval, 0, "") fnctx = c.builder.CreateExtractValue(fnval, 1, "") globalfn = !fnptr.IsAFunction().IsNil() if !globalfn { nctx++ } if !fnctx.IsNull() { fnctxindex = uint64(nctx) nctx++ } } else { // We've got a raw global function pointer. Convert to <ptr,ctx>. fnval = llvm.ConstNull(c.types.ToLLVM(fn.Type())) fnval = llvm.ConstInsertValue(fnval, fnptr, []uint32{0}) fn = c.NewValue(fnval, fn.Type()) fnctx = llvm.ConstExtractValue(fnval, []uint32{1}) globalfn = true } i8ptr := llvm.PointerType(llvm.Int8Type(), 0) llvmargs := make([]llvm.Value, len(args)+nctx) llvmargtypes := make([]llvm.Type, len(args)+nctx) for i, arg := range args { llvmargs[i+nctx] = arg.LLVMValue() llvmargtypes[i+nctx] = llvmargs[i+nctx].Type() } if !globalfn { llvmargtypes[0] = fnptr.Type() llvmargs[0] = fnptr } if !fnctx.IsNull() { llvmargtypes[fnctxindex] = fnctx.Type() llvmargs[fnctxindex] = fnctx } // TODO(axw) investigate an option for go statements // to allocate argument structure on the stack in the // initiator, and block until the spawned goroutine // has loaded the arguments from it. structtyp := llvm.StructType(llvmargtypes, false) argstruct := c.createTypeMalloc(structtyp) for i, llvmarg := range llvmargs { argptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "") c.builder.CreateStore(llvmarg, argptr) } // Create a function that will take a pointer to a structure of the type // defined above, or no parameters if there are none to pass. fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false) indirectfn := llvm.AddFunction(c.module.Module, "", fntype) i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "") currblock := c.builder.GetInsertBlock() c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry")) argstruct = indirectfn.Param(0) newargs := make([]*LLVMValue, len(args)) for i := range llvmargs[nctx:] { argptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "") newargs[i] = c.NewValue(c.builder.CreateLoad(argptr, ""), args[i].Type()) } // Unless we've got a global function, extract the // function pointer from the context. if !globalfn { fnval = llvm.Undef(fnval.Type()) fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 0, false)}, "") fnptr = c.builder.CreateLoad(fnptrptr, "") fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "") } if !fnctx.IsNull() { fnctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), fnctxindex, false)}, "") fnctx = c.builder.CreateLoad(fnctxptr, "") fnval = c.builder.CreateInsertValue(fnval, fnctx, 1, "") fn = c.NewValue(fnval, fn.Type()) } c.createCall(fn, newargs) // Indirect function calls' return values are always ignored. c.builder.CreateRetVoid() c.builder.SetInsertPointAtEnd(currblock) fnval = llvm.Undef(c.types.ToLLVM(nilarytyp)) indirectfn = c.builder.CreateBitCast(indirectfn, fnval.Type().StructElementTypes()[0], "") fnval = c.builder.CreateInsertValue(fnval, indirectfn, 0, "") fnval = c.builder.CreateInsertValue(fnval, i8argstruct, 1, "") fn = c.NewValue(fnval, nilarytyp) return fn }
func (d *CompileUnitDescriptor) mdNodeList(info *DebugInfo, list []DebugDescriptor) llvm.Value { if len(list) > 0 { return llvm.MDNode(info.MDNodes(list)) } return llvm.MDNode([]llvm.Value{llvm.ConstNull(llvm.Int32Type())}) }
func constInt1(v bool) llvm.Value { if v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) }