Added different output types to LLVM backend to ease debugging.
authorErik Verbruggen <erik.verbruggen@digia.com>
Tue, 13 Nov 2012 08:54:24 +0000 (09:54 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Wed, 14 Nov 2012 07:40:37 +0000 (08:40 +0100)
While in that area of code, also throw in the pass-managers for
some extra optimisations during compilation.

Change-Id: I1239ab9d21fc50b2e65c2f9d77a03ae593b607bc
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
main.cpp
qv4_llvm_p.h
qv4isel_llvm.cpp

index 623ee20..530757e 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -159,7 +159,7 @@ int executeLLVMCode(void *codePtr)
     return EXIT_SUCCESS;
 }
 
-int compile(const QString &fileName, const QString &source, bool runInJit)
+int compile(const QString &fileName, const QString &source, QQmlJS::LLVMOutputType outputType)
 {
     using namespace QQmlJS;
 
@@ -185,17 +185,17 @@ int compile(const QString &fileName, const QString &source, bool runInJit)
     Codegen cg;
     /*IR::Function *globalCode =*/ cg(program, &module);
 
-    int (*exec)(void *) = runInJit ? executeLLVMCode : 0;
-    return compileWithLLVM(&module, fileName, exec);
+    int (*exec)(void *) = outputType == LLVMOutputJit ? executeLLVMCode : 0;
+    return compileWithLLVM(&module, fileName, outputType, exec);
 }
 
