func (n *VarExpr) Gen(cg *CG) llvm.Value { fun := cg.GetInsertBlock().Parent() var oldBindingNames []string var oldBindingValues []llvm.Value for name, init := range n.Names { var initVal llvm.Value if init != nil { init.Gen(cg) if initVal.IsNil() { return llvm.Value{} } } else { initVal = llvm.ConstFloat(cg.FloatType(), 0) } alloca := createEntryBlockAlloca(fun, name) cg.CreateStore(initVal, alloca) oldBindingNames = append(oldBindingNames, name) oldBindingValues = append(oldBindingValues, cg.NamedValues[name]) cg.NamedValues[name] = alloca } bodyVal := n.Body.Gen(cg) if bodyVal.IsNil() { return llvm.Value{} } for i, name := range oldBindingNames { cg.NamedValues[name] = oldBindingValues[i] } return bodyVal }
func (n *ForExpr) Gen(cg *CG) llvm.Value { startVal := n.Start.Gen(cg) if startVal.IsNil() { return errv("Code generation failed for start expression") } fun := cg.GetInsertBlock().Parent() alloca := createEntryBlockAlloca(fun, n.Var) cg.CreateStore(startVal, alloca) loopBB := llvm.AddBasicBlock(fun, "loop") cg.CreateBr(loopBB) cg.SetInsertPointAtEnd(loopBB) oldVal := cg.NamedValues[n.Var] cg.NamedValues[n.Var] = alloca if n.Body.Gen(cg).IsNil() { return llvm.Value{} } var stepVal llvm.Value if n.Step != nil { stepVal = n.Step.Gen(cg) if stepVal.IsNil() { return llvm.ConstNull(llvm.DoubleType()) } } else { stepVal = llvm.ConstFloat(llvm.DoubleType(), 1) } endVal := n.End.Gen(cg) if endVal.IsNil() { return llvm.Value{} } curVar := cg.CreateLoad(alloca, n.Var) nextVar := cg.CreateFAdd(curVar, stepVal, "nextvar") cg.CreateStore(nextVar, alloca) endVal = cg.CreateFCmp(llvm.FloatONE, endVal, llvm.ConstFloat(llvm.DoubleType(), 0), "loopcond") afterBB := cg.AddBasicBlock(fun, "afterloop") cg.CreateCondBr(endVal, loopBB, afterBB) cg.SetInsertPointAtEnd(afterBB) if !oldVal.IsNil() { cg.NamedValues[n.Var] = oldVal } else { delete(cg.NamedValues, n.Var) } return llvm.ConstFloat(llvm.DoubleType(), 0) }
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") } }
func (c *Codegen) generateCall(node *parser.CallExprNode, obj llvm.Value) llvm.Value { fn, args := c.getFunction(node.Function) if !obj.IsNil() { args = append([]llvm.Value{obj}, args...) } for i, arg := range node.Arguments { expr := c.generateExpression(arg) if fn.Type().ElementType().ParamTypesCount() > i { expr = c.convert(expr, fn.Type().ElementType().ParamTypes()[i]) } //Unbox arguments for C functions if fn.BasicBlocksCount() == 0 { expr = c.unbox(expr) } args = append(args, expr) } return c.builder.CreateCall(fn, args, "") }
func (fr *frame) slice(x llvm.Value, xtyp types.Type, low, high, max llvm.Value) llvm.Value { if !low.IsNil() { low = fr.createZExtOrTrunc(low, fr.types.inttype, "") } else { low = llvm.ConstNull(fr.types.inttype) } if !high.IsNil() { high = fr.createZExtOrTrunc(high, fr.types.inttype, "") } if !max.IsNil() { max = fr.createZExtOrTrunc(max, fr.types.inttype, "") } var arrayptr, arraylen, arraycap llvm.Value var elemtyp types.Type var errcode uint64 switch typ := xtyp.Underlying().(type) { case *types.Pointer: // *array errcode = gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS arraytyp := typ.Elem().Underlying().(*types.Array) elemtyp = arraytyp.Elem() arrayptr = x arrayptr = fr.builder.CreateBitCast(arrayptr, llvm.PointerType(llvm.Int8Type(), 0), "") arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) arraycap = arraylen case *types.Slice: errcode = gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS elemtyp = typ.Elem() arrayptr = fr.builder.CreateExtractValue(x, 0, "") arraylen = fr.builder.CreateExtractValue(x, 1, "") arraycap = fr.builder.CreateExtractValue(x, 2, "") case *types.Basic: if high.IsNil() { high = llvm.ConstAllOnes(fr.types.inttype) // -1 } result := fr.runtime.stringSlice.call(fr, x, low, high) return result[0] default: panic("unimplemented") } if high.IsNil() { high = arraylen } if max.IsNil() { max = arraycap } // Bounds checking: 0 <= low <= high <= max <= cap zero := llvm.ConstNull(fr.types.inttype) l0 := fr.builder.CreateICmp(llvm.IntSLT, low, zero, "") hl := fr.builder.CreateICmp(llvm.IntSLT, high, low, "") mh := fr.builder.CreateICmp(llvm.IntSLT, max, high, "") cm := fr.builder.CreateICmp(llvm.IntSLT, arraycap, max, "") cond := fr.builder.CreateOr(l0, hl, "") cond = fr.builder.CreateOr(cond, mh, "") cond = fr.builder.CreateOr(cond, cm, "") fr.condBrRuntimeError(cond, errcode) slicelen := fr.builder.CreateSub(high, low, "") slicecap := fr.builder.CreateSub(max, low, "") elemsize := llvm.ConstInt(fr.llvmtypes.inttype, uint64(fr.llvmtypes.Sizeof(elemtyp)), false) offset := fr.builder.CreateMul(low, elemsize, "") sliceptr := fr.builder.CreateInBoundsGEP(arrayptr, []llvm.Value{offset}, "") llslicetyp := fr.llvmtypes.sliceBackendType().ToLLVM(fr.llvmtypes.ctx) sliceValue := llvm.Undef(llslicetyp) sliceValue = fr.builder.CreateInsertValue(sliceValue, sliceptr, 0, "") sliceValue = fr.builder.CreateInsertValue(sliceValue, slicelen, 1, "") sliceValue = fr.builder.CreateInsertValue(sliceValue, slicecap, 2, "") return sliceValue }
func (v *Codegen) genBinop(operator parser.BinOpType, resType, lhandType, rhandType parser.Type, lhand, rhand llvm.Value) llvm.Value { if lhand.IsNil() || rhand.IsNil() { v.err("invalid binary expr") } else { switch operator { // Arithmetic case parser.BINOP_ADD: if resType.IsFloatingType() { return v.builder().CreateFAdd(lhand, rhand, "") } else { return v.builder().CreateAdd(lhand, rhand, "") } case parser.BINOP_SUB: if resType.IsFloatingType() { return v.builder().CreateFSub(lhand, rhand, "") } else { return v.builder().CreateSub(lhand, rhand, "") } case parser.BINOP_MUL: if resType.IsFloatingType() { return v.builder().CreateFMul(lhand, rhand, "") } else { return v.builder().CreateMul(lhand, rhand, "") } case parser.BINOP_DIV: if resType.IsFloatingType() { return v.builder().CreateFDiv(lhand, rhand, "") } else { if resType.(parser.PrimitiveType).IsSigned() { return v.builder().CreateSDiv(lhand, rhand, "") } else { return v.builder().CreateUDiv(lhand, rhand, "") } } case parser.BINOP_MOD: if resType.IsFloatingType() { return v.builder().CreateFRem(lhand, rhand, "") } else { if resType.(parser.PrimitiveType).IsSigned() { return v.builder().CreateSRem(lhand, rhand, "") } else { return v.builder().CreateURem(lhand, rhand, "") } } // Comparison case parser.BINOP_GREATER, parser.BINOP_LESS, parser.BINOP_GREATER_EQ, parser.BINOP_LESS_EQ, parser.BINOP_EQ, parser.BINOP_NOT_EQ: if lhandType.IsFloatingType() { return v.builder().CreateFCmp(comparisonOpToFloatPredicate(operator), lhand, rhand, "") } else { return v.builder().CreateICmp(comparisonOpToIntPredicate(operator, lhandType.IsSigned()), lhand, rhand, "") } // Bitwise case parser.BINOP_BIT_AND: return v.builder().CreateAnd(lhand, rhand, "") case parser.BINOP_BIT_OR: return v.builder().CreateOr(lhand, rhand, "") case parser.BINOP_BIT_XOR: return v.builder().CreateXor(lhand, rhand, "") case parser.BINOP_BIT_LEFT: return v.builder().CreateShl(lhand, rhand, "") case parser.BINOP_BIT_RIGHT: // TODO make sure both operands are same type (create type cast here?) // TODO in semantic.go, make sure rhand is *unsigned* (LLVM always treats it that way) // TODO doc this if lhandType.IsSigned() { return v.builder().CreateAShr(lhand, rhand, "") } else { return v.builder().CreateLShr(lhand, rhand, "") } default: panic("umimplented binop") } } panic("unreachable") }