func (v *Codegen) genAddressOfExpr(n *parser.AddressOfExpr) llvm.Value { gep := v.builder.CreateGEP(v.variableLookup[n.Access.Accesses[0].Variable], []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false)}, "") for i := 0; i < len(n.Access.Accesses); i++ { switch n.Access.Accesses[i].AccessType { case parser.ACCESS_ARRAY: gepIndexes := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 1, false)} gep = v.builder.CreateGEP(gep, gepIndexes, "") load := v.builder.CreateLoad(gep, "") // TODO check that access is in bounds! gepIndexes = []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), v.genExpr(n.Access.Accesses[i].Subscript)} gep = v.builder.CreateGEP(load, gepIndexes, "") case parser.ACCESS_VARIABLE: // nothing to do case parser.ACCESS_STRUCT: index := n.Access.Accesses[i].Variable.Type.(*parser.StructType).VariableIndex(n.Access.Accesses[i+1].Variable) gep = v.builder.CreateGEP(gep, []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(index), false)}, "") default: panic("") } } return gep }
// 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 (c *Codegen) generateExpression(node parser.Node) llvm.Value { switch n := node.(type) { case *parser.BinaryExprNode: return c.generateBinaryExpression(n) case *parser.NumLitNode: if n.IsFloat { return llvm.ConstFloat(PRIMITIVE_TYPES["float"], n.FloatValue) } else { return llvm.ConstInt(PRIMITIVE_TYPES["int"], uint64(n.IntValue), false) } case *parser.BoolLitNode: i := 0 if n.Value { i = 1 } return llvm.ConstInt(PRIMITIVE_TYPES["boolean"], uint64(i), false) case *parser.CharLitNode: return llvm.ConstInt(PRIMITIVE_TYPES["char"], uint64(n.Value), false) case *parser.VarAccessNode, *parser.ObjectAccessNode, *parser.ArrayAccessNode, *parser.CallExprNode, *parser.StringLitNode, *parser.MakeExprNode: return c.generateAccess(n, true) } return null }
func (c *Codegen) generateStringConcat(str1, str2 llvm.Value) llvm.Value { // one := llvm.ConstInt(PRIMITIVE_TYPES["int"], 1, false) len1 := c.builder.CreateCall(c.module.NamedFunction("-string-len"), []llvm.Value{str1}, "") len2 := c.builder.CreateLoad(c.builder.CreateStructGEP(str2, 1, ""), "") len_sum := c.builder.CreateAdd(len1, len2, "") chars := c.builder.CreateCall(c.module.NamedFunction("malloc"), []llvm.Value{len_sum}, "") c.builder.CreateCall(c.module.NamedFunction("llvm.memcpy.p0i8.p0i8.i32"), []llvm.Value{ chars, c.unbox(str1), len1, llvm.ConstInt(PRIMITIVE_TYPES["int"], 0, false), llvm.ConstInt(PRIMITIVE_TYPES["boolean"], 0, false), }, "") c.builder.CreateCall(c.module.NamedFunction("llvm.memcpy.p0i8.p0i8.i32"), []llvm.Value{ c.builder.CreateGEP(chars, []llvm.Value{len1}, ""), c.unbox(str2), len2, llvm.ConstInt(PRIMITIVE_TYPES["int"], 0, false), llvm.ConstInt(PRIMITIVE_TYPES["boolean"], 0, false), }, "") str := c.builder.CreateMalloc(c.templates["string"].Type, "") c.builder.CreateStore(chars, c.builder.CreateStructGEP(str, 0, "")) c.builder.CreateStore(len_sum, c.builder.CreateStructGEP(str, 1, "")) c.builder.CreateStore(len_sum, c.builder.CreateStructGEP(str, 2, "")) return str }
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 (v *Codegen) genAccessGEP(n parser.Expr) llvm.Value { switch access := n.(type) { case *parser.VariableAccessExpr: varType := v.getVariable(access.Variable) log.Debugln("codegen", "%v => %v", access.Variable, varType) if varType.IsNil() { panic("varType was nil") } gep := v.builder().CreateGEP(varType, []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false)}, "") if _, ok := access.GetType().(parser.MutableReferenceType); ok { return v.builder().CreateLoad(gep, "") } if _, ok := access.GetType().(parser.ConstantReferenceType); ok { return v.builder().CreateLoad(gep, "") } return gep case *parser.StructAccessExpr: gep := v.genAccessGEP(access.Struct) typ := access.Struct.GetType().ActualType() index := typ.(parser.StructType).VariableIndex(access.Variable) return v.builder().CreateStructGEP(gep, index, "") case *parser.ArrayAccessExpr: gep := v.genAccessGEP(access.Array) subscriptExpr := v.genExpr(access.Subscript) v.genBoundsCheck(v.builder().CreateLoad(v.builder().CreateStructGEP(gep, 0, ""), ""), subscriptExpr, access.Subscript.GetType()) gep = v.builder().CreateStructGEP(gep, 1, "") load := v.builder().CreateLoad(gep, "") gepIndexes := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), subscriptExpr} return v.builder().CreateGEP(load, gepIndexes, "") case *parser.TupleAccessExpr: gep := v.genAccessGEP(access.Tuple) // TODO: Check overflow return v.builder().CreateStructGEP(gep, int(access.Index), "") case *parser.DerefAccessExpr: return v.genExpr(access.Expr) default: panic("unhandled access type") } }
func (fr *frame) setBranchWeightMetadata(br llvm.Value, trueweight, falseweight uint64) { mdprof := llvm.MDKindID("prof") mdnode := llvm.MDNode([]llvm.Value{ llvm.MDString("branch_weights"), llvm.ConstInt(llvm.Int32Type(), trueweight, false), llvm.ConstInt(llvm.Int32Type(), falseweight, false), }) br.SetMetadata(mdprof, mdnode) }
func (fr *frame) chanSelect(states []selectState, blocking bool) (index, recvOk *govalue, recvElems []*govalue) { n := uint64(len(states)) if !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. // // TODO(axw) check if received elements have any users, and // elide stack allocation if not (pass nil to recv2 instead.) ptrs := make([]llvm.Value, len(states)) for i, state := range states { chantyp := state.Chan.Type().Underlying().(*types.Chan) elemtyp := fr.types.ToLLVM(chantyp.Elem()) ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "") if state.Dir == types.SendOnly { fr.builder.CreateStore(state.Send.value, ptrs[i]) } else { 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 !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 states { ch := state.Chan.value 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 }
// 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 (fr *frame) callCap(arg *govalue) *govalue { var v llvm.Value switch typ := arg.Type().Underlying().(type) { case *types.Array: v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(typ.Len()), false) case *types.Pointer: atyp := typ.Elem().Underlying().(*types.Array) v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(atyp.Len()), false) case *types.Slice: v = fr.builder.CreateExtractValue(arg.value, 2, "") case *types.Chan: v = fr.runtime.chanCap.call(fr, arg.value)[0] } return newValue(v, types.Typ[types.Int]) }
func (v *Codegen) genAccessGEP(n parser.Expr) llvm.Value { switch n.(type) { case *parser.VariableAccessExpr: vae := n.(*parser.VariableAccessExpr) return v.builder.CreateGEP(v.variableLookup[vae.Variable], []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false)}, "") case *parser.StructAccessExpr: sae := n.(*parser.StructAccessExpr) gep := v.genAccessGEP(sae.Struct) typ := sae.Struct.GetType().ActualType() index := typ.(*parser.StructType).VariableIndex(sae.Variable) return v.builder.CreateStructGEP(gep, index, "") case *parser.ArrayAccessExpr: aae := n.(*parser.ArrayAccessExpr) gep := v.genAccessGEP(aae.Array) subscriptExpr := v.genExpr(aae.Subscript) v.genBoundsCheck(v.builder.CreateLoad(v.builder.CreateStructGEP(gep, 0, ""), ""), subscriptExpr, aae.Subscript.GetType()) gep = v.builder.CreateStructGEP(gep, 1, "") load := v.builder.CreateLoad(gep, "") gepIndexes := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), subscriptExpr} return v.builder.CreateGEP(load, gepIndexes, "") case *parser.TupleAccessExpr: tae := n.(*parser.TupleAccessExpr) gep := v.genAccessGEP(tae.Tuple) // TODO: Check overflow return v.builder.CreateStructGEP(gep, int(tae.Index), "") case *parser.DerefAccessExpr: dae := n.(*parser.DerefAccessExpr) return v.genExpr(dae.Expr) default: panic("unhandled access type") } }
func (v *Codegen) genNumericLiteral(n *parser.NumericLiteral) llvm.Value { if n.Type.IsFloatingType() { return llvm.ConstFloat(v.typeToLLVMType(n.Type), n.AsFloat()) } else { return llvm.ConstInt(v.typeToLLVMType(n.Type), n.AsInt(), false) } }
func (v *Codegen) genBoundsCheck(limit llvm.Value, index llvm.Value, indexType parser.Type) { segvBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_segv") endBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_end") upperCheckBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_upper_block") tooLow := v.builder().CreateICmp(llvm.IntSGT, llvm.ConstInt(index.Type(), 0, false), index, "boundscheck_lower") v.builder().CreateCondBr(tooLow, segvBlock, upperCheckBlock) v.builder().SetInsertPointAtEnd(upperCheckBlock) // make sure limit and index have same width castedLimit := limit castedIndex := index if index.Type().IntTypeWidth() < limit.Type().IntTypeWidth() { if indexType.IsSigned() { castedIndex = v.builder().CreateSExt(index, limit.Type(), "") } else { castedIndex = v.builder().CreateZExt(index, limit.Type(), "") } } else if index.Type().IntTypeWidth() > limit.Type().IntTypeWidth() { castedLimit = v.builder().CreateZExt(limit, index.Type(), "") } tooHigh := v.builder().CreateICmp(llvm.IntSLE, castedLimit, castedIndex, "boundscheck_upper") v.builder().CreateCondBr(tooHigh, segvBlock, endBlock) v.builder().SetInsertPointAtEnd(segvBlock) v.genRaiseSegfault() v.builder().CreateUnreachable() v.builder().SetInsertPointAtEnd(endBlock) }
// 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 (fr *frame) condBrRuntimeError(cond llvm.Value, errcode uint64) { if cond.IsNull() { return } errorbb := fr.runtimeErrorBlocks[errcode] newbb := errorbb.C == nil if newbb { errorbb = llvm.AddBasicBlock(fr.function, "") fr.runtimeErrorBlocks[errcode] = errorbb } contbb := llvm.AddBasicBlock(fr.function, "") br := fr.builder.CreateCondBr(cond, errorbb, contbb) fr.setBranchWeightMetadata(br, 1, 1000) if newbb { fr.builder.SetInsertPointAtEnd(errorbb) fr.runtime.runtimeError.call(fr, llvm.ConstInt(llvm.Int32Type(), errcode, false)) fr.builder.CreateUnreachable() } fr.builder.SetInsertPointAtEnd(contbb) }
// 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 }
func (v *Codegen) genDefaultValue(typ parser.Type) llvm.Value { atyp := typ.ActualType() // Generate default struct values if structType, ok := atyp.(parser.StructType); ok { lit := createStructInitializer(typ) if lit != nil { return v.genStructLiteral(lit) } else { return llvm.Undef(v.typeToLLVMType(structType)) } } if tupleType, ok := atyp.(parser.TupleType); ok { values := make([]llvm.Value, len(tupleType.Members)) for idx, member := range tupleType.Members { values[idx] = v.genDefaultValue(member) } return llvm.ConstStruct(values, false) } if atyp.IsIntegerType() || atyp == parser.PRIMITIVE_bool { return llvm.ConstInt(v.typeToLLVMType(atyp), 0, false) } if atyp.IsFloatingType() { return llvm.ConstFloat(v.typeToLLVMType(atyp), 0) } panic("type does not have default value: " + atyp.TypeName()) }
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 (v *Codegen) genLogicalBinop(n *parser.BinaryExpr) llvm.Value { and := n.Op == parser.BINOP_LOG_AND next := llvm.AddBasicBlock(v.currentLLVMFunction(), "and_next") exit := llvm.AddBasicBlock(v.currentLLVMFunction(), "and_exit") b1 := v.genExpr(n.Lhand) first := v.builder().GetInsertBlock() if and { v.builder().CreateCondBr(b1, next, exit) } else { v.builder().CreateCondBr(b1, exit, next) } v.builder().SetInsertPointAtEnd(next) b2 := v.genExpr(n.Rhand) next = v.builder().GetInsertBlock() v.builder().CreateBr(exit) v.builder().SetInsertPointAtEnd(exit) phi := v.builder().CreatePHI(b2.Type(), "and_phi") var testIncVal uint64 if and { testIncVal = 0 } else { testIncVal = 1 } phi.AddIncoming([]llvm.Value{llvm.ConstInt(llvm.IntType(1), testIncVal, false), b2}, []llvm.BasicBlock{first, next}) return phi }
// If this value is sufficiently large, look through referrers to see if we can // avoid a load. func (fr *frame) canAvoidLoad(instr *ssa.UnOp, op llvm.Value) bool { if fr.types.Sizeof(instr.Type()) < 16 { // Don't bother with small values. return false } // Keep track of whether our pointer may escape. We conservatively assume // that MakeInterfaces will escape. esc := false // We only know how to avoid loads if they are used to create an interface // or read an element of the structure. If we see any other referrer, abort. for _, ref := range *instr.Referrers() { switch ref.(type) { case *ssa.MakeInterface: esc = true case *ssa.Field, *ssa.Index: // ok default: return false } } var opcopy llvm.Value if esc { opcopy = fr.createTypeMalloc(instr.Type()) } else { opcopy = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(instr.Type()), "") } fr.memcpy(opcopy, op, llvm.ConstInt(fr.types.inttype, uint64(fr.types.Sizeof(instr.Type())), false)) fr.ptr[instr] = opcopy return true }
// callAppend takes two slices of the same type, and yields // the result of appending the second to the first. func (fr *frame) callAppend(a, b *govalue) *govalue { bptr := fr.builder.CreateExtractValue(b.value, 0, "") blen := fr.builder.CreateExtractValue(b.value, 1, "") elemsizeInt64 := fr.types.Sizeof(a.Type().Underlying().(*types.Slice).Elem()) elemsize := llvm.ConstInt(fr.target.IntPtrType(), uint64(elemsizeInt64), false) result := fr.runtime.append.call(fr, a.value, bptr, blen, elemsize)[0] return newValue(result, a.Type()) }
func (v *Codegen) genEnumLiteral(n *parser.EnumLiteral) llvm.Value { enumType := n.Type.ActualType().(parser.EnumType) enumLLVMType := v.typeToLLVMType(n.Type) memberIdx := enumType.MemberIndex(n.Member) member := enumType.Members[memberIdx] if enumType.Simple { return llvm.ConstInt(enumLLVMType, uint64(member.Tag), false) } // TODO: Handle other integer size, maybe dynamic depending on max value? tagValue := llvm.ConstInt(llvm.IntType(32), uint64(member.Tag), false) enumValue := llvm.Undef(enumLLVMType) enumValue = v.builder().CreateInsertValue(enumValue, tagValue, 0, "") memberLLVMType := v.typeToLLVMType(member.Type) var memberValue llvm.Value if n.TupleLiteral != nil { memberValue = v.genTupleLiteral(n.TupleLiteral) } else if n.CompositeLiteral != nil { memberValue = v.genCompositeLiteral(n.CompositeLiteral) } if v.inFunction() { alloc := v.builder().CreateAlloca(enumLLVMType, "") tagGep := v.builder().CreateStructGEP(alloc, 0, "") v.builder().CreateStore(tagValue, tagGep) if !memberValue.IsNil() { dataGep := v.builder().CreateStructGEP(alloc, 1, "") dataGep = v.builder().CreateBitCast(dataGep, llvm.PointerType(memberLLVMType, 0), "") v.builder().CreateStore(memberValue, dataGep) } return v.builder().CreateLoad(alloc, "") } else { panic("unimplemented: global enum literal") } }
// SetLocation sets the current debug location. func (d *DIBuilder) SetLocation(b llvm.Builder, pos token.Pos) { if !pos.IsValid() { return } position := d.fset.Position(pos) d.lb = llvm.Value{nil} if position.Filename != d.fnFile && position.Filename != "" { // This can happen rarely, e.g. in init functions. diFile := d.builder.CreateFile(d.remapFilePath(position.Filename), "") d.lb = d.builder.CreateLexicalBlockFile(d.scope(), diFile, 0) } b.SetCurrentDebugLocation(llvm.MDNode([]llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(position.Line), false), llvm.ConstInt(llvm.Int32Type(), uint64(position.Column), false), d.scope(), llvm.Value{}, })) }
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 (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 (v *Codegen) genBoolLiteral(n *parser.BoolLiteral) llvm.Value { var num uint64 if n.Value { num = 1 } return llvm.ConstInt(v.typeToLLVMType(n.GetType()), num, true) }
// Finalize must be called after all compilation units are translated, // generating the final debug metadata for the module. func (d *DIBuilder) Finalize() { d.module.AddNamedMetadataOperand( "llvm.module.flags", llvm.GlobalContext().MDNode([]llvm.Metadata{ llvm.ConstInt(llvm.Int32Type(), 2, false).ConstantAsMetadata(), // Warn on mismatch llvm.GlobalContext().MDString("Dwarf Version"), llvm.ConstInt(llvm.Int32Type(), 4, false).ConstantAsMetadata(), }), ) d.module.AddNamedMetadataOperand( "llvm.module.flags", llvm.GlobalContext().MDNode([]llvm.Metadata{ llvm.ConstInt(llvm.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch llvm.GlobalContext().MDString("Debug Info Version"), llvm.ConstInt(llvm.Int32Type(), 2, false).ConstantAsMetadata(), }), ) d.builder.Finalize() }
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) } }
func (v *Codegen) genSizeofExpr(n *parser.SizeofExpr) llvm.Value { var typ llvm.Type if n.Expr != nil { typ = v.typeToLLVMType(n.Expr.GetType()) } else { typ = v.typeToLLVMType(n.Type) } return llvm.ConstInt(v.targetData.IntPtrType(), v.targetData.TypeAllocSize(typ), false) }
func (v *Codegen) genRaiseSegfault() { fn := v.curFile.LlvmModule.NamedFunction("raise") intType := v.typeToLLVMType(parser.PRIMITIVE_int) if fn.IsNil() { fnType := llvm.FunctionType(intType, []llvm.Type{intType}, false) fn = llvm.AddFunction(v.curFile.LlvmModule, "raise", fnType) } v.builder().CreateCall(fn, []llvm.Value{llvm.ConstInt(intType, 11, false)}, "segfault") }