-int compileFiles(const QStringList &files, bool runInJit)
+int compileFiles(const QStringList &files, QQmlJS::LLVMOutputType outputType)
 {
     foreach (const QString &fileName, files) {
         QFile file(fileName);
         if (file.open(QFile::ReadOnly)) {
             QString source = QString::fromUtf8(file.readAll());
-            int result = compile(fileName, source, runInJit);
+            int result = compile(fileName, source, outputType);
             if (result != EXIT_SUCCESS)
                 return result;
         }
@@ -324,6 +324,10 @@ int main(int argc, char *argv[])
         use_llvm_jit
     } mode = use_masm;
 
+#ifndef QMLJS_NO_LLVM
+    QQmlJS::LLVMOutputType fileType = QQmlJS::LLVMOutputObject;
+#endif // QMLJS_NO_LLVM
+
     if (!args.isEmpty()) {
         if (args.first() == QLatin1String("--jit")) {
             mode = use_masm;
@@ -339,6 +343,18 @@ int main(int argc, char *argv[])
         if (args.first() == QLatin1String("--compile")) {
             mode = use_llvm_compiler;
             args.removeFirst();
+
+            if (!args.isEmpty() && args.first() == QLatin1String("-t")) {
+                args.removeFirst();
+                // Note: keep this list in sync with the enum!
+                static QStringList fileTypes = QStringList() << QLatin1String("ll") << QLatin1String("bc") << QLatin1String("asm") << QLatin1String("obj");
+                if (args.isEmpty() || !fileTypes.contains(args.first())) {
+                    std::cerr << "file types: ll, bc, asm, obj" << std::endl;
+                    return EXIT_FAILURE;
+                }
+                fileType = (QQmlJS::LLVMOutputType) fileTypes.indexOf(args.first());
+                args.removeFirst();
+            }
         }
 
         if (args.first() == QLatin1String("--aot")) {
@@ -366,9 +382,9 @@ int main(int argc, char *argv[])
         return EXIT_FAILURE;
 #else // QMLJS_NO_LLVM
     case use_llvm_jit:
-        return compileFiles(args, true);
+        return compileFiles(args, QQmlJS::LLVMOutputJit);
     case use_llvm_compiler:
-        return compileFiles(args, false);
+        return compileFiles(args, fileType);
     case use_llvm_runtime:
         return evaluateCompiledCode(args);
 #endif // QMLJS_NO_LLVM
index e15479a..c0f18e5 100644 (file)
 
 namespace QQmlJS {
 
-int compileWithLLVM(IR::Module *module, const QString &fileName, int (*exec)(void *));
+// Note: keep this enum in sync with the command-line option!
+enum LLVMOutputType {
+    LLVMOutputJit = -1,
+    LLVMOutputIR = 0, // .ll
+    LLVMOutputBitcode = 1, // .bc
+    LLVMOutputAssembler = 2, // .s
+    LLVMOutputObject = 3 // .o
+};
+
+int compileWithLLVM(IR::Module *module, const QString &fileName,  LLVMOutputType outputType, int (*exec)(void *));
 
 } // QQmlJS
 
index c674377..9b69071 100644 (file)
 
 namespace QQmlJS {
 
-int compileWithLLVM(IR::Module *module, const QString &fileName, int (*exec)(void *))
+int compileWithLLVM(IR::Module *module, const QString &fileName, LLVMOutputType outputType, int (*exec)(void *))
 {
     Q_ASSERT(module);
+    Q_ASSERT(exec || outputType != LLVMOutputJit);
 
     // TODO: should this be done here?
     LLVMInitializeX86TargetInfo();
@@ -103,44 +104,61 @@ int compileWithLLVM(IR::Module *module, const QString &fileName, int (*exec)(voi
     llvm::StringRef moduleId(moduleName.toUtf8().constData());
     llvm::Module *llvmModule = new llvm::Module(moduleId, llvmIsel.getContext());
 
-    if (exec) {
+    if (outputType == LLVMOutputJit) {
         // The execution engine takes ownership of the model. No need to delete it anymore.
         std::string errStr;
         llvm::ExecutionEngine *execEngine = llvm::EngineBuilder(llvmModule)
-                .setUseMCJIT(true)
-//                .setJITMemoryManager(llvm::JITMemoryManager::CreateDefaultMemManager())
+//                .setUseMCJIT(true)
                 .setErrorStr(&errStr).create();
         if (!execEngine) {
             std::cerr << "Could not create LLVM JIT: " << errStr << std::endl;
             return EXIT_FAILURE;
         }
 
-        llvm::FunctionPassManager fpm(llvmModule);
+        llvm::FunctionPassManager functionPassManager(llvmModule);
         // Set up the optimizer pipeline.  Start with registering info about how the
         // target lays out data structures.
-        fpm.add(new llvm::DataLayout(*execEngine->getDataLayout()));
+        functionPassManager.add(new llvm::DataLayout(*execEngine->getDataLayout()));
+        // Promote allocas to registers.
+        functionPassManager.add(llvm::createPromoteMemoryToRegisterPass());
         // Provide basic AliasAnalysis support for GVN.
-        fpm.add(llvm::createBasicAliasAnalysisPass());
+        functionPassManager.add(llvm::createBasicAliasAnalysisPass());
         // Do simple "peephole" optimizations and bit-twiddling optzns.
-        fpm.add(llvm::createInstructionCombiningPass());
+        functionPassManager.add(llvm::createInstructionCombiningPass());
         // Reassociate expressions.
-        fpm.add(llvm::createReassociatePass());
+        functionPassManager.add(llvm::createReassociatePass());
         // Eliminate Common SubExpressions.
-        fpm.add(llvm::createGVNPass());
+        functionPassManager.add(llvm::createGVNPass());
         // Simplify the control flow graph (deleting unreachable blocks, etc).
-        fpm.add(llvm::createCFGSimplificationPass());
+        functionPassManager.add(llvm::createCFGSimplificationPass());
 
-        fpm.doInitialization();
+        functionPassManager.doInitialization();
 
-        llvmIsel.buildLLVMModule(module, llvmModule, &fpm);
+        llvmIsel.buildLLVMModule(module, llvmModule, &functionPassManager);
 
         llvm::Function *entryPoint = llvmModule->getFunction("%entry");
         Q_ASSERT(entryPoint);
         void *funcPtr = execEngine->getPointerToFunction(entryPoint);
         return exec(funcPtr);
     } else {
-        // TODO: add a FunctionPassManager
-        llvmIsel.buildLLVMModule(module, llvmModule, 0);
+        llvm::FunctionPassManager functionPassManager(llvmModule);
+        // Set up the optimizer pipeline.
+        // Promote allocas to registers.
+        functionPassManager.add(llvm::createPromoteMemoryToRegisterPass());
+        // Provide basic AliasAnalysis support for GVN.
+        functionPassManager.add(llvm::createBasicAliasAnalysisPass());
+        // Do simple "peephole" optimizations and bit-twiddling optzns.
+        functionPassManager.add(llvm::createInstructionCombiningPass());
+        // Reassociate expressions.
+        functionPassManager.add(llvm::createReassociatePass());
+        // Eliminate Common SubExpressions.
+        functionPassManager.add(llvm::createGVNPass());
+        // Simplify the control flow graph (deleting unreachable blocks, etc).
+        functionPassManager.add(llvm::createCFGSimplificationPass());
+
+        functionPassManager.doInitialization();
+
+        llvmIsel.buildLLVMModule(module, llvmModule, &functionPassManager);
 
         // TODO: if output type is .ll, print the module to file
 
@@ -162,12 +180,16 @@ int compileWithLLVM(IR::Module *module, const QString &fileName, int (*exec)(voi
         llvm::TargetMachine::CodeGenFileType ft;
         QString ofName;
 
-        ft = llvm::TargetMachine::CGFT_ObjectFile;
-        ofName = fileName + QLatin1String(".o");
-
-        // TODO:
-        //    ft = llvm::TargetMachine::CGFT_AssemblyFile;
-        //    ofName = fileName + QLatin1String(".s");
+        if (outputType == LLVMOutputObject) {
+            ft = llvm::TargetMachine::CGFT_ObjectFile;
+            ofName = fileName + QLatin1String(".o");
+        } else if (outputType == LLVMOutputAssembler) {
+            ft = llvm::TargetMachine::CGFT_AssemblyFile;
+            ofName = fileName + QLatin1String(".s");
+        } else {
+            // ft is not used.
+            ofName = fileName + QLatin1String(".ll");
+        }
 
         llvm::raw_fd_ostream dest(ofName.toUtf8().constData(), err, llvm::raw_fd_ostream::F_Binary);
         llvm::formatted_raw_ostream destf(dest);
@@ -176,15 +198,25 @@ int compileWithLLVM(IR::Module *module, const QString &fileName, int (*exec)(voi
             delete llvmModule;
         }
 
-        llvm::PassManager PM;
-        PM.add(llvm::createScalarReplAggregatesPass());
-        PM.add(llvm::createInstructionCombiningPass());
-        PM.add(llvm::createGlobalOptimizerPass());
-        PM.add(llvm::createFunctionInliningPass(25));
-        if (targetMachine->addPassesToEmitFile(PM, destf, ft)) {
-            std::cerr << err << " (probably no DataLayout in TargetMachine)" << std::endl;
-        } else {
-            PM.run(*llvmModule);
+        llvm::PassManager globalPassManager;
+        globalPassManager.add(llvm::createScalarReplAggregatesPass());
+        globalPassManager.add(llvm::createInstructionCombiningPass());
+        globalPassManager.add(llvm::createGlobalOptimizerPass());
+        globalPassManager.add(llvm::createFunctionInliningPass(25));
+//        globalPassManager.add(llvm::createFunctionInliningPass(125));
+
+        if (outputType == LLVMOutputObject || outputType == LLVMOutputAssembler) {
+            if (targetMachine->addPassesToEmitFile(globalPassManager, destf, ft)) {
+                std::cerr << err << " (probably no DataLayout in TargetMachine)" << std::endl;
+            } else {
+                globalPassManager.run(*llvmModule);
+
+                destf.flush();
+                dest.flush();
+            }
+        } else { // .ll
+            globalPassManager.run(*llvmModule);
+            llvmModule->print(destf, 0);
 
             destf.flush();
             dest.flush();
@@ -261,6 +293,7 @@ void LLVMInstructionSelection::buildLLVMModule(IR::Module *module, llvm::Module
 
     foreach (IR::Function *function, module->functions)
         (void) compileLLVMFunction(function);
+    qSwap(_fpm, fpm);
     qSwap(_llvmModule, llvmModule);
 }