Beispiel #1
0
        public LLVMModuleRef Generate(SyntaxTree tree)
        {
            m_VariablePointers            = new Dictionary <VariableSymbol, LLVMValueRef>();
            m_FunctionPointers            = new Dictionary <FunctionSymbol, LLVMValueRef>();
            m_Types                       = new Dictionary <TypeSymbol, LLVMTypeRef>();
            m_BreakableStatementSuccessor = new Dictionary <Statement, LLVMBasicBlockRef>();

            m_Module  = LLVM.ModuleCreateWithName("test");
            m_Builder = LLVM.CreateBuilder();

            m_Tree = tree;
            LoadTypes(m_Tree.GlobalSymbols);
            foreach (var stmt in m_Tree.Root)
            {
                VisitStmt(stmt);
            }

            LLVM.DisposeBuilder(m_Builder);

            LLVMPassManagerRef pm = LLVM.CreatePassManager();

            LLVM.AddPromoteMemoryToRegisterPass(pm);
            LLVM.AddInstructionCombiningPass(pm);
            LLVM.AddReassociatePass(pm);
            LLVM.AddGVNPass(pm);
            LLVM.AddCFGSimplificationPass(pm);
            LLVM.RunPassManager(pm, m_Module);

            return(m_Module);
        }
        public override CompilerResult VisitProgram(DesignScriptParser.ProgramContext context)
        {
            var success = new LLVMBool(0);

            module  = LLVM.ModuleCreateWithName("DesignScript");
            builder = LLVM.CreateBuilder();

            LLVM.LinkInMCJIT();
            LLVM.InitializeX86TargetInfo();
            LLVM.InitializeX86Target();
            LLVM.InitializeX86TargetMC();

            LLVM.InitializeX86AsmParser();
            LLVM.InitializeX86AsmPrinter();

            LLVMMCJITCompilerOptions options = new LLVMMCJITCompilerOptions {
                NoFramePointerElim = 1
            };

            LLVM.InitializeMCJITCompilerOptions(options);
            if (LLVM.CreateExecutionEngineForModule(out engine, module, out var errorMessage).Value == 1)
            {
                Console.WriteLine(errorMessage);
                return(new NullCompilerResult());
            }

            #region Add optimization passes
            // Create a function pass manager for this engine
            passManager = LLVM.CreateFunctionPassManagerForModule(module);

            // Do simple "peephole" optimizations and bit-twiddling optzns.
            LLVM.AddInstructionCombiningPass(passManager);

            // Reassociate expressions.
            LLVM.AddReassociatePass(passManager);

            // Eliminate Common SubExpressions.
            LLVM.AddGVNPass(passManager);

            // Simplify the control flow graph (deleting unreachable blocks, etc).
            LLVM.AddCFGSimplificationPass(passManager);

            LLVM.InitializeFunctionPassManager(passManager);
            #endregion

            base.VisitProgram(context);

            if (LLVM.VerifyModule(module, LLVMVerifierFailureAction.LLVMPrintMessageAction, out var error) != success)
            {
                Console.WriteLine($"Error: {error}");
            }

            LLVM.DumpModule(module);
            LLVM.DisposeBuilder(builder);
            LLVM.DisposeExecutionEngine(engine);

            return(new NullCompilerResult());
        }
Beispiel #3
0
        private void Optimize()
        {
            var passManager = LLVM.CreatePassManager();

            LLVM.AddBasicAliasAnalysisPass(passManager);
            LLVM.AddInstructionCombiningPass(passManager);
            LLVM.AddGVNPass(passManager);
            LLVM.AddReassociatePass(passManager);

            LLVM.RunPassManager(passManager, _module);
        }
Beispiel #4
0
    // Create a new module with the given name.
    // The passed target triple can be used for cross compilation.
    // If it is null, the current platform will be used.
    public Module(string name, string targetTriple, bool useOptimizations)
    {
        // Create the module and the builder.
        this.Mod     = LLVM.ModuleCreateWithName(name);
        this.Builder = LLVM.CreateBuilder();

        // Get the default target triple if necessary:
        if (targetTriple == null)
        {
            targetTriple = Marshal.PtrToStringAnsi(LLVM.GetDefaultTargetTriple());
        }

        // Select the target based on the triple.
        if (LLVM.GetTargetFromTriple(targetTriple, out var target, out var error))
        {
            throw new ArgumentException($"Failed to obtain target from triple '{ targetTriple }': { error }");
        }

        LLVM.SetTarget(this.Mod, targetTriple);

        // Create a target machine.
        this._targetMachine = LLVM.CreateTargetMachine(target, targetTriple, "generic", "",
                                                       LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault, LLVMRelocMode.LLVMRelocPIC, LLVMCodeModel.LLVMCodeModelDefault);

        // Create a data layout from the machine and assign it to the module.
        var dataLayout = LLVM.CreateTargetDataLayout(this._targetMachine);

        LLVM.SetModuleDataLayout(this.Mod, dataLayout);

        // Create the function pass manager for optimized runs.
        if (useOptimizations)
        {
            var funcPassManager = LLVM.CreateFunctionPassManagerForModule(this.Mod);

            // Add some nice optimization passes.
            LLVM.AddBasicAliasAnalysisPass(funcPassManager);
            LLVM.AddPromoteMemoryToRegisterPass(funcPassManager);
            LLVM.AddInstructionCombiningPass(funcPassManager);
            LLVM.AddReassociatePass(funcPassManager);
            LLVM.AddGVNPass(funcPassManager);
            LLVM.AddCFGSimplificationPass(funcPassManager);

            // TODO: Add more!

            // Initialize the manager and its passes and store it.
            LLVM.InitializeFunctionPassManager(funcPassManager);
            this._funcPassManager = funcPassManager;
        }
        else
        {
            this._funcPassManager = null;
        }
    }
Beispiel #5
0
        public override CompilerResult VisitFile([NotNull] LangParser.FileContext context)
        {
            module   = LLVM.ModuleCreateWithName("Lang");
            contexts = new Stack <Context>();

            LLVMPassManagerRef passManager = LLVM.CreateFunctionPassManagerForModule(module);

            // Set up the optimizer pipeline.  Start with registering info about how the
            // target lays out data structures.
            // LLVM.DisposeTargetData(LLVM.GetExecutionEngineTargetData(engine));

            // Provide basic AliasAnalysis support for GVN.
            LLVM.AddBasicAliasAnalysisPass(passManager);

            // Promote allocas to registers.
            LLVM.AddPromoteMemoryToRegisterPass(passManager);

            // Do simple "peephole" optimizations and bit-twiddling optzns.
            LLVM.AddInstructionCombiningPass(passManager);

            // Reassociate expressions.
            LLVM.AddReassociatePass(passManager);

            // Eliminate Common SubExpressions.
            LLVM.AddGVNPass(passManager);

            // Simplify the control flow graph (deleting unreachable blocks, etc).
            LLVM.AddCFGSimplificationPass(passManager);

            LLVM.InitializeFunctionPassManager(passManager);
            this.passManager = passManager;

            base.VisitFile(context);



            LLVM.VerifyModule(module, LLVMVerifierFailureAction.LLVMPrintMessageAction, out string str);

            LLVM.DumpModule(module);

            LLVM.WriteBitcodeToFile(module, @"C:\Users\superblaubeere27\Desktop\compilerTest\Compiler\Compiler\code\compiled.bc");

            LLVM.DisposePassManager(passManager);
            LLVM.DisposeModule(module);


            return(NullCompilerResult.INSTANCE);
        }
Beispiel #6
0
        static void Main(string[] args)
        {
            string filename = @"test.ni";
            string outname  = Path.GetFileNameWithoutExtension(filename) + ".bc";

            if (args.Length == 1)
            {
                filename = args[0];
            }
            module  = LLVM.ModuleCreateWithName(Path.GetFileNameWithoutExtension(filename));
            builder = LLVM.CreateBuilder();

            var FPM = LLVM.CreateFunctionPassManagerForModule(module);

            LLVM.AddPromoteMemoryToRegisterPass(FPM);
            LLVM.AddInstructionCombiningPass(FPM);
            LLVM.AddReassociatePass(FPM);
            LLVM.AddNewGVNPass(FPM);
            LLVM.AddCFGSimplificationPass(FPM);
            LLVM.FinalizeFunctionPassManager(FPM);

            string file   = File.ReadAllText(filename);
            var    lexer  = new Lexer(file);
            var    parser = new Parser(lexer, new Visitor(module, builder, FPM));
            var    token  = lexer.NextToken();

            LLVM.DumpModule(module);

            while (lexer.CurrentToken.type != TokenType.EOF)
            {
                parser.ParsePrimary();
                Console.WriteLine("\n##################################################################################################################\n");
                LLVM.DumpModule(module);
            }

            string error = "";

            Console.WriteLine("\n##################################################################################################################\n");
            LLVM.DumpModule(module);
            LLVM.VerifyModule(module, LLVMVerifierFailureAction.LLVMPrintMessageAction, out error);
            LLVM.WriteBitcodeToFile(module, outname);
            var clang = Process.Start("clang++", "test.bc -o test.exe");

            clang.WaitForExit();
            Console.Read();
        }
Beispiel #7
0
 public void AddReassociatePass() => LLVM.AddReassociatePass(this.Unwrap());
Beispiel #8
0
        private static void Main(string[] args)
        {
            // Make the module, which holds all the code.
            LLVMModuleRef  module  = LLVM.ModuleCreateWithName("my cool jit");
            LLVMBuilderRef builder = LLVM.CreateBuilder();

            LLVM.LinkInJIT();
            LLVM.InitializeX86TargetInfo();
            LLVM.InitializeX86Target();
            LLVM.InitializeX86TargetMC();

            LLVMExecutionEngineRef engine;
            IntPtr errorMessage;

            if (LLVM.CreateExecutionEngineForModule(out engine, module, out errorMessage).Value == 1)
            {
                Console.WriteLine(Marshal.PtrToStringAnsi(errorMessage));
                LLVM.DisposeMessage(errorMessage);
                return;
            }

            // Create a function pass manager for this engine
            LLVMPassManagerRef passManager = LLVM.CreateFunctionPassManagerForModule(module);

            // Set up the optimizer pipeline.  Start with registering info about how the
            // target lays out data structures.
            LLVM.AddTargetData(LLVM.GetExecutionEngineTargetData(engine), passManager);

            // Provide basic AliasAnalysis support for GVN.
            LLVM.AddBasicAliasAnalysisPass(passManager);

            // Promote allocas to registers.
            LLVM.AddPromoteMemoryToRegisterPass(passManager);

            // Do simple "peephole" optimizations and bit-twiddling optzns.
            LLVM.AddInstructionCombiningPass(passManager);

            // Reassociate expressions.
            LLVM.AddReassociatePass(passManager);

            // Eliminate Common SubExpressions.
            LLVM.AddGVNPass(passManager);

            // Simplify the control flow graph (deleting unreachable blocks, etc).
            LLVM.AddCFGSimplificationPass(passManager);

            LLVM.InitializeFunctionPassManager(passManager);

            var codeGenlistener = new CodeGenParserListener(engine, passManager, new CodeGenVisitor(module, builder));

            // Install standard binary operators.
            // 1 is lowest precedence.
            var binopPrecedence = new Dictionary <char, int>();

            binopPrecedence['<'] = 10;
            binopPrecedence['+'] = 20;
            binopPrecedence['-'] = 20;
            binopPrecedence['*'] = 40;  // highest.

            var scanner = new Lexer(Console.In, binopPrecedence);
            var parser  = new Parser(scanner, codeGenlistener);

            // Prime the first token.
            Console.Write("ready> ");
            scanner.GetNextToken();

            // Run the main "interpreter loop" now.
            MainLoop(scanner, parser);

            // Print out all of the generated code.
            LLVM.DumpModule(module);
        }
Beispiel #9
0
        /// <summary>
        /// Compiles an IL assembly to LLVM bytecode.
        /// </summary>
        /// <param name="moduleName">The module name.</param>
        public void Compile(string moduleName)
        {
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();

            // Create LLVM module and its context.
            LLVM.EnablePrettyStackTrace();
            mModule  = LLVM.ModuleCreateWithName(moduleName);
            mContext = LLVM.GetModuleContext(mModule);

            // Targets.
            LLVM.InitializeAllTargetInfos();
            LLVM.InitializeAllTargets();
            LLVM.InitializeAllTargetMCs();
            LLVM.InitializeAllAsmParsers();
            LLVM.InitializeAllAsmPrinters();

            string   triplet = (Options.Target == "default") ? LLVM.GetDefaultTargetTriple() : Options.Target;
            MyString error   = new MyString();

            LLVM.SetTarget(mModule, triplet);
            TargetRef target;

            if (LLVM.GetTargetFromTriple(triplet, out target, error))
            {
                throw new InvalidOperationException(error.ToString());
            }

            // Optimizer.
            mFunctionPassManager = LLVM.CreateFunctionPassManagerForModule(mModule);
            mPassManager         = LLVM.CreatePassManager();
            LLVM.InitializeFunctionPassManager(mFunctionPassManager);

#if !DEBUG
            // O0
            if (Options.Optimization >= OptimizationLevel.O0)
            {
                // Function passes.
                LLVM.AddPromoteMemoryToRegisterPass(mFunctionPassManager);
                LLVM.AddConstantPropagationPass(mFunctionPassManager);
                LLVM.AddReassociatePass(mFunctionPassManager);
                LLVM.AddInstructionCombiningPass(mFunctionPassManager);

                // Module passes.
                LLVM.AddAlwaysInlinerPass(mPassManager);
                LLVM.AddStripDeadPrototypesPass(mPassManager);
                LLVM.AddStripSymbolsPass(mPassManager);
            }

            // O1
            if (Options.Optimization >= OptimizationLevel.O1)
            {
                // Function passes.
                LLVM.AddLowerExpectIntrinsicPass(mFunctionPassManager);
                LLVM.AddEarlyCSEPass(mFunctionPassManager);
                LLVM.AddLoopRotatePass(mFunctionPassManager);
                LLVM.AddLoopUnswitchPass(mFunctionPassManager);
                LLVM.AddLoopUnrollPass(mFunctionPassManager);
                LLVM.AddLoopDeletionPass(mFunctionPassManager);
                LLVM.AddTailCallEliminationPass(mFunctionPassManager);
                LLVM.AddGVNPass(mFunctionPassManager);
                LLVM.AddDeadStoreEliminationPass(mFunctionPassManager);
                LLVM.AddJumpThreadingPass(mFunctionPassManager);
                LLVM.AddCFGSimplificationPass(mFunctionPassManager);
                LLVM.AddMemCpyOptPass(mFunctionPassManager);

                // Module passes.
                LLVM.AddDeadArgEliminationPass(mPassManager);
                LLVM.AddAggressiveDCEPass(mFunctionPassManager);
            }

            // O2
            if (Options.Optimization >= OptimizationLevel.O2)
            {
                // Function passes.
                LLVM.AddLoopVectorizePass(mFunctionPassManager);
                LLVM.AddSLPVectorizePass(mFunctionPassManager);

                // Module passes.
                LLVM.AddFunctionInliningPass(mPassManager);
                LLVM.AddConstantMergePass(mPassManager);
                LLVM.AddArgumentPromotionPass(mPassManager);
            }
#endif

            // Initialize types and runtime.
            string dataLayout = LLVM.GetDataLayout(Module);
            TargetData = LLVM.CreateTargetData(dataLayout);

            TypeHelper.Init(TargetData, this);
            RuntimeHelper.ImportFunctions(Module);
            mBuiltinCompiler.Compile();
            compileModules();
            LLVM.RunPassManager(mPassManager, Module);

            // Log time.
            stopWatch.Stop();
            Logger.LogDetail("Compilation time: " + stopWatch.Elapsed);

            // Debug: print LLVM assembly code.
#if DEBUG
            Console.WriteLine(LLVM.PrintModuleToString(mModule));
#endif

            // Verify and throw exception on error.
            Console.ForegroundColor = ConsoleColor.DarkGray;
            if (LLVM.VerifyModule(mModule, VerifierFailureAction.ReturnStatusAction, error))
            {
                Logger.LogError("Compilation of module failed.");
                Logger.LogInfo(error.ToString());
                LLVM.DisposeTargetData(TargetData);
                return;
            }
            else
            {
                Logger.LogDetail("Compilation of module succeeded.");
            }

            // Output assembly or object file.
            if (!Options.OutputLLVMIR && !Options.OutputLLVMBitCode)
            {
                TargetMachineRef machine = LLVM.CreateTargetMachine(target, triplet, "generic", "", CodeGenOptLevel.CodeGenLevelDefault, RelocMode.RelocDefault, CodeModel.CodeModelDefault);
                LLVM.SetModuleDataLayout(mModule, LLVM.CreateTargetDataLayout(machine));
                CodeGenFileType type = (Options.OutputAssembly) ? CodeGenFileType.AssemblyFile : CodeGenFileType.ObjectFile;

                if (LLVM.TargetMachineEmitToFile(machine, mModule, Options.OutputFile, type, error))
                {
                    throw new InvalidOperationException(error.ToString());
                }
            }
            // Output LLVM IR code to a file.
            else if (Options.OutputLLVMIR)
            {
                if (LLVM.PrintModuleToFile(mModule, Options.OutputFile, error))
                {
                    Logger.LogError("Writing the LLVM code to a file failed.");
                    Logger.LogInfo(error.ToString());
                }
            }
            // Output LLVM bitcode.
            else if (Options.OutputLLVMBitCode)
            {
                if (LLVM.WriteBitcodeToFile(mModule, Options.OutputFile) != 0)
                {
                    Logger.LogError("Writing the LLVM code to a file failed.");
                    Logger.LogInfo(error.ToString());
                }
            }

            // Cleanup.
            LLVM.DisposeTargetData(TargetData);
        }
Beispiel #10
0
        public void Compile()
        {
            string triple = "x86_64-pc-linux-gnu";

            LLVM.InitializeX86TargetInfo();
            LLVM.InitializeX86Target();
            LLVM.InitializeX86TargetMC();
            LLVM.InitializeX86AsmParser();
            LLVM.InitializeX86AsmPrinter();

            LLVM.SetTarget(ModuleRef, triple);

            var fnPassManager     = LLVM.CreateFunctionPassManagerForModule(ModuleRef);
            var modulePassManager = LLVM.CreatePassManager();

            LLVM.InitializeFunctionPassManager(fnPassManager);

            // Optimizations
            LLVM.AddPromoteMemoryToRegisterPass(fnPassManager);
            LLVM.AddInstructionCombiningPass(fnPassManager);
            LLVM.AddJumpThreadingPass(fnPassManager);
            LLVM.AddEarlyCSEPass(fnPassManager);
            LLVM.AddConstantPropagationPass(fnPassManager);
            LLVM.AddCFGSimplificationPass(fnPassManager);
            LLVM.AddReassociatePass(fnPassManager);
            LLVM.AddLoopUnrollPass(fnPassManager);
            LLVM.AddLoopRerollPass(fnPassManager);
            LLVM.AddLoopDeletionPass(fnPassManager);
            LLVM.AddLoopRotatePass(fnPassManager);
            LLVM.AddLoopIdiomPass(fnPassManager);
            LLVM.AddLoopUnswitchPass(fnPassManager);
            LLVM.AddDeadStoreEliminationPass(fnPassManager);
            LLVM.AddBasicAliasAnalysisPass(fnPassManager);
            LLVM.AddIndVarSimplifyPass(fnPassManager);
            LLVM.AddSCCPPass(fnPassManager);
            LLVM.AddLICMPass(fnPassManager);
            LLVM.AddCorrelatedValuePropagationPass(fnPassManager);
            LLVM.AddScopedNoAliasAAPass(modulePassManager);
            LLVM.AddDeadArgEliminationPass(modulePassManager);
            LLVM.AddTailCallEliminationPass(modulePassManager);
            LLVM.AddLoopUnswitchPass(modulePassManager);
            LLVM.AddIPSCCPPass(modulePassManager);
            LLVM.AddReassociatePass(modulePassManager);
            LLVM.AddAlwaysInlinerPass(modulePassManager);

            // O2
            LLVM.AddNewGVNPass(fnPassManager);
            LLVM.AddLowerExpectIntrinsicPass(fnPassManager);
            LLVM.AddScalarReplAggregatesPassSSA(fnPassManager);
            LLVM.AddMergedLoadStoreMotionPass(fnPassManager);
            LLVM.AddSLPVectorizePass(fnPassManager);
            LLVM.AddConstantMergePass(modulePassManager);
            LLVM.AddConstantMergePass(modulePassManager);
            LLVM.AddFunctionInliningPass(modulePassManager);

            void RecurseTypes(Collection <TypeDefinition> collection, Action <TypeDefinition> callback)
            {
                foreach (TypeDefinition typeDef in collection)
                {
                    callback(typeDef);
                    RecurseTypes(typeDef.NestedTypes, callback);
                }
            }

            // First, declare all types and only define the types in a later pass.
            // The reason is that we may have cycles of types.
            var typeList = new List <TypeDefinition>();

            foreach (ModuleDefinition moduleDef in assemblyDefinition.Modules)
            {
                RecurseTypes(moduleDef.Types, typeDef =>
                {
                    typeList.Add(typeDef);
                    TypeLookup.DeclareType(typeDef);
                });
            }

            // Now, we have all types, so we can declare the methods.
            // Again, we may have cycles so the methods are declared and defined in separate passes.
            // Also define the types now.
            var methodCompilerLookup = new Dictionary <MethodDefinition, MethodCompiler>();

            foreach (var typeDef in typeList)
            {
                TypeLookup.DefineType(typeDef);
                StaticFieldLookup.DeclareFieldsFor(typeDef);

                foreach (MethodDefinition methodDef in typeDef.Methods)
                {
                    methodCompilerLookup.Add(methodDef, new MethodCompiler(this, methodDef));
                }
            }

            // Compile the methods.
            Action <TypeDefinition> methodCompilationFn = typeDef =>
            {
                foreach (MethodDefinition methodDef in typeDef.Methods)
                {
                    var methodCompiler = methodCompilerLookup[methodDef];
                    methodCompiler.Compile();

                    if (!LLVM.VerifyFunction(methodCompiler.FunctionValueRef, LLVMVerifierFailureAction.LLVMPrintMessageAction))
                    {
                        LLVM.RunFunctionPassManager(fnPassManager, methodCompiler.FunctionValueRef);
                    }
                }
            };

            if (LLVM.StartMultithreaded())
            {
                Parallel.ForEach(typeList, methodCompilationFn);
            }
            else
            {
                typeList.ForEach(methodCompilationFn);
            }

            // Free memory already.
            MethodLookup.Finish();
            methodCompilerLookup.Clear();

            Console.WriteLine("-------------------");

            if (LLVM.VerifyModule(ModuleRef, LLVMVerifierFailureAction.LLVMPrintMessageAction, out var outMsg))
            {
                Console.WriteLine(outMsg);
            }

            LLVM.RunPassManager(modulePassManager, ModuleRef);

            // Cleanup
            LLVM.DisposePassManager(modulePassManager);
            LLVM.DumpModule(ModuleRef);



            // XXX

            string        errorMsg;
            LLVMTargetRef targetRef;

            if (LLVM.GetTargetFromTriple(triple, out targetRef, out errorMsg))
            {
                Console.WriteLine(errorMsg);
            }

            LLVMTargetMachineRef machineRef = LLVM.CreateTargetMachine(targetRef, triple, "generic", "", LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault, LLVMRelocMode.LLVMRelocDefault, LLVMCodeModel.LLVMCodeModelDefault);

            System.IO.File.Delete("test.s");
            if (LLVM.TargetMachineEmitToFile(machineRef, ModuleRef, Marshal.StringToHGlobalAnsi("test.s"), LLVMCodeGenFileType.LLVMAssemblyFile, out errorMsg))
            {
                Console.WriteLine(errorMsg);
            }

            Console.WriteLine("written");

            LLVM.DisposeTargetMachine(machineRef);
        }
Beispiel #11
0
        public bool Compile(CompilerOptions pOptions, out LLVMModuleRef?pModule)
        {
            double totalTime = 0;
            var    sw        = new System.Diagnostics.Stopwatch();

            sw.Start();

            //Read source files
            pModule = null;
            string source = string.IsNullOrEmpty(pOptions.SourceFile) ? pOptions.Source : ReadSourceFile(pOptions.SourceFile);

            if (source == null)
            {
                return(false);
            }

            var lexer  = new SmallerLexer();
            var stream = lexer.StartTokenStream(source, pOptions.SourceFile);
            var parser = new SmallerParser(stream);

            //Create AST
            var tree = parser.Parse();

            if (CompilerErrors.ErrorOccurred)
            {
                return(false);
            }

            totalTime += RecordPerfData(sw, "Parsed in: ");

            //Type inference, type checking, AST transformations
            var compilationModule = ModuleBuilder.Build(tree);

            if (compilationModule == null)
            {
                return(false);
            }

            totalTime += RecordPerfData(sw, "Type checked in: ");

            LLVMModuleRef      module      = LLVM.ModuleCreateWithName(tree.Name);
            LLVMPassManagerRef passManager = LLVM.CreateFunctionPassManagerForModule(module);

            if (pOptions.Optimizations)
            {
                LLVM.AddConstantPropagationPass(passManager);

                //Promote allocas to registers
                LLVM.AddPromoteMemoryToRegisterPass(passManager);

                //Do simple peephole optimizations
                LLVM.AddInstructionCombiningPass(passManager);

                //Re-associate expressions
                LLVM.AddReassociatePass(passManager);

                //Eliminate common subexpressions
                LLVM.AddGVNPass(passManager);

                //Simplify control flow graph
                LLVM.AddCFGSimplificationPass(passManager);
            }
            LLVM.InitializeFunctionPassManager(passManager);

            //Emitting LLVM bytecode
            using (var c = new EmittingContext(module, passManager, pOptions.Debug))
            {
                compilationModule.Emit(c);

                if (LLVM.VerifyModule(module, LLVMVerifierFailureAction.LLVMPrintMessageAction, out string message).Value != 0)
                {
                    LLVM.DumpModule(module);
                    LLVM.DisposePassManager(passManager);
                    pModule = null;
                    return(false);
                }
            }

            pModule = module;
            LLVM.DisposePassManager(passManager);

            totalTime += RecordPerfData(sw, "Emitted bytecode in: ");

            Console.WriteLine("Total time: " + totalTime + "s");

            return(true);
        }