func (v *Codegen) genFunctionBody(fn *parser.Function, llvmFn llvm.Value) { block := llvm.AddBasicBlock(llvmFn, "entry") v.pushFunction(fn) v.builders[v.currentFunction()] = llvm.NewBuilder() v.builder().SetInsertPointAtEnd(block) pars := fn.Parameters if fn.Type.Receiver != nil { newPars := make([]*parser.VariableDecl, len(pars)+1) newPars[0] = fn.Receiver copy(newPars[1:], pars) pars = newPars } for i, par := range pars { alloc := v.builder().CreateAlloca(v.typeToLLVMType(par.Variable.Type), par.Variable.Name) v.variableLookup[par.Variable] = alloc v.builder().CreateStore(llvmFn.Params()[i], alloc) } v.genBlock(fn.Body) v.builder().Dispose() delete(v.builders, v.currentFunction()) delete(v.curLoopExits, v.currentFunction()) delete(v.curLoopNexts, v.currentFunction()) v.popFunction() }
func NewCG() *CG { cg := &CG{ Context: llvm.GlobalContext(), Builder: llvm.NewBuilder(), Mod: llvm.NewModule("kaleidoscope"), NamedValues: make(map[string]llvm.Value), Protos: make(map[string]*ProtoDecl), } cg.Init() return cg }
func (v *Codegen) genVariableDecl(n *parser.VariableDecl, semicolon bool) llvm.Value { var res llvm.Value if v.inFunction() { mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE) funcEntry := v.currentLLVMFunction().EntryBasicBlock() // use this builder() for the variable alloca // this means all allocas go at the start of the function // so each variable is only allocated once allocBuilder := llvm.NewBuilder() if funcEntry == v.builder().GetInsertBlock() { allocBuilder.SetInsertPointAtEnd(funcEntry) } else { allocBuilder.SetInsertPointBefore(funcEntry.LastInstruction()) } varType := v.typeToLLVMType(n.Variable.Type) alloc := allocBuilder.CreateAlloca(varType, mangledName) allocBuilder.Dispose() v.variableLookup[n.Variable] = alloc if n.Assignment != nil { if value := v.genExpr(n.Assignment); !value.IsNil() { v.builder().CreateStore(value, alloc) } } } else { // TODO cbindings cBinding := false mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE) varType := v.typeToLLVMType(n.Variable.Type) value := llvm.AddGlobal(v.curFile.LlvmModule, varType, mangledName) // TODO: External by default to export everything, change once we get access specifiers if !cBinding && !n.IsPublic() { value.SetLinkage(nonPublicLinkage) } value.SetGlobalConstant(!n.Variable.Mutable) if n.Assignment != nil { value.SetInitializer(v.genExpr(n.Assignment)) } v.variableLookup[n.Variable] = value } return res }
func Construct(tree *parser.AST) *Codegen { return &Codegen{ tree: tree, scope: &Scope{variables: map[string]llvm.Value{}}, module: llvm.NewModule("main"), builder: llvm.NewBuilder(), templates: map[string]*Template{}, functions: map[string]llvm.BasicBlock{}, } }
func (v *Codegen) Generate(input []*parser.Module, modules map[string]*parser.Module, verbose bool) { v.input = input v.builder = llvm.NewBuilder() v.variableLookup = make(map[*parser.Variable]llvm.Value) v.structLookup_UseHelperFunction = make(map[*parser.StructType]llvm.Type) if verbose { fmt.Println(util.TEXT_BOLD + util.TEXT_GREEN + "Started codegenning" + util.TEXT_RESET) } t := time.Now() passManager := llvm.NewPassManager() passBuilder := llvm.NewPassManagerBuilder() passBuilder.SetOptLevel(3) //passBuilder.Populate(passManager) //leave this off until the compiler is better v.modules = make(map[string]*parser.Module) for _, infile := range input { infile.Module = llvm.NewModule(infile.Name) v.curFile = infile fmt.Println("adding module " + v.curFile.Name) v.modules[v.curFile.Name] = v.curFile v.declareDecls(infile.Nodes) for _, node := range infile.Nodes { v.genNode(node) } if verbose { infile.Module.Dump() } if err := llvm.VerifyModule(infile.Module, llvm.ReturnStatusAction); err != nil { v.err("%s", err.Error()) } passManager.Run(infile.Module) } passManager.Dispose() v.createBinary() dur := time.Since(t) if verbose { fmt.Printf(util.TEXT_BOLD+util.TEXT_GREEN+"Finished codegenning"+util.TEXT_RESET+" (%.2fms)\n", float32(dur.Nanoseconds())/1000000) } }
func (v *Codegen) genVariableDecl(n *parser.VariableDecl, semicolon bool) llvm.Value { var res llvm.Value if v.inFunction { mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE) funcEntry := v.currentFunction.EntryBasicBlock() // use this builder for the variable alloca // this means all allocas go at the start of the function // so each variable is only allocated once allocBuilder := llvm.NewBuilder() if funcEntry == v.builder.GetInsertBlock() { allocBuilder.SetInsertPointAtEnd(funcEntry) } else { allocBuilder.SetInsertPointBefore(funcEntry.LastInstruction()) } alloc := allocBuilder.CreateAlloca(v.typeToLLVMType(n.Variable.Type), mangledName) allocBuilder.Dispose() v.variableLookup[n.Variable] = alloc if n.Assignment != nil { if value := v.genExpr(n.Assignment); !value.IsNil() { v.builder.CreateStore(value, alloc) } } } else { mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE) varType := v.typeToLLVMType(n.Variable.Type) value := llvm.AddGlobal(v.curFile.Module, varType, mangledName) value.SetLinkage(llvm.InternalLinkage) value.SetGlobalConstant(!n.Variable.Mutable) if n.Assignment != nil { value.SetInitializer(v.genExpr(n.Assignment)) } v.variableLookup[n.Variable] = value } return res }
func (v *Codegen) Generate(input []*parser.Module) { v.builders = make(map[*parser.Function]llvm.Builder) v.inBlocks = make(map[*parser.Function][]*parser.Block) v.globalBuilder = llvm.NewBuilder() defer v.globalBuilder.Dispose() v.curLoopExits = make(map[*parser.Function][]llvm.BasicBlock) v.curLoopNexts = make(map[*parser.Function][]llvm.BasicBlock) v.input = make([]*WrappedModule, len(input)) for idx, mod := range input { v.input[idx] = &WrappedModule{Module: mod} } v.variableLookup = make(map[*parser.Variable]llvm.Value) v.namedTypeLookup = make(map[string]llvm.Type) // initialize llvm target llvm.InitializeNativeTarget() llvm.InitializeNativeAsmPrinter() // setup target stuff var err error v.target, err = llvm.GetTargetFromTriple(llvm.DefaultTargetTriple()) if err != nil { panic(err) } v.targetMachine = v.target.CreateTargetMachine(llvm.DefaultTargetTriple(), "", "", llvm.CodeGenLevelNone, llvm.RelocDefault, llvm.CodeModelDefault) v.targetData = v.targetMachine.TargetData() passManager := llvm.NewPassManager() passBuilder := llvm.NewPassManagerBuilder() if v.OptLevel > 0 { passBuilder.SetOptLevel(v.OptLevel) passBuilder.Populate(passManager) } v.blockDeferData = make(map[*parser.Block][]*deferData) for _, infile := range v.input { log.Timed("codegenning", infile.Name.String(), func() { infile.LlvmModule = llvm.NewModule(infile.Name.String()) v.curFile = infile for _, submod := range infile.Parts { v.declareDecls(submod.Nodes) for _, node := range submod.Nodes { v.genNode(node) } } if err := llvm.VerifyModule(infile.LlvmModule, llvm.ReturnStatusAction); err != nil { infile.LlvmModule.Dump() v.err("%s", err.Error()) } passManager.Run(infile.LlvmModule) if log.AtLevel(log.LevelDebug) { infile.LlvmModule.Dump() } }) } passManager.Dispose() log.Timed("creating binary", "", func() { v.createBinary() }) }
func (v *Codegen) genVariableDecl(n *parser.VariableDecl, semicolon bool) llvm.Value { var res llvm.Value if v.inFunction { mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE) funcEntry := v.currentFunction.EntryBasicBlock() // use this builder for the variable alloca // this means all allocas go at the start of the function // so each variable is only allocated once allocBuilder := llvm.NewBuilder() if funcEntry == v.builder.GetInsertBlock() { allocBuilder.SetInsertPointAtEnd(funcEntry) } else { allocBuilder.SetInsertPointBefore(funcEntry.LastInstruction()) } alloc := allocBuilder.CreateAlloca(v.typeToLLVMType(n.Variable.Type), mangledName) // set allocated memory to zero fn := v.curFile.Module.NamedFunction("llvm.memset.p0i8.i32") if fn.IsNil() { fnType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{llvm.PointerType(llvm.IntType(8), 0), llvm.IntType(8), llvm.IntType(32), llvm.IntType(32), llvm.IntType(1)}, false) fn = llvm.AddFunction(v.curFile.Module, "llvm.memset.p0i8.i32", fnType) } // cast alloc to byte array castAlloc := allocBuilder.CreateBitCast(alloc, llvm.PointerType(llvm.IntType(8), 0), "") // get type length gep := allocBuilder.CreateGEP(llvm.ConstNull(llvm.PointerType(v.typeToLLVMType(n.Variable.Type), 0)), []llvm.Value{llvm.ConstInt(llvm.IntType(32), 1, false)}, "") length := allocBuilder.CreatePtrToInt(gep, llvm.IntType(32), "") // call memset intrinsic allocBuilder.CreateCall(fn, []llvm.Value{castAlloc, llvm.ConstInt(llvm.IntType(8), 0, false), length, llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(1), 0, false)}, "") allocBuilder.Dispose() v.variableLookup[n.Variable] = alloc if n.Assignment != nil { if value := v.genExpr(n.Assignment); !value.IsNil() { v.builder.CreateStore(value, alloc) } } } else { mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE) varType := v.typeToLLVMType(n.Variable.Type) value := llvm.AddGlobal(v.curFile.Module, varType, mangledName) value.SetLinkage(llvm.InternalLinkage) value.SetGlobalConstant(!n.Variable.Mutable) if n.Assignment != nil { value.SetInitializer(v.genExpr(n.Assignment)) } v.variableLookup[n.Variable] = value } return res }
func createEntryBlockAlloca(f llvm.Value, name string) llvm.Value { b := llvm.NewBuilder() b.SetInsertPoint(f.EntryBasicBlock(), f.EntryBasicBlock().FirstInstruction()) return b.CreateAlloca(llvm.DoubleType(), name) }
func (v *Codegen) Generate(input []*parser.Module, modules map[string]*parser.Module) { v.input = input v.builder = llvm.NewBuilder() v.variableLookup = make(map[*parser.Variable]llvm.Value) v.structLookup_UseHelperFunction = make(map[*parser.StructType]llvm.Type) v.enumLookup_UseHelperFunction = make(map[*parser.EnumType]llvm.Type) // initialize llvm target llvm.InitializeNativeTarget() // setup target stuff var err error v.target, err = llvm.GetTargetFromTriple(llvm.DefaultTargetTriple()) if err != nil { panic(err) } v.targetMachine = v.target.CreateTargetMachine(llvm.DefaultTargetTriple(), "", "", llvm.CodeGenLevelNone, llvm.RelocDefault, llvm.CodeModelDefault) v.targetData = v.targetMachine.TargetData() passManager := llvm.NewPassManager() passBuilder := llvm.NewPassManagerBuilder() if v.OptLevel > 0 { passBuilder.SetOptLevel(v.OptLevel) passBuilder.Populate(passManager) } v.modules = make(map[string]*parser.Module) v.blockDeferData = make(map[*parser.Block][]*deferData) for _, infile := range input { log.Verboseln("codegen", util.TEXT_BOLD+util.TEXT_GREEN+"Started codegenning "+util.TEXT_RESET+infile.Name) t := time.Now() infile.Module = llvm.NewModule(infile.Name) v.curFile = infile v.modules[v.curFile.Name] = v.curFile v.declareDecls(infile.Nodes) for _, node := range infile.Nodes { v.genNode(node) } if err := llvm.VerifyModule(infile.Module, llvm.ReturnStatusAction); err != nil { infile.Module.Dump() v.err("%s", err.Error()) } passManager.Run(infile.Module) if log.AtLevel(log.LevelVerbose) { infile.Module.Dump() } dur := time.Since(t) log.Verbose("codegen", util.TEXT_BOLD+util.TEXT_GREEN+"Finished codegenning "+util.TEXT_RESET+infile.Name+" (%.2fms)\n", float32(dur.Nanoseconds())/1000000) } passManager.Dispose() log.Timed("create binary", func() { v.createBinary() }) }