Esempio n. 1
0
            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, "");
            }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
            /// <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);
            }