From: Erik Verbruggen Date: Tue, 13 Nov 2012 08:54:24 +0000 (+0100) Subject: Added different output types to LLVM backend to ease debugging. X-Git-Tag: upstream/5.2.1~669^2~659^2~849 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2a8d0b894ba59c6e8966b39bf872ce081579f50d;p=platform%2Fupstream%2Fqtdeclarative.git Added different output types to LLVM backend to ease debugging. 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 --- diff --git a/main.cpp b/main.cpp index 623ee20..530757e 100644 --- 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 diff --git a/qv4_llvm_p.h b/qv4_llvm_p.h index e15479a..c0f18e5 100644 --- a/qv4_llvm_p.h +++ b/qv4_llvm_p.h @@ -36,7 +36,16 @@ 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 diff --git a/qv4isel_llvm.cpp b/qv4isel_llvm.cpp index c674377..9b69071 100644 --- a/qv4isel_llvm.cpp +++ b/qv4isel_llvm.cpp @@ -82,9 +82,10 @@ 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); }