// interfaceMethod returns a function and receiver pointer for the specified // interface and method pair. func (fr *frame) interfaceMethod(lliface llvm.Value, ifacety types.Type, method *types.Func) (fn, recv *govalue) { llitab := fr.builder.CreateExtractValue(lliface, 0, "") recv = newValue(fr.builder.CreateExtractValue(lliface, 1, ""), types.Typ[types.UnsafePointer]) methodset := fr.types.MethodSet(ifacety) // TODO(axw) cache ordered method index index := -1 for i, m := range orderedMethodSet(methodset) { if m.Obj() == method { index = i break } } if index == -1 { panic("could not find method index") } llitab = fr.builder.CreateBitCast(llitab, llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0), "") // Skip runtime type pointer. llifnptr := fr.builder.CreateGEP(llitab, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(index+1), false), }, "") llifn := fr.builder.CreateLoad(llifnptr, "") // Replace receiver type with unsafe.Pointer. recvparam := types.NewParam(0, nil, "", types.Typ[types.UnsafePointer]) sig := method.Type().(*types.Signature) sig = types.NewSignature(nil, recvparam, sig.Params(), sig.Results(), sig.Variadic()) fn = newValue(llifn, sig) return }
func (c *Codegen) stdString() { tmpl := &Template{ Type: llvm.GlobalContext().StructCreateNamed("string"), Variables: map[string]int{}, } c.templates["string"] = tmpl vars := []llvm.Type{ llvm.PointerType(PRIMITIVE_TYPES["char"], 0), PRIMITIVE_TYPES["int"], PRIMITIVE_TYPES["int"], } tmpl.Type.StructSetBody(vars, false) lenFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{llvm.PointerType(tmpl.Type, 0)}, false) lenFunc := llvm.AddFunction(c.module, "-string-len", lenFuncType) lenFunc.Param(0).SetName("this") block := llvm.AddBasicBlock(c.module.NamedFunction("-string-len"), "entry") c.functions["-string-len"] = block c.currFunc = "-string-len" c.builder.SetInsertPoint(block, block.LastInstruction()) ret := c.builder.CreateStructGEP(c.getCurrParam("this"), 1, "") ret = c.builder.CreateLoad(ret, "") ret = c.builder.CreateSub(ret, llvm.ConstInt(PRIMITIVE_TYPES["int"], 1, false), "") c.builder.CreateRet(ret) printFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{ llvm.PointerType(PRIMITIVE_TYPES["char"], 0), }, true) llvm.AddFunction(c.module, "printf", printFuncType) }
func directDecode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, valType llvm.Type, args []llvm.Value) llvm.Value { var alloca llvm.Value switch len(args) { case 0: return llvm.ConstNull(ctx.StructType(nil, false)) case 1: if args[0].Type().C == valType.C { return args[0] } alloca = allocaBuilder.CreateAlloca(valType, "") bitcast := builder.CreateBitCast(alloca, llvm.PointerType(args[0].Type(), 0), "") builder.CreateStore(args[0], bitcast) case 2: alloca = allocaBuilder.CreateAlloca(valType, "") var argTypes []llvm.Type for _, a := range args { argTypes = append(argTypes, a.Type()) } encodeType := ctx.StructType(argTypes, false) bitcast := builder.CreateBitCast(alloca, llvm.PointerType(encodeType, 0), "") builder.CreateStore(args[0], builder.CreateStructGEP(bitcast, 0, "")) builder.CreateStore(args[1], builder.CreateStructGEP(bitcast, 1, "")) default: panic("unexpected argTypes size") } return builder.CreateLoad(alloca, "") }
func directEncode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, argTypes []llvm.Type, args []llvm.Value, val llvm.Value) { valType := val.Type() switch len(argTypes) { case 0: // do nothing case 1: if argTypes[0].C == valType.C { args[0] = val return } alloca := allocaBuilder.CreateAlloca(valType, "") bitcast := builder.CreateBitCast(alloca, llvm.PointerType(argTypes[0], 0), "") builder.CreateStore(val, alloca) args[0] = builder.CreateLoad(bitcast, "") case 2: encodeType := llvm.StructType(argTypes, false) alloca := allocaBuilder.CreateAlloca(valType, "") bitcast := builder.CreateBitCast(alloca, llvm.PointerType(encodeType, 0), "") builder.CreateStore(val, alloca) args[0] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 0, ""), "") args[1] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 1, ""), "") default: panic("unexpected argTypes size") } }
func (fr *frame) memcpy(dest llvm.Value, src llvm.Value, size llvm.Value) { memcpy := fr.runtime.memcpy dest = fr.builder.CreateBitCast(dest, llvm.PointerType(llvm.Int8Type(), 0), "") src = fr.builder.CreateBitCast(src, llvm.PointerType(llvm.Int8Type(), 0), "") size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "") align := llvm.ConstInt(llvm.Int32Type(), 1, false) isvolatile := llvm.ConstNull(llvm.Int1Type()) fr.builder.CreateCall(memcpy, []llvm.Value{dest, src, size, align, isvolatile}, "") }
func (c *Codegen) declareMemcpy() { t := llvm.FunctionType(llvm.VoidType(), []llvm.Type{ llvm.PointerType(PRIMITIVE_TYPES["char"], 0), llvm.PointerType(PRIMITIVE_TYPES["char"], 0), PRIMITIVE_TYPES["int"], PRIMITIVE_TYPES["int"], PRIMITIVE_TYPES["boolean"], }, false) llvm.AddFunction(c.module, "llvm.memcpy.p0i8.p0i8.i32", t) }
func (fr *frame) registerGcRoots() { if len(fr.gcRoots) != 0 { rootty := fr.gcRoots[0].Type() roots := append(fr.gcRoots, llvm.ConstNull(rootty)) rootsarr := llvm.ConstArray(rootty, roots) rootsstruct := llvm.ConstStruct([]llvm.Value{llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0)), rootsarr}, false) rootsglobal := llvm.AddGlobal(fr.module.Module, rootsstruct.Type(), "") rootsglobal.SetInitializer(rootsstruct) rootsglobal.SetLinkage(llvm.InternalLinkage) fr.runtime.registerGcRoots.callOnly(fr, llvm.ConstBitCast(rootsglobal, llvm.PointerType(llvm.Int8Type(), 0))) } }
// Allocates a literal array on the stack func (v *Codegen) genArrayLiteral(n *parser.ArrayLiteral) llvm.Value { arrayLLVMType := v.typeToLLVMType(n.Type) memberLLVMType := v.typeToLLVMType(n.Type.(parser.ArrayType).MemberType) if v.inFunction { // allocate backing array arrAlloca := v.builder.CreateAlloca(llvm.ArrayType(memberLLVMType, len(n.Members)), "") // copy the constant array to the backing array for idx, value := range n.Members { gep := v.builder.CreateGEP(arrAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), uint64(idx), false)}, "") value := v.genExpr(value) v.builder.CreateStore(value, gep) } // allocate struct structAlloca := v.builder.CreateAlloca(arrayLLVMType, "") // set the length of the array lenGEP := v.builder.CreateGEP(structAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), 0, false)}, "") v.builder.CreateStore(llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false), lenGEP) // set the array pointer to the backing array we allocated arrGEP := v.builder.CreateGEP(structAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), 1, false)}, "") v.builder.CreateStore(v.builder.CreateBitCast(arrAlloca, llvm.PointerType(llvm.ArrayType(memberLLVMType, 0), 0), ""), arrGEP) return v.builder.CreateLoad(structAlloca, "") } else { backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex) v.arrayIndex++ backGlob := llvm.AddGlobal(v.curFile.Module, llvm.ArrayType(memberLLVMType, len(n.Members)), backName) backGlob.SetLinkage(llvm.InternalLinkage) backGlob.SetGlobalConstant(false) arrConstVals := make([]llvm.Value, len(n.Members)) for idx, mem := range n.Members { value := v.genExpr(mem) if !value.IsConstant() { v.err("Encountered non-constant value in global array") } arrConstVals[idx] = v.genExpr(mem) } backGlob.SetInitializer(llvm.ConstArray(memberLLVMType, arrConstVals)) lengthVal := llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false) backRef := llvm.ConstBitCast(backGlob, llvm.PointerType(llvm.ArrayType(memberLLVMType, 0), 0)) return llvm.ConstStruct([]llvm.Value{lengthVal, backRef}, false) } }
func (c *Codegen) declareTemplate(n *parser.TemplateNode) { name := n.Name.Value var vars []llvm.Type for i, v := range n.Variables { vars = append(vars, c.getLLVMType(v.Type)) c.templates[name].Variables[v.Name.Value] = i } c.templates[name].Type.StructSetBody(vars, false) pointer := llvm.PointerType(c.templates[name].Type, 0) if n.Constructor != nil { f := &parser.FuncNode{ Signature: &parser.FuncSignatureNode{ Name: parser.Identifier{Value: "-" + n.Name.Value}, Parameters: n.Constructor.Parameters, }, } c.declareFunc(f, pointer) c.templates[name].HasConstructor = true } for _, meth := range n.Methods { name := "-" + n.Name.Value + "-" + meth.Function.Signature.Name.Value meth.Function.Signature.Name = parser.Identifier{Value: name} c.declareFunc(meth.Function, pointer) } }
// Allocates a literal array on the stack func (v *Codegen) genArrayLiteral(n *parser.ArrayLiteral) llvm.Value { memberLLVMType := v.typeToLLVMType(n.Type.(parser.ArrayType).MemberType) // allocate backing array arrAlloca := v.builder.CreateArrayAlloca(llvm.ArrayType(memberLLVMType, len(n.Members)), llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false), "") // allocate the array object structAlloca := v.builder.CreateAlloca(v.typeToLLVMType(n.Type), "") // set the length of the array lenGEP := v.builder.CreateGEP(structAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), 0, false)}, "") v.builder.CreateStore(llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false), lenGEP) // set the array pointer to the backing array we allocated arrGEP := v.builder.CreateGEP(structAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), 1, false)}, "") v.builder.CreateStore(v.builder.CreateBitCast(arrAlloca, llvm.PointerType(llvm.ArrayType(memberLLVMType, 0), 0), ""), arrGEP) // copy the constant array to the backing array arrConstVals := make([]llvm.Value, 0, len(n.Members)) for _, mem := range n.Members { arrConstVals = append(arrConstVals, v.genExpr(mem)) } arrConst := llvm.ConstArray(llvm.ArrayType(memberLLVMType, len(n.Members)), arrConstVals) v.builder.CreateStore(arrConst, arrAlloca) return v.builder.CreateLoad(structAlloca, "") }
func primitiveTypeToLLVMType(typ parser.PrimitiveType) llvm.Type { switch typ { case parser.PRIMITIVE_int, parser.PRIMITIVE_uint: return llvm.IntType(intSize * 8) case parser.PRIMITIVE_s8, parser.PRIMITIVE_u8: return llvm.IntType(8) case parser.PRIMITIVE_s16, parser.PRIMITIVE_u16: return llvm.IntType(16) case parser.PRIMITIVE_s32, parser.PRIMITIVE_u32: return llvm.IntType(32) case parser.PRIMITIVE_s64, parser.PRIMITIVE_u64: return llvm.IntType(64) case parser.PRIMITIVE_i128, parser.PRIMITIVE_u128: return llvm.IntType(128) case parser.PRIMITIVE_f32: return llvm.FloatType() case parser.PRIMITIVE_f64: return llvm.DoubleType() case parser.PRIMITIVE_f128: return llvm.FP128Type() case parser.PRIMITIVE_rune: // runes are signed 32-bit int return llvm.IntType(32) case parser.PRIMITIVE_bool: return llvm.IntType(1) case parser.PRIMITIVE_str: return llvm.PointerType(llvm.IntType(8), 0) default: panic("Unimplemented primitive type in LLVM codegen") } }
func (v *Codegen) functionTypeToLLVMType(typ parser.FunctionType, ptr bool) llvm.Type { numOfParams := len(typ.Parameters) if typ.Receiver != nil { numOfParams++ } params := make([]llvm.Type, 0, numOfParams) if typ.Receiver != nil { params = append(params, v.typeToLLVMType(typ.Receiver)) } for _, par := range typ.Parameters { params = append(params, v.typeToLLVMType(par)) } var returnType llvm.Type // oo theres a type, let's try figure it out if typ.Return != nil { returnType = v.typeToLLVMType(typ.Return) } else { returnType = llvm.VoidType() } // create the function type funcType := llvm.FunctionType(returnType, params, typ.IsVariadic) if ptr { funcType = llvm.PointerType(funcType, 0) } return funcType }
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) { int8ptr := llvm.PointerType(c.types.ctx.Int8Type(), 0) ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false) initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp) c.addCommonFunctionAttrs(initMain) entry := llvm.AddBasicBlock(initMain, "entry") builder := llvm.GlobalContext().NewBuilder() defer builder.Dispose() builder.SetInsertPointAtEnd(entry) args := []llvm.Value{llvm.Undef(int8ptr)} if !c.GccgoABI { initfn := c.module.Module.NamedFunction("main..import") if !initfn.IsNil() { builder.CreateCall(initfn, args, "") } builder.CreateRetVoid() return } initdata := c.buildPackageInitData(mainPkg) for _, init := range initdata.Inits { initfn := c.module.Module.NamedFunction(init.InitFunc) if initfn.IsNil() { initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp) } builder.CreateCall(initfn, args, "") } builder.CreateRetVoid() }
// emitInitPrologue emits the init-specific function prologue (guard check and // initialization of dependent packages under the llgo native ABI), and returns // the basic block into which the GC registration call should be emitted. func (fr *frame) emitInitPrologue() llvm.BasicBlock { if fr.GccgoABI { return fr.builder.GetInsertBlock() } initGuard := llvm.AddGlobal(fr.module.Module, llvm.Int1Type(), "init$guard") initGuard.SetLinkage(llvm.InternalLinkage) initGuard.SetInitializer(llvm.ConstNull(llvm.Int1Type())) returnBlock := llvm.AddBasicBlock(fr.function, "") initBlock := llvm.AddBasicBlock(fr.function, "") initGuardVal := fr.builder.CreateLoad(initGuard, "") fr.builder.CreateCondBr(initGuardVal, returnBlock, initBlock) fr.builder.SetInsertPointAtEnd(returnBlock) fr.builder.CreateRetVoid() fr.builder.SetInsertPointAtEnd(initBlock) fr.builder.CreateStore(llvm.ConstInt(llvm.Int1Type(), 1, false), initGuard) int8ptr := llvm.PointerType(fr.types.ctx.Int8Type(), 0) ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false) for _, pkg := range fr.pkg.Object.Imports() { initname := ManglePackagePath(pkg.Path()) + "..import" initfn := fr.module.Module.NamedFunction(initname) if initfn.IsNil() { initfn = llvm.AddFunction(fr.module.Module, initname, ftyp) } args := []llvm.Value{llvm.Undef(int8ptr)} fr.builder.CreateCall(initfn, args, "") } return initBlock }
// Reads the value from the given interface type, assuming that the // interface holds a value of the correct type. func (fr *frame) getInterfaceValue(v *govalue, ty types.Type) *govalue { val := fr.builder.CreateExtractValue(v.value, 1, "") if _, ok := ty.Underlying().(*types.Pointer); !ok { typedval := fr.builder.CreateBitCast(val, llvm.PointerType(fr.types.ToLLVM(ty), 0), "") val = fr.builder.CreateLoad(typedval, "") } return newValue(val, ty) }
// callInstruction translates function call instructions. func (fr *frame) callInstruction(instr ssa.CallInstruction) []*govalue { call := instr.Common() if builtin, ok := call.Value.(*ssa.Builtin); ok { var typ types.Type if v := instr.Value(); v != nil { typ = v.Type() } return fr.callBuiltin(typ, builtin, call.Args) } args := make([]*govalue, len(call.Args)) for i, arg := range call.Args { args[i] = fr.value(arg) } var fn *govalue var chain llvm.Value if call.IsInvoke() { var recv *govalue fn, recv = fr.interfaceMethod(fr.llvmvalue(call.Value), call.Value.Type(), call.Method) args = append([]*govalue{recv}, args...) } else { if ssafn, ok := call.Value.(*ssa.Function); ok { llfn := fr.resolveFunctionGlobal(ssafn) llfn = llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0)) fn = newValue(llfn, ssafn.Type()) } else { // First-class function values are stored as *{*fnptr}, so // we must extract the function pointer. We must also // set the chain, in case the function is a closure. fn = fr.value(call.Value) chain = fn.value fnptr := fr.builder.CreateBitCast(fn.value, llvm.PointerType(fn.value.Type(), 0), "") fnptr = fr.builder.CreateLoad(fnptr, "") fn = newValue(fnptr, fn.Type()) } if recv := call.Signature().Recv(); recv != nil { if _, ok := recv.Type().Underlying().(*types.Pointer); !ok { recvalloca := fr.allocaBuilder.CreateAlloca(args[0].value.Type(), "") fr.builder.CreateStore(args[0].value, recvalloca) args[0] = newValue(recvalloca, types.NewPointer(args[0].Type())) } } } return fr.createCall(fn, chain, args) }
func (c *Codegen) getLLVMType(node parser.Node) llvm.Type { switch t := node.(type) { /* case *FuncTypeNode: case *ArrayTypeNode: */ case *parser.NamedTypeNode: name := t.Name.Value if prim, ok := PRIMITIVE_TYPES[name]; ok { return prim } if t, ok := c.templates[name]; ok { return llvm.PointerType(t.Type, 0) } case *parser.BinaryExprNode: return c.getLLVMType(t.Left) case *parser.CharLitNode: return PRIMITIVE_TYPES["char"] case *parser.BoolLitNode: return PRIMITIVE_TYPES["boolean"] case *parser.NumLitNode: if t.IsFloat { return PRIMITIVE_TYPES["float"] } else { return PRIMITIVE_TYPES["int"] } case *parser.StringLitNode: return llvm.PointerType(c.templates["string"].Type, 0) case *parser.VarAccessNode: if param := c.getCurrParam(t.Name.Value); !param.IsNil() { return param.Type() } else if t := c.scope.GetValue(t.Name.Value).Type(); t != llvm.VoidType() { return t } case *parser.ObjectAccessNode: obj := c.getLLVMType(t.Object) tmpl := c.templates[c.getStructFromPointer(obj)] return c.getLLVMType(tmpl.Values[tmpl.Variables[t.Member.Value]].Type) case *parser.CallExprNode: return c.getLLVMTypeOfCall(t) } return llvm.VoidType() }
func (fr *frame) chanSelect(sel *ssa.Select) (index, recvOk *govalue, recvElems []*govalue) { n := uint64(len(sel.States)) if !sel.Blocking { // non-blocking means there's a default case n++ } size := llvm.ConstInt(llvm.Int32Type(), n, false) selectp := fr.runtime.newSelect.call(fr, size)[0] // Allocate stack for the values to send and receive. ptrs := make([]llvm.Value, len(sel.States)) for i, state := range sel.States { chantyp := state.Chan.Type().Underlying().(*types.Chan) elemtyp := fr.types.ToLLVM(chantyp.Elem()) if state.Dir == types.SendOnly { ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "") fr.builder.CreateStore(fr.llvmvalue(state.Send), ptrs[i]) } else { // Only allocate stack space if the received value is used. used := chanSelectStateUsed(sel, len(recvElems)) if used { ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "") } else { ptrs[i] = llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0)) } recvElems = append(recvElems, newValue(ptrs[i], chantyp.Elem())) } } // Create select{send,recv2} calls. var receivedp llvm.Value if len(recvElems) > 0 { receivedp = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(types.Typ[types.Bool]), "") } if !sel.Blocking { // If the default case is chosen, the index must be -1. fr.runtime.selectdefault.call(fr, selectp, llvm.ConstAllOnes(llvm.Int32Type())) } for i, state := range sel.States { ch := fr.llvmvalue(state.Chan) index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false) if state.Dir == types.SendOnly { fr.runtime.selectsend.call(fr, selectp, ch, ptrs[i], index) } else { fr.runtime.selectrecv2.call(fr, selectp, ch, ptrs[i], receivedp, index) } } // Fire off the select. index = newValue(fr.runtime.selectgo.call(fr, selectp)[0], types.Typ[types.Int]) if len(recvElems) > 0 { recvOk = newValue(fr.builder.CreateLoad(receivedp, ""), types.Typ[types.Bool]) for _, recvElem := range recvElems { recvElem.value = fr.builder.CreateLoad(recvElem.value, "") } } return index, recvOk, recvElems }
func (fr *frame) memsetZero(ptr llvm.Value, size llvm.Value) { memset := fr.runtime.memset ptr = fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "") fill := llvm.ConstNull(llvm.Int8Type()) size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "") align := llvm.ConstInt(llvm.Int32Type(), 1, false) isvolatile := llvm.ConstNull(llvm.Int1Type()) fr.builder.CreateCall(memset, []llvm.Value{ptr, fill, size, align, isvolatile}, "") }
func (fr *frame) makeInterfaceFromPointer(vptr llvm.Value, vty types.Type, iface types.Type) *govalue { i8ptr := llvm.PointerType(llvm.Int8Type(), 0) llv := fr.builder.CreateBitCast(vptr, i8ptr, "") value := llvm.Undef(fr.types.ToLLVM(iface)) itab := fr.types.getItabPointer(vty, iface.Underlying().(*types.Interface)) value = fr.builder.CreateInsertValue(value, itab, 0, "") value = fr.builder.CreateInsertValue(value, llv, 1, "") return newValue(value, iface) }
func (v *Codegen) genSizeofExpr(n *parser.SizeofExpr) llvm.Value { if n.Expr != nil { gep := v.builder.CreateGEP(llvm.ConstNull(llvm.PointerType(v.typeToLLVMType(n.Expr.GetType()), 0)), []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 1, false)}, "") return v.builder.CreatePtrToInt(gep, v.typeToLLVMType(n.GetType()), "sizeof") } else { // we have a type panic("can't do this yet") } }
func (fi *functionTypeInfo) call(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, callee llvm.Value, chain llvm.Value, args []llvm.Value) []llvm.Value { callArgs := make([]llvm.Value, len(fi.argAttrs)) if chain.C == nil { chain = llvm.Undef(llvm.PointerType(ctx.Int8Type(), 0)) } callArgs[fi.chainIndex] = chain for i, a := range args { fi.argInfos[i].encode(ctx, allocaBuilder, builder, callArgs, a) } fi.retInf.prepare(ctx, allocaBuilder, callArgs) typedCallee := builder.CreateBitCast(callee, llvm.PointerType(fi.functionType, 0), "") call := builder.CreateCall(typedCallee, callArgs, "") call.AddInstrAttribute(0, fi.retAttr) for i, a := range fi.argAttrs { call.AddInstrAttribute(i+1, a) } return fi.retInf.decode(ctx, allocaBuilder, builder, call) }
func (fr *frame) createLandingPad(cleanup bool) llvm.Value { lp := fr.builder.CreateLandingPad(fr.runtime.gccgoExceptionType, fr.runtime.gccgoPersonality, 0, "") if cleanup { lp.SetCleanup(true) } else { lp.AddClause(llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0))) } return lp }
// chanSend implements ch<- x func (fr *frame) chanSend(ch *govalue, elem *govalue) { elemtyp := ch.Type().Underlying().(*types.Chan).Elem() elem = fr.convert(elem, elemtyp) elemptr := fr.allocaBuilder.CreateAlloca(elem.value.Type(), "") fr.builder.CreateStore(elem.value, elemptr) elemptr = fr.builder.CreateBitCast(elemptr, llvm.PointerType(llvm.Int8Type(), 0), "") chantyp := fr.types.ToRuntime(ch.Type()) fr.runtime.sendBig.call(fr, chantyp, ch.value, elemptr) }
// Allocates a literal array on the stack func (v *Codegen) genArrayLiteral(n *parser.CompositeLiteral) llvm.Value { arrayLLVMType := v.typeToLLVMType(n.Type) memberLLVMType := v.typeToLLVMType(n.Type.ActualType().(parser.ArrayType).MemberType) arrayValues := make([]llvm.Value, len(n.Values)) for idx, mem := range n.Values { value := v.genExpr(mem) if !v.inFunction() && !value.IsConstant() { v.err("Encountered non-constant value in global array") } arrayValues[idx] = value } lengthValue := llvm.ConstInt(v.typeToLLVMType(parser.PRIMITIVE_uint), uint64(len(n.Values)), false) var backingArrayPointer llvm.Value if v.inFunction() { // allocate backing array backingArray := v.builder().CreateAlloca(llvm.ArrayType(memberLLVMType, len(n.Values)), "") // copy the constant array to the backing array for idx, value := range arrayValues { gep := v.builder().CreateStructGEP(backingArray, idx, "") v.builder().CreateStore(value, gep) } backingArrayPointer = v.builder().CreateBitCast(backingArray, llvm.PointerType(memberLLVMType, 0), "") } else { backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex) v.arrayIndex++ backingArray := llvm.AddGlobal(v.curFile.LlvmModule, llvm.ArrayType(memberLLVMType, len(n.Values)), backName) backingArray.SetLinkage(llvm.InternalLinkage) backingArray.SetGlobalConstant(false) backingArray.SetInitializer(llvm.ConstArray(memberLLVMType, arrayValues)) backingArrayPointer = llvm.ConstBitCast(backingArray, llvm.PointerType(memberLLVMType, 0)) } structValue := llvm.Undef(arrayLLVMType) structValue = v.builder().CreateInsertValue(structValue, lengthValue, 0, "") structValue = v.builder().CreateInsertValue(structValue, backingArrayPointer, 1, "") return structValue }
// resolveFunctionDescriptorGlobal returns a reference to the LLVM global // storing the function's descriptor. func (u *unit) resolveFunctionDescriptorGlobal(f *ssa.Function) llvm.Value { llfd, ok := u.funcDescriptors[f] if !ok { name := u.types.mc.mangleFunctionName(f) + "$descriptor" llfd = llvm.AddGlobal(u.module.Module, llvm.PointerType(llvm.Int8Type(), 0), name) llfd.SetGlobalConstant(true) u.funcDescriptors[f] = llfd } return llfd }
func (u *unit) addGlobal(global llvm.Value, ty types.Type) { u.globalInits[global] = new(globalInit) if hasPointers(ty) { global = llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0)) size := llvm.ConstInt(u.types.inttype, uint64(u.types.Sizeof(ty)), false) root := llvm.ConstStruct([]llvm.Value{global, size}, false) u.gcRoots = append(u.gcRoots, root) } }
// makeMap implements make(maptype[, initial space]) func (fr *frame) makeMap(typ types.Type, cap_ *govalue) *govalue { // TODO(pcc): call __go_new_map_big here if needed dyntyp := fr.types.getMapDescriptorPointer(typ) dyntyp = fr.builder.CreateBitCast(dyntyp, llvm.PointerType(llvm.Int8Type(), 0), "") var cap llvm.Value if cap_ != nil { cap = fr.convert(cap_, types.Typ[types.Uintptr]).value } else { cap = llvm.ConstNull(fr.types.inttype) } m := fr.runtime.newMap.call(fr, dyntyp, cap) return newValue(m[0], typ) }
// mapUpdate implements m[k] = v func (fr *frame) mapUpdate(m, k, v *govalue) { llk := k.value pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "") fr.builder.CreateStore(llk, pk) valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(true))[0] valptr.AddInstrAttribute(2, llvm.NoCaptureAttribute) valptr.AddInstrAttribute(2, llvm.ReadOnlyAttribute) elemtyp := m.Type().Underlying().(*types.Map).Elem() llelemtyp := fr.types.ToLLVM(elemtyp) typedvalptr := fr.builder.CreateBitCast(valptr, llvm.PointerType(llelemtyp, 0), "") fr.builder.CreateStore(v.value, typedvalptr) }
func (v *Codegen) genStringLiteral(n *parser.StringLiteral) llvm.Value { memberLLVMType := v.typeToLLVMType(parser.PRIMITIVE_u8) nullTerm := n.IsCString length := len(n.Value) if nullTerm { length++ } var backingArrayPointer llvm.Value if v.inFunction() { // allocate backing array backingArray := v.builder().CreateAlloca(llvm.ArrayType(memberLLVMType, length), "stackstr") v.builder().CreateStore(llvm.ConstString(n.Value, nullTerm), backingArray) backingArrayPointer = v.builder().CreateBitCast(backingArray, llvm.PointerType(memberLLVMType, 0), "") } else { backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex) v.arrayIndex++ backingArray := llvm.AddGlobal(v.curFile.LlvmModule, llvm.ArrayType(memberLLVMType, length), backName) backingArray.SetLinkage(llvm.InternalLinkage) backingArray.SetGlobalConstant(false) backingArray.SetInitializer(llvm.ConstString(n.Value, nullTerm)) backingArrayPointer = llvm.ConstBitCast(backingArray, llvm.PointerType(memberLLVMType, 0)) } if n.Type.ActualType().Equals(parser.ArrayOf(parser.PRIMITIVE_u8)) { lengthValue := llvm.ConstInt(v.typeToLLVMType(parser.PRIMITIVE_uint), uint64(length), false) structValue := llvm.Undef(v.typeToLLVMType(n.Type)) structValue = v.builder().CreateInsertValue(structValue, lengthValue, 0, "") structValue = v.builder().CreateInsertValue(structValue, backingArrayPointer, 1, "") return structValue } else { return backingArrayPointer } }