diff --git a/Module.mk b/Module.mk index c12f7481..eb61d771 100644 --- a/Module.mk +++ b/Module.mk @@ -85,7 +85,7 @@ CLINGEXCCXXFLAGS := -fno-exceptions CLINGLIBEXTRA = $(CLINGLDFLAGSEXTRA) -L$(shell $(LLVMCONFIG) --libdir) \ $(addprefix -lclang,\ Frontend Serialization Driver CodeGen Parse Sema Analysis RewriteCore AST Edit Lex Basic) \ - $(shell $(LLVMCONFIG) --libs jit native option)\ + $(shell $(LLVMCONFIG) --libs bitwriter jit native option ipo instrumentation objcarcopts)\ $(shell $(LLVMCONFIG) --ldflags) $(shell $(LLVMCONFIG) --system-libs) ifneq (,$(filter $(ARCH),win32gcc win64gcc)) diff --git a/lib/Interpreter/BackendPass.cpp b/lib/Interpreter/BackendPass.cpp new file mode 100644 index 00000000..5abaa1be --- /dev/null +++ b/lib/Interpreter/BackendPass.cpp @@ -0,0 +1,457 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// author: Vassil Vassilev +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +#include "BackendPass.h" + +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/PassManager.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetLibraryInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/ObjCARC.h" +#include "llvm/Transforms/Scalar.h" + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" + +using namespace llvm; +using namespace clang; + +namespace { + + class PassManagerBuilderWithOpts: public PassManagerBuilder { + public: + const clang::LangOptions& m_LangOpts; + const clang::CodeGenOptions& m_CodeGenOpts; + PassManagerBuilderWithOpts(const clang::LangOptions& LangOpts, + const clang::CodeGenOptions& CodeGenOpts): + m_LangOpts(LangOpts), m_CodeGenOpts(CodeGenOpts) {} + + const clang::LangOptions& getLangOpts() const { return m_LangOpts; } + const clang::CodeGenOptions& getCGOpts() const { return m_CodeGenOpts; } + }; + +static void +addObjCARCAPElimPass(const PassManagerBuilder &Builder, PassManagerBase &PM) { + if (Builder.OptLevel > 0) + PM.add(createObjCARCAPElimPass()); +} + +static void +addObjCARCExpandPass(const PassManagerBuilder &Builder, PassManagerBase &PM) { + if (Builder.OptLevel > 0) + PM.add(createObjCARCExpandPass()); +} + +static void +addObjCARCOptPass(const PassManagerBuilder &Builder, PassManagerBase &PM) { + if (Builder.OptLevel > 0) + PM.add(createObjCARCOptPass()); +} + +#if 0 +static void addSampleProfileLoaderPass(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + const PassManagerBuilderWithOpts &BuilderWrapper = + static_cast(Builder); + const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); + PM.add(createSampleProfileLoaderPass(CGOpts.SampleProfileFile)); +} +#endif + +static void addBoundsCheckingPass(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + PM.add(createBoundsCheckingPass()); +} + +static void addAddressSanitizerPasses(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + const PassManagerBuilderWithOpts &BuilderWrapper = + static_cast(Builder); + const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); + const LangOptions &LangOpts = BuilderWrapper.getLangOpts(); + PM.add(createAddressSanitizerFunctionPass( + LangOpts.Sanitize.InitOrder, + LangOpts.Sanitize.UseAfterReturn, + LangOpts.Sanitize.UseAfterScope, + CGOpts.SanitizerBlacklistFile)); + PM.add(createAddressSanitizerModulePass( + LangOpts.Sanitize.InitOrder, + CGOpts.SanitizerBlacklistFile)); +} + +static void addMemorySanitizerPass(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + const PassManagerBuilderWithOpts &BuilderWrapper = + static_cast(Builder); + const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); + PM.add(createMemorySanitizerPass(CGOpts.SanitizeMemoryTrackOrigins, + CGOpts.SanitizerBlacklistFile)); + + // MemorySanitizer inserts complex instrumentation that mostly follows + // the logic of the original code, but operates on "shadow" values. + // It can benefit from re-running some general purpose optimization passes. + if (Builder.OptLevel > 0) { + PM.add(createEarlyCSEPass()); + PM.add(createReassociatePass()); + PM.add(createLICMPass()); + PM.add(createGVNPass()); + PM.add(createInstructionCombiningPass()); + PM.add(createDeadStoreEliminationPass()); + } +} + +static void addThreadSanitizerPass(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + const PassManagerBuilderWithOpts &BuilderWrapper = + static_cast(Builder); + const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); + PM.add(createThreadSanitizerPass(CGOpts.SanitizerBlacklistFile)); +} + +static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + const PassManagerBuilderWithOpts &BuilderWrapper = + static_cast(Builder); + const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); + PM.add(createDataFlowSanitizerPass(CGOpts.SanitizerBlacklistFile)); +} +} + +namespace cling { + + BackendPass::BackendPass(clang::Sema* S, llvm::Module* M, + clang::DiagnosticsEngine& Diags, + const clang::TargetOptions& TOpts, + const clang::LangOptions& LangOpts, + const clang::CodeGenOptions& CodeGenOpts): + TransactionTransformer(S), m_Module(M) { + m_TM.reset(CreateTargetMachine(Diags, TOpts, LangOpts, CodeGenOpts)); + if (m_TM) + CreatePasses(LangOpts, CodeGenOpts); + } + + llvm::FunctionPassManager *BackendPass::getPerFunctionPasses() { + if (!m_PerFunctionPasses) { + m_PerFunctionPasses.reset(new FunctionPassManager(m_Module)); + m_PerFunctionPasses->add(new DataLayoutPass(m_Module)); + m_TM->addAnalysisPasses(*m_PerFunctionPasses); + } + return m_PerFunctionPasses.get(); + } + + llvm::PassManager *BackendPass::getPerModulePasses() { + if (!m_PerModulePasses) { + m_PerModulePasses.reset(new PassManager()); + m_PerModulePasses->add(new DataLayoutPass(m_Module)); + m_TM->addAnalysisPasses(*m_PerModulePasses); + } + return m_PerModulePasses.get(); + } + + llvm::TargetMachine* + BackendPass::CreateTargetMachine(clang::DiagnosticsEngine& Diags, + const clang::TargetOptions& TargetOpts, + const clang::LangOptions& LangOpts, + const clang::CodeGenOptions& CodeGenOpts) { + // Create the TargetMachine for generating code. + // FIXME: Expose these capabilities via actual APIs!!!! Aside from just + // being gross, this is also totally broken if we ever care about + // concurrency. + + TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); + + TargetMachine::setFunctionSections(CodeGenOpts.FunctionSections); + TargetMachine::setDataSections (CodeGenOpts.DataSections); + + // FIXME: Parse this earlier. + llvm::CodeModel::Model CM; + if (CodeGenOpts.CodeModel == "small") { + CM = llvm::CodeModel::Small; + } else if (CodeGenOpts.CodeModel == "kernel") { + CM = llvm::CodeModel::Kernel; + } else if (CodeGenOpts.CodeModel == "medium") { + CM = llvm::CodeModel::Medium; + } else if (CodeGenOpts.CodeModel == "large") { + CM = llvm::CodeModel::Large; + } else { + assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); + CM = llvm::CodeModel::Default; + } + + SmallVector BackendArgs; + BackendArgs.push_back("cling"); // Fake program name. + if (!CodeGenOpts.DebugPass.empty()) { + BackendArgs.push_back("-debug-pass"); + BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); + } + if (!CodeGenOpts.LimitFloatPrecision.empty()) { + BackendArgs.push_back("-limit-float-precision"); + BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); + } + if (llvm::TimePassesIsEnabled) + BackendArgs.push_back("-time-passes"); + for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i) + BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str()); + if (CodeGenOpts.NoGlobalMerge) + BackendArgs.push_back("-global-merge=false"); + BackendArgs.push_back(0); + llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, + BackendArgs.data()); + + std::string FeaturesStr; + if (TargetOpts.Features.size()) { + SubtargetFeatures Features; + for (std::vector::const_iterator + it = TargetOpts.Features.begin(), + ie = TargetOpts.Features.end(); it != ie; ++it) + Features.AddFeature(*it); + FeaturesStr = Features.getString(); + } + + llvm::Reloc::Model RM = llvm::Reloc::Default; + if (CodeGenOpts.RelocationModel == "static") { + RM = llvm::Reloc::Static; + } else if (CodeGenOpts.RelocationModel == "pic") { + RM = llvm::Reloc::PIC_; + } else { + assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && + "Invalid PIC model!"); + RM = llvm::Reloc::DynamicNoPIC; + } + + CodeGenOpt::Level OptLevel = CodeGenOpt::Default; + switch (CodeGenOpts.OptimizationLevel) { + default: break; + case 0: OptLevel = CodeGenOpt::None; break; + case 3: OptLevel = CodeGenOpt::Aggressive; break; + } + + llvm::TargetOptions Options; + + if (CodeGenOpts.DisableIntegratedAS) + Options.DisableIntegratedAS = true; + + // Set frame pointer elimination mode. + if (!CodeGenOpts.DisableFPElim) { + Options.NoFramePointerElim = false; + } else if (CodeGenOpts.OmitLeafFramePointer) { + Options.NoFramePointerElim = false; + } else { + Options.NoFramePointerElim = true; + } + + if (CodeGenOpts.UseInitArray) + Options.UseInitArray = true; + + // Set float ABI type. + if (CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp") + Options.FloatABIType = llvm::FloatABI::Soft; + else if (CodeGenOpts.FloatABI == "hard") + Options.FloatABIType = llvm::FloatABI::Hard; + else { + assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); + Options.FloatABIType = llvm::FloatABI::Default; + } + + // Set FP fusion mode. + switch (CodeGenOpts.getFPContractMode()) { + case CodeGenOptions::FPC_Off: + Options.AllowFPOpFusion = llvm::FPOpFusion::Strict; + break; + case CodeGenOptions::FPC_On: + Options.AllowFPOpFusion = llvm::FPOpFusion::Standard; + break; + case CodeGenOptions::FPC_Fast: + Options.AllowFPOpFusion = llvm::FPOpFusion::Fast; + break; + } + + Options.LessPreciseFPMADOption = CodeGenOpts.LessPreciseFPMAD; + Options.NoInfsFPMath = CodeGenOpts.NoInfsFPMath; + Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath; + Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; + Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath; + Options.UseSoftFloat = CodeGenOpts.SoftFloat; + Options.StackAlignmentOverride = CodeGenOpts.StackAlignment; + Options.DisableTailCalls = CodeGenOpts.DisableTailCalls; + Options.TrapFuncName = CodeGenOpts.TrapFuncName; + Options.PositionIndependentExecutable = LangOpts.PIELevel != 0; + Options.EnableSegmentedStacks = CodeGenOpts.EnableSegmentedStacks; + + Triple TheTriple; + TheTriple.setTriple(sys::getProcessTriple()); + std::string Error; + const Target* TheTarget + = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error); + if (!TheTarget) { + Diags.Report(diag::err_fe_unable_to_create_target) << Error; + return 0; + } + + TargetMachine *TM = TheTarget->createTargetMachine(TheTriple.getTriple(), + TargetOpts.CPU, + FeaturesStr, Options, + RM, CM, OptLevel); + + if (CodeGenOpts.RelaxAll) + TM->setMCRelaxAll(true); + if (CodeGenOpts.SaveTempLabels) + TM->setMCSaveTempLabels(true); + if (CodeGenOpts.NoDwarf2CFIAsm) + TM->setMCUseCFI(false); + if (!CodeGenOpts.NoDwarfDirectoryAsm) + TM->setMCUseDwarfDirectory(true); + if (CodeGenOpts.NoExecStack) + TM->setMCNoExecStack(true); + + return TM; + } + + void BackendPass::CreatePasses(const clang::LangOptions& LangOpts, + const clang::CodeGenOptions& CodeGenOpts) { + // See clang/lib/CodeGen/BackendUtil.cpp EmitAssemblyHelper::CreatePasses() + unsigned OptLevel = CodeGenOpts.OptimizationLevel; + CodeGenOptions::InliningMethod Inlining = CodeGenOpts.getInlining(); + + // Handle disabling of LLVM optimization, where we want to preserve the + // internal module before any optimization. + if (CodeGenOpts.DisableLLVMOpts) { + OptLevel = 0; + Inlining = CodeGenOpts.NoInlining; + } + + PassManagerBuilderWithOpts PMBuilder(LangOpts, CodeGenOpts); + PMBuilder.OptLevel = OptLevel; + PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize; + PMBuilder.BBVectorize = CodeGenOpts.VectorizeBB; + PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP; + PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop; + + PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime; + PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops; + PMBuilder.RerollLoops = CodeGenOpts.RerollLoops; + +#if 0 + if (!CodeGenOpts.SampleProfileFile.empty()) + PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible, + addSampleProfileLoaderPass); +#endif + + // In ObjC ARC mode, add the main ARC optimization passes. + if (LangOpts.ObjCAutoRefCount) { + PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible, + addObjCARCExpandPass); + PMBuilder.addExtension(PassManagerBuilder::EP_ModuleOptimizerEarly, + addObjCARCAPElimPass); + PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate, + addObjCARCOptPass); + } + + if (LangOpts.Sanitize.LocalBounds) { + PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate, + addBoundsCheckingPass); + PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addBoundsCheckingPass); + } + + if (LangOpts.Sanitize.Address) { + PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, + addAddressSanitizerPasses); + PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addAddressSanitizerPasses); + } + + if (LangOpts.Sanitize.Memory) { + PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, + addMemorySanitizerPass); + PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addMemorySanitizerPass); + } + + if (LangOpts.Sanitize.Thread) { + PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, + addThreadSanitizerPass); + PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addThreadSanitizerPass); + } + + if (LangOpts.Sanitize.DataFlow) { + PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, + addDataFlowSanitizerPass); + PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addDataFlowSanitizerPass); + } + + // Figure out TargetLibraryInfo. + Triple TargetTriple(m_Module->getTargetTriple()); + PMBuilder.LibraryInfo = new TargetLibraryInfo(TargetTriple); + if (!CodeGenOpts.SimplifyLibCalls) + PMBuilder.LibraryInfo->disableAllFunctions(); + + switch (Inlining) { + case CodeGenOptions::NoInlining: break; + case CodeGenOptions::NormalInlining: { + // FIXME: Derive these constants in a principled fashion. + unsigned Threshold = 225; + if (CodeGenOpts.OptimizeSize == 1) // -Os + Threshold = 75; + else if (CodeGenOpts.OptimizeSize == 2) // -Oz + Threshold = 25; + else if (OptLevel > 2) + Threshold = 275; + PMBuilder.Inliner = createFunctionInliningPass(Threshold); + break; + } + case CodeGenOptions::OnlyAlwaysInlining: + // Respect always_inline. + if (OptLevel == 0) + // Do not insert lifetime intrinsics at -O0. + PMBuilder.Inliner = createAlwaysInlinerPass(false); + else + PMBuilder.Inliner = createAlwaysInlinerPass(); + break; + } + + // Set up the per-function pass manager. + FunctionPassManager *FPM = getPerFunctionPasses(); + if (CodeGenOpts.VerifyModule) + FPM->add(createVerifierPass()); + PMBuilder.populateFunctionPassManager(*FPM); + + // The Inliner is a module pass; register it. + PMBuilder.populateModulePassManager(*getPerModulePasses()); + } + + // pin the vtable and OwningPtrs' dtors. + BackendPass::~BackendPass() {} + + void BackendPass::Transform() { + // FIXME: This should not revisit the whole module but only its + // llvm::Functions created by the current transaction. + for (auto& F: *m_Module) { + if (!F.isDeclaration()) + m_PerFunctionPasses->run(F); + } + // Do not remove force_inline functions: we might need them for + // inlining them into the next function calling them, and CodeGen will + // not emit them anymore. + //m_PerFunctionPasses->doFinalization(); + } +} // end namespace cling diff --git a/lib/Interpreter/BackendPass.h b/lib/Interpreter/BackendPass.h new file mode 100644 index 00000000..7d3b93f8 --- /dev/null +++ b/lib/Interpreter/BackendPass.h @@ -0,0 +1,77 @@ +//--------------------------------------------------------------------*- C++ -*- +// CLING - the C++ LLVM-based InterpreterG :) +// author: Vassil Vassilev +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +#ifndef CLING_TRANSACTION_BACKENDPASS_H +#define CLING_TRANSACTION_BACKENDPASS_H + +#include "llvm/ADT/OwningPtr.h" + +#include "TransactionTransformer.h" + +namespace clang { + class CodeGenOptions; + class DiagnosticsEngine; + class LangOptions; + class TargetOptions; +} +namespace llvm { + namespace legacy { + class FunctionPassManager; + class PassManager; + } + using legacy::FunctionPassManager; + using legacy::PassManager; + class Module; + class Target; + class TargetMachine; +} + +namespace cling { + + ///\brief Run the backend passes. A stripped-down, streaming version + /// of what's used by clang's BackendUtil. Implements no CodeGenPasses and + /// no PerModulePasses. + class BackendPass: public TransactionTransformer { + llvm::Module* m_Module; + llvm::OwningPtr m_PerFunctionPasses; + llvm::OwningPtr m_PerModulePasses; + llvm::OwningPtr m_TM; + + public: + ///\brief Initializes a new transaction transformer. + /// + ///\param[in] S - The semantic analysis object. + /// + BackendPass(clang::Sema* S, llvm::Module* M, + clang::DiagnosticsEngine& Diags, + const clang::TargetOptions& TOpts, + const clang::LangOptions& LangOpts, + const clang::CodeGenOptions& CodeGenOpts); + virtual ~BackendPass(); + + protected: + ///\brief Transforms the current transaction. + /// + void Transform() override; + + void CreatePasses(const clang::LangOptions& LangOpts, + const clang::CodeGenOptions& CodeGenOpts); + /// CreateTargetMachine - Generates the TargetMachine. + /// Returns Null if it is unable to create the target machine. + llvm::TargetMachine* + CreateTargetMachine(clang::DiagnosticsEngine& Diags, + const clang::TargetOptions &TOpts, + const clang::LangOptions& LangOpts, + const clang::CodeGenOptions& CodeGenOpts); + + llvm::FunctionPassManager *getPerFunctionPasses(); + llvm::PassManager *getPerModulePasses(); + }; +} // end namespace cling +#endif // CLING_TRANSACTION_TRANSFORMER_H diff --git a/lib/Interpreter/IncrementalParser.cpp b/lib/Interpreter/IncrementalParser.cpp index 34a9363a..47c964b2 100644 --- a/lib/Interpreter/IncrementalParser.cpp +++ b/lib/Interpreter/IncrementalParser.cpp @@ -10,6 +10,7 @@ #include "IncrementalParser.h" #include "ASTNodeEraser.h" #include "AutoSynthesizer.h" +#include "BackendPass.h" #include "CheckEmptyTransactionTransformer.h" #include "DeclCollector.h" #include "DeclExtractor.h" @@ -81,6 +82,16 @@ namespace cling { m_ASTTransformers.push_back(new ValueExtractionSynthesizer(TheSema)); m_ASTTransformers.push_back(new NullDerefProtectionTransformer(TheSema)); m_ASTTransformers.push_back(new CheckEmptyTransactionTransformer(TheSema)); + + if (m_CodeGen) { + llvm::Module* TheModule = m_CodeGen->GetModule(); + // IR passes make sense if we do CodeGen. + m_IRTransformers.push_back(new BackendPass(TheSema, TheModule, + CI->getDiagnostics(), + CI->getTargetOpts(), + CI->getLangOpts(), + CI->getCodeGenOpts())); + } } void