public Function(CodeGeneratorContext genContext, FunctionDefinitionNode leaf) { _leaf = leaf; // Create function type and add the function node without appending any basic blocks // This results in a function declaration in LLVM-IR Type[] paramTypes = Array.ConvertAll(leaf.Parameters, param => genContext.LookupType(param.Type) !.Value); FunctionType = genContext.Context.FunctionType(genContext.LookupType(leaf.ReturnType) !.Value, paramTypes, false); FunctionValue = genContext.Module.AddFunction(leaf.Name, FunctionType); // Process the static keyword in the same manner as clang FunctionValue.SetLinkage(leaf.IsExported ? LLVMLinkage.LLVMExternalLinkage : LLVMLinkage.LLVMInternalLinkage); genContext.TryGetNodeSymbol(leaf, out Symbol range); DiFwdDecl = genContext.DiBuilder.CreateReplaceableCompositeType( LLVMDWARFTag.subroutine_type, leaf.Name, genContext.DiFile, genContext.DiFile, range.LLVMLine, 0, 0, 0, LLVMDIFlags.LLVMDIFlagFwdDecl, ""); }
public static Module Generate(Context context, string path, SemanticModule module, SemanticContext semanticContext, string targetTriple, PassManagerBuilder?optBuilder, bool debugInfo, bool columnInfo) { // Path information for debug info nodes string fileName = Path.GetFileName(path); string dirName = Path.GetDirectoryName(path); if (dirName == null) { dirName = "/"; } else if (dirName.Length == 0) { dirName = "."; } // Create module and file-level debug info nodes using CodeGeneratorContext genContext = new CodeGeneratorContext(context, module, semanticContext, fileName, dirName, targetTriple, optBuilder != null, debugInfo, columnInfo); // Enum pass foreach (EnumNode enumNode in genContext.ParseModule.Enums) { Metadata[] enumerators = new Metadata[enumNode.Declarations.Count]; for (int i = 0, ilen = enumNode.Declarations.Count; i < ilen; ++i) { var enumeration = enumNode.Declarations[i]; enumerators[i] = genContext.DiBuilder.CreateEnumerator(enumeration.Name, i, false); } genContext.TryGetNodeSymbol(enumNode, out Symbol range); genContext.DiBuilder.CreateEnumerationType(genContext.DiFile, (enumNode.IsExported ? "export." : "") + $"enum.{fileName}.{range.LLVMLine}", genContext.DiFile, range.LLVMLine, genContext.DiBuilder.Int32Type.GetTypeSizeInBits(), genContext.DiBuilder.Int32Type.GetTypeAlignInBits(), enumerators, genContext.DiBuilder.Int32Type); } // Struct pass foreach (StructNode structNode in genContext.ParseModule.Structs) { genContext.EnsureStruct(structNode); } // Declaration pass foreach (FunctionDefinitionNode function in genContext.ParseModule.Functions) { genContext.RegisterDefinedFunction(function); } // Definition pass foreach (FunctionDefinitionNode function in genContext.ParseModule.Functions) { CodeGeneratorContext.Function ctxFunction = genContext.GetFunctionDefinition(function); using Builder builder = genContext.Context.CreateBuilder(); FunctionCodeGenVisitor functionCodeGenVisitor = new FunctionCodeGenVisitor(genContext, ctxFunction, builder, ctxFunction.StartDefinition(genContext, builder)); builder.PositionAtEnd(functionCodeGenVisitor._basicBlock); function.Body.VisitStatements(functionCodeGenVisitor); if (genContext.DebugInfo) { // TODO: Use the body end rather than the function end genContext.TryGetNodeSymbol(function, out Symbol range); Metadata location = genContext.Context.CreateDebugLocation(range.End.Line + 1, genContext.ColumnInfo ? range.End.Column + 1 : 0, ctxFunction.DiFunctionDef, Metadata.Null); builder.SetCurrentDebugLocation(location); } // If we still have a valid insert block, this function did not end with a return; Insert one now if (builder.InsertBlock.IsValid) { if (ctxFunction.ReturnBlock != null) { builder.BuildBr(ctxFunction.ReturnBlock.Value); } else { builder.BuildRetVoid(); } } if (ctxFunction.ReturnBlock != null && ctxFunction.RetvalStorage != null) { ctxFunction.FunctionValue.AppendExistingBasicBlock(ctxFunction.ReturnBlock.Value); builder.PositionAtEnd(ctxFunction.ReturnBlock.Value); Value retVal = builder.BuildLoad(ctxFunction.RetvalStorage.Value); builder.BuildRet(retVal); } } // Remove unused metadata nodes for undefined functions genContext.FinalizeFunctions(); // Finalize debug info genContext.DiBuilder.BuilderFinalize(); // Run optimization passes on functions and module if a builder is supplied if (optBuilder != null) { using ModulePassManager modulePassManager = new ModulePassManager(optBuilder); using FunctionPassManager functionPassManager = new FunctionPassManager(genContext.Module, optBuilder); functionPassManager.Initialize(); foreach (var function in genContext.DefinedFunctions) { functionPassManager.Run(function.Value.FunctionValue); } functionPassManager.FinalizeFunctionPassManager(); modulePassManager.Run(genContext.Module); } // Done with everything in CodeGeneratorContext besides the Module return(genContext.Module); }
/// <summary> /// Add entry basic block to this function and fill in additional debug info. /// If not called, this is a function declaration. /// </summary> /// <param name="genContext"></param> /// <param name="builder"></param> /// <returns>Entry basic block</returns> public BasicBlock StartDefinition(CodeGeneratorContext genContext, Builder builder) { BasicBlock basicBlock = genContext.Context.AppendBasicBlock(FunctionValue, "entry"); builder.PositionAtEnd(basicBlock); // Build return value storage if necessary Type returnType = FunctionType.ReturnType; if (returnType.Kind != LLVMTypeKind.LLVMVoidTypeKind) { ReturnBlock = genContext.Context.CreateBasicBlock("return"); RetvalStorage = builder.BuildAlloca(returnType, "retval"); } // Visit all declaration nodes and create storage (parameters and variables) StackLayoutGenerator layoutGenerator = new StackLayoutGenerator(new IndexTypeSizeManager()); layoutGenerator.VisitFunctionDefinition(_leaf); FunctionStackLayout layout = layoutGenerator.GetLayout(); foreach (var v in layout.Variables) { Type varType = genContext.LookupType(v.Key.Type) !.Value; Value varStorage = builder.BuildAlloca(varType, v.Key.Name); VariableValues[v.Key] = varStorage; } // Emit store instruction for return value if (RetvalStorage != null && !returnType.IsStructType()) { builder.BuildStore(Value.ConstInt(returnType, 0, true), RetvalStorage.Value); } // Emit store instructions for parameters Value[] funcParams = FunctionValue.Params; for (int i = 0, ilen = funcParams.Length; i < ilen; ++i) { DeclarationNode parameter = _leaf.Parameters[i]; Value paramValue = funcParams[i]; VariableValues.TryGetValue(parameter, out Value varStorage); varStorage.SetName($"{parameter.Name}.addr"); builder.BuildStore(paramValue, varStorage); paramValue.SetName(parameter.Name); } // Create subroutine type debug info genContext.TryGetNodeSymbol(_leaf, out Symbol range); Metadata subroutineType = genContext.DiBuilder.CreateSubroutineType(genContext.DiFile, Array.ConvertAll(_leaf.Parameters, param => genContext.LookupDiType(param.Type) !.Value), LLVMDIFlags.LLVMDIFlagZero); Metadata funcLocation = genContext.Context.CreateDebugLocation(range.LLVMLine, genContext.ColumnInfo ? range.LLVMColumn : 0, DiFwdDecl, Metadata.Null); // Create subroutine debug info and substitute over forward declaration DiFunctionDef = genContext.DiBuilder.CreateFunction(genContext.DiFile, _leaf.Name, _leaf.Name, genContext.DiFile, range.LLVMLine, subroutineType, true, true, range.LLVMLine, LLVMDIFlags.LLVMDIFlagZero, false); DiFwdDecl.ReplaceAllUsesWith(DiFunctionDef); // Create llvm.dbg.declare calls for each parameter's storage if (genContext.DebugInfo) { Metadata paramExpression = genContext.DiBuilder.CreateExpression(); for (int i = 0, ilen = _leaf.Parameters.Length; i < ilen; ++i) { DeclarationNode parameter = _leaf.Parameters[i]; genContext.TryGetNodeSymbol(parameter, out Symbol paramRange); Metadata paramType = genContext.LookupDiType(parameter.Type) !.Value; Metadata paramMetadata = genContext.DiBuilder.CreateParameterVariable(DiFunctionDef, parameter.Name, (uint)i + 1, genContext.DiFile, paramRange.LLVMLine, paramType, true, LLVMDIFlags.LLVMDIFlagZero); VariableValues.TryGetValue(parameter, out Value varStorage); genContext.DiBuilder.InsertDeclareAtEnd(varStorage, paramMetadata, paramExpression, funcLocation, basicBlock); } } // Associate debug info nodes with function FunctionValue.SetFuncSubprogram(DiFunctionDef); return(basicBlock); }