diff --git a/deps/llvm.mk b/deps/llvm.mk index df33c73b00b70..196ababb9dc7d 100644 --- a/deps/llvm.mk +++ b/deps/llvm.mk @@ -466,6 +466,26 @@ $(eval $(call LLVM_PATCH,llvm-rL293230-icc17-cmake)) # Remove for 4.0 $(eval $(call LLVM_PATCH,llvm-D32593)) $(eval $(call LLVM_PATCH,llvm-D33179)) $(eval $(call LLVM_PATCH,llvm-PR29010-i386-xmm)) # Remove for 4.0 +else ifeq ($(LLVM_VER_SHORT),4.0) +# Cygwin and openSUSE still use win32-threads mingw, https://llvm.org/bugs/show_bug.cgi?id=26365 +$(eval $(call LLVM_PATCH,llvm-4.0.0_threads)) +$(eval $(call LLVM_PATCH,llvm-3.9.0_D27296-libssp)) +$(eval $(call LLVM_PATCH,llvm-D27629-AArch64-large_model_4.0)) +$(eval $(call LLVM_PATCH,llvm-D28215_FreeBSD_shlib)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D28759-loopclearance)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D28786-callclearance_4.0)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D32593)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D33179)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D32203-SORA-non-integral)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D33110-codegen-prepare-inttoptr)) +$(eval $(call LLVM_PATCH,llvm-D30478-VNCoercion)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-VNCoercion-signatures)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-VNCoercion-template)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D32196-LIR-non-integral)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D32208-coerce-non-integral)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D32623-GVN-non-integral)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-D33129-scevexpander-non-integral)) # Remove for 5.0 +$(eval $(call LLVM_PATCH,llvm-Yet-another-fix)) endif # LLVM_VER $(LLVM_BUILDDIR_withtype)/build-configured: $(LLVM_PATCH_PREV) diff --git a/deps/patches/llvm-4.0.0_threads.patch b/deps/patches/llvm-4.0.0_threads.patch new file mode 100644 index 0000000000000..d3ed7ee7931b9 --- /dev/null +++ b/deps/patches/llvm-4.0.0_threads.patch @@ -0,0 +1,2032 @@ +From dfead72dc82a76a62433c4f0ed2262407ef51bf0 Mon Sep 17 00:00:00 2001 +From: Alex Crichton +Date: Thu, 28 Jan 2016 20:44:50 -0800 +Subject: [PATCH] Don't compile usage of std::thread + +As of the time of this writing it's not actually used anywhere meaningfullly +throughout the LLVM repo that we need, and it unfortunately uses `std::thread` +which isn't available in mingw-w64 toolchains with the win32 threading model +(the one that we use). + +The change made to achive this was to just always use the single-threaded +support in `include/llvm/Support/thread.h`, and hopefuly that'll be enough... + +For reference, the upstream LLVM bug has been reported [1] + +[1]: https://llvm.org/bugs/show_bug.cgi?id=26365 +--- + include/llvm/Support/ThreadPool.h | 4 + + include/llvm/Support/thread.h | 2 +- + lib/CodeGen/ParallelCG.cpp | 2 + + lib/LTO/LTO.cpp | 6 +- + lib/LTO/LTOBackend.cpp | 2 + + lib/LTO/ThinLTOCodeGenerator.cpp | 6 +- + lib/Support/ThreadPool.cpp | 6 +- + test/CMakeLists.txt | 1 - + tools/lli/CMakeLists.txt | 4 - + tools/lli/ChildTarget/CMakeLists.txt | 13 -- + tools/lli/ChildTarget/ChildTarget.cpp | 67 ------- + tools/lli/ChildTarget/LLVMBuild.txt | 21 --- + tools/lli/LLVMBuild.txt | 3 - + tools/lli/OrcLazyJIT.cpp | 3 +- + tools/lli/OrcLazyJIT.h | 175 ------------------ + tools/lli/RemoteJITUtils.h | 153 ---------------- + tools/lli/lli.cpp | 7 + + tools/llvm-cov/CodeCoverage.cpp | 4 + + tools/llvm-cov/CoverageExporterJson.cpp | 2 + + tools/llvm-cov/CoverageFilters.cpp | 2 + + tools/llvm-cov/CoverageFilters.h | 127 ------------- + tools/llvm-cov/CoverageReport.cpp | 2 + + tools/llvm-cov/CoverageReport.h | 51 ------ + tools/llvm-cov/CoverageSummaryInfo.cpp | 2 + + tools/llvm-cov/CoverageSummaryInfo.h | 165 ----------------- + tools/llvm-cov/CoverageViewOptions.h | 68 ------- + tools/llvm-cov/RenderingSupport.h | 61 ------- + tools/llvm-cov/SourceCoverageView.cpp | 2 + + tools/llvm-cov/SourceCoverageView.h | 289 ------------------------------ + tools/llvm-cov/SourceCoverageViewHTML.cpp | 3 + + tools/llvm-cov/SourceCoverageViewHTML.h | 96 ---------- + tools/llvm-cov/SourceCoverageViewText.cpp | 3 + + tools/llvm-cov/SourceCoverageViewText.h | 89 --------- + tools/llvm-cov/TestingSupport.cpp | 2 + + tools/llvm-cov/gcov.cpp | 2 + + tools/llvm-cov/llvm-cov.cpp | 4 + + tools/llvm-profdata/llvm-profdata.cpp | 5 + + tools/sancov/sancov.cc | 5 + + unittests/Support/ThreadPool.cpp | 4 + + 39 files changed, 73 insertions(+), 1390 deletions(-) + delete mode 100644 tools/lli/ChildTarget/CMakeLists.txt + delete mode 100644 tools/lli/ChildTarget/ChildTarget.cpp + delete mode 100644 tools/lli/ChildTarget/LLVMBuild.txt + delete mode 100644 tools/lli/OrcLazyJIT.h + delete mode 100644 tools/lli/RemoteJITUtils.h + delete mode 100644 tools/llvm-cov/CoverageFilters.h + delete mode 100644 tools/llvm-cov/CoverageReport.h + delete mode 100644 tools/llvm-cov/CoverageSummaryInfo.h + delete mode 100644 tools/llvm-cov/CoverageViewOptions.h + delete mode 100644 tools/llvm-cov/RenderingSupport.h + delete mode 100644 tools/llvm-cov/SourceCoverageView.h + delete mode 100644 tools/llvm-cov/SourceCoverageViewHTML.h + delete mode 100644 tools/llvm-cov/SourceCoverageViewText.h + +diff --git a/include/llvm/Support/ThreadPool.h b/include/llvm/Support/ThreadPool.h +index 665cec2465b..c3aa64de8cc 100644 +--- a/include/llvm/Support/ThreadPool.h ++++ b/include/llvm/Support/ThreadPool.h +@@ -16,6 +16,8 @@ + + #include "llvm/Support/thread.h" + ++# if 0 ++ + #ifdef _MSC_VER + // concrt.h depends on eh.h for __uncaught_exception declaration + // even if we disable exceptions. +@@ -134,4 +136,6 @@ private: + }; + } + ++# endif ++ + #endif // LLVM_SUPPORT_THREAD_POOL_H +diff --git a/include/llvm/Support/thread.h b/include/llvm/Support/thread.h +index 9c45418df55..27d42d23f61 100644 +--- a/include/llvm/Support/thread.h ++++ b/include/llvm/Support/thread.h +@@ -19,7 +19,7 @@ + + #include "llvm/Config/llvm-config.h" + +-#if LLVM_ENABLE_THREADS ++#if LLVM_ENABLE_THREADS && 0 + + #ifdef _MSC_VER + // concrt.h depends on eh.h for __uncaught_exception declaration +diff --git a/lib/CodeGen/ParallelCG.cpp b/lib/CodeGen/ParallelCG.cpp +index 50dd44fa659..e91898e0fa7 100644 +--- a/lib/CodeGen/ParallelCG.cpp ++++ b/lib/CodeGen/ParallelCG.cpp +@@ -50,6 +50,7 @@ std::unique_ptr llvm::splitCodeGen( + return M; + } + ++#if 0 + // Create ThreadPool in nested scope so that threads will be joined + // on destruction. + { +@@ -96,5 +97,6 @@ std::unique_ptr llvm::splitCodeGen( + PreserveLocals); + } + ++#endif + return {}; + } +diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp +index e3e2f9f806c..530946c03bb 100644 +--- a/lib/LTO/LTO.cpp ++++ b/lib/LTO/LTO.cpp +@@ -630,7 +630,6 @@ public: + + namespace { + class InProcessThinBackend : public ThinBackendProc { +- ThreadPool BackendThreadPool; + AddStreamFn AddStream; + NativeObjectCache Cache; + +@@ -644,7 +643,6 @@ public: + const StringMap &ModuleToDefinedGVSummaries, + AddStreamFn AddStream, NativeObjectCache Cache) + : ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries), +- BackendThreadPool(ThinLTOParallelismLevel), + AddStream(std::move(AddStream)), Cache(std::move(Cache)) {} + + Error runThinLTOBackendThread( +@@ -690,6 +688,7 @@ public: + const FunctionImporter::ExportSetTy &ExportList, + const std::map &ResolvedODR, + MapVector &ModuleMap) override { ++#if 0 + StringRef ModulePath = BM.getModuleIdentifier(); + assert(ModuleToDefinedGVSummaries.count(ModulePath)); + const GVSummaryMapTy &DefinedGlobals = +@@ -716,11 +715,14 @@ public: + BM, std::ref(CombinedIndex), std::ref(ImportList), + std::ref(ExportList), std::ref(ResolvedODR), std::ref(DefinedGlobals), + std::ref(ModuleMap)); ++#endif + return Error::success(); + } + + Error wait() override { ++#if 0 + BackendThreadPool.wait(); ++#endif + if (Err) + return std::move(*Err); + else +diff --git a/lib/LTO/LTOBackend.cpp b/lib/LTO/LTOBackend.cpp +index 809db80bc91..73a355ecf1a 100644 +--- a/lib/LTO/LTOBackend.cpp ++++ b/lib/LTO/LTOBackend.cpp +@@ -216,6 +216,7 @@ void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, + void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, + unsigned ParallelCodeGenParallelismLevel, + std::unique_ptr Mod) { ++#if 0 + ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel); + unsigned ThreadCount = 0; + const Target *T = &TM->getTarget(); +@@ -259,6 +260,7 @@ void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, + // variables, we need to wait for the worker threads to terminate before we + // can leave the function scope. + CodegenThreadPool.wait(); ++#endif + } + + Expected initAndLookupTarget(Config &C, Module &Mod) { +diff --git a/lib/LTO/ThinLTOCodeGenerator.cpp b/lib/LTO/ThinLTOCodeGenerator.cpp +index 40537e4fa78..470e9e57df5 100644 +--- a/lib/LTO/ThinLTOCodeGenerator.cpp ++++ b/lib/LTO/ThinLTOCodeGenerator.cpp +@@ -70,8 +70,8 @@ extern cl::opt LTOPassRemarksWithHotness; + + namespace { + +-static cl::opt +- ThreadCount("threads", cl::init(llvm::heavyweight_hardware_concurrency())); ++static cl::opt ThreadCount("threads", ++ cl::init(1)); + + Expected> + setupOptimizationRemarks(LLVMContext &Ctx, int Count) { +@@ -830,6 +830,7 @@ static std::string writeGeneratedObject(int count, StringRef CacheEntryPath, + + // Main entry point for the ThinLTO processing + void ThinLTOCodeGenerator::run() { ++#if 0 + // Prepare the resulting object vector + assert(ProducedBinaries.empty() && "The generator should not be reused"); + if (SavedObjectsDirectoryPath.empty()) +@@ -1052,4 +1053,5 @@ void ThinLTOCodeGenerator::run() { + // If statistics were requested, print them out now. + if (llvm::AreStatisticsEnabled()) + llvm::PrintStatistics(); ++#endif + } +diff --git a/lib/Support/ThreadPool.cpp b/lib/Support/ThreadPool.cpp +index db03a4d6240..71f49330f91 100644 +--- a/lib/Support/ThreadPool.cpp ++++ b/lib/Support/ThreadPool.cpp +@@ -11,6 +11,8 @@ + // + //===----------------------------------------------------------------------===// + ++#if 0 ++ + #include "llvm/Support/ThreadPool.h" + + #include "llvm/Config/llvm-config.h" +@@ -18,7 +20,7 @@ + + using namespace llvm; + +-#if LLVM_ENABLE_THREADS ++#if LLVM_ENABLE_THREADS && 0 + + // Default to std::thread::hardware_concurrency + ThreadPool::ThreadPool() : ThreadPool(std::thread::hardware_concurrency()) {} +@@ -156,3 +158,5 @@ ThreadPool::~ThreadPool() { + } + + #endif ++ ++#endif +diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt +index c1667049f80..aa7d7f105b2 100644 +--- a/test/CMakeLists.txt ++++ b/test/CMakeLists.txt +@@ -35,7 +35,6 @@ set(LLVM_TEST_DEPENDS + count + llc + lli +- lli-child-target + llvm-ar + llvm-as + llvm-bcanalyzer +diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt +index f02e19313b7..ca2e82abcd0 100644 +--- a/tools/lli/CMakeLists.txt ++++ b/tools/lli/CMakeLists.txt +@@ -1,7 +1,3 @@ +-if ( LLVM_INCLUDE_UTILS ) +- add_subdirectory(ChildTarget) +-endif() +- + set(LLVM_LINK_COMPONENTS + CodeGen + Core +diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt +deleted file mode 100644 +index f08ce57c295..00000000000 +--- a/tools/lli/ChildTarget/CMakeLists.txt ++++ /dev/null +@@ -1,13 +0,0 @@ +-set(LLVM_LINK_COMPONENTS +- OrcJIT +- RuntimeDyld +- Support +- ) +- +-add_llvm_utility(lli-child-target +- ChildTarget.cpp +- +- DEPENDS +- intrinsics_gen +-) +- +diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp +deleted file mode 100644 +index 77b1d47a946..00000000000 +--- a/tools/lli/ChildTarget/ChildTarget.cpp ++++ /dev/null +@@ -1,67 +0,0 @@ +-#include "llvm/ExecutionEngine/Orc/OrcABISupport.h" +-#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h" +-#include "llvm/Support/Debug.h" +-#include "llvm/Support/DynamicLibrary.h" +-#include "llvm/Support/Process.h" +-#include +- +-#include "../RemoteJITUtils.h" +- +-using namespace llvm; +-using namespace llvm::orc; +-using namespace llvm::sys; +- +-#ifdef __x86_64__ +-typedef OrcX86_64_SysV HostOrcArch; +-#else +-typedef OrcGenericABI HostOrcArch; +-#endif +- +-ExitOnError ExitOnErr; +- +-int main(int argc, char *argv[]) { +- +- if (argc != 3) { +- errs() << "Usage: " << argv[0] << " \n"; +- return 1; +- } +- +- ExitOnErr.setBanner(std::string(argv[0]) + ":"); +- +- int InFD; +- int OutFD; +- { +- std::istringstream InFDStream(argv[1]), OutFDStream(argv[2]); +- InFDStream >> InFD; +- OutFDStream >> OutFD; +- } +- +- if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) { +- errs() << "Error loading program symbols.\n"; +- return 1; +- } +- +- auto SymbolLookup = [](const std::string &Name) { +- return RTDyldMemoryManager::getSymbolAddressInProcess(Name); +- }; +- +- auto RegisterEHFrames = [](uint8_t *Addr, uint32_t Size) { +- RTDyldMemoryManager::registerEHFramesInProcess(Addr, Size); +- }; +- +- auto DeregisterEHFrames = [](uint8_t *Addr, uint32_t Size) { +- RTDyldMemoryManager::deregisterEHFramesInProcess(Addr, Size); +- }; +- +- FDRawChannel Channel(InFD, OutFD); +- typedef remote::OrcRemoteTargetServer JITServer; +- JITServer Server(Channel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames); +- +- while (!Server.receivedTerminate()) +- ExitOnErr(Server.handleOne()); +- +- close(InFD); +- close(OutFD); +- +- return 0; +-} +diff --git a/tools/lli/ChildTarget/LLVMBuild.txt b/tools/lli/ChildTarget/LLVMBuild.txt +deleted file mode 100644 +index daf6df11324..00000000000 +--- a/tools/lli/ChildTarget/LLVMBuild.txt ++++ /dev/null +@@ -1,21 +0,0 @@ +-;===- ./tools/lli/ChildTarget/LLVMBuild.txt --------------------*- Conf -*--===; +-; +-; The LLVM Compiler Infrastructure +-; +-; This file is distributed under the University of Illinois Open Source +-; License. See LICENSE.TXT for details. +-; +-;===------------------------------------------------------------------------===; +-; +-; This is an LLVMBuild description file for the components in this subdirectory. +-; +-; For more information on the LLVMBuild system, please see: +-; +-; http://llvm.org/docs/LLVMBuild.html +-; +-;===------------------------------------------------------------------------===; +- +-[component_0] +-type = Tool +-name = lli-child-target +-parent = lli +diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt +index 9d889bf4c2e..47385048e08 100644 +--- a/tools/lli/LLVMBuild.txt ++++ b/tools/lli/LLVMBuild.txt +@@ -15,9 +15,6 @@ + ; + ;===------------------------------------------------------------------------===; + +-[common] +-subdirectories = ChildTarget +- + [component_0] + type = Tool + name = lli +diff --git a/tools/lli/OrcLazyJIT.cpp b/tools/lli/OrcLazyJIT.cpp +index ec61ce5e154..640cfd9b6ef 100644 +--- a/tools/lli/OrcLazyJIT.cpp ++++ b/tools/lli/OrcLazyJIT.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===------ OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution -------===// + // + // The LLVM Compiler Infrastructure +@@ -158,4 +159,4 @@ int llvm::runOrcLazyJIT(std::vector> Ms, + auto Main = fromTargetAddress(MainSym.getAddress()); + return Main(ArgV.size(), (const char**)ArgV.data()); + } +- ++#endif +diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h +deleted file mode 100644 +index 05319c34548..00000000000 +--- a/tools/lli/OrcLazyJIT.h ++++ /dev/null +@@ -1,175 +0,0 @@ +-//===--- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution --*- C++ -*-===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-// +-// Simple Orc-based JIT. Uses the compile-on-demand layer to break up and +-// lazily compile modules. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_TOOLS_LLI_ORCLAZYJIT_H +-#define LLVM_TOOLS_LLI_ORCLAZYJIT_H +- +-#include "llvm/ADT/Triple.h" +-#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" +-#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +-#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +-#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +-#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" +-#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +-#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +- +-namespace llvm { +- +-class OrcLazyJIT { +-public: +- +- typedef orc::JITCompileCallbackManager CompileCallbackMgr; +- typedef orc::ObjectLinkingLayer<> ObjLayerT; +- typedef orc::IRCompileLayer CompileLayerT; +- typedef std::function(std::unique_ptr)> +- TransformFtor; +- typedef orc::IRTransformLayer IRDumpLayerT; +- typedef orc::CompileOnDemandLayer CODLayerT; +- typedef CODLayerT::IndirectStubsManagerBuilderT +- IndirectStubsManagerBuilder; +- typedef CODLayerT::ModuleSetHandleT ModuleSetHandleT; +- +- OrcLazyJIT(std::unique_ptr TM, +- std::unique_ptr CCMgr, +- IndirectStubsManagerBuilder IndirectStubsMgrBuilder, +- bool InlineStubs) +- : TM(std::move(TM)), DL(this->TM->createDataLayout()), +- CCMgr(std::move(CCMgr)), +- ObjectLayer(), +- CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)), +- IRDumpLayer(CompileLayer, createDebugDumper()), +- CODLayer(IRDumpLayer, extractSingleFunction, *this->CCMgr, +- std::move(IndirectStubsMgrBuilder), InlineStubs), +- CXXRuntimeOverrides( +- [this](const std::string &S) { return mangle(S); }) {} +- +- ~OrcLazyJIT() { +- // Run any destructors registered with __cxa_atexit. +- CXXRuntimeOverrides.runDestructors(); +- // Run any IR destructors. +- for (auto &DtorRunner : IRStaticDestructorRunners) +- DtorRunner.runViaLayer(CODLayer); +- } +- +- ModuleSetHandleT addModuleSet(std::vector> Ms) { +- // Attach a data-layouts if they aren't already present. +- for (auto &M : Ms) +- if (M->getDataLayout().isDefault()) +- M->setDataLayout(DL); +- +- // Rename, bump linkage and record static constructors and destructors. +- // We have to do this before we hand over ownership of the module to the +- // JIT. +- std::vector CtorNames, DtorNames; +- { +- unsigned CtorId = 0, DtorId = 0; +- for (auto &M : Ms) { +- for (auto Ctor : orc::getConstructors(*M)) { +- std::string NewCtorName = ("$static_ctor." + Twine(CtorId++)).str(); +- Ctor.Func->setName(NewCtorName); +- Ctor.Func->setLinkage(GlobalValue::ExternalLinkage); +- Ctor.Func->setVisibility(GlobalValue::HiddenVisibility); +- CtorNames.push_back(mangle(NewCtorName)); +- } +- for (auto Dtor : orc::getDestructors(*M)) { +- std::string NewDtorName = ("$static_dtor." + Twine(DtorId++)).str(); +- Dtor.Func->setLinkage(GlobalValue::ExternalLinkage); +- Dtor.Func->setVisibility(GlobalValue::HiddenVisibility); +- DtorNames.push_back(mangle(Dtor.Func->getName())); +- Dtor.Func->setName(NewDtorName); +- } +- } +- } +- +- // Symbol resolution order: +- // 1) Search the JIT symbols. +- // 2) Check for C++ runtime overrides. +- // 3) Search the host process (LLI)'s symbol table. +- auto Resolver = +- orc::createLambdaResolver( +- [this](const std::string &Name) -> JITSymbol { +- if (auto Sym = CODLayer.findSymbol(Name, true)) +- return Sym; +- return CXXRuntimeOverrides.searchOverrides(Name); +- }, +- [](const std::string &Name) { +- if (auto Addr = +- RTDyldMemoryManager::getSymbolAddressInProcess(Name)) +- return JITSymbol(Addr, JITSymbolFlags::Exported); +- return JITSymbol(nullptr); +- } +- ); +- +- // Add the module to the JIT. +- auto H = CODLayer.addModuleSet(std::move(Ms), +- llvm::make_unique(), +- std::move(Resolver)); +- +- // Run the static constructors, and save the static destructor runner for +- // execution when the JIT is torn down. +- orc::CtorDtorRunner CtorRunner(std::move(CtorNames), H); +- CtorRunner.runViaLayer(CODLayer); +- +- IRStaticDestructorRunners.emplace_back(std::move(DtorNames), H); +- +- return H; +- } +- +- JITSymbol findSymbol(const std::string &Name) { +- return CODLayer.findSymbol(mangle(Name), true); +- } +- +- JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name) { +- return CODLayer.findSymbolIn(H, mangle(Name), true); +- } +- +-private: +- +- std::string mangle(const std::string &Name) { +- std::string MangledName; +- { +- raw_string_ostream MangledNameStream(MangledName); +- Mangler::getNameWithPrefix(MangledNameStream, Name, DL); +- } +- return MangledName; +- } +- +- static std::set extractSingleFunction(Function &F) { +- std::set Partition; +- Partition.insert(&F); +- return Partition; +- } +- +- static TransformFtor createDebugDumper(); +- +- std::unique_ptr TM; +- DataLayout DL; +- SectionMemoryManager CCMgrMemMgr; +- +- std::unique_ptr CCMgr; +- ObjLayerT ObjectLayer; +- CompileLayerT CompileLayer; +- IRDumpLayerT IRDumpLayer; +- CODLayerT CODLayer; +- +- orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides; +- std::vector> IRStaticDestructorRunners; +-}; +- +-int runOrcLazyJIT(std::vector> Ms, +- const std::vector &Args); +- +-} // end namespace llvm +- +-#endif +diff --git a/tools/lli/RemoteJITUtils.h b/tools/lli/RemoteJITUtils.h +deleted file mode 100644 +index 89a51420256..00000000000 +--- a/tools/lli/RemoteJITUtils.h ++++ /dev/null +@@ -1,153 +0,0 @@ +-//===-- RemoteJITUtils.h - Utilities for remote-JITing with LLI -*- C++ -*-===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-// +-// Utilities for remote-JITing with LLI. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H +-#define LLVM_TOOLS_LLI_REMOTEJITUTILS_H +- +-#include "llvm/ExecutionEngine/Orc/RawByteChannel.h" +-#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +-#include +- +-#if !defined(_MSC_VER) && !defined(__MINGW32__) +-#include +-#else +-#include +-#endif +- +-/// RPC channel that reads from and writes from file descriptors. +-class FDRawChannel final : public llvm::orc::rpc::RawByteChannel { +-public: +- FDRawChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {} +- +- llvm::Error readBytes(char *Dst, unsigned Size) override { +- assert(Dst && "Attempt to read into null."); +- ssize_t Completed = 0; +- while (Completed < static_cast(Size)) { +- ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed); +- if (Read <= 0) { +- auto ErrNo = errno; +- if (ErrNo == EAGAIN || ErrNo == EINTR) +- continue; +- else +- return llvm::errorCodeToError( +- std::error_code(errno, std::generic_category())); +- } +- Completed += Read; +- } +- return llvm::Error::success(); +- } +- +- llvm::Error appendBytes(const char *Src, unsigned Size) override { +- assert(Src && "Attempt to append from null."); +- ssize_t Completed = 0; +- while (Completed < static_cast(Size)) { +- ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed); +- if (Written < 0) { +- auto ErrNo = errno; +- if (ErrNo == EAGAIN || ErrNo == EINTR) +- continue; +- else +- return llvm::errorCodeToError( +- std::error_code(errno, std::generic_category())); +- } +- Completed += Written; +- } +- return llvm::Error::success(); +- } +- +- llvm::Error send() override { return llvm::Error::success(); } +- +-private: +- int InFD, OutFD; +-}; +- +-// launch the remote process (see lli.cpp) and return a channel to it. +-std::unique_ptr launchRemote(); +- +-namespace llvm { +- +-// ForwardingMM - Adapter to connect MCJIT to Orc's Remote8 +-// memory manager. +-class ForwardingMemoryManager : public llvm::RTDyldMemoryManager { +-public: +- void setMemMgr(std::unique_ptr MemMgr) { +- this->MemMgr = std::move(MemMgr); +- } +- +- void setResolver(std::unique_ptr Resolver) { +- this->Resolver = std::move(Resolver); +- } +- +- uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, +- unsigned SectionID, +- StringRef SectionName) override { +- return MemMgr->allocateCodeSection(Size, Alignment, SectionID, SectionName); +- } +- +- uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, +- unsigned SectionID, StringRef SectionName, +- bool IsReadOnly) override { +- return MemMgr->allocateDataSection(Size, Alignment, SectionID, SectionName, +- IsReadOnly); +- } +- +- void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, +- uintptr_t RODataSize, uint32_t RODataAlign, +- uintptr_t RWDataSize, +- uint32_t RWDataAlign) override { +- MemMgr->reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign, +- RWDataSize, RWDataAlign); +- } +- +- bool needsToReserveAllocationSpace() override { +- return MemMgr->needsToReserveAllocationSpace(); +- } +- +- void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, +- size_t Size) override { +- MemMgr->registerEHFrames(Addr, LoadAddr, Size); +- } +- +- void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, +- size_t Size) override { +- MemMgr->deregisterEHFrames(Addr, LoadAddr, Size); +- } +- +- bool finalizeMemory(std::string *ErrMsg = nullptr) override { +- return MemMgr->finalizeMemory(ErrMsg); +- } +- +- void notifyObjectLoaded(RuntimeDyld &RTDyld, +- const object::ObjectFile &Obj) override { +- MemMgr->notifyObjectLoaded(RTDyld, Obj); +- } +- +- // Don't hide the sibling notifyObjectLoaded from RTDyldMemoryManager. +- using RTDyldMemoryManager::notifyObjectLoaded; +- +- JITSymbol findSymbol(const std::string &Name) override { +- return Resolver->findSymbol(Name); +- } +- +- JITSymbol +- findSymbolInLogicalDylib(const std::string &Name) override { +- return Resolver->findSymbolInLogicalDylib(Name); +- } +- +-private: +- std::unique_ptr MemMgr; +- std::unique_ptr Resolver; +-}; +-} +- +-#endif +diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp +index 0823ff469de..8e9b9f87577 100644 +--- a/tools/lli/lli.cpp ++++ b/tools/lli/lli.cpp +@@ -13,6 +13,8 @@ + // + //===----------------------------------------------------------------------===// + ++#if 0 ++ + #include "OrcLazyJIT.h" + #include "RemoteJITUtils.h" + #include "llvm/IR/LLVMContext.h" +@@ -758,3 +760,8 @@ std::unique_ptr launchRemote() { + return llvm::make_unique(PipeFD[1][0], PipeFD[0][1]); + #endif + } ++#endif ++ ++int main(int argc, char **argv, char * const *envp) { ++ return 0; ++} +diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp +index 0a9807ab003..0b7ffd366b9 100644 +--- a/tools/llvm-cov/CodeCoverage.cpp ++++ b/tools/llvm-cov/CodeCoverage.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===// + // + // The LLVM Compiler Infrastructure +@@ -864,7 +865,10 @@ int reportMain(int argc, const char *argv[]) { + return Tool.run(CodeCoverageTool::Report, argc, argv); + } + ++ + int exportMain(int argc, const char *argv[]) { + CodeCoverageTool Tool; + return Tool.run(CodeCoverageTool::Export, argc, argv); + } ++ ++#endif +diff --git a/tools/llvm-cov/CoverageExporterJson.cpp b/tools/llvm-cov/CoverageExporterJson.cpp +index ef50bba2123..d3d0a8f5f01 100644 +--- a/tools/llvm-cov/CoverageExporterJson.cpp ++++ b/tools/llvm-cov/CoverageExporterJson.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- CoverageExporterJson.cpp - Code coverage export --------------------===// + // + // The LLVM Compiler Infrastructure +@@ -419,3 +420,4 @@ void exportCoverageDataToJson(const CoverageMapping &CoverageMapping, + + Exporter.print(); + } ++#endif +diff --git a/tools/llvm-cov/CoverageFilters.cpp b/tools/llvm-cov/CoverageFilters.cpp +index 325dd723578..8a41ba8c1d8 100644 +--- a/tools/llvm-cov/CoverageFilters.cpp ++++ b/tools/llvm-cov/CoverageFilters.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- CoverageFilters.cpp - Function coverage mapping filters ------------===// + // + // The LLVM Compiler Infrastructure +@@ -57,3 +58,4 @@ CoverageFiltersMatchAll::matches(const coverage::FunctionRecord &Function) { + } + return true; + } ++#endif +diff --git a/tools/llvm-cov/CoverageFilters.h b/tools/llvm-cov/CoverageFilters.h +deleted file mode 100644 +index 756c4b47872..00000000000 +--- a/tools/llvm-cov/CoverageFilters.h ++++ /dev/null +@@ -1,127 +0,0 @@ +-//===- CoverageFilters.h - Function coverage mapping filters --------------===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-// +-// These classes provide filtering for function coverage mapping records. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_COV_COVERAGEFILTERS_H +-#define LLVM_COV_COVERAGEFILTERS_H +- +-#include "llvm/ProfileData/Coverage/CoverageMapping.h" +-#include +-#include +- +-namespace llvm { +- +-/// \brief Matches specific functions that pass the requirement of this filter. +-class CoverageFilter { +-public: +- virtual ~CoverageFilter() {} +- +- /// \brief Return true if the function passes the requirements of this filter. +- virtual bool matches(const coverage::FunctionRecord &Function) { +- return true; +- } +-}; +- +-/// \brief Matches functions that contain a specific string in their name. +-class NameCoverageFilter : public CoverageFilter { +- StringRef Name; +- +-public: +- NameCoverageFilter(StringRef Name) : Name(Name) {} +- +- bool matches(const coverage::FunctionRecord &Function) override; +-}; +- +-/// \brief Matches functions whose name matches a certain regular expression. +-class NameRegexCoverageFilter : public CoverageFilter { +- StringRef Regex; +- +-public: +- NameRegexCoverageFilter(StringRef Regex) : Regex(Regex) {} +- +- bool matches(const coverage::FunctionRecord &Function) override; +-}; +- +-/// \brief Matches numbers that pass a certain threshold. +-template class StatisticThresholdFilter { +-public: +- enum Operation { LessThan, GreaterThan }; +- +-protected: +- Operation Op; +- T Threshold; +- +- StatisticThresholdFilter(Operation Op, T Threshold) +- : Op(Op), Threshold(Threshold) {} +- +- /// \brief Return true if the given number is less than +- /// or greater than the certain threshold. +- bool PassesThreshold(T Value) const { +- switch (Op) { +- case LessThan: +- return Value < Threshold; +- case GreaterThan: +- return Value > Threshold; +- } +- return false; +- } +-}; +- +-/// \brief Matches functions whose region coverage percentage +-/// is above/below a certain percentage. +-class RegionCoverageFilter : public CoverageFilter, +- public StatisticThresholdFilter { +-public: +- RegionCoverageFilter(Operation Op, double Threshold) +- : StatisticThresholdFilter(Op, Threshold) {} +- +- bool matches(const coverage::FunctionRecord &Function) override; +-}; +- +-/// \brief Matches functions whose line coverage percentage +-/// is above/below a certain percentage. +-class LineCoverageFilter : public CoverageFilter, +- public StatisticThresholdFilter { +-public: +- LineCoverageFilter(Operation Op, double Threshold) +- : StatisticThresholdFilter(Op, Threshold) {} +- +- bool matches(const coverage::FunctionRecord &Function) override; +-}; +- +-/// \brief A collection of filters. +-/// Matches functions that match any filters contained +-/// in an instance of this class. +-class CoverageFilters : public CoverageFilter { +-protected: +- std::vector> Filters; +- +-public: +- /// \brief Append a filter to this collection. +- void push_back(std::unique_ptr Filter); +- +- bool empty() const { return Filters.empty(); } +- +- bool matches(const coverage::FunctionRecord &Function) override; +-}; +- +-/// \brief A collection of filters. +-/// Matches functions that match all of the filters contained +-/// in an instance of this class. +-class CoverageFiltersMatchAll : public CoverageFilters { +-public: +- bool matches(const coverage::FunctionRecord &Function) override; +-}; +- +-} // namespace llvm +- +-#endif // LLVM_COV_COVERAGEFILTERS_H +diff --git a/tools/llvm-cov/CoverageReport.cpp b/tools/llvm-cov/CoverageReport.cpp +index e88cb186acd..67fdaa6f57e 100644 +--- a/tools/llvm-cov/CoverageReport.cpp ++++ b/tools/llvm-cov/CoverageReport.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- CoverageReport.cpp - Code coverage report -------------------------===// + // + // The LLVM Compiler Infrastructure +@@ -353,3 +354,4 @@ void CoverageReport::renderFileReports(raw_ostream &OS, + } + + } // end namespace llvm ++#endif +diff --git a/tools/llvm-cov/CoverageReport.h b/tools/llvm-cov/CoverageReport.h +deleted file mode 100644 +index 7a416497e25..00000000000 +--- a/tools/llvm-cov/CoverageReport.h ++++ /dev/null +@@ -1,51 +0,0 @@ +-//===- CoverageReport.h - Code coverage report ---------------------------===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-// +-// This class implements rendering of a code coverage report. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_COV_COVERAGEREPORT_H +-#define LLVM_COV_COVERAGEREPORT_H +- +-#include "CoverageSummaryInfo.h" +-#include "CoverageViewOptions.h" +- +-namespace llvm { +- +-/// \brief Displays the code coverage report. +-class CoverageReport { +- const CoverageViewOptions &Options; +- const coverage::CoverageMapping &Coverage; +- +- void render(const FileCoverageSummary &File, raw_ostream &OS) const; +- void render(const FunctionCoverageSummary &Function, raw_ostream &OS) const; +- +-public: +- CoverageReport(const CoverageViewOptions &Options, +- const coverage::CoverageMapping &Coverage) +- : Options(Options), Coverage(Coverage) {} +- +- void renderFunctionReports(ArrayRef Files, raw_ostream &OS); +- +- /// Prepare file reports for the files specified in \p Files. +- static std::vector +- prepareFileReports(const coverage::CoverageMapping &Coverage, +- FileCoverageSummary &Totals, ArrayRef Files); +- +- /// Render file reports for every unique file in the coverage mapping. +- void renderFileReports(raw_ostream &OS) const; +- +- /// Render file reports for the files specified in \p Files. +- void renderFileReports(raw_ostream &OS, ArrayRef Files) const; +-}; +- +-} // end namespace llvm +- +-#endif // LLVM_COV_COVERAGEREPORT_H +diff --git a/tools/llvm-cov/CoverageSummaryInfo.cpp b/tools/llvm-cov/CoverageSummaryInfo.cpp +index 21aa7ff73a0..5a325b40cf8 100644 +--- a/tools/llvm-cov/CoverageSummaryInfo.cpp ++++ b/tools/llvm-cov/CoverageSummaryInfo.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- CoverageSummaryInfo.cpp - Coverage summary for function/file -------===// + // + // The LLVM Compiler Infrastructure +@@ -81,3 +82,4 @@ void FunctionCoverageSummary::update(const FunctionCoverageSummary &Summary) { + LineCoverage.NotCovered = + std::min(LineCoverage.NotCovered, Summary.LineCoverage.NotCovered); + } ++#endif +diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h +deleted file mode 100644 +index c04a4d42ccd..00000000000 +--- a/tools/llvm-cov/CoverageSummaryInfo.h ++++ /dev/null +@@ -1,165 +0,0 @@ +-//===- CoverageSummaryInfo.h - Coverage summary for function/file ---------===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-// +-// These structures are used to represent code coverage metrics +-// for functions/files. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_COV_COVERAGESUMMARYINFO_H +-#define LLVM_COV_COVERAGESUMMARYINFO_H +- +-#include "llvm/ProfileData/Coverage/CoverageMapping.h" +-#include "llvm/Support/raw_ostream.h" +- +-namespace llvm { +- +-/// \brief Provides information about region coverage for a function/file. +-struct RegionCoverageInfo { +- /// \brief The number of regions that were executed at least once. +- size_t Covered; +- +- /// \brief The number of regions that weren't executed. +- size_t NotCovered; +- +- /// \brief The total number of regions in a function/file. +- size_t NumRegions; +- +- RegionCoverageInfo() : Covered(0), NotCovered(0), NumRegions(0) {} +- +- RegionCoverageInfo(size_t Covered, size_t NumRegions) +- : Covered(Covered), NotCovered(NumRegions - Covered), +- NumRegions(NumRegions) {} +- +- RegionCoverageInfo &operator+=(const RegionCoverageInfo &RHS) { +- Covered += RHS.Covered; +- NotCovered += RHS.NotCovered; +- NumRegions += RHS.NumRegions; +- return *this; +- } +- +- bool isFullyCovered() const { return Covered == NumRegions; } +- +- double getPercentCovered() const { +- if (NumRegions == 0) +- return 0.0; +- return double(Covered) / double(NumRegions) * 100.0; +- } +-}; +- +-/// \brief Provides information about line coverage for a function/file. +-struct LineCoverageInfo { +- /// \brief The number of lines that were executed at least once. +- size_t Covered; +- +- /// \brief The number of lines that weren't executed. +- size_t NotCovered; +- +- /// \brief The total number of lines in a function/file. +- size_t NumLines; +- +- LineCoverageInfo() : Covered(0), NotCovered(0), NumLines(0) {} +- +- LineCoverageInfo(size_t Covered, size_t NumLines) +- : Covered(Covered), NotCovered(NumLines - Covered), NumLines(NumLines) {} +- +- LineCoverageInfo &operator+=(const LineCoverageInfo &RHS) { +- Covered += RHS.Covered; +- NotCovered += RHS.NotCovered; +- NumLines += RHS.NumLines; +- return *this; +- } +- +- bool isFullyCovered() const { return Covered == NumLines; } +- +- double getPercentCovered() const { +- if (NumLines == 0) +- return 0.0; +- return double(Covered) / double(NumLines) * 100.0; +- } +-}; +- +-/// \brief Provides information about function coverage for a file. +-struct FunctionCoverageInfo { +- /// \brief The number of functions that were executed. +- size_t Executed; +- +- /// \brief The total number of functions in this file. +- size_t NumFunctions; +- +- FunctionCoverageInfo() : Executed(0), NumFunctions(0) {} +- +- FunctionCoverageInfo(size_t Executed, size_t NumFunctions) +- : Executed(Executed), NumFunctions(NumFunctions) {} +- +- void addFunction(bool Covered) { +- if (Covered) +- ++Executed; +- ++NumFunctions; +- } +- +- bool isFullyCovered() const { return Executed == NumFunctions; } +- +- double getPercentCovered() const { +- if (NumFunctions == 0) +- return 0.0; +- return double(Executed) / double(NumFunctions) * 100.0; +- } +-}; +- +-/// \brief A summary of function's code coverage. +-struct FunctionCoverageSummary { +- StringRef Name; +- uint64_t ExecutionCount; +- RegionCoverageInfo RegionCoverage; +- LineCoverageInfo LineCoverage; +- +- FunctionCoverageSummary(StringRef Name) : Name(Name), ExecutionCount(0) {} +- +- FunctionCoverageSummary(StringRef Name, uint64_t ExecutionCount, +- const RegionCoverageInfo &RegionCoverage, +- const LineCoverageInfo &LineCoverage) +- : Name(Name), ExecutionCount(ExecutionCount), +- RegionCoverage(RegionCoverage), LineCoverage(LineCoverage) { +- } +- +- /// \brief Compute the code coverage summary for the given function coverage +- /// mapping record. +- static FunctionCoverageSummary +- get(const coverage::FunctionRecord &Function); +- +- /// \brief Update the summary with information from another instantiation +- /// of this function. +- void update(const FunctionCoverageSummary &Summary); +-}; +- +-/// \brief A summary of file's code coverage. +-struct FileCoverageSummary { +- StringRef Name; +- RegionCoverageInfo RegionCoverage; +- LineCoverageInfo LineCoverage; +- FunctionCoverageInfo FunctionCoverage; +- FunctionCoverageInfo InstantiationCoverage; +- +- FileCoverageSummary(StringRef Name) : Name(Name) {} +- +- void addFunction(const FunctionCoverageSummary &Function) { +- RegionCoverage += Function.RegionCoverage; +- LineCoverage += Function.LineCoverage; +- FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0); +- } +- +- void addInstantiation(const FunctionCoverageSummary &Function) { +- InstantiationCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0); +- } +-}; +- +-} // namespace llvm +- +-#endif // LLVM_COV_COVERAGESUMMARYINFO_H +diff --git a/tools/llvm-cov/CoverageViewOptions.h b/tools/llvm-cov/CoverageViewOptions.h +deleted file mode 100644 +index 266b380b7d3..00000000000 +--- a/tools/llvm-cov/CoverageViewOptions.h ++++ /dev/null +@@ -1,68 +0,0 @@ +-//===- CoverageViewOptions.h - Code coverage display options -------------===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_COV_COVERAGEVIEWOPTIONS_H +-#define LLVM_COV_COVERAGEVIEWOPTIONS_H +- +-#include "RenderingSupport.h" +-#include +- +-namespace llvm { +- +-/// \brief The options for displaying the code coverage information. +-struct CoverageViewOptions { +- enum class OutputFormat { +- Text, +- HTML +- }; +- +- bool Debug; +- bool Colors; +- bool ShowLineNumbers; +- bool ShowLineStats; +- bool ShowRegionMarkers; +- bool ShowLineStatsOrRegionMarkers; +- bool ShowExpandedRegions; +- bool ShowFunctionInstantiations; +- bool ShowFullFilenames; +- OutputFormat Format; +- std::string ShowOutputDirectory; +- std::vector DemanglerOpts; +- uint32_t TabSize; +- std::string ProjectTitle; +- std::string CreatedTimeStr; +- +- /// \brief Change the output's stream color if the colors are enabled. +- ColoredRawOstream colored_ostream(raw_ostream &OS, +- raw_ostream::Colors Color) const { +- return llvm::colored_ostream(OS, Color, Colors); +- } +- +- /// \brief Check if an output directory has been specified. +- bool hasOutputDirectory() const { return !ShowOutputDirectory.empty(); } +- +- /// \brief Check if a demangler has been specified. +- bool hasDemangler() const { return !DemanglerOpts.empty(); } +- +- /// \brief Check if a project title has been specified. +- bool hasProjectTitle() const { return !ProjectTitle.empty(); } +- +- /// \brief Check if the created time of the profile data file is available. +- bool hasCreatedTime() const { return !CreatedTimeStr.empty(); } +- +- /// \brief Get the LLVM version string. +- std::string getLLVMVersionString() const { +- std::string VersionString = "Generated by llvm-cov -- llvm version "; +- VersionString += LLVM_VERSION_STRING; +- return VersionString; +- } +-}; +-} +- +-#endif // LLVM_COV_COVERAGEVIEWOPTIONS_H +diff --git a/tools/llvm-cov/RenderingSupport.h b/tools/llvm-cov/RenderingSupport.h +deleted file mode 100644 +index aa70fbc23e3..00000000000 +--- a/tools/llvm-cov/RenderingSupport.h ++++ /dev/null +@@ -1,61 +0,0 @@ +-//===- RenderingSupport.h - output stream rendering support functions ----===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_COV_RENDERINGSUPPORT_H +-#define LLVM_COV_RENDERINGSUPPORT_H +- +-#include "llvm/Support/raw_ostream.h" +-#include +- +-namespace llvm { +- +-/// \brief A helper class that resets the output stream's color if needed +-/// when destroyed. +-class ColoredRawOstream { +- ColoredRawOstream(const ColoredRawOstream &OS) = delete; +- +-public: +- raw_ostream &OS; +- bool IsColorUsed; +- +- ColoredRawOstream(raw_ostream &OS, bool IsColorUsed) +- : OS(OS), IsColorUsed(IsColorUsed) {} +- +- ColoredRawOstream(ColoredRawOstream &&Other) +- : OS(Other.OS), IsColorUsed(Other.IsColorUsed) { +- // Reset the other IsColorUsed so that the other object won't reset the +- // color when destroyed. +- Other.IsColorUsed = false; +- } +- +- ~ColoredRawOstream() { +- if (IsColorUsed) +- OS.resetColor(); +- } +-}; +- +-template +-inline raw_ostream &operator<<(const ColoredRawOstream &OS, T &&Value) { +- return OS.OS << std::forward(Value); +-} +- +-/// \brief Change the color of the output stream if the `IsColorUsed` flag +-/// is true. Returns an object that resets the color when destroyed. +-inline ColoredRawOstream colored_ostream(raw_ostream &OS, +- raw_ostream::Colors Color, +- bool IsColorUsed = true, +- bool Bold = false, bool BG = false) { +- if (IsColorUsed) +- OS.changeColor(Color, Bold, BG); +- return ColoredRawOstream(OS, IsColorUsed); +-} +- +-} // namespace llvm +- +-#endif // LLVM_COV_RENDERINGSUPPORT_H +diff --git a/tools/llvm-cov/SourceCoverageView.cpp b/tools/llvm-cov/SourceCoverageView.cpp +index 52b8ff1747f..84c2cb7e8d6 100644 +--- a/tools/llvm-cov/SourceCoverageView.cpp ++++ b/tools/llvm-cov/SourceCoverageView.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- SourceCoverageView.cpp - Code coverage view for source code --------===// + // + // The LLVM Compiler Infrastructure +@@ -265,3 +266,4 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile, + + renderViewFooter(OS); + } ++#endif +diff --git a/tools/llvm-cov/SourceCoverageView.h b/tools/llvm-cov/SourceCoverageView.h +deleted file mode 100644 +index 9cb608fed60..00000000000 +--- a/tools/llvm-cov/SourceCoverageView.h ++++ /dev/null +@@ -1,289 +0,0 @@ +-//===- SourceCoverageView.h - Code coverage view for source code ----------===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-/// +-/// \file This class implements rendering for code coverage of source code. +-/// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_COV_SOURCECOVERAGEVIEW_H +-#define LLVM_COV_SOURCECOVERAGEVIEW_H +- +-#include "CoverageViewOptions.h" +-#include "llvm/ProfileData/Coverage/CoverageMapping.h" +-#include "llvm/Support/MemoryBuffer.h" +-#include +- +-namespace llvm { +- +-class SourceCoverageView; +- +-/// \brief A view that represents a macro or include expansion. +-struct ExpansionView { +- coverage::CounterMappingRegion Region; +- std::unique_ptr View; +- +- ExpansionView(const coverage::CounterMappingRegion &Region, +- std::unique_ptr View) +- : Region(Region), View(std::move(View)) {} +- ExpansionView(ExpansionView &&RHS) +- : Region(std::move(RHS.Region)), View(std::move(RHS.View)) {} +- ExpansionView &operator=(ExpansionView &&RHS) { +- Region = std::move(RHS.Region); +- View = std::move(RHS.View); +- return *this; +- } +- +- unsigned getLine() const { return Region.LineStart; } +- unsigned getStartCol() const { return Region.ColumnStart; } +- unsigned getEndCol() const { return Region.ColumnEnd; } +- +- friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) { +- return LHS.Region.startLoc() < RHS.Region.startLoc(); +- } +-}; +- +-/// \brief A view that represents a function instantiation. +-struct InstantiationView { +- StringRef FunctionName; +- unsigned Line; +- std::unique_ptr View; +- +- InstantiationView(StringRef FunctionName, unsigned Line, +- std::unique_ptr View) +- : FunctionName(FunctionName), Line(Line), View(std::move(View)) {} +- +- friend bool operator<(const InstantiationView &LHS, +- const InstantiationView &RHS) { +- return LHS.Line < RHS.Line; +- } +-}; +- +-/// \brief Coverage statistics for a single line. +-struct LineCoverageStats { +- uint64_t ExecutionCount; +- unsigned RegionCount; +- bool Mapped; +- +- LineCoverageStats() : ExecutionCount(0), RegionCount(0), Mapped(false) {} +- +- bool isMapped() const { return Mapped; } +- +- bool hasMultipleRegions() const { return RegionCount > 1; } +- +- void addRegionStartCount(uint64_t Count) { +- // The max of all region starts is the most interesting value. +- addRegionCount(RegionCount ? std::max(ExecutionCount, Count) : Count); +- ++RegionCount; +- } +- +- void addRegionCount(uint64_t Count) { +- Mapped = true; +- ExecutionCount = Count; +- } +-}; +- +-/// \brief A file manager that handles format-aware file creation. +-class CoveragePrinter { +-public: +- struct StreamDestructor { +- void operator()(raw_ostream *OS) const; +- }; +- +- using OwnedStream = std::unique_ptr; +- +-protected: +- const CoverageViewOptions &Opts; +- +- CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {} +- +- /// \brief Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is +- /// false, skip the ToplevelDir component. If \p Relative is false, skip the +- /// OutputDir component. +- std::string getOutputPath(StringRef Path, StringRef Extension, +- bool InToplevel, bool Relative = true) const; +- +- /// \brief If directory output is enabled, create a file in that directory +- /// at the path given by getOutputPath(). Otherwise, return stdout. +- Expected createOutputStream(StringRef Path, StringRef Extension, +- bool InToplevel) const; +- +- /// \brief Return the sub-directory name for file coverage reports. +- static StringRef getCoverageDir() { return "coverage"; } +- +-public: +- static std::unique_ptr +- create(const CoverageViewOptions &Opts); +- +- virtual ~CoveragePrinter() {} +- +- /// @name File Creation Interface +- /// @{ +- +- /// \brief Create a file to print a coverage view into. +- virtual Expected createViewFile(StringRef Path, +- bool InToplevel) = 0; +- +- /// \brief Close a file which has been used to print a coverage view. +- virtual void closeViewFile(OwnedStream OS) = 0; +- +- /// \brief Create an index which lists reports for the given source files. +- virtual Error createIndexFile(ArrayRef SourceFiles, +- const coverage::CoverageMapping &Coverage) = 0; +- +- /// @} +-}; +- +-/// \brief A code coverage view of a source file or function. +-/// +-/// A source coverage view and its nested sub-views form a file-oriented +-/// representation of code coverage data. This view can be printed out by a +-/// renderer which implements the Rendering Interface. +-class SourceCoverageView { +- /// A function or file name. +- StringRef SourceName; +- +- /// A memory buffer backing the source on display. +- const MemoryBuffer &File; +- +- /// Various options to guide the coverage renderer. +- const CoverageViewOptions &Options; +- +- /// Complete coverage information about the source on display. +- coverage::CoverageData CoverageInfo; +- +- /// A container for all expansions (e.g macros) in the source on display. +- std::vector ExpansionSubViews; +- +- /// A container for all instantiations (e.g template functions) in the source +- /// on display. +- std::vector InstantiationSubViews; +- +- /// Get the first uncovered line number for the source file. +- unsigned getFirstUncoveredLineNo(); +- +-protected: +- struct LineRef { +- StringRef Line; +- int64_t LineNo; +- +- LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {} +- }; +- +- using CoverageSegmentArray = ArrayRef; +- +- /// @name Rendering Interface +- /// @{ +- +- /// \brief Render a header for the view. +- virtual void renderViewHeader(raw_ostream &OS) = 0; +- +- /// \brief Render a footer for the view. +- virtual void renderViewFooter(raw_ostream &OS) = 0; +- +- /// \brief Render the source name for the view. +- virtual void renderSourceName(raw_ostream &OS, bool WholeFile) = 0; +- +- /// \brief Render the line prefix at the given \p ViewDepth. +- virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0; +- +- /// \brief Render the line suffix at the given \p ViewDepth. +- virtual void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) = 0; +- +- /// \brief Render a view divider at the given \p ViewDepth. +- virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0; +- +- /// \brief Render a source line with highlighting. +- virtual void renderLine(raw_ostream &OS, LineRef L, +- const coverage::CoverageSegment *WrappedSegment, +- CoverageSegmentArray Segments, unsigned ExpansionCol, +- unsigned ViewDepth) = 0; +- +- /// \brief Render the line's execution count column. +- virtual void renderLineCoverageColumn(raw_ostream &OS, +- const LineCoverageStats &Line) = 0; +- +- /// \brief Render the line number column. +- virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0; +- +- /// \brief Render all the region's execution counts on a line. +- virtual void renderRegionMarkers(raw_ostream &OS, +- CoverageSegmentArray Segments, +- unsigned ViewDepth) = 0; +- +- /// \brief Render the site of an expansion. +- virtual void +- renderExpansionSite(raw_ostream &OS, LineRef L, +- const coverage::CoverageSegment *WrappedSegment, +- CoverageSegmentArray Segments, unsigned ExpansionCol, +- unsigned ViewDepth) = 0; +- +- /// \brief Render an expansion view and any nested views. +- virtual void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, +- unsigned ViewDepth) = 0; +- +- /// \brief Render an instantiation view and any nested views. +- virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, +- unsigned ViewDepth) = 0; +- +- /// \brief Render \p Title, a project title if one is available, and the +- /// created time. +- virtual void renderTitle(raw_ostream &OS, StringRef CellText) = 0; +- +- /// \brief Render the table header for a given source file. +- virtual void renderTableHeader(raw_ostream &OS, unsigned FirstUncoveredLineNo, +- unsigned IndentLevel) = 0; +- +- /// @} +- +- /// \brief Format a count using engineering notation with 3 significant +- /// digits. +- static std::string formatCount(uint64_t N); +- +- /// \brief Check if region marker output is expected for a line. +- bool shouldRenderRegionMarkers(bool LineHasMultipleRegions) const; +- +- /// \brief Check if there are any sub-views attached to this view. +- bool hasSubViews() const; +- +- SourceCoverageView(StringRef SourceName, const MemoryBuffer &File, +- const CoverageViewOptions &Options, +- coverage::CoverageData &&CoverageInfo) +- : SourceName(SourceName), File(File), Options(Options), +- CoverageInfo(std::move(CoverageInfo)) {} +- +-public: +- static std::unique_ptr +- create(StringRef SourceName, const MemoryBuffer &File, +- const CoverageViewOptions &Options, +- coverage::CoverageData &&CoverageInfo); +- +- virtual ~SourceCoverageView() {} +- +- /// \brief Return the source name formatted for the host OS. +- std::string getSourceName() const; +- +- const CoverageViewOptions &getOptions() const { return Options; } +- +- /// \brief Add an expansion subview to this view. +- void addExpansion(const coverage::CounterMappingRegion &Region, +- std::unique_ptr View); +- +- /// \brief Add a function instantiation subview to this view. +- void addInstantiation(StringRef FunctionName, unsigned Line, +- std::unique_ptr View); +- +- /// \brief Print the code coverage information for a specific portion of a +- /// source file to the output stream. +- void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName, +- unsigned ViewDepth = 0); +-}; +- +-} // namespace llvm +- +-#endif // LLVM_COV_SOURCECOVERAGEVIEW_H +diff --git a/tools/llvm-cov/SourceCoverageViewHTML.cpp b/tools/llvm-cov/SourceCoverageViewHTML.cpp +index 64b888e89d7..929b224b66b 100644 +--- a/tools/llvm-cov/SourceCoverageViewHTML.cpp ++++ b/tools/llvm-cov/SourceCoverageViewHTML.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- SourceCoverageViewHTML.cpp - A html code coverage view -------------===// + // + // The LLVM Compiler Infrastructure +@@ -636,3 +637,5 @@ void SourceCoverageViewHTML::renderTableHeader(raw_ostream &OS, + << SourceLabel; + renderLineSuffix(OS, ViewDepth); + } ++ ++#endif +diff --git a/tools/llvm-cov/SourceCoverageViewHTML.h b/tools/llvm-cov/SourceCoverageViewHTML.h +deleted file mode 100644 +index 94b08a5e7fc..00000000000 +--- a/tools/llvm-cov/SourceCoverageViewHTML.h ++++ /dev/null +@@ -1,96 +0,0 @@ +-//===- SourceCoverageViewHTML.h - A html code coverage view ---------------===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-/// +-/// \file This file defines the interface to the html coverage renderer. +-/// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_COV_SOURCECOVERAGEVIEWHTML_H +-#define LLVM_COV_SOURCECOVERAGEVIEWHTML_H +- +-#include "SourceCoverageView.h" +- +-namespace llvm { +- +-struct FileCoverageSummary; +- +-/// \brief A coverage printer for html output. +-class CoveragePrinterHTML : public CoveragePrinter { +-public: +- Expected createViewFile(StringRef Path, +- bool InToplevel) override; +- +- void closeViewFile(OwnedStream OS) override; +- +- Error createIndexFile(ArrayRef SourceFiles, +- const coverage::CoverageMapping &Coverage) override; +- +- CoveragePrinterHTML(const CoverageViewOptions &Opts) +- : CoveragePrinter(Opts) {} +- +-private: +- void emitFileSummary(raw_ostream &OS, StringRef SF, +- const FileCoverageSummary &FCS, +- bool IsTotals = false) const; +-}; +- +-/// \brief A code coverage view which supports html-based rendering. +-class SourceCoverageViewHTML : public SourceCoverageView { +- void renderViewHeader(raw_ostream &OS) override; +- +- void renderViewFooter(raw_ostream &OS) override; +- +- void renderSourceName(raw_ostream &OS, bool WholeFile) override; +- +- void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override; +- +- void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) override; +- +- void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) override; +- +- void renderLine(raw_ostream &OS, LineRef L, +- const coverage::CoverageSegment *WrappedSegment, +- CoverageSegmentArray Segments, unsigned ExpansionCol, +- unsigned ViewDepth) override; +- +- void renderExpansionSite(raw_ostream &OS, LineRef L, +- const coverage::CoverageSegment *WrappedSegment, +- CoverageSegmentArray Segments, unsigned ExpansionCol, +- unsigned ViewDepth) override; +- +- void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, +- unsigned ViewDepth) override; +- +- void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, +- unsigned ViewDepth) override; +- +- void renderLineCoverageColumn(raw_ostream &OS, +- const LineCoverageStats &Line) override; +- +- void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override; +- +- void renderRegionMarkers(raw_ostream &OS, CoverageSegmentArray Segments, +- unsigned ViewDepth) override; +- +- void renderTitle(raw_ostream &OS, StringRef Title) override; +- +- void renderTableHeader(raw_ostream &OS, unsigned FirstUncoveredLineNo, +- unsigned IndentLevel) override; +- +-public: +- SourceCoverageViewHTML(StringRef SourceName, const MemoryBuffer &File, +- const CoverageViewOptions &Options, +- coverage::CoverageData &&CoverageInfo) +- : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo)) { +- } +-}; +- +-} // namespace llvm +- +-#endif // LLVM_COV_SOURCECOVERAGEVIEWHTML_H +diff --git a/tools/llvm-cov/SourceCoverageViewText.cpp b/tools/llvm-cov/SourceCoverageViewText.cpp +index 4ad120f642e..03422a36a37 100644 +--- a/tools/llvm-cov/SourceCoverageViewText.cpp ++++ b/tools/llvm-cov/SourceCoverageViewText.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- SourceCoverageViewText.cpp - A text-based code coverage view -------===// + // + // The LLVM Compiler Infrastructure +@@ -237,3 +238,5 @@ void SourceCoverageViewText::renderTitle(raw_ostream &OS, StringRef Title) { + + void SourceCoverageViewText::renderTableHeader(raw_ostream &, unsigned, + unsigned) {} ++ ++#endif +diff --git a/tools/llvm-cov/SourceCoverageViewText.h b/tools/llvm-cov/SourceCoverageViewText.h +deleted file mode 100644 +index c3f20de9297..00000000000 +--- a/tools/llvm-cov/SourceCoverageViewText.h ++++ /dev/null +@@ -1,89 +0,0 @@ +-//===- SourceCoverageViewText.h - A text-based code coverage view ---------===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-/// +-/// \file This file defines the interface to the text-based coverage renderer. +-/// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLVM_COV_SOURCECOVERAGEVIEWTEXT_H +-#define LLVM_COV_SOURCECOVERAGEVIEWTEXT_H +- +-#include "SourceCoverageView.h" +- +-namespace llvm { +- +-/// \brief A coverage printer for text output. +-class CoveragePrinterText : public CoveragePrinter { +-public: +- Expected createViewFile(StringRef Path, +- bool InToplevel) override; +- +- void closeViewFile(OwnedStream OS) override; +- +- Error createIndexFile(ArrayRef SourceFiles, +- const coverage::CoverageMapping &Coverage) override; +- +- CoveragePrinterText(const CoverageViewOptions &Opts) +- : CoveragePrinter(Opts) {} +-}; +- +-/// \brief A code coverage view which supports text-based rendering. +-class SourceCoverageViewText : public SourceCoverageView { +- void renderViewHeader(raw_ostream &OS) override; +- +- void renderViewFooter(raw_ostream &OS) override; +- +- void renderSourceName(raw_ostream &OS, bool WholeFile) override; +- +- void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override; +- +- void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) override; +- +- void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) override; +- +- void renderLine(raw_ostream &OS, LineRef L, +- const coverage::CoverageSegment *WrappedSegment, +- CoverageSegmentArray Segments, unsigned ExpansionCol, +- unsigned ViewDepth) override; +- +- void renderExpansionSite(raw_ostream &OS, LineRef L, +- const coverage::CoverageSegment *WrappedSegment, +- CoverageSegmentArray Segments, unsigned ExpansionCol, +- unsigned ViewDepth) override; +- +- void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, +- unsigned ViewDepth) override; +- +- void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, +- unsigned ViewDepth) override; +- +- void renderLineCoverageColumn(raw_ostream &OS, +- const LineCoverageStats &Line) override; +- +- void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override; +- +- void renderRegionMarkers(raw_ostream &OS, CoverageSegmentArray Segments, +- unsigned ViewDepth) override; +- +- void renderTitle(raw_ostream &OS, StringRef Title) override; +- +- void renderTableHeader(raw_ostream &OS, unsigned FirstUncoveredLineNo, +- unsigned IndentLevel) override; +- +-public: +- SourceCoverageViewText(StringRef SourceName, const MemoryBuffer &File, +- const CoverageViewOptions &Options, +- coverage::CoverageData &&CoverageInfo) +- : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo)) { +- } +-}; +- +-} // namespace llvm +- +-#endif // LLVM_COV_SOURCECOVERAGEVIEWTEXT_H +diff --git a/tools/llvm-cov/TestingSupport.cpp b/tools/llvm-cov/TestingSupport.cpp +index 72768f4fd58..89111d87b6e 100644 +--- a/tools/llvm-cov/TestingSupport.cpp ++++ b/tools/llvm-cov/TestingSupport.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- TestingSupport.cpp - Convert objects files into test files --------===// + // + // The LLVM Compiler Infrastructure +@@ -90,3 +91,4 @@ int convertForTestingMain(int argc, const char *argv[]) { + + return 0; + } ++#endif +diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp +index 4652fed2a38..ee742efdc15 100644 +--- a/tools/llvm-cov/gcov.cpp ++++ b/tools/llvm-cov/gcov.cpp +@@ -1,3 +1,4 @@ ++#if 0 + //===- gcov.cpp - GCOV compatible LLVM coverage tool ----------------------===// + // + // The LLVM Compiler Infrastructure +@@ -143,3 +144,4 @@ int gcovMain(int argc, const char *argv[]) { + Options); + return 0; + } ++#endif +diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp +index 15841587025..5103688cd7c 100644 +--- a/tools/llvm-cov/llvm-cov.cpp ++++ b/tools/llvm-cov/llvm-cov.cpp +@@ -11,6 +11,7 @@ + // + //===----------------------------------------------------------------------===// + ++#if 0 + #include "llvm/ADT/StringRef.h" + #include "llvm/ADT/StringSwitch.h" + #include "llvm/Support/CommandLine.h" +@@ -57,8 +58,10 @@ static int versionMain(int argc, const char *argv[]) { + cl::PrintVersionMessage(); + return 0; + } ++#endif + + int main(int argc, const char **argv) { ++#if 0 + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(argv[0]); + PrettyStackTraceProgram X(argc, argv); +@@ -96,5 +99,6 @@ int main(int argc, const char **argv) { + errs().resetColor(); + } + helpMain(argc, argv); ++#endif + return 1; + } +diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp +index 6715566a166..cfcebbbb082 100644 +--- a/tools/llvm-profdata/llvm-profdata.cpp ++++ b/tools/llvm-profdata/llvm-profdata.cpp +@@ -11,6 +11,8 @@ + // + //===----------------------------------------------------------------------===// + ++#if 0 ++ + #include "llvm/ADT/SmallSet.h" + #include "llvm/ADT/SmallVector.h" + #include "llvm/ADT/StringRef.h" +@@ -652,8 +654,10 @@ static int show_main(int argc, const char *argv[]) { + return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, + ShowFunction, OS); + } ++#endif + + int main(int argc, const char *argv[]) { ++#if 0 + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(argv[0]); + PrettyStackTraceProgram X(argc, argv); +@@ -692,5 +696,6 @@ int main(int argc, const char *argv[]) { + errs() << ProgName << ": Unknown command!\n"; + + errs() << "USAGE: " << ProgName << " [args...]\n"; ++#endif + return 1; + } +diff --git a/tools/sancov/sancov.cc b/tools/sancov/sancov.cc +index ff2039de35e..abb924c3644 100644 +--- a/tools/sancov/sancov.cc ++++ b/tools/sancov/sancov.cc +@@ -10,6 +10,7 @@ + // This file is a command-line tool for reading and analyzing sanitizer + // coverage. + //===----------------------------------------------------------------------===// ++#if 0 + #include "llvm/ADT/STLExtras.h" + #include "llvm/ADT/StringExtras.h" + #include "llvm/ADT/Twine.h" +@@ -1181,8 +1182,10 @@ readSymbolizeAndMergeCmdArguments(std::vector FileNames) { + } + + } // namespace ++#endif + + int main(int Argc, char **Argv) { ++#if 0 + // Print stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(Argv[0]); + PrettyStackTraceProgram X(Argc, Argv); +@@ -1236,4 +1239,6 @@ int main(int Argc, char **Argv) { + case PrintCovPointsAction: + llvm_unreachable("unsupported action"); + } ++#endif ++ return 1; + } +diff --git a/unittests/Support/ThreadPool.cpp b/unittests/Support/ThreadPool.cpp +index 8e03aacfb1e..6ee0055c1ff 100644 +--- a/unittests/Support/ThreadPool.cpp ++++ b/unittests/Support/ThreadPool.cpp +@@ -7,6 +7,8 @@ + // + //===----------------------------------------------------------------------===// + ++#if 0 ++ + #include "llvm/Support/ThreadPool.h" + + #include "llvm/ADT/STLExtras.h" +@@ -164,3 +166,5 @@ TEST_F(ThreadPoolTest, PoolDestruction) { + } + ASSERT_EQ(5, checked_in); + } ++ ++#endif +-- +2.13.1 + diff --git a/deps/patches/llvm-D27629-AArch64-large_model_4.0.patch b/deps/patches/llvm-D27629-AArch64-large_model_4.0.patch new file mode 100644 index 0000000000000..3e4ae2e076c70 --- /dev/null +++ b/deps/patches/llvm-D27629-AArch64-large_model_4.0.patch @@ -0,0 +1,77 @@ +From 6e7b660ee185445640110c80d80aafd436682fca Mon Sep 17 00:00:00 2001 +From: Yichao Yu +Date: Fri, 9 Dec 2016 15:59:46 -0500 +Subject: [PATCH] Fix unwind info relocation with large code model on AArch64 + +--- + lib/MC/MCObjectFileInfo.cpp | 2 ++ + .../AArch64/ELF_ARM64_BE-large-relocations.s | 18 ++++++++++++++++++ + .../RuntimeDyld/AArch64/ELF_ARM64_large-relocations.s | 18 ++++++++++++++++++ + 3 files changed, 38 insertions(+) + create mode 100644 test/ExecutionEngine/RuntimeDyld/AArch64/ELF_ARM64_BE-large-relocations.s + create mode 100644 test/ExecutionEngine/RuntimeDyld/AArch64/ELF_ARM64_large-relocations.s + +diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp +index 687ad3dc83a..da51f4e26d9 100644 +--- a/lib/MC/MCObjectFileInfo.cpp ++++ b/lib/MC/MCObjectFileInfo.cpp +@@ -281,6 +281,8 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) { + case Triple::mips64el: + FDECFIEncoding = dwarf::DW_EH_PE_sdata8; + break; ++ case Triple::aarch64: ++ case Triple::aarch64_be: + case Triple::x86_64: + FDECFIEncoding = dwarf::DW_EH_PE_pcrel | + ((CMModel == CodeModel::Large) ? dwarf::DW_EH_PE_sdata8 +diff --git a/test/ExecutionEngine/RuntimeDyld/AArch64/ELF_ARM64_BE-large-relocations.s b/test/ExecutionEngine/RuntimeDyld/AArch64/ELF_ARM64_BE-large-relocations.s +new file mode 100644 +index 00000000000..e3eeb02ff01 +--- /dev/null ++++ b/test/ExecutionEngine/RuntimeDyld/AArch64/ELF_ARM64_BE-large-relocations.s +@@ -0,0 +1,18 @@ ++# RUN: llvm-mc -triple=aarch64_be-none-linux-gnu -code-model=large -filetype=obj -o %T/be-large-reloc.o %s ++# RUN: llvm-rtdyld -triple=aarch64_be-none-linux-gnu -verify -map-section be-large-reloc.o,.eh_frame=0x10000 -map-section be-large-reloc.o,.text=0xffff000000000000 -check=%s %T/be-large-reloc.o ++ ++ .text ++ .globl g ++ .p2align 2 ++ .type g,@function ++g: ++ .cfi_startproc ++ mov x0, xzr ++ ret ++ .Lfunc_end0: ++ .size g, .Lfunc_end0-g ++ .cfi_endproc ++ ++# Skip the CIE and load the 8 bytes PC begin pointer. ++# Assuming the CIE and the FDE length are both 4 bytes. ++# rtdyld-check: *{8}(section_addr(be-large-reloc.o, .eh_frame) + (*{4}(section_addr(be-large-reloc.o, .eh_frame))) + 0xc) = g - (section_addr(be-large-reloc.o, .eh_frame) + (*{4}(section_addr(be-large-reloc.o, .eh_frame))) + 0xc) +diff --git a/test/ExecutionEngine/RuntimeDyld/AArch64/ELF_ARM64_large-relocations.s b/test/ExecutionEngine/RuntimeDyld/AArch64/ELF_ARM64_large-relocations.s +new file mode 100644 +index 00000000000..ec30f19c476 +--- /dev/null ++++ b/test/ExecutionEngine/RuntimeDyld/AArch64/ELF_ARM64_large-relocations.s +@@ -0,0 +1,18 @@ ++# RUN: llvm-mc -triple=arm64-none-linux-gnu -code-model=large -filetype=obj -o %T/large-reloc.o %s ++# RUN: llvm-rtdyld -triple=arm64-none-linux-gnu -verify -map-section large-reloc.o,.eh_frame=0x10000 -map-section large-reloc.o,.text=0xffff000000000000 -check=%s %T/large-reloc.o ++ ++ .text ++ .globl g ++ .p2align 2 ++ .type g,@function ++g: ++ .cfi_startproc ++ mov x0, xzr ++ ret ++ .Lfunc_end0: ++ .size g, .Lfunc_end0-g ++ .cfi_endproc ++ ++# Skip the CIE and load the 8 bytes PC begin pointer. ++# Assuming the CIE and the FDE length are both 4 bytes. ++# rtdyld-check: *{8}(section_addr(large-reloc.o, .eh_frame) + (*{4}(section_addr(large-reloc.o, .eh_frame))) + 0xc) = g - (section_addr(large-reloc.o, .eh_frame) + (*{4}(section_addr(large-reloc.o, .eh_frame))) + 0xc) +-- +2.12.2 + diff --git a/deps/patches/llvm-D28786-callclearance_4.0.patch b/deps/patches/llvm-D28786-callclearance_4.0.patch new file mode 100644 index 0000000000000..2735c7f5b3e94 --- /dev/null +++ b/deps/patches/llvm-D28786-callclearance_4.0.patch @@ -0,0 +1,344 @@ +diff --git a/include/llvm/Target/TargetInstrInfo.h b/include/llvm/Target/TargetInstrInfo.h +index 247d694f2e4..e455549cdc6 100644 +--- a/include/llvm/Target/TargetInstrInfo.h ++++ b/include/llvm/Target/TargetInstrInfo.h +@@ -1421,6 +1421,17 @@ public: + virtual void breakPartialRegDependency(MachineInstr &MI, unsigned OpNum, + const TargetRegisterInfo *TRI) const {} + ++ /// May return true if the instruction in question is a dependency breaking ++ /// instruction. If so, the register number for which it is dependency ++ /// breaking should be returned in `OutReg`. It is prefereable to return ++ /// false if the result cannot be determined. This would at worst result ++ /// in the insertion of an unnecessary instruction, while the other ++ /// alternative could result in significant false-dependency penalties. ++ virtual bool isDependencyBreak(MachineInstr &MI, ++ unsigned *OutReg = nullptr) const { ++ return false; ++ } ++ + /// Create machine specific model for scheduling. + virtual DFAPacketizer * + CreateTargetScheduleState(const TargetSubtargetInfo &) const { +diff --git a/lib/CodeGen/ExecutionDepsFix.cpp b/lib/CodeGen/ExecutionDepsFix.cpp +index 64aed533a9d..9f3bd634622 100644 +--- a/lib/CodeGen/ExecutionDepsFix.cpp ++++ b/lib/CodeGen/ExecutionDepsFix.cpp +@@ -214,13 +214,18 @@ private: + bool isBlockDone(MachineBasicBlock *); + void processBasicBlock(MachineBasicBlock *MBB, bool PrimaryPass, bool Done); + void updateSuccessors(MachineBasicBlock *MBB, bool Primary, bool Done); +- bool visitInstr(MachineInstr *); ++ bool visitInstr(MachineInstr *, bool PrimaryPass); + void processDefs(MachineInstr *, bool BlockDone, bool Kill); + void visitSoftInstr(MachineInstr*, unsigned mask); + void visitHardInstr(MachineInstr*, unsigned domain); +- void pickBestRegisterForUndef(MachineInstr *MI, unsigned OpIdx, +- unsigned Pref); ++ void pickBestRegisterForUndef(MachineInstr *MI, unsigned OpIdx, unsigned Pref, ++ bool &TrueDependency); + bool shouldBreakDependence(MachineInstr*, unsigned OpIdx, unsigned Pref); ++ ++ // Undef Reads ++ void collapseUndefReads(unsigned from, unsigned to, unsigned Reg); ++ unsigned updateChooseableRegs(SparseSet &, ++ const TargetRegisterClass *, bool); + void processUndefReads(MachineBasicBlock*); + }; + } +@@ -394,11 +399,19 @@ void ExeDepsFix::enterBasicBlock(MachineBasicBlock *MBB) { + + // This is the entry block. + if (MBB->pred_empty()) { ++ // Treat all registers as being defined just before the first instruction. ++ // Howver, we want the logic later to prefer non live-ins over live-ins, ++ // so pretend the live-ins were defined slightly later. ++ // We used to only do this for live-ins, but that's a bit of a gamble. ++ // If our caller does arithmetic with these registers is is quite likely ++ // that it will have used registers beyond the ones that are live here. ++ // Given the immense penalty for getting this wrong, being conservative ++ // here seems worth it. ++ for (unsigned rx = 0; rx != NumRegs; ++rx) { ++ LiveRegs[rx].Def = -2; ++ } + for (const auto &LI : MBB->liveins()) { + for (int rx : regIndices(LI.PhysReg)) { +- // Treat function live-ins as if they were defined just before the first +- // instruction. Usually, function arguments are set up immediately +- // before the call. + LiveRegs[rx].Def = -1; + } + } +@@ -470,24 +483,36 @@ void ExeDepsFix::leaveBasicBlock(MachineBasicBlock *MBB) { + LiveRegs = nullptr; + } + +-bool ExeDepsFix::visitInstr(MachineInstr *MI) { +- // Update instructions with explicit execution domains. +- std::pair DomP = TII->getExecutionDomain(*MI); +- if (DomP.first) { +- if (DomP.second) +- visitSoftInstr(MI, DomP.second); +- else +- visitHardInstr(MI, DomP.first); ++bool ExeDepsFix::visitInstr(MachineInstr *MI, bool PrimaryPass) { ++ bool Kill = false; ++ ++ if (PrimaryPass) { ++ // Update instructions with explicit execution domains. ++ std::pair DomP = TII->getExecutionDomain(*MI); ++ if (DomP.first) { ++ if (DomP.second) ++ visitSoftInstr(MI, DomP.second); ++ else ++ visitHardInstr(MI, DomP.first); ++ } ++ Kill = !DomP.first; ++ } ++ ++ // If this is a call, pretend all registers we are considering are def'd here. ++ // We have no idea which registers the callee may use. ++ if (MI->isCall()) { ++ for (unsigned i = 0, e = NumRegs; i != e; ++i) ++ LiveRegs[i].Def = CurInstr; + } + +- return !DomP.first; ++ return Kill; + } + + /// \brief Helps avoid false dependencies on undef registers by updating the + /// machine instructions' undef operand to use a register that the instruction + /// is truly dependent on, or use a register with clearance higher than Pref. + void ExeDepsFix::pickBestRegisterForUndef(MachineInstr *MI, unsigned OpIdx, +- unsigned Pref) { ++ unsigned Pref, bool &TrueDependency) { + MachineOperand &MO = MI->getOperand(OpIdx); + assert(MO.isUndef() && "Expected undef machine operand"); + +@@ -510,6 +535,7 @@ void ExeDepsFix::pickBestRegisterForUndef(MachineInstr *MI, unsigned OpIdx, + // We found a true dependency - replace the undef register with the true + // dependency. + MO.setReg(CurrMO.getReg()); ++ TrueDependency = true; + return; + } + +@@ -571,9 +597,14 @@ void ExeDepsFix::processDefs(MachineInstr *MI, bool BlockDone, bool Kill) { + if (BlockDone) { + unsigned Pref = TII->getUndefRegClearance(*MI, OpNum, TRI); + if (Pref) { +- pickBestRegisterForUndef(MI, OpNum, Pref); +- if (shouldBreakDependence(MI, OpNum, Pref)) ++ bool TrueDependency = false; ++ pickBestRegisterForUndef(MI, OpNum, Pref, TrueDependency); ++ // Don't bother adding true dependencies to UndefReads. All we'd find out ++ // is that the register is live (since this very instruction depends on ++ // it), so we can't do anything. ++ if (!TrueDependency && shouldBreakDependence(MI, OpNum, Pref)) { + UndefReads.push_back(std::make_pair(MI, OpNum)); ++ } + } + } + const MCInstrDesc &MCID = MI->getDesc(); +@@ -606,9 +637,52 @@ void ExeDepsFix::processDefs(MachineInstr *MI, bool BlockDone, bool Kill) { + kill(rx); + } + } ++ unsigned DepReg = 0; ++ if (TII->isDependencyBreak(*MI, &DepReg)) { ++ for (int rx : regIndices(DepReg)) { ++ // This instruction is a dependency break, so there are no clearance ++ // issues, reset the counter. ++ LiveRegs[rx].Def = -(1 << 20); ++ } ++ } + ++CurInstr; + } + ++// Set the undef read register to `Reg` for all UndefReads in the range ++// [from,to). ++void ExeDepsFix::collapseUndefReads(unsigned from, unsigned to, unsigned Reg) { ++ if (from >= to) ++ return; ++ for (unsigned i = from; i < to; ++i) { ++ MachineInstr *MI = std::get<0>(UndefReads[i]); ++ unsigned OpIdx = std::get<1>(UndefReads[i]); ++ MachineOperand &MO = MI->getOperand(OpIdx); ++ MO.setReg(Reg); ++ } ++ TII->breakPartialRegDependency(*std::get<0>(UndefReads[from]), ++ std::get<1>(UndefReads[from]), TRI); ++} ++ ++unsigned ExeDepsFix::updateChooseableRegs(SparseSet &ChoosableRegs, ++ const TargetRegisterClass *OpRC, ++ bool add) { ++ unsigned LowestValid = (unsigned)-1; ++ ++ for (auto Reg : OpRC->getRegisters()) { ++ if (LiveRegSet.contains(Reg)) ++ ChoosableRegs.erase(Reg); ++ else if (add) { ++ ChoosableRegs.insert(Reg); ++ if (LowestValid == (unsigned)-1) ++ LowestValid = Reg; ++ } else if (ChoosableRegs.count(Reg) == 1) { ++ if (LowestValid == (unsigned)-1) ++ LowestValid = Reg; ++ } ++ } ++ return LowestValid; ++} ++ + /// \break Break false dependencies on undefined register reads. + /// + /// Walk the block backward computing precise liveness. This is expensive, so we +@@ -619,31 +693,87 @@ void ExeDepsFix::processUndefReads(MachineBasicBlock *MBB) { + if (UndefReads.empty()) + return; + ++ // We want to be slightly clever here, to avoid the following common pattern: ++ // Suppose we have some instruction `vrandom %in, %out` and the following code ++ // vrandom %xmm0, %xmm0 ++ // vrandom %xmm1, %xmm1 ++ // vrandom %xmm2, %xmm2 ++ // vrandom %xmm3, %xmm3 ++ // The earlier logic likes to produce these, because it picks the first ++ // register ++ // to break ties in clearance. However, most register allocators pick the dest ++ // register the same way. Naively, we'd have to insert a dependency break, ++ // before every instruction above. However, what we really want is ++ // vxorps %xmm3, %xmm3, %xmm3 ++ // vrandom %xmm3, %xmm0 ++ // vrandom %xmm3, %xmm1 ++ // vrandom %xmm3, %xmm2 ++ // vrandom %xmm3, %xmm3 ++ // To do so, we walk backwards and cumulatively keep track of which registers ++ // we can use to break the dependency. Then, once the set has collapsed, we ++ // reset the undef read register for all following instructions. ++ + // Collect this block's live out register units. + LiveRegSet.init(*TRI); + // We do not need to care about pristine registers as they are just preserved + // but not actually used in the function. + LiveRegSet.addLiveOutsNoPristines(*MBB); + +- MachineInstr *UndefMI = UndefReads.back().first; +- unsigned OpIdx = UndefReads.back().second; ++ SparseSet ChoosableRegs; ++ ChoosableRegs.setUniverse(TRI->getNumRegs()); ++ ++ unsigned LastValid = (unsigned)-1; ++ const TargetRegisterClass *LastOpRC = nullptr; ++ size_t i, LastInit; ++ i = LastInit = UndefReads.size() - 1; ++ MachineInstr *UndefMI = std::get<0>(UndefReads[i]); + + for (MachineInstr &I : make_range(MBB->rbegin(), MBB->rend())) { + // Update liveness, including the current instruction's defs. + LiveRegSet.stepBackward(I); + ++ // This ensures that we don't accidentally pick a register whose live region ++ // lies entirely between two undef reads (since that would defeat the ++ // purpose of breaking the dependency). ++ for (auto LiveReg : LiveRegSet) ++ ChoosableRegs.erase(LiveReg); ++ + if (UndefMI == &I) { +- if (!LiveRegSet.contains(UndefMI->getOperand(OpIdx).getReg())) +- TII->breakPartialRegDependency(*UndefMI, OpIdx, TRI); ++ unsigned OpIdx = std::get<1>(UndefReads[i]); ++ // Get the undef operand's register class ++ const TargetRegisterClass *OpRC = ++ TII->getRegClass(UndefMI->getDesc(), OpIdx, TRI, *MF); ++ if (OpRC != LastOpRC || ChoosableRegs.size() == 0) { ++ if (LastInit != i) { ++ if (LastValid != (unsigned)-1) ++ collapseUndefReads(i + 1, LastInit + 1, LastValid); ++ ChoosableRegs.clear(); ++ LastInit = i; ++ } ++ } ++ ++ unsigned LowestValid = ++ updateChooseableRegs(ChoosableRegs, OpRC, LastInit == i); ++ ++ if (ChoosableRegs.size() == 0) { ++ if (LastInit != i) { ++ if (LastValid != (unsigned)-1) ++ collapseUndefReads(i + 1, LastInit + 1, LastValid); ++ LowestValid = updateChooseableRegs(ChoosableRegs, OpRC, true); ++ LastInit = i; ++ } ++ } ++ LastValid = LowestValid; ++ LastOpRC = OpRC; + +- UndefReads.pop_back(); +- if (UndefReads.empty()) +- return; ++ if (i == 0) ++ break; + +- UndefMI = UndefReads.back().first; +- OpIdx = UndefReads.back().second; ++ UndefMI = std::get<0>(UndefReads[--i]); + } + } ++ if (LastValid != (unsigned)-1) ++ collapseUndefReads(0, LastInit + 1, LastValid); + } + + // A hard instruction only works in one domain. All input registers will be +@@ -787,9 +917,7 @@ void ExeDepsFix::processBasicBlock(MachineBasicBlock *MBB, bool PrimaryPass, + enterBasicBlock(MBB); + for (MachineInstr &MI : *MBB) { + if (!MI.isDebugValue()) { +- bool Kill = false; +- if (PrimaryPass) +- Kill = visitInstr(&MI); ++ bool Kill = visitInstr(&MI, PrimaryPass); + processDefs(&MI, isBlockDone(MBB), Kill); + } + } +diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp +index 627b6120b04..26665b2a15d 100644 +--- a/lib/Target/X86/X86InstrInfo.cpp ++++ b/lib/Target/X86/X86InstrInfo.cpp +@@ -7432,6 +7432,23 @@ void X86InstrInfo::breakPartialRegDependency( + } + } + ++bool X86InstrInfo::isDependencyBreak(MachineInstr &MI, unsigned *OutReg) const { ++ unsigned Opc = MI.getOpcode(); ++ if (!(Opc == X86::VXORPSrr || Opc == X86::VXORPDrr || Opc == X86::XORPSrr || ++ Opc == X86::XORPDrr)) ++ return false; ++ unsigned Reg = 0; ++ for (unsigned i = 0; i < MI.getNumOperands(); ++i) { ++ const MachineOperand &MO = MI.getOperand(i); ++ if (!MO.isReg() || (Reg != 0 && MO.getReg() != Reg)) ++ return false; ++ Reg = MO.getReg(); ++ } ++ if (OutReg) ++ *OutReg = Reg; ++ return true; ++} ++ + MachineInstr * + X86InstrInfo::foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI, + ArrayRef Ops, +diff --git a/lib/Target/X86/X86InstrInfo.h b/lib/Target/X86/X86InstrInfo.h +index acfdef4da7a..4ea9ddfc863 100644 +--- a/lib/Target/X86/X86InstrInfo.h ++++ b/lib/Target/X86/X86InstrInfo.h +@@ -477,6 +477,7 @@ public: + const TargetRegisterInfo *TRI) const override; + void breakPartialRegDependency(MachineInstr &MI, unsigned OpNum, + const TargetRegisterInfo *TRI) const override; ++ bool isDependencyBreak(MachineInstr &MI, unsigned *OutReg) const override; + + MachineInstr *foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI, + unsigned OpNum, diff --git a/deps/patches/llvm-D30478-VNCoercion.patch b/deps/patches/llvm-D30478-VNCoercion.patch new file mode 100644 index 0000000000000..99ba3d9739bf4 --- /dev/null +++ b/deps/patches/llvm-D30478-VNCoercion.patch @@ -0,0 +1,1139 @@ +From 6a7ec8843d08cb2cb8d4f55353c67d879ceacb92 Mon Sep 17 00:00:00 2001 +From: Daniel Berlin +Date: Fri, 10 Mar 2017 04:54:10 +0000 +Subject: [PATCH 1/5] Move memory coercion functions from GVN.cpp to + VNCoercion.cpp so they can be shared between GVN and NewGVN. + +Summary: +These are the functions used to determine when values of loads can be +extracted from stores, etc, and to perform the necessary insertions to +do this. There are no changes to the functions themselves except +reformatting, and one case where memdep was informed of a removed load +(which was pushed into the caller). + +Reviewers: davide + +Subscribers: mgorny, llvm-commits, Prazek + +Differential Revision: https://reviews.llvm.org/D30478 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297438 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + include/llvm/Transforms/Utils/VNCoercion.h | 96 ++++++ + lib/Transforms/Scalar/GVN.cpp | 466 ++--------------------------- + lib/Transforms/Utils/CMakeLists.txt | 1 + + lib/Transforms/Utils/VNCoercion.cpp | 440 +++++++++++++++++++++++++++ + 4 files changed, 556 insertions(+), 447 deletions(-) + create mode 100644 include/llvm/Transforms/Utils/VNCoercion.h + create mode 100644 lib/Transforms/Utils/VNCoercion.cpp + +diff --git a/include/llvm/Transforms/Utils/VNCoercion.h b/include/llvm/Transforms/Utils/VNCoercion.h +new file mode 100644 +index 00000000000..d3c998fa8a8 +--- /dev/null ++++ b/include/llvm/Transforms/Utils/VNCoercion.h +@@ -0,0 +1,96 @@ ++//===- VNCoercion.h - Value Numbering Coercion Utilities --------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++/// \file / This file provides routines used by LLVM's value numbering passes to ++/// perform various forms of value extraction from memory when the types are not ++/// identical. For example, given ++/// ++/// store i32 8, i32 *%foo ++/// %a = bitcast i32 *%foo to i16 ++/// %val = load i16, i16 *%a ++/// ++/// It possible to extract the value of the load of %a from the store to %foo. ++/// These routines know how to tell whether they can do that (the analyze* ++/// routines), and can also insert the necessary IR to do it (the get* ++/// routines). ++ ++#ifndef LLVM_TRANSFORMS_UTILS_VNCOERCION_H ++#define LLVM_TRANSFORMS_UTILS_VNCOERCION_H ++#include "llvm/IR/IRBuilder.h" ++ ++namespace llvm { ++class Function; ++class StoreInst; ++class LoadInst; ++class MemIntrinsic; ++class Instruction; ++class Value; ++class Type; ++class DataLayout; ++namespace VNCoercion { ++/// Return true if CoerceAvailableValueToLoadType would succeed if it was ++/// called. ++bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, ++ const DataLayout &DL); ++ ++/// If we saw a store of a value to memory, and then a load from a must-aliased ++/// pointer of a different type, try to coerce the stored value to the loaded ++/// type. LoadedTy is the type of the load we want to replace. IRB is ++/// IRBuilder used to insert new instructions. ++/// ++/// If we can't do it, return null. ++Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, ++ IRBuilder<> &IRB, const DataLayout &DL); ++ ++/// This function determines whether a value for the pointer LoadPtr can be ++/// extracted from the store at DepSI. ++/// ++/// On success, it returns the offset into DepSI that extraction would start. ++/// On failure, it returns -1. ++int analyzeLoadFromClobberingStore(Type *LoadTy, Value *LoadPtr, ++ StoreInst *DepSI); ++ ++/// This function determines whether a value for the pointer LoadPtr can be ++/// extracted from the load at DepLI. ++/// ++/// On success, it returns the offset into DepLI that extraction would start. ++/// On failure, it returns -1. ++int analyzeLoadFromClobberingLoad(Type *LoadTy, Value *LoadPtr, LoadInst *DepLI, ++ const DataLayout &DL); ++ ++/// This function determines whether a value for the pointer LoadPtr can be ++/// extracted from the memory intrinsic at DepMI. ++/// ++/// On success, it returns the offset into DepMI that extraction would start. ++/// On failure, it returns -1. ++int analyzeLoadFromClobberingMemInst(Type *LoadTy, Value *LoadPtr, ++ MemIntrinsic *DepMI, const DataLayout &DL); ++ ++/// If analyzeLoadFromClobberingStore returned an offset, this function can be ++/// used to actually perform the extraction of the bits from the store. It ++/// inserts instructions to do so at InsertPt, and returns the extracted value. ++Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, ++ Instruction *InsertPt, const DataLayout &DL); ++ ++/// If analyzeLoadFromClobberingLoad returned an offset, this function can be ++/// used to actually perform the extraction of the bits from the load, including ++/// any necessary load widening. It inserts instructions to do so at InsertPt, ++/// and returns the extracted value. ++Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, ++ Instruction *InsertPt); ++ ++/// If analyzeLoadFromClobberingMemInst returned an offset, this function can be ++/// used to actually perform the extraction of the bits from the memory ++/// intrinsic. It inserts instructions to do so at InsertPt, and returns the ++/// extracted value. ++Value *getMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, ++ Type *LoadTy, Instruction *InsertPt, ++ const DataLayout &DL); ++} ++} ++#endif +diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp +index 0137378b828..132c7297d77 100644 +--- a/lib/Transforms/Scalar/GVN.cpp ++++ b/lib/Transforms/Scalar/GVN.cpp +@@ -36,7 +36,6 @@ + #include "llvm/Analysis/OptimizationDiagnosticInfo.h" + #include "llvm/Analysis/PHITransAddr.h" + #include "llvm/Analysis/TargetLibraryInfo.h" +-#include "llvm/Analysis/ValueTracking.h" + #include "llvm/IR/DataLayout.h" + #include "llvm/IR/Dominators.h" + #include "llvm/IR/GlobalVariable.h" +@@ -51,9 +50,12 @@ + #include "llvm/Transforms/Utils/BasicBlockUtils.h" + #include "llvm/Transforms/Utils/Local.h" + #include "llvm/Transforms/Utils/SSAUpdater.h" ++#include "llvm/Transforms/Utils/VNCoercion.h" ++ + #include + using namespace llvm; + using namespace llvm::gvn; ++using namespace llvm::VNCoercion; + using namespace PatternMatch; + + #define DEBUG_TYPE "gvn" +@@ -690,442 +692,6 @@ SpeculationFailure: + } + + +-/// Return true if CoerceAvailableValueToLoadType will succeed. +-static bool CanCoerceMustAliasedValueToLoad(Value *StoredVal, +- Type *LoadTy, +- const DataLayout &DL) { +- // If the loaded or stored value is an first class array or struct, don't try +- // to transform them. We need to be able to bitcast to integer. +- if (LoadTy->isStructTy() || LoadTy->isArrayTy() || +- StoredVal->getType()->isStructTy() || +- StoredVal->getType()->isArrayTy()) +- return false; +- +- // The store has to be at least as big as the load. +- if (DL.getTypeSizeInBits(StoredVal->getType()) < +- DL.getTypeSizeInBits(LoadTy)) +- return false; +- +- return true; +-} +- +-/// If we saw a store of a value to memory, and +-/// then a load from a must-aliased pointer of a different type, try to coerce +-/// the stored value. LoadedTy is the type of the load we want to replace. +-/// IRB is IRBuilder used to insert new instructions. +-/// +-/// If we can't do it, return null. +-static Value *CoerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, +- IRBuilder<> &IRB, +- const DataLayout &DL) { +- assert(CanCoerceMustAliasedValueToLoad(StoredVal, LoadedTy, DL) && +- "precondition violation - materialization can't fail"); +- +- if (auto *C = dyn_cast(StoredVal)) +- if (auto *FoldedStoredVal = ConstantFoldConstant(C, DL)) +- StoredVal = FoldedStoredVal; +- +- // If this is already the right type, just return it. +- Type *StoredValTy = StoredVal->getType(); +- +- uint64_t StoredValSize = DL.getTypeSizeInBits(StoredValTy); +- uint64_t LoadedValSize = DL.getTypeSizeInBits(LoadedTy); +- +- // If the store and reload are the same size, we can always reuse it. +- if (StoredValSize == LoadedValSize) { +- // Pointer to Pointer -> use bitcast. +- if (StoredValTy->getScalarType()->isPointerTy() && +- LoadedTy->getScalarType()->isPointerTy()) { +- StoredVal = IRB.CreateBitCast(StoredVal, LoadedTy); +- } else { +- // Convert source pointers to integers, which can be bitcast. +- if (StoredValTy->getScalarType()->isPointerTy()) { +- StoredValTy = DL.getIntPtrType(StoredValTy); +- StoredVal = IRB.CreatePtrToInt(StoredVal, StoredValTy); +- } +- +- Type *TypeToCastTo = LoadedTy; +- if (TypeToCastTo->getScalarType()->isPointerTy()) +- TypeToCastTo = DL.getIntPtrType(TypeToCastTo); +- +- if (StoredValTy != TypeToCastTo) +- StoredVal = IRB.CreateBitCast(StoredVal, TypeToCastTo); +- +- // Cast to pointer if the load needs a pointer type. +- if (LoadedTy->getScalarType()->isPointerTy()) +- StoredVal = IRB.CreateIntToPtr(StoredVal, LoadedTy); +- } +- +- if (auto *C = dyn_cast(StoredVal)) +- if (auto *FoldedStoredVal = ConstantFoldConstant(C, DL)) +- StoredVal = FoldedStoredVal; +- +- return StoredVal; +- } +- +- // If the loaded value is smaller than the available value, then we can +- // extract out a piece from it. If the available value is too small, then we +- // can't do anything. +- assert(StoredValSize >= LoadedValSize && +- "CanCoerceMustAliasedValueToLoad fail"); +- +- // Convert source pointers to integers, which can be manipulated. +- if (StoredValTy->getScalarType()->isPointerTy()) { +- StoredValTy = DL.getIntPtrType(StoredValTy); +- StoredVal = IRB.CreatePtrToInt(StoredVal, StoredValTy); +- } +- +- // Convert vectors and fp to integer, which can be manipulated. +- if (!StoredValTy->isIntegerTy()) { +- StoredValTy = IntegerType::get(StoredValTy->getContext(), StoredValSize); +- StoredVal = IRB.CreateBitCast(StoredVal, StoredValTy); +- } +- +- // If this is a big-endian system, we need to shift the value down to the low +- // bits so that a truncate will work. +- if (DL.isBigEndian()) { +- uint64_t ShiftAmt = DL.getTypeStoreSizeInBits(StoredValTy) - +- DL.getTypeStoreSizeInBits(LoadedTy); +- StoredVal = IRB.CreateLShr(StoredVal, ShiftAmt, "tmp"); +- } +- +- // Truncate the integer to the right size now. +- Type *NewIntTy = IntegerType::get(StoredValTy->getContext(), LoadedValSize); +- StoredVal = IRB.CreateTrunc(StoredVal, NewIntTy, "trunc"); +- +- if (LoadedTy != NewIntTy) { +- // If the result is a pointer, inttoptr. +- if (LoadedTy->getScalarType()->isPointerTy()) +- StoredVal = IRB.CreateIntToPtr(StoredVal, LoadedTy, "inttoptr"); +- else +- // Otherwise, bitcast. +- StoredVal = IRB.CreateBitCast(StoredVal, LoadedTy, "bitcast"); +- } +- +- if (auto *C = dyn_cast(StoredVal)) +- if (auto *FoldedStoredVal = ConstantFoldConstant(C, DL)) +- StoredVal = FoldedStoredVal; +- +- return StoredVal; +-} +- +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering memory write (store, +-/// memset, memcpy, memmove). This means that the write *may* provide bits used +-/// by the load but we can't be sure because the pointers don't mustalias. +-/// +-/// Check this case to see if there is anything more we can do before we give +-/// up. This returns -1 if we have to give up, or a byte number in the stored +-/// value of the piece that feeds the load. +-static int AnalyzeLoadFromClobberingWrite(Type *LoadTy, Value *LoadPtr, +- Value *WritePtr, +- uint64_t WriteSizeInBits, +- const DataLayout &DL) { +- // If the loaded or stored value is a first class array or struct, don't try +- // to transform them. We need to be able to bitcast to integer. +- if (LoadTy->isStructTy() || LoadTy->isArrayTy()) +- return -1; +- +- int64_t StoreOffset = 0, LoadOffset = 0; +- Value *StoreBase = +- GetPointerBaseWithConstantOffset(WritePtr, StoreOffset, DL); +- Value *LoadBase = GetPointerBaseWithConstantOffset(LoadPtr, LoadOffset, DL); +- if (StoreBase != LoadBase) +- return -1; +- +- // If the load and store are to the exact same address, they should have been +- // a must alias. AA must have gotten confused. +- // FIXME: Study to see if/when this happens. One case is forwarding a memset +- // to a load from the base of the memset. +- +- // If the load and store don't overlap at all, the store doesn't provide +- // anything to the load. In this case, they really don't alias at all, AA +- // must have gotten confused. +- uint64_t LoadSize = DL.getTypeSizeInBits(LoadTy); +- +- if ((WriteSizeInBits & 7) | (LoadSize & 7)) +- return -1; +- uint64_t StoreSize = WriteSizeInBits / 8; // Convert to bytes. +- LoadSize /= 8; +- +- +- bool isAAFailure = false; +- if (StoreOffset < LoadOffset) +- isAAFailure = StoreOffset+int64_t(StoreSize) <= LoadOffset; +- else +- isAAFailure = LoadOffset+int64_t(LoadSize) <= StoreOffset; +- +- if (isAAFailure) +- return -1; +- +- // If the Load isn't completely contained within the stored bits, we don't +- // have all the bits to feed it. We could do something crazy in the future +- // (issue a smaller load then merge the bits in) but this seems unlikely to be +- // valuable. +- if (StoreOffset > LoadOffset || +- StoreOffset+StoreSize < LoadOffset+LoadSize) +- return -1; +- +- // Okay, we can do this transformation. Return the number of bytes into the +- // store that the load is. +- return LoadOffset-StoreOffset; +-} +- +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering store. +-static int AnalyzeLoadFromClobberingStore(Type *LoadTy, Value *LoadPtr, +- StoreInst *DepSI) { +- // Cannot handle reading from store of first-class aggregate yet. +- if (DepSI->getValueOperand()->getType()->isStructTy() || +- DepSI->getValueOperand()->getType()->isArrayTy()) +- return -1; +- +- const DataLayout &DL = DepSI->getModule()->getDataLayout(); +- Value *StorePtr = DepSI->getPointerOperand(); +- uint64_t StoreSize =DL.getTypeSizeInBits(DepSI->getValueOperand()->getType()); +- return AnalyzeLoadFromClobberingWrite(LoadTy, LoadPtr, +- StorePtr, StoreSize, DL); +-} +- +-/// This function is called when we have a +-/// memdep query of a load that ends up being clobbered by another load. See if +-/// the other load can feed into the second load. +-static int AnalyzeLoadFromClobberingLoad(Type *LoadTy, Value *LoadPtr, +- LoadInst *DepLI, const DataLayout &DL){ +- // Cannot handle reading from store of first-class aggregate yet. +- if (DepLI->getType()->isStructTy() || DepLI->getType()->isArrayTy()) +- return -1; +- +- Value *DepPtr = DepLI->getPointerOperand(); +- uint64_t DepSize = DL.getTypeSizeInBits(DepLI->getType()); +- int R = AnalyzeLoadFromClobberingWrite(LoadTy, LoadPtr, DepPtr, DepSize, DL); +- if (R != -1) return R; +- +- // If we have a load/load clobber an DepLI can be widened to cover this load, +- // then we should widen it! +- int64_t LoadOffs = 0; +- const Value *LoadBase = +- GetPointerBaseWithConstantOffset(LoadPtr, LoadOffs, DL); +- unsigned LoadSize = DL.getTypeStoreSize(LoadTy); +- +- unsigned Size = MemoryDependenceResults::getLoadLoadClobberFullWidthSize( +- LoadBase, LoadOffs, LoadSize, DepLI); +- if (Size == 0) return -1; +- +- // Check non-obvious conditions enforced by MDA which we rely on for being +- // able to materialize this potentially available value +- assert(DepLI->isSimple() && "Cannot widen volatile/atomic load!"); +- assert(DepLI->getType()->isIntegerTy() && "Can't widen non-integer load"); +- +- return AnalyzeLoadFromClobberingWrite(LoadTy, LoadPtr, DepPtr, Size*8, DL); +-} +- +- +- +-static int AnalyzeLoadFromClobberingMemInst(Type *LoadTy, Value *LoadPtr, +- MemIntrinsic *MI, +- const DataLayout &DL) { +- // If the mem operation is a non-constant size, we can't handle it. +- ConstantInt *SizeCst = dyn_cast(MI->getLength()); +- if (!SizeCst) return -1; +- uint64_t MemSizeInBits = SizeCst->getZExtValue()*8; +- +- // If this is memset, we just need to see if the offset is valid in the size +- // of the memset.. +- if (MI->getIntrinsicID() == Intrinsic::memset) +- return AnalyzeLoadFromClobberingWrite(LoadTy, LoadPtr, MI->getDest(), +- MemSizeInBits, DL); +- +- // If we have a memcpy/memmove, the only case we can handle is if this is a +- // copy from constant memory. In that case, we can read directly from the +- // constant memory. +- MemTransferInst *MTI = cast(MI); +- +- Constant *Src = dyn_cast(MTI->getSource()); +- if (!Src) return -1; +- +- GlobalVariable *GV = dyn_cast(GetUnderlyingObject(Src, DL)); +- if (!GV || !GV->isConstant()) return -1; +- +- // See if the access is within the bounds of the transfer. +- int Offset = AnalyzeLoadFromClobberingWrite(LoadTy, LoadPtr, +- MI->getDest(), MemSizeInBits, DL); +- if (Offset == -1) +- return Offset; +- +- unsigned AS = Src->getType()->getPointerAddressSpace(); +- // Otherwise, see if we can constant fold a load from the constant with the +- // offset applied as appropriate. +- Src = ConstantExpr::getBitCast(Src, +- Type::getInt8PtrTy(Src->getContext(), AS)); +- Constant *OffsetCst = +- ConstantInt::get(Type::getInt64Ty(Src->getContext()), (unsigned)Offset); +- Src = ConstantExpr::getGetElementPtr(Type::getInt8Ty(Src->getContext()), Src, +- OffsetCst); +- Src = ConstantExpr::getBitCast(Src, PointerType::get(LoadTy, AS)); +- if (ConstantFoldLoadFromConstPtr(Src, LoadTy, DL)) +- return Offset; +- return -1; +-} +- +- +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering store. This means +-/// that the store provides bits used by the load but we the pointers don't +-/// mustalias. Check this case to see if there is anything more we can do +-/// before we give up. +-static Value *GetStoreValueForLoad(Value *SrcVal, unsigned Offset, +- Type *LoadTy, +- Instruction *InsertPt, const DataLayout &DL){ +- LLVMContext &Ctx = SrcVal->getType()->getContext(); +- +- uint64_t StoreSize = (DL.getTypeSizeInBits(SrcVal->getType()) + 7) / 8; +- uint64_t LoadSize = (DL.getTypeSizeInBits(LoadTy) + 7) / 8; +- +- IRBuilder<> Builder(InsertPt); +- +- // Compute which bits of the stored value are being used by the load. Convert +- // to an integer type to start with. +- if (SrcVal->getType()->getScalarType()->isPointerTy()) +- SrcVal = Builder.CreatePtrToInt(SrcVal, +- DL.getIntPtrType(SrcVal->getType())); +- if (!SrcVal->getType()->isIntegerTy()) +- SrcVal = Builder.CreateBitCast(SrcVal, IntegerType::get(Ctx, StoreSize*8)); +- +- // Shift the bits to the least significant depending on endianness. +- unsigned ShiftAmt; +- if (DL.isLittleEndian()) +- ShiftAmt = Offset*8; +- else +- ShiftAmt = (StoreSize-LoadSize-Offset)*8; +- +- if (ShiftAmt) +- SrcVal = Builder.CreateLShr(SrcVal, ShiftAmt); +- +- if (LoadSize != StoreSize) +- SrcVal = Builder.CreateTrunc(SrcVal, IntegerType::get(Ctx, LoadSize*8)); +- +- return CoerceAvailableValueToLoadType(SrcVal, LoadTy, Builder, DL); +-} +- +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering load. This means +-/// that the load *may* provide bits used by the load but we can't be sure +-/// because the pointers don't mustalias. Check this case to see if there is +-/// anything more we can do before we give up. +-static Value *GetLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, +- Type *LoadTy, Instruction *InsertPt, +- GVN &gvn) { +- const DataLayout &DL = SrcVal->getModule()->getDataLayout(); +- // If Offset+LoadTy exceeds the size of SrcVal, then we must be wanting to +- // widen SrcVal out to a larger load. +- unsigned SrcValStoreSize = DL.getTypeStoreSize(SrcVal->getType()); +- unsigned LoadSize = DL.getTypeStoreSize(LoadTy); +- if (Offset+LoadSize > SrcValStoreSize) { +- assert(SrcVal->isSimple() && "Cannot widen volatile/atomic load!"); +- assert(SrcVal->getType()->isIntegerTy() && "Can't widen non-integer load"); +- // If we have a load/load clobber an DepLI can be widened to cover this +- // load, then we should widen it to the next power of 2 size big enough! +- unsigned NewLoadSize = Offset+LoadSize; +- if (!isPowerOf2_32(NewLoadSize)) +- NewLoadSize = NextPowerOf2(NewLoadSize); +- +- Value *PtrVal = SrcVal->getPointerOperand(); +- +- // Insert the new load after the old load. This ensures that subsequent +- // memdep queries will find the new load. We can't easily remove the old +- // load completely because it is already in the value numbering table. +- IRBuilder<> Builder(SrcVal->getParent(), ++BasicBlock::iterator(SrcVal)); +- Type *DestPTy = +- IntegerType::get(LoadTy->getContext(), NewLoadSize*8); +- DestPTy = PointerType::get(DestPTy, +- PtrVal->getType()->getPointerAddressSpace()); +- Builder.SetCurrentDebugLocation(SrcVal->getDebugLoc()); +- PtrVal = Builder.CreateBitCast(PtrVal, DestPTy); +- LoadInst *NewLoad = Builder.CreateLoad(PtrVal); +- NewLoad->takeName(SrcVal); +- NewLoad->setAlignment(SrcVal->getAlignment()); +- +- DEBUG(dbgs() << "GVN WIDENED LOAD: " << *SrcVal << "\n"); +- DEBUG(dbgs() << "TO: " << *NewLoad << "\n"); +- +- // Replace uses of the original load with the wider load. On a big endian +- // system, we need to shift down to get the relevant bits. +- Value *RV = NewLoad; +- if (DL.isBigEndian()) +- RV = Builder.CreateLShr(RV, (NewLoadSize - SrcValStoreSize) * 8); +- RV = Builder.CreateTrunc(RV, SrcVal->getType()); +- SrcVal->replaceAllUsesWith(RV); +- +- // We would like to use gvn.markInstructionForDeletion here, but we can't +- // because the load is already memoized into the leader map table that GVN +- // tracks. It is potentially possible to remove the load from the table, +- // but then there all of the operations based on it would need to be +- // rehashed. Just leave the dead load around. +- gvn.getMemDep().removeInstruction(SrcVal); +- SrcVal = NewLoad; +- } +- +- return GetStoreValueForLoad(SrcVal, Offset, LoadTy, InsertPt, DL); +-} +- +- +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering mem intrinsic. +-static Value *GetMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, +- Type *LoadTy, Instruction *InsertPt, +- const DataLayout &DL){ +- LLVMContext &Ctx = LoadTy->getContext(); +- uint64_t LoadSize = DL.getTypeSizeInBits(LoadTy)/8; +- +- IRBuilder<> Builder(InsertPt); +- +- // We know that this method is only called when the mem transfer fully +- // provides the bits for the load. +- if (MemSetInst *MSI = dyn_cast(SrcInst)) { +- // memset(P, 'x', 1234) -> splat('x'), even if x is a variable, and +- // independently of what the offset is. +- Value *Val = MSI->getValue(); +- if (LoadSize != 1) +- Val = Builder.CreateZExt(Val, IntegerType::get(Ctx, LoadSize*8)); +- +- Value *OneElt = Val; +- +- // Splat the value out to the right number of bits. +- for (unsigned NumBytesSet = 1; NumBytesSet != LoadSize; ) { +- // If we can double the number of bytes set, do it. +- if (NumBytesSet*2 <= LoadSize) { +- Value *ShVal = Builder.CreateShl(Val, NumBytesSet*8); +- Val = Builder.CreateOr(Val, ShVal); +- NumBytesSet <<= 1; +- continue; +- } +- +- // Otherwise insert one byte at a time. +- Value *ShVal = Builder.CreateShl(Val, 1*8); +- Val = Builder.CreateOr(OneElt, ShVal); +- ++NumBytesSet; +- } +- +- return CoerceAvailableValueToLoadType(Val, LoadTy, Builder, DL); +- } +- +- // Otherwise, this is a memcpy/memmove from a constant global. +- MemTransferInst *MTI = cast(SrcInst); +- Constant *Src = cast(MTI->getSource()); +- unsigned AS = Src->getType()->getPointerAddressSpace(); +- +- // Otherwise, see if we can constant fold a load from the constant with the +- // offset applied as appropriate. +- Src = ConstantExpr::getBitCast(Src, +- Type::getInt8PtrTy(Src->getContext(), AS)); +- Constant *OffsetCst = +- ConstantInt::get(Type::getInt64Ty(Src->getContext()), (unsigned)Offset); +- Src = ConstantExpr::getGetElementPtr(Type::getInt8Ty(Src->getContext()), Src, +- OffsetCst); +- Src = ConstantExpr::getBitCast(Src, PointerType::get(LoadTy, AS)); +- return ConstantFoldLoadFromConstPtr(Src, LoadTy, DL); +-} + + + /// Given a set of loads specified by ValuesPerBlock, +@@ -1171,7 +737,7 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *LI, + if (isSimpleValue()) { + Res = getSimpleValue(); + if (Res->getType() != LoadTy) { +- Res = GetStoreValueForLoad(Res, Offset, LoadTy, InsertPt, DL); ++ Res = getStoreValueForLoad(Res, Offset, LoadTy, InsertPt, DL); + + DEBUG(dbgs() << "GVN COERCED NONLOCAL VAL:\nOffset: " << Offset << " " + << *getSimpleValue() << '\n' +@@ -1182,14 +748,20 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *LI, + if (Load->getType() == LoadTy && Offset == 0) { + Res = Load; + } else { +- Res = GetLoadValueForLoad(Load, Offset, LoadTy, InsertPt, gvn); +- ++ Res = getLoadValueForLoad(Load, Offset, LoadTy, InsertPt); ++ // We would like to use gvn.markInstructionForDeletion here, but we can't ++ // because the load is already memoized into the leader map table that GVN ++ // tracks. It is potentially possible to remove the load from the table, ++ // but then there all of the operations based on it would need to be ++ // rehashed. Just leave the dead load around. ++ gvn.getMemDep().removeInstruction(Load); + DEBUG(dbgs() << "GVN COERCED NONLOCAL LOAD:\nOffset: " << Offset << " " + << *getCoercedLoadValue() << '\n' +- << *Res << '\n' << "\n\n\n"); ++ << *Res << '\n' ++ << "\n\n\n"); + } + } else if (isMemIntrinValue()) { +- Res = GetMemInstValueForLoad(getMemIntrinValue(), Offset, LoadTy, ++ Res = getMemInstValueForLoad(getMemIntrinValue(), Offset, LoadTy, + InsertPt, DL); + DEBUG(dbgs() << "GVN COERCED NONLOCAL MEM INTRIN:\nOffset: " << Offset + << " " << *getMemIntrinValue() << '\n' +@@ -1258,7 +830,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo, + // Can't forward from non-atomic to atomic without violating memory model. + if (Address && LI->isAtomic() <= DepSI->isAtomic()) { + int Offset = +- AnalyzeLoadFromClobberingStore(LI->getType(), Address, DepSI); ++ analyzeLoadFromClobberingStore(LI->getType(), Address, DepSI); + if (Offset != -1) { + Res = AvailableValue::get(DepSI->getValueOperand(), Offset); + return true; +@@ -1276,7 +848,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo, + // Can't forward from non-atomic to atomic without violating memory model. + if (DepLI != LI && Address && LI->isAtomic() <= DepLI->isAtomic()) { + int Offset = +- AnalyzeLoadFromClobberingLoad(LI->getType(), Address, DepLI, DL); ++ analyzeLoadFromClobberingLoad(LI->getType(), Address, DepLI, DL); + + if (Offset != -1) { + Res = AvailableValue::getLoad(DepLI, Offset); +@@ -1289,7 +861,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo, + // forward a value on from it. + if (MemIntrinsic *DepMI = dyn_cast(DepInfo.getInst())) { + if (Address && !LI->isAtomic()) { +- int Offset = AnalyzeLoadFromClobberingMemInst(LI->getType(), Address, ++ int Offset = analyzeLoadFromClobberingMemInst(LI->getType(), Address, + DepMI, DL); + if (Offset != -1) { + Res = AvailableValue::getMI(DepMI, Offset); +@@ -1334,7 +906,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo, + // different types if we have to. If the stored value is larger or equal to + // the loaded value, we can reuse it. + if (S->getValueOperand()->getType() != LI->getType() && +- !CanCoerceMustAliasedValueToLoad(S->getValueOperand(), ++ !canCoerceMustAliasedValueToLoad(S->getValueOperand(), + LI->getType(), DL)) + return false; + +@@ -1351,7 +923,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo, + // If the stored value is larger or equal to the loaded value, we can reuse + // it. + if (LD->getType() != LI->getType() && +- !CanCoerceMustAliasedValueToLoad(LD, LI->getType(), DL)) ++ !canCoerceMustAliasedValueToLoad(LD, LI->getType(), DL)) + return false; + + // Can't forward from non-atomic to atomic without violating memory model. +diff --git a/lib/Transforms/Utils/CMakeLists.txt b/lib/Transforms/Utils/CMakeLists.txt +index 69889ec72f9..838761fd71d 100644 +--- a/lib/Transforms/Utils/CMakeLists.txt ++++ b/lib/Transforms/Utils/CMakeLists.txt +@@ -51,6 +51,7 @@ add_llvm_library(LLVMTransformUtils + UnifyFunctionExitNodes.cpp + Utils.cpp + ValueMapper.cpp ++ VNCoercion.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms +diff --git a/lib/Transforms/Utils/VNCoercion.cpp b/lib/Transforms/Utils/VNCoercion.cpp +new file mode 100644 +index 00000000000..38d26e922c3 +--- /dev/null ++++ b/lib/Transforms/Utils/VNCoercion.cpp +@@ -0,0 +1,440 @@ ++#include "llvm/Transforms/Utils/VNCoercion.h" ++#include "llvm/Analysis/AliasAnalysis.h" ++#include "llvm/Analysis/ConstantFolding.h" ++#include "llvm/Analysis/MemoryDependenceAnalysis.h" ++#include "llvm/Analysis/ValueTracking.h" ++#include "llvm/IR/IRBuilder.h" ++#include "llvm/IR/IntrinsicInst.h" ++#include "llvm/Support/Debug.h" ++ ++#define DEBUG_TYPE "vncoerce" ++namespace llvm { ++namespace VNCoercion { ++ ++/// Return true if coerceAvailableValueToLoadType will succeed. ++bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, ++ const DataLayout &DL) { ++ // If the loaded or stored value is an first class array or struct, don't try ++ // to transform them. We need to be able to bitcast to integer. ++ if (LoadTy->isStructTy() || LoadTy->isArrayTy() || ++ StoredVal->getType()->isStructTy() || StoredVal->getType()->isArrayTy()) ++ return false; ++ ++ // The store has to be at least as big as the load. ++ if (DL.getTypeSizeInBits(StoredVal->getType()) < DL.getTypeSizeInBits(LoadTy)) ++ return false; ++ ++ return true; ++} ++ ++/// If we saw a store of a value to memory, and ++/// then a load from a must-aliased pointer of a different type, try to coerce ++/// the stored value. LoadedTy is the type of the load we want to replace. ++/// IRB is IRBuilder used to insert new instructions. ++/// ++/// If we can't do it, return null. ++Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, ++ IRBuilder<> &IRB, const DataLayout &DL) { ++ assert(canCoerceMustAliasedValueToLoad(StoredVal, LoadedTy, DL) && ++ "precondition violation - materialization can't fail"); ++ ++ if (auto *C = dyn_cast(StoredVal)) ++ if (auto *FoldedStoredVal = ConstantFoldConstant(C, DL)) ++ StoredVal = FoldedStoredVal; ++ ++ // If this is already the right type, just return it. ++ Type *StoredValTy = StoredVal->getType(); ++ ++ uint64_t StoredValSize = DL.getTypeSizeInBits(StoredValTy); ++ uint64_t LoadedValSize = DL.getTypeSizeInBits(LoadedTy); ++ ++ // If the store and reload are the same size, we can always reuse it. ++ if (StoredValSize == LoadedValSize) { ++ // Pointer to Pointer -> use bitcast. ++ if (StoredValTy->getScalarType()->isPointerTy() && ++ LoadedTy->getScalarType()->isPointerTy()) { ++ StoredVal = IRB.CreateBitCast(StoredVal, LoadedTy); ++ } else { ++ // Convert source pointers to integers, which can be bitcast. ++ if (StoredValTy->getScalarType()->isPointerTy()) { ++ StoredValTy = DL.getIntPtrType(StoredValTy); ++ StoredVal = IRB.CreatePtrToInt(StoredVal, StoredValTy); ++ } ++ ++ Type *TypeToCastTo = LoadedTy; ++ if (TypeToCastTo->getScalarType()->isPointerTy()) ++ TypeToCastTo = DL.getIntPtrType(TypeToCastTo); ++ ++ if (StoredValTy != TypeToCastTo) ++ StoredVal = IRB.CreateBitCast(StoredVal, TypeToCastTo); ++ ++ // Cast to pointer if the load needs a pointer type. ++ if (LoadedTy->getScalarType()->isPointerTy()) ++ StoredVal = IRB.CreateIntToPtr(StoredVal, LoadedTy); ++ } ++ ++ if (auto *C = dyn_cast(StoredVal)) ++ if (auto *FoldedStoredVal = ConstantFoldConstant(C, DL)) ++ StoredVal = FoldedStoredVal; ++ ++ return StoredVal; ++ } ++ ++ // If the loaded value is smaller than the available value, then we can ++ // extract out a piece from it. If the available value is too small, then we ++ // can't do anything. ++ assert(StoredValSize >= LoadedValSize && ++ "canCoerceMustAliasedValueToLoad fail"); ++ ++ // Convert source pointers to integers, which can be manipulated. ++ if (StoredValTy->getScalarType()->isPointerTy()) { ++ StoredValTy = DL.getIntPtrType(StoredValTy); ++ StoredVal = IRB.CreatePtrToInt(StoredVal, StoredValTy); ++ } ++ ++ // Convert vectors and fp to integer, which can be manipulated. ++ if (!StoredValTy->isIntegerTy()) { ++ StoredValTy = IntegerType::get(StoredValTy->getContext(), StoredValSize); ++ StoredVal = IRB.CreateBitCast(StoredVal, StoredValTy); ++ } ++ ++ // If this is a big-endian system, we need to shift the value down to the low ++ // bits so that a truncate will work. ++ if (DL.isBigEndian()) { ++ uint64_t ShiftAmt = DL.getTypeStoreSizeInBits(StoredValTy) - ++ DL.getTypeStoreSizeInBits(LoadedTy); ++ StoredVal = IRB.CreateLShr(StoredVal, ShiftAmt, "tmp"); ++ } ++ ++ // Truncate the integer to the right size now. ++ Type *NewIntTy = IntegerType::get(StoredValTy->getContext(), LoadedValSize); ++ StoredVal = IRB.CreateTrunc(StoredVal, NewIntTy, "trunc"); ++ ++ if (LoadedTy != NewIntTy) { ++ // If the result is a pointer, inttoptr. ++ if (LoadedTy->getScalarType()->isPointerTy()) ++ StoredVal = IRB.CreateIntToPtr(StoredVal, LoadedTy, "inttoptr"); ++ else ++ // Otherwise, bitcast. ++ StoredVal = IRB.CreateBitCast(StoredVal, LoadedTy, "bitcast"); ++ } ++ ++ if (auto *C = dyn_cast(StoredVal)) ++ if (auto *FoldedStoredVal = ConstantFoldConstant(C, DL)) ++ StoredVal = FoldedStoredVal; ++ ++ return StoredVal; ++} ++ ++/// This function is called when we have a ++/// memdep query of a load that ends up being a clobbering memory write (store, ++/// memset, memcpy, memmove). This means that the write *may* provide bits used ++/// by the load but we can't be sure because the pointers don't mustalias. ++/// ++/// Check this case to see if there is anything more we can do before we give ++/// up. This returns -1 if we have to give up, or a byte number in the stored ++/// value of the piece that feeds the load. ++static int analyzeLoadFromClobberingWrite(Type *LoadTy, Value *LoadPtr, ++ Value *WritePtr, ++ uint64_t WriteSizeInBits, ++ const DataLayout &DL) { ++ // If the loaded or stored value is a first class array or struct, don't try ++ // to transform them. We need to be able to bitcast to integer. ++ if (LoadTy->isStructTy() || LoadTy->isArrayTy()) ++ return -1; ++ ++ int64_t StoreOffset = 0, LoadOffset = 0; ++ Value *StoreBase = ++ GetPointerBaseWithConstantOffset(WritePtr, StoreOffset, DL); ++ Value *LoadBase = GetPointerBaseWithConstantOffset(LoadPtr, LoadOffset, DL); ++ if (StoreBase != LoadBase) ++ return -1; ++ ++ // If the load and store are to the exact same address, they should have been ++ // a must alias. AA must have gotten confused. ++ // FIXME: Study to see if/when this happens. One case is forwarding a memset ++ // to a load from the base of the memset. ++ ++ // If the load and store don't overlap at all, the store doesn't provide ++ // anything to the load. In this case, they really don't alias at all, AA ++ // must have gotten confused. ++ uint64_t LoadSize = DL.getTypeSizeInBits(LoadTy); ++ ++ if ((WriteSizeInBits & 7) | (LoadSize & 7)) ++ return -1; ++ uint64_t StoreSize = WriteSizeInBits / 8; // Convert to bytes. ++ LoadSize /= 8; ++ ++ bool isAAFailure = false; ++ if (StoreOffset < LoadOffset) ++ isAAFailure = StoreOffset + int64_t(StoreSize) <= LoadOffset; ++ else ++ isAAFailure = LoadOffset + int64_t(LoadSize) <= StoreOffset; ++ ++ if (isAAFailure) ++ return -1; ++ ++ // If the Load isn't completely contained within the stored bits, we don't ++ // have all the bits to feed it. We could do something crazy in the future ++ // (issue a smaller load then merge the bits in) but this seems unlikely to be ++ // valuable. ++ if (StoreOffset > LoadOffset || ++ StoreOffset + StoreSize < LoadOffset + LoadSize) ++ return -1; ++ ++ // Okay, we can do this transformation. Return the number of bytes into the ++ // store that the load is. ++ return LoadOffset - StoreOffset; ++} ++ ++/// This function is called when we have a ++/// memdep query of a load that ends up being a clobbering store. ++int analyzeLoadFromClobberingStore(Type *LoadTy, Value *LoadPtr, ++ StoreInst *DepSI) { ++ // Cannot handle reading from store of first-class aggregate yet. ++ if (DepSI->getValueOperand()->getType()->isStructTy() || ++ DepSI->getValueOperand()->getType()->isArrayTy()) ++ return -1; ++ ++ const DataLayout &DL = DepSI->getModule()->getDataLayout(); ++ Value *StorePtr = DepSI->getPointerOperand(); ++ uint64_t StoreSize = ++ DL.getTypeSizeInBits(DepSI->getValueOperand()->getType()); ++ return analyzeLoadFromClobberingWrite(LoadTy, LoadPtr, StorePtr, StoreSize, ++ DL); ++} ++ ++/// This function is called when we have a ++/// memdep query of a load that ends up being clobbered by another load. See if ++/// the other load can feed into the second load. ++int analyzeLoadFromClobberingLoad(Type *LoadTy, Value *LoadPtr, LoadInst *DepLI, ++ const DataLayout &DL) { ++ // Cannot handle reading from store of first-class aggregate yet. ++ if (DepLI->getType()->isStructTy() || DepLI->getType()->isArrayTy()) ++ return -1; ++ ++ Value *DepPtr = DepLI->getPointerOperand(); ++ uint64_t DepSize = DL.getTypeSizeInBits(DepLI->getType()); ++ int R = analyzeLoadFromClobberingWrite(LoadTy, LoadPtr, DepPtr, DepSize, DL); ++ if (R != -1) ++ return R; ++ ++ // If we have a load/load clobber an DepLI can be widened to cover this load, ++ // then we should widen it! ++ int64_t LoadOffs = 0; ++ const Value *LoadBase = ++ GetPointerBaseWithConstantOffset(LoadPtr, LoadOffs, DL); ++ unsigned LoadSize = DL.getTypeStoreSize(LoadTy); ++ ++ unsigned Size = MemoryDependenceResults::getLoadLoadClobberFullWidthSize( ++ LoadBase, LoadOffs, LoadSize, DepLI); ++ if (Size == 0) ++ return -1; ++ ++ // Check non-obvious conditions enforced by MDA which we rely on for being ++ // able to materialize this potentially available value ++ assert(DepLI->isSimple() && "Cannot widen volatile/atomic load!"); ++ assert(DepLI->getType()->isIntegerTy() && "Can't widen non-integer load"); ++ ++ return analyzeLoadFromClobberingWrite(LoadTy, LoadPtr, DepPtr, Size * 8, DL); ++} ++ ++int analyzeLoadFromClobberingMemInst(Type *LoadTy, Value *LoadPtr, ++ MemIntrinsic *MI, const DataLayout &DL) { ++ // If the mem operation is a non-constant size, we can't handle it. ++ ConstantInt *SizeCst = dyn_cast(MI->getLength()); ++ if (!SizeCst) ++ return -1; ++ uint64_t MemSizeInBits = SizeCst->getZExtValue() * 8; ++ ++ // If this is memset, we just need to see if the offset is valid in the size ++ // of the memset.. ++ if (MI->getIntrinsicID() == Intrinsic::memset) ++ return analyzeLoadFromClobberingWrite(LoadTy, LoadPtr, MI->getDest(), ++ MemSizeInBits, DL); ++ ++ // If we have a memcpy/memmove, the only case we can handle is if this is a ++ // copy from constant memory. In that case, we can read directly from the ++ // constant memory. ++ MemTransferInst *MTI = cast(MI); ++ ++ Constant *Src = dyn_cast(MTI->getSource()); ++ if (!Src) ++ return -1; ++ ++ GlobalVariable *GV = dyn_cast(GetUnderlyingObject(Src, DL)); ++ if (!GV || !GV->isConstant()) ++ return -1; ++ ++ // See if the access is within the bounds of the transfer. ++ int Offset = analyzeLoadFromClobberingWrite(LoadTy, LoadPtr, MI->getDest(), ++ MemSizeInBits, DL); ++ if (Offset == -1) ++ return Offset; ++ ++ unsigned AS = Src->getType()->getPointerAddressSpace(); ++ // Otherwise, see if we can constant fold a load from the constant with the ++ // offset applied as appropriate. ++ Src = ++ ConstantExpr::getBitCast(Src, Type::getInt8PtrTy(Src->getContext(), AS)); ++ Constant *OffsetCst = ++ ConstantInt::get(Type::getInt64Ty(Src->getContext()), (unsigned)Offset); ++ Src = ConstantExpr::getGetElementPtr(Type::getInt8Ty(Src->getContext()), Src, ++ OffsetCst); ++ Src = ConstantExpr::getBitCast(Src, PointerType::get(LoadTy, AS)); ++ if (ConstantFoldLoadFromConstPtr(Src, LoadTy, DL)) ++ return Offset; ++ return -1; ++} ++ ++/// This function is called when we have a ++/// memdep query of a load that ends up being a clobbering store. This means ++/// that the store provides bits used by the load but we the pointers don't ++/// mustalias. Check this case to see if there is anything more we can do ++/// before we give up. ++Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, ++ Instruction *InsertPt, const DataLayout &DL) { ++ LLVMContext &Ctx = SrcVal->getType()->getContext(); ++ ++ uint64_t StoreSize = (DL.getTypeSizeInBits(SrcVal->getType()) + 7) / 8; ++ uint64_t LoadSize = (DL.getTypeSizeInBits(LoadTy) + 7) / 8; ++ ++ IRBuilder<> Builder(InsertPt); ++ ++ // Compute which bits of the stored value are being used by the load. Convert ++ // to an integer type to start with. ++ if (SrcVal->getType()->getScalarType()->isPointerTy()) ++ SrcVal = ++ Builder.CreatePtrToInt(SrcVal, DL.getIntPtrType(SrcVal->getType())); ++ if (!SrcVal->getType()->isIntegerTy()) ++ SrcVal = ++ Builder.CreateBitCast(SrcVal, IntegerType::get(Ctx, StoreSize * 8)); ++ ++ // Shift the bits to the least significant depending on endianness. ++ unsigned ShiftAmt; ++ if (DL.isLittleEndian()) ++ ShiftAmt = Offset * 8; ++ else ++ ShiftAmt = (StoreSize - LoadSize - Offset) * 8; ++ ++ if (ShiftAmt) ++ SrcVal = Builder.CreateLShr(SrcVal, ShiftAmt); ++ ++ if (LoadSize != StoreSize) ++ SrcVal = Builder.CreateTrunc(SrcVal, IntegerType::get(Ctx, LoadSize * 8)); ++ ++ return coerceAvailableValueToLoadType(SrcVal, LoadTy, Builder, DL); ++} ++ ++/// This function is called when we have a ++/// memdep query of a load that ends up being a clobbering load. This means ++/// that the load *may* provide bits used by the load but we can't be sure ++/// because the pointers don't mustalias. Check this case to see if there is ++/// anything more we can do before we give up. ++Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, ++ Instruction *InsertPt) { ++ ++ const DataLayout &DL = SrcVal->getModule()->getDataLayout(); ++ // If Offset+LoadTy exceeds the size of SrcVal, then we must be wanting to ++ // widen SrcVal out to a larger load. ++ unsigned SrcValStoreSize = DL.getTypeStoreSize(SrcVal->getType()); ++ unsigned LoadSize = DL.getTypeStoreSize(LoadTy); ++ if (Offset + LoadSize > SrcValStoreSize) { ++ assert(SrcVal->isSimple() && "Cannot widen volatile/atomic load!"); ++ assert(SrcVal->getType()->isIntegerTy() && "Can't widen non-integer load"); ++ // If we have a load/load clobber an DepLI can be widened to cover this ++ // load, then we should widen it to the next power of 2 size big enough! ++ unsigned NewLoadSize = Offset + LoadSize; ++ if (!isPowerOf2_32(NewLoadSize)) ++ NewLoadSize = NextPowerOf2(NewLoadSize); ++ ++ Value *PtrVal = SrcVal->getPointerOperand(); ++ ++ // Insert the new load after the old load. This ensures that subsequent ++ // memdep queries will find the new load. We can't easily remove the old ++ // load completely because it is already in the value numbering table. ++ IRBuilder<> Builder(SrcVal->getParent(), ++BasicBlock::iterator(SrcVal)); ++ Type *DestPTy = IntegerType::get(LoadTy->getContext(), NewLoadSize * 8); ++ DestPTy = ++ PointerType::get(DestPTy, PtrVal->getType()->getPointerAddressSpace()); ++ Builder.SetCurrentDebugLocation(SrcVal->getDebugLoc()); ++ PtrVal = Builder.CreateBitCast(PtrVal, DestPTy); ++ LoadInst *NewLoad = Builder.CreateLoad(PtrVal); ++ NewLoad->takeName(SrcVal); ++ NewLoad->setAlignment(SrcVal->getAlignment()); ++ ++ DEBUG(dbgs() << "GVN WIDENED LOAD: " << *SrcVal << "\n"); ++ DEBUG(dbgs() << "TO: " << *NewLoad << "\n"); ++ ++ // Replace uses of the original load with the wider load. On a big endian ++ // system, we need to shift down to get the relevant bits. ++ Value *RV = NewLoad; ++ if (DL.isBigEndian()) ++ RV = Builder.CreateLShr(RV, (NewLoadSize - SrcValStoreSize) * 8); ++ RV = Builder.CreateTrunc(RV, SrcVal->getType()); ++ SrcVal->replaceAllUsesWith(RV); ++ ++ SrcVal = NewLoad; ++ } ++ ++ return getStoreValueForLoad(SrcVal, Offset, LoadTy, InsertPt, DL); ++} ++ ++/// This function is called when we have a ++/// memdep query of a load that ends up being a clobbering mem intrinsic. ++Value *getMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, ++ Type *LoadTy, Instruction *InsertPt, ++ const DataLayout &DL) { ++ LLVMContext &Ctx = LoadTy->getContext(); ++ uint64_t LoadSize = DL.getTypeSizeInBits(LoadTy) / 8; ++ ++ IRBuilder<> Builder(InsertPt); ++ ++ // We know that this method is only called when the mem transfer fully ++ // provides the bits for the load. ++ if (MemSetInst *MSI = dyn_cast(SrcInst)) { ++ // memset(P, 'x', 1234) -> splat('x'), even if x is a variable, and ++ // independently of what the offset is. ++ Value *Val = MSI->getValue(); ++ if (LoadSize != 1) ++ Val = Builder.CreateZExt(Val, IntegerType::get(Ctx, LoadSize * 8)); ++ ++ Value *OneElt = Val; ++ ++ // Splat the value out to the right number of bits. ++ for (unsigned NumBytesSet = 1; NumBytesSet != LoadSize;) { ++ // If we can double the number of bytes set, do it. ++ if (NumBytesSet * 2 <= LoadSize) { ++ Value *ShVal = Builder.CreateShl(Val, NumBytesSet * 8); ++ Val = Builder.CreateOr(Val, ShVal); ++ NumBytesSet <<= 1; ++ continue; ++ } ++ ++ // Otherwise insert one byte at a time. ++ Value *ShVal = Builder.CreateShl(Val, 1 * 8); ++ Val = Builder.CreateOr(OneElt, ShVal); ++ ++NumBytesSet; ++ } ++ ++ return coerceAvailableValueToLoadType(Val, LoadTy, Builder, DL); ++ } ++ ++ // Otherwise, this is a memcpy/memmove from a constant global. ++ MemTransferInst *MTI = cast(SrcInst); ++ Constant *Src = cast(MTI->getSource()); ++ unsigned AS = Src->getType()->getPointerAddressSpace(); ++ ++ // Otherwise, see if we can constant fold a load from the constant with the ++ // offset applied as appropriate. ++ Src = ++ ConstantExpr::getBitCast(Src, Type::getInt8PtrTy(Src->getContext(), AS)); ++ Constant *OffsetCst = ++ ConstantInt::get(Type::getInt64Ty(Src->getContext()), (unsigned)Offset); ++ Src = ConstantExpr::getGetElementPtr(Type::getInt8Ty(Src->getContext()), Src, ++ OffsetCst); ++ Src = ConstantExpr::getBitCast(Src, PointerType::get(LoadTy, AS)); ++ return ConstantFoldLoadFromConstPtr(Src, LoadTy, DL); ++} ++} // namespace VNCoercion ++} // namespace llvm +-- +2.13.1 + diff --git a/deps/patches/llvm-D32196-LIR-non-integral.patch b/deps/patches/llvm-D32196-LIR-non-integral.patch new file mode 100644 index 0000000000000..28b4abdafa225 --- /dev/null +++ b/deps/patches/llvm-D32196-LIR-non-integral.patch @@ -0,0 +1,95 @@ +From aebd138996c29589d44d6eccea659757c6184b44 Mon Sep 17 00:00:00 2001 +From: Sanjoy Das +Date: Mon, 24 Apr 2017 20:12:10 +0000 +Subject: [PATCH 3/5] [LIR] Obey non-integral pointer semantics + +Summary: See http://llvm.org/docs/LangRef.html#non-integral-pointer-type + +Reviewers: haicheng + +Reviewed By: haicheng + +Subscribers: mcrosier, mzolotukhin, llvm-commits + +Differential Revision: https://reviews.llvm.org/D32196 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301238 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + lib/Transforms/Scalar/LoopIdiomRecognize.cpp | 5 +++ + test/Transforms/LoopIdiom/non-integral-pointers.ll | 48 ++++++++++++++++++++++ + 2 files changed, 53 insertions(+) + create mode 100644 test/Transforms/LoopIdiom/non-integral-pointers.ll + +diff --git a/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +index 5fec51c095d..570c55a3e76 100644 +--- a/lib/Transforms/Scalar/LoopIdiomRecognize.cpp ++++ b/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +@@ -345,6 +345,11 @@ bool LoopIdiomRecognize::isLegalStore(StoreInst *SI, bool &ForMemset, + if (!SI->isSimple()) + return false; + ++ // Don't convert stores of non-integral pointer types to memsets (which stores ++ // integers). ++ if (DL->isNonIntegralPointerType(SI->getValueOperand()->getType())) ++ return false; ++ + // Avoid merging nontemporal stores. + if (SI->getMetadata(LLVMContext::MD_nontemporal)) + return false; +diff --git a/test/Transforms/LoopIdiom/non-integral-pointers.ll b/test/Transforms/LoopIdiom/non-integral-pointers.ll +new file mode 100644 +index 00000000000..7646d5ac72d +--- /dev/null ++++ b/test/Transforms/LoopIdiom/non-integral-pointers.ll +@@ -0,0 +1,48 @@ ++; RUN: opt -S -basicaa -loop-idiom < %s | FileCheck %s ++ ++target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4" ++target triple = "x86_64-unknown-linux-gnu" ++ ++define void @f_0(i8 addrspace(3)** %ptr) { ++; CHECK-LABEL: @f_0( ++; CHECK: call{{.*}}memset ++ ++; LIR'ing stores of pointers with address space 3 is fine, since ++; they're integral pointers. ++ ++entry: ++ br label %for.body ++ ++for.body: ++ %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.body ] ++ %arrayidx = getelementptr i8 addrspace(3)*, i8 addrspace(3)** %ptr, i64 %indvar ++ store i8 addrspace(3)* null, i8 addrspace(3)** %arrayidx, align 4 ++ %indvar.next = add i64 %indvar, 1 ++ %exitcond = icmp eq i64 %indvar.next, 10000 ++ br i1 %exitcond, label %for.end, label %for.body ++ ++for.end: ++ ret void ++} ++ ++define void @f_1(i8 addrspace(4)** %ptr) { ++; CHECK-LABEL: @f_1( ++; CHECK-NOT: call{{.*}}memset ++ ++; LIR'ing stores of pointers with address space 4 is not ok, since ++; they're non-integral pointers. ++ ++entry: ++ br label %for.body ++ ++for.body: ++ %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %for.body ] ++ %arrayidx = getelementptr i8 addrspace(4)*, i8 addrspace(4)** %ptr, i64 %indvar ++ store i8 addrspace(4)* null, i8 addrspace(4)** %arrayidx, align 4 ++ %indvar.next = add i64 %indvar, 1 ++ %exitcond = icmp eq i64 %indvar.next, 10000 ++ br i1 %exitcond, label %for.end, label %for.body ++ ++for.end: ++ ret void ++} +-- +2.13.1 + diff --git a/deps/patches/llvm-D32203-SORA-non-integral.patch b/deps/patches/llvm-D32203-SORA-non-integral.patch new file mode 100644 index 0000000000000..6c9b75b1ca0da --- /dev/null +++ b/deps/patches/llvm-D32203-SORA-non-integral.patch @@ -0,0 +1,99 @@ +From 2fe2c1173e286203309e5bb9b034fd55dc9fc8fc Mon Sep 17 00:00:00 2001 +From: Sanjoy Das +Date: Sat, 17 Jun 2017 11:06:25 -0400 +Subject: [PATCH 1/2] [SROA] Add support for non-integral pointers + +Summary: C.f. http://llvm.org/docs/LangRef.html#non-integral-pointer-type + +Reviewers: chandlerc, loladiro + +Reviewed By: loladiro + +Subscribers: reames, loladiro, mcrosier, llvm-commits + +Differential Revision: https://reviews.llvm.org/D32203 +--- + lib/Transforms/Scalar/SROA.cpp | 13 ++++++-- + test/Transforms/SROA/non-integral-pointers.ll | 46 +++++++++++++++++++++++++++ + 2 files changed, 57 insertions(+), 2 deletions(-) + create mode 100644 test/Transforms/SROA/non-integral-pointers.ll + +diff --git a/lib/Transforms/Scalar/SROA.cpp b/lib/Transforms/Scalar/SROA.cpp +index d28490f3a50..ec8636fe25a 100644 +--- a/lib/Transforms/Scalar/SROA.cpp ++++ b/lib/Transforms/Scalar/SROA.cpp +@@ -1636,8 +1636,17 @@ static bool canConvertValue(const DataLayout &DL, Type *OldTy, Type *NewTy) { + return cast(NewTy)->getPointerAddressSpace() == + cast(OldTy)->getPointerAddressSpace(); + } +- if (NewTy->isIntegerTy() || OldTy->isIntegerTy()) +- return true; ++ ++ // We can convert integers to integral pointers, but not to non-integral ++ // pointers. ++ if (OldTy->isIntegerTy()) ++ return !DL.isNonIntegralPointerType(NewTy); ++ ++ // We can convert integral pointers to integers, but non-integral pointers ++ // need to remain pointers. ++ if (!DL.isNonIntegralPointerType(OldTy)) ++ return NewTy->isIntegerTy(); ++ + return false; + } + +diff --git a/test/Transforms/SROA/non-integral-pointers.ll b/test/Transforms/SROA/non-integral-pointers.ll +new file mode 100644 +index 00000000000..63286309f6f +--- /dev/null ++++ b/test/Transforms/SROA/non-integral-pointers.ll +@@ -0,0 +1,46 @@ ++; RUN: opt -sroa -S < %s | FileCheck %s ++ ++; This test checks that SROA does not introduce ptrtoint and inttoptr ++; casts from and to non-integral pointers. The "ni:4" bit in the ++; datalayout states that pointers of address space 4 are to be ++; considered "non-integral". ++ ++target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4" ++target triple = "x86_64-unknown-linux-gnu" ++ ++define void @f0(i1 %alwaysFalse, i64 %val) { ++; CHECK-LABEL: @f0( ++; CHECK-NOT: inttoptr ++; CHECK-NOT: ptrtoint ++entry: ++ %loc = alloca i64 ++ store i64 %val, i64* %loc ++ br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken ++ ++neverTaken: ++ %loc.bc = bitcast i64* %loc to i8 addrspace(4)** ++ %ptr = load i8 addrspace(4)*, i8 addrspace(4)** %loc.bc ++ store i8 5, i8 addrspace(4)* %ptr ++ ret void ++ ++alwaysTaken: ++ ret void ++} ++ ++define i64 @f1(i1 %alwaysFalse, i8 addrspace(4)* %val) { ++; CHECK-LABEL: @f1( ++; CHECK-NOT: inttoptr ++; CHECK-NOT: ptrtoint ++entry: ++ %loc = alloca i8 addrspace(4)* ++ store i8 addrspace(4)* %val, i8 addrspace(4)** %loc ++ br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken ++ ++neverTaken: ++ %loc.bc = bitcast i8 addrspace(4)** %loc to i64* ++ %int = load i64, i64* %loc.bc ++ ret i64 %int ++ ++alwaysTaken: ++ ret i64 42 ++} +-- +2.13.1 + diff --git a/deps/patches/llvm-D32208-coerce-non-integral.patch b/deps/patches/llvm-D32208-coerce-non-integral.patch new file mode 100644 index 0000000000000..bc0ec8a594e72 --- /dev/null +++ b/deps/patches/llvm-D32208-coerce-non-integral.patch @@ -0,0 +1,137 @@ +From 2a7ef55ed78bb5f147900af862fed32103257839 Mon Sep 17 00:00:00 2001 +From: Sanjoy Das +Date: Wed, 19 Apr 2017 18:21:09 +0000 +Subject: [PATCH 2/5] [GVN] Don't coerce non-integral pointers to integers or + vice versa + +Summary: +See http://llvm.org/docs/LangRef.html#non-integral-pointer-type + +The NewGVN test does not fail without these changes (perhaps it does +try to coerce pointers <-> integers to begin with?), but I added the +test case anyway. + +Reviewers: dberlin + +Subscribers: mcrosier, llvm-commits, Prazek + +Differential Revision: https://reviews.llvm.org/D32208 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300730 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + lib/Transforms/Utils/VNCoercion.cpp | 5 ++++ + test/Transforms/GVN/non-integral-pointers.ll | 39 +++++++++++++++++++++++++ + test/Transforms/NewGVN/non-integral-pointers.ll | 39 +++++++++++++++++++++++++ + 3 files changed, 83 insertions(+) + create mode 100644 test/Transforms/GVN/non-integral-pointers.ll + create mode 100644 test/Transforms/NewGVN/non-integral-pointers.ll + +diff --git a/lib/Transforms/Utils/VNCoercion.cpp b/lib/Transforms/Utils/VNCoercion.cpp +index 38d26e922c3..80762ccc0d4 100644 +--- a/lib/Transforms/Utils/VNCoercion.cpp ++++ b/lib/Transforms/Utils/VNCoercion.cpp +@@ -24,6 +24,11 @@ bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, + if (DL.getTypeSizeInBits(StoredVal->getType()) < DL.getTypeSizeInBits(LoadTy)) + return false; + ++ // Don't coerce non-integral pointers to integers or vice versa. ++ if (DL.isNonIntegralPointerType(StoredVal->getType()) != ++ DL.isNonIntegralPointerType(LoadTy)) ++ return false; ++ + return true; + } + +diff --git a/test/Transforms/GVN/non-integral-pointers.ll b/test/Transforms/GVN/non-integral-pointers.ll +new file mode 100644 +index 00000000000..9ae4132231d +--- /dev/null ++++ b/test/Transforms/GVN/non-integral-pointers.ll +@@ -0,0 +1,39 @@ ++; RUN: opt -gvn -S < %s | FileCheck %s ++ ++target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4" ++target triple = "x86_64-unknown-linux-gnu" ++ ++define void @f0(i1 %alwaysFalse, i64 %val, i64* %loc) { ++; CHECK-LABEL: @f0( ++; CHECK-NOT: inttoptr ++; CHECK-NOT: ptrtoint ++ entry: ++ store i64 %val, i64* %loc ++ br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken ++ ++ neverTaken: ++ %loc.bc = bitcast i64* %loc to i8 addrspace(4)** ++ %ptr = load i8 addrspace(4)*, i8 addrspace(4)** %loc.bc ++ store i8 5, i8 addrspace(4)* %ptr ++ ret void ++ ++ alwaysTaken: ++ ret void ++} ++ ++define i64 @f1(i1 %alwaysFalse, i8 addrspace(4)* %val, i8 addrspace(4)** %loc) { ++; CHECK-LABEL: @f1( ++; CHECK-NOT: inttoptr ++; CHECK-NOT: ptrtoint ++ entry: ++ store i8 addrspace(4)* %val, i8 addrspace(4)** %loc ++ br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken ++ ++ neverTaken: ++ %loc.bc = bitcast i8 addrspace(4)** %loc to i64* ++ %int = load i64, i64* %loc.bc ++ ret i64 %int ++ ++ alwaysTaken: ++ ret i64 42 ++} +diff --git a/test/Transforms/NewGVN/non-integral-pointers.ll b/test/Transforms/NewGVN/non-integral-pointers.ll +new file mode 100644 +index 00000000000..75b8285d51f +--- /dev/null ++++ b/test/Transforms/NewGVN/non-integral-pointers.ll +@@ -0,0 +1,39 @@ ++; RUN: opt -newgvn -S < %s | FileCheck %s ++ ++target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4" ++target triple = "x86_64-unknown-linux-gnu" ++ ++define void @f0(i1 %alwaysFalse, i64 %val, i64* %loc) { ++; CHECK-LABEL: @f0( ++; CHECK-NOT: inttoptr ++; CHECK-NOT: ptrtoint ++ entry: ++ store i64 %val, i64* %loc ++ br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken ++ ++ neverTaken: ++ %loc.bc = bitcast i64* %loc to i8 addrspace(4)** ++ %ptr = load i8 addrspace(4)*, i8 addrspace(4)** %loc.bc ++ store i8 5, i8 addrspace(4)* %ptr ++ ret void ++ ++ alwaysTaken: ++ ret void ++} ++ ++define i64 @f1(i1 %alwaysFalse, i8 addrspace(4)* %val, i8 addrspace(4)** %loc) { ++; CHECK-LABEL: @f1( ++; CHECK-NOT: inttoptr ++; CHECK-NOT: ptrtoint ++ entry: ++ store i8 addrspace(4)* %val, i8 addrspace(4)** %loc ++ br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken ++ ++ neverTaken: ++ %loc.bc = bitcast i8 addrspace(4)** %loc to i64* ++ %int = load i64, i64* %loc.bc ++ ret i64 %int ++ ++ alwaysTaken: ++ ret i64 42 ++} +-- +2.13.1 + diff --git a/deps/patches/llvm-D32623-GVN-non-integral.patch b/deps/patches/llvm-D32623-GVN-non-integral.patch new file mode 100644 index 0000000000000..5ddc76bc046d5 --- /dev/null +++ b/deps/patches/llvm-D32623-GVN-non-integral.patch @@ -0,0 +1,94 @@ +From ad3b6cad4fcd66aab2ef2e93566d5868505c03bb Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Tue, 9 May 2017 21:07:20 +0000 +Subject: [PATCH 4/5] [GVN] Fix a crash on encountering non-integral pointers + +Summary: +This fixes the immediate crash caused by introducing an incorrect inttoptr +before attempting the conversion. There may still be a legality +check missing somewhere earlier for non-integral pointers, but this change +seems necessary in any case. + +Reviewers: sanjoy, dberlin + +Reviewed By: dberlin + +Subscribers: llvm-commits + +Differential Revision: https://reviews.llvm.org/D32623 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302587 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + lib/Transforms/Utils/VNCoercion.cpp | 9 ++++++++ + test/Transforms/GVN/PRE/nonintegral.ll | 39 ++++++++++++++++++++++++++++++++++ + 2 files changed, 48 insertions(+) + create mode 100644 test/Transforms/GVN/PRE/nonintegral.ll + +diff --git a/lib/Transforms/Utils/VNCoercion.cpp b/lib/Transforms/Utils/VNCoercion.cpp +index 80762ccc0d4..9d2eab19ded 100644 +--- a/lib/Transforms/Utils/VNCoercion.cpp ++++ b/lib/Transforms/Utils/VNCoercion.cpp +@@ -301,6 +301,15 @@ Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, + Instruction *InsertPt, const DataLayout &DL) { + LLVMContext &Ctx = SrcVal->getType()->getContext(); + ++ // If two pointers are in the same address space, they have the same size, ++ // so we don't need to do any truncation, etc. This avoids introducing ++ // ptrtoint instructions for pointers that may be non-integral. ++ if (SrcVal->getType()->isPointerTy() && LoadTy->isPointerTy() && ++ cast(SrcVal->getType())->getAddressSpace() == ++ cast(LoadTy)->getAddressSpace()) { ++ return SrcVal; ++ } ++ + uint64_t StoreSize = (DL.getTypeSizeInBits(SrcVal->getType()) + 7) / 8; + uint64_t LoadSize = (DL.getTypeSizeInBits(LoadTy) + 7) / 8; + +diff --git a/test/Transforms/GVN/PRE/nonintegral.ll b/test/Transforms/GVN/PRE/nonintegral.ll +new file mode 100644 +index 00000000000..75a756e8af8 +--- /dev/null ++++ b/test/Transforms/GVN/PRE/nonintegral.ll +@@ -0,0 +1,39 @@ ++; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ++; RUN: opt -gvn -S < %s | FileCheck %s ++ ++target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4" ++target triple = "x86_64-unknown-linux-gnu" ++ ++define void @nipre(double addrspace(4)** noalias %p, i64 addrspace(4)** noalias %p2, i8 %jmp) { ++ ++; CHECK-LABEL: @nipre( ++; CHECK: [[PCAST:%.*]] = bitcast double addrspace(4)** [[P:%.*]] to i64 addrspace(4)** ++; CHECK: a: ++; CHECK: [[L1:%.*]] = load i64 addrspace(4)*, i64 addrspace(4)** [[PCAST]] ++; CHECK: [[TMP0:%.*]] = bitcast i64 addrspace(4)* [[L1]] to double addrspace(4)* ++; CHECK: b: ++; CHECK: [[L2:%.*]] = load i64 addrspace(4)*, i64 addrspace(4)** [[PCAST]] ++; CHECK: [[TMP1:%.*]] = bitcast i64 addrspace(4)* [[L2]] to double addrspace(4)* ++; CHECK: c: ++; CHECK-NEXT: [[L3_PRE:%.*]] = load double addrspace(4)*, double addrspace(4)** %p ++ ++entry: ++ %pcast = bitcast double addrspace(4)** %p to i64 addrspace(4)** ++ switch i8 %jmp, label %c [ i8 0, label %a ++ i8 1, label %b] ++a: ++ %l1 = load i64 addrspace(4)*, i64 addrspace(4)** %pcast ++ store i64 addrspace(4)* %l1, i64 addrspace(4)** %p2 ++ br label %tail ++b: ++ %l2 = load i64 addrspace(4)*, i64 addrspace(4)** %pcast ++ store i64 addrspace(4)* %l2, i64 addrspace(4)** %p2 ++ br label %tail ++c: ++ br label %tail ++tail: ++ %l3 = load double addrspace(4)*, double addrspace(4)** %p ++ %l3cast = bitcast double addrspace(4)* %l3 to i64 addrspace(4)* ++ store i64 addrspace(4)* %l3cast, i64 addrspace(4)** %p2 ++ ret void ++} +-- +2.13.1 + diff --git a/deps/patches/llvm-D33110-codegen-prepare-inttoptr.patch b/deps/patches/llvm-D33110-codegen-prepare-inttoptr.patch new file mode 100644 index 0000000000000..5f1f874c3db83 --- /dev/null +++ b/deps/patches/llvm-D33110-codegen-prepare-inttoptr.patch @@ -0,0 +1,119 @@ +From 8a2f775df3c8548bedd8437c0b96b54e9e71549d Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 17 Jun 2017 11:07:26 -0400 +Subject: [PATCH 2/2] [CodeGenPrepare] Don't create inttoptr for ni ptrs + +Summary: +Arguably non-integral pointers probably shouldn't show up here at all, +but since the backend doesn't complain and this takes valid (according +to the Verifier) IR and makes it invalid, make sure not to introduce +any inttoptr instructions if we're dealing with non-integral pointers. + +Reviewers: sanjoy + +Subscribers: llvm-commits + +Differential Revision: https://reviews.llvm.org/D33110 +--- + lib/CodeGen/CodeGenPrepare.cpp | 23 ++++++++----- + test/Transforms/CodeGenPrepare/nonintegral.ll | 47 +++++++++++++++++++++++++++ + 2 files changed, 62 insertions(+), 8 deletions(-) + create mode 100644 test/Transforms/CodeGenPrepare/nonintegral.ll + +diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp +index 934b470f13b..44d6b3e264c 100644 +--- a/lib/CodeGen/CodeGenPrepare.cpp ++++ b/lib/CodeGen/CodeGenPrepare.cpp +@@ -3973,14 +3973,16 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr, + // If the real base value actually came from an inttoptr, then the matcher + // will look through it and provide only the integer value. In that case, + // use it here. +- if (!ResultPtr && AddrMode.BaseReg) { +- ResultPtr = +- Builder.CreateIntToPtr(AddrMode.BaseReg, Addr->getType(), "sunkaddr"); +- AddrMode.BaseReg = nullptr; +- } else if (!ResultPtr && AddrMode.Scale == 1) { +- ResultPtr = +- Builder.CreateIntToPtr(AddrMode.ScaledReg, Addr->getType(), "sunkaddr"); +- AddrMode.Scale = 0; ++ if (!DL->isNonIntegralPointerType(Addr->getType())) { ++ if (!ResultPtr && AddrMode.BaseReg) { ++ ResultPtr = Builder.CreateIntToPtr(AddrMode.BaseReg, Addr->getType(), ++ "sunkaddr"); ++ AddrMode.BaseReg = nullptr; ++ } else if (!ResultPtr && AddrMode.Scale == 1) { ++ ResultPtr = Builder.CreateIntToPtr(AddrMode.ScaledReg, Addr->getType(), ++ "sunkaddr"); ++ AddrMode.Scale = 0; ++ } + } + + if (!ResultPtr && +@@ -4061,6 +4063,11 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr, + SunkAddr = Builder.CreateBitCast(SunkAddr, Addr->getType()); + } + } else { ++ // We'd require an inttoptr down the line, which we can't do for ++ // non-integral pointers, so in that case bail out now. ++ if (DL->isNonIntegralPointerType(Addr->getType())) ++ return false; ++ + DEBUG(dbgs() << "CGP: SINKING nonlocal addrmode: " << AddrMode << " for " + << *MemoryInst << "\n"); + Type *IntPtrTy = DL->getIntPtrType(Addr->getType()); +diff --git a/test/Transforms/CodeGenPrepare/nonintegral.ll b/test/Transforms/CodeGenPrepare/nonintegral.ll +new file mode 100644 +index 00000000000..e49977bc940 +--- /dev/null ++++ b/test/Transforms/CodeGenPrepare/nonintegral.ll +@@ -0,0 +1,47 @@ ++; RUN: opt -S -codegenprepare < %s | FileCheck %s ++; RUN: opt -S -codegenprepare -addr-sink-using-gep=false < %s | FileCheck %s ++ ++; This target data layout is modified to have a non-integral addrspace(1), ++; in order to verify that codegenprepare does not try to introduce illegal ++; inttoptrs. ++target datalayout = ++"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-ni:1" ++target triple = "x86_64-unknown-linux-gnu" ++ ++define void @test_simple(i1 %cond, i64 addrspace(1)* %base) { ++; CHECK-LABEL: @test_simple ++; CHECK-NOT: inttoptr {{.*}} to i64 addrspace(1)* ++entry: ++ %addr = getelementptr inbounds i64, i64 addrspace(1)* %base, i64 5 ++ %casted = bitcast i64 addrspace(1)* %addr to i32 addrspace(1)* ++ br i1 %cond, label %if.then, label %fallthrough ++ ++if.then: ++ %v = load i32, i32 addrspace(1)* %casted, align 4 ++ br label %fallthrough ++ ++fallthrough: ++ ret void ++} ++ ++ ++define void @test_inttoptr_base(i1 %cond, i64 %base) { ++; CHECK-LABEL: @test_inttoptr_base ++; CHECK-NOT: inttoptr {{.*}} to i64 addrspace(1)* ++entry: ++; Doing the inttoptr in the integral addrspace(0) followed by an explicit ++; (frontend-introduced) addrspacecast is fine. We cannot however introduce ++; a direct inttoptr to addrspace(1) ++ %baseptr = inttoptr i64 %base to i64* ++ %baseptrni = addrspacecast i64 *%baseptr to i64 addrspace(1)* ++ %addr = getelementptr inbounds i64, i64 addrspace(1)* %baseptrni, i64 5 ++ %casted = bitcast i64 addrspace(1)* %addr to i32 addrspace(1)* ++ br i1 %cond, label %if.then, label %fallthrough ++ ++if.then: ++ %v = load i32, i32 addrspace(1)* %casted, align 4 ++ br label %fallthrough ++ ++fallthrough: ++ ret void ++} +-- +2.13.1 + diff --git a/deps/patches/llvm-D33129-scevexpander-non-integral.patch b/deps/patches/llvm-D33129-scevexpander-non-integral.patch new file mode 100644 index 0000000000000..1dab29f94c041 --- /dev/null +++ b/deps/patches/llvm-D33129-scevexpander-non-integral.patch @@ -0,0 +1,153 @@ +From d551af32da5fd6654e7804848a7a409e9444aeea Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Sat, 27 May 2017 03:22:55 +0000 +Subject: [PATCH 5/5] [SCEVExpander] Try harder to avoid introducing inttoptr + +Summary: +This fixes introduction of an incorrect inttoptr/ptrtoint pair in +the included test case which makes use of non-integral pointers. I +suspect there are more cases like this left, but this takes care of +the one I was seeing at the moment. + +Reviewers: sanjoy + +Subscribers: mzolotukhin, llvm-commits + +Differential Revision: https://reviews.llvm.org/D33129 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@304058 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + lib/Analysis/ScalarEvolutionExpander.cpp | 20 ++++++++-- + test/Transforms/LoopStrengthReduce/nonintegral.ll | 45 +++++++++++++++++++++++ + unittests/Analysis/ScalarEvolutionTest.cpp | 11 +++--- + 3 files changed, 67 insertions(+), 9 deletions(-) + create mode 100644 test/Transforms/LoopStrengthReduce/nonintegral.ll + +diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp +index d15a7dbd20e..e7d9e9a633e 100644 +--- a/lib/Analysis/ScalarEvolutionExpander.cpp ++++ b/lib/Analysis/ScalarEvolutionExpander.cpp +@@ -1306,12 +1306,17 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { + // Expand the core addrec. If we need post-loop scaling, force it to + // expand to an integer type to avoid the need for additional casting. + Type *ExpandTy = PostLoopScale ? IntTy : STy; ++ // We can't use a pointer type for the addrec if the pointer type is ++ // non-integral. ++ Type *AddRecPHIExpandTy = ++ DL.isNonIntegralPointerType(STy) ? Normalized->getType() : ExpandTy; ++ + // In some cases, we decide to reuse an existing phi node but need to truncate + // it and/or invert the step. + Type *TruncTy = nullptr; + bool InvertStep = false; +- PHINode *PN = getAddRecExprPHILiterally(Normalized, L, ExpandTy, IntTy, +- TruncTy, InvertStep); ++ PHINode *PN = getAddRecExprPHILiterally(Normalized, L, AddRecPHIExpandTy, ++ IntTy, TruncTy, InvertStep); + + // Accommodate post-inc mode, if necessary. + Value *Result; +@@ -1384,8 +1389,15 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { + // Re-apply any non-loop-dominating offset. + if (PostLoopOffset) { + if (PointerType *PTy = dyn_cast(ExpandTy)) { +- const SCEV *const OffsetArray[1] = { PostLoopOffset }; +- Result = expandAddToGEP(OffsetArray, OffsetArray+1, PTy, IntTy, Result); ++ if (Result->getType()->isIntegerTy()) { ++ Value *Base = expandCodeFor(PostLoopOffset, ExpandTy); ++ const SCEV *const OffsetArray[1] = {SE.getUnknown(Result)}; ++ Result = expandAddToGEP(OffsetArray, OffsetArray + 1, PTy, IntTy, Base); ++ } else { ++ const SCEV *const OffsetArray[1] = {PostLoopOffset}; ++ Result = ++ expandAddToGEP(OffsetArray, OffsetArray + 1, PTy, IntTy, Result); ++ } + } else { + Result = InsertNoopCastOfTo(Result, IntTy); + Result = Builder.CreateAdd(Result, +diff --git a/test/Transforms/LoopStrengthReduce/nonintegral.ll b/test/Transforms/LoopStrengthReduce/nonintegral.ll +new file mode 100644 +index 00000000000..5648e3aa74a +--- /dev/null ++++ b/test/Transforms/LoopStrengthReduce/nonintegral.ll +@@ -0,0 +1,45 @@ ++; RUN: opt -S -loop-reduce < %s | FileCheck %s ++ ++; Address Space 10 is non-integral. The optimizer is not allowed to use ++; ptrtoint/inttoptr instructions. Make sure that this doesn't happen ++target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:10:11:12" ++target triple = "x86_64-unknown-linux-gnu" ++ ++define void @japi1__unsafe_getindex_65028(i64 addrspace(10)* %arg) { ++; CHECK-NOT: inttoptr ++; CHECK-NOT: ptrtoint ++; How exactly SCEV chooses to materialize isn't all that important, as ++; long as it doesn't try to round-trip through integers. As of this writing, ++; it emits a byte-wise gep, which is fine. ++; CHECK: getelementptr i64, i64 addrspace(10)* {{.*}}, i64 {{.*}} ++top: ++ br label %L86 ++ ++L86: ; preds = %L86, %top ++ %i.0 = phi i64 [ 0, %top ], [ %tmp, %L86 ] ++ %tmp = add i64 %i.0, 1 ++ br i1 undef, label %L86, label %if29 ++ ++if29: ; preds = %L86 ++ %tmp1 = shl i64 %tmp, 1 ++ %tmp2 = add i64 %tmp1, -2 ++ br label %if31 ++ ++if31: ; preds = %if38, %if29 ++ %"#temp#1.sroa.0.022" = phi i64 [ 0, %if29 ], [ %tmp3, %if38 ] ++ br label %L119 ++ ++L119: ; preds = %L119, %if31 ++ %i5.0 = phi i64 [ %"#temp#1.sroa.0.022", %if31 ], [ %tmp3, %L119 ] ++ %tmp3 = add i64 %i5.0, 1 ++ br i1 undef, label %L119, label %if38 ++ ++if38: ; preds = %L119 ++ %tmp4 = add i64 %tmp2, %i5.0 ++ %tmp5 = getelementptr i64, i64 addrspace(10)* %arg, i64 %tmp4 ++ %tmp6 = load i64, i64 addrspace(10)* %tmp5 ++ br i1 undef, label %done, label %if31 ++ ++done: ; preds = %if38 ++ ret void ++} +diff --git a/unittests/Analysis/ScalarEvolutionTest.cpp b/unittests/Analysis/ScalarEvolutionTest.cpp +index f4370842edb..1af241fdfbe 100644 +--- a/unittests/Analysis/ScalarEvolutionTest.cpp ++++ b/unittests/Analysis/ScalarEvolutionTest.cpp +@@ -7,21 +7,22 @@ + // + //===----------------------------------------------------------------------===// + +-#include "llvm/Analysis/ScalarEvolutionExpander.h" +-#include "llvm/Analysis/ScalarEvolutionExpressions.h" ++#include "llvm/ADT/SmallVector.h" + #include "llvm/Analysis/AssumptionCache.h" + #include "llvm/Analysis/LoopInfo.h" +-#include "llvm/Analysis/TargetLibraryInfo.h" +-#include "llvm/ADT/SmallVector.h" + #include "llvm/Analysis/LoopInfo.h" ++#include "llvm/Analysis/ScalarEvolutionExpander.h" ++#include "llvm/Analysis/ScalarEvolutionExpressions.h" ++#include "llvm/Analysis/TargetLibraryInfo.h" + #include "llvm/AsmParser/Parser.h" + #include "llvm/IR/Constants.h" + #include "llvm/IR/Dominators.h" + #include "llvm/IR/GlobalVariable.h" ++#include "llvm/IR/IRBuilder.h" + #include "llvm/IR/InstIterator.h" + #include "llvm/IR/LLVMContext.h" +-#include "llvm/IR/Module.h" + #include "llvm/IR/LegacyPassManager.h" ++#include "llvm/IR/Module.h" + #include "llvm/IR/Verifier.h" + #include "llvm/Support/SourceMgr.h" + #include "gtest/gtest.h" +-- +2.13.1 + diff --git a/deps/patches/llvm-VNCoercion-signatures.patch b/deps/patches/llvm-VNCoercion-signatures.patch new file mode 100644 index 0000000000000..5b8923ee47678 --- /dev/null +++ b/deps/patches/llvm-VNCoercion-signatures.patch @@ -0,0 +1,60 @@ +From a0946a413f7ee14ed26c48a249b2a326ade70a42 Mon Sep 17 00:00:00 2001 +From: Daniel Berlin +Date: Sat, 11 Mar 2017 00:51:01 +0000 +Subject: [PATCH 6/7] VNCoercion: Make the function signatures all consistent + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297537 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + include/llvm/Transforms/Utils/VNCoercion.h | 2 +- + lib/Transforms/Scalar/GVN.cpp | 2 +- + lib/Transforms/Utils/VNCoercion.cpp | 3 +-- + 3 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/include/llvm/Transforms/Utils/VNCoercion.h b/include/llvm/Transforms/Utils/VNCoercion.h +index d3c998fa8a8..edc63ca38db 100644 +--- a/include/llvm/Transforms/Utils/VNCoercion.h ++++ b/include/llvm/Transforms/Utils/VNCoercion.h +@@ -53,7 +53,7 @@ Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, + /// On success, it returns the offset into DepSI that extraction would start. + /// On failure, it returns -1. + int analyzeLoadFromClobberingStore(Type *LoadTy, Value *LoadPtr, +- StoreInst *DepSI); ++ StoreInst *DepSI, const DataLayout &DL); + + /// This function determines whether a value for the pointer LoadPtr can be + /// extracted from the load at DepLI. +diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp +index 132c7297d77..7b8948c065b 100644 +--- a/lib/Transforms/Scalar/GVN.cpp ++++ b/lib/Transforms/Scalar/GVN.cpp +@@ -830,7 +830,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo, + // Can't forward from non-atomic to atomic without violating memory model. + if (Address && LI->isAtomic() <= DepSI->isAtomic()) { + int Offset = +- analyzeLoadFromClobberingStore(LI->getType(), Address, DepSI); ++ analyzeLoadFromClobberingStore(LI->getType(), Address, DepSI, DL); + if (Offset != -1) { + Res = AvailableValue::get(DepSI->getValueOperand(), Offset); + return true; +diff --git a/lib/Transforms/Utils/VNCoercion.cpp b/lib/Transforms/Utils/VNCoercion.cpp +index 9d2eab19ded..6fa9aca8436 100644 +--- a/lib/Transforms/Utils/VNCoercion.cpp ++++ b/lib/Transforms/Utils/VNCoercion.cpp +@@ -195,13 +195,12 @@ static int analyzeLoadFromClobberingWrite(Type *LoadTy, Value *LoadPtr, + /// This function is called when we have a + /// memdep query of a load that ends up being a clobbering store. + int analyzeLoadFromClobberingStore(Type *LoadTy, Value *LoadPtr, +- StoreInst *DepSI) { ++ StoreInst *DepSI, const DataLayout &DL) { + // Cannot handle reading from store of first-class aggregate yet. + if (DepSI->getValueOperand()->getType()->isStructTy() || + DepSI->getValueOperand()->getType()->isArrayTy()) + return -1; + +- const DataLayout &DL = DepSI->getModule()->getDataLayout(); + Value *StorePtr = DepSI->getPointerOperand(); + uint64_t StoreSize = + DL.getTypeSizeInBits(DepSI->getValueOperand()->getType()); +-- +2.13.1 + diff --git a/deps/patches/llvm-VNCoercion-template.patch b/deps/patches/llvm-VNCoercion-template.patch new file mode 100644 index 0000000000000..6aa87a1cf3a33 --- /dev/null +++ b/deps/patches/llvm-VNCoercion-template.patch @@ -0,0 +1,410 @@ +From 67cb3073f40c0d02334e161a1c9c749be777f411 Mon Sep 17 00:00:00 2001 +From: Daniel Berlin +Date: Mon, 20 Mar 2017 16:08:29 +0000 +Subject: [PATCH 7/7] Templatize parts of VNCoercion, and add constant-only + versions of the functions to be used in NewGVN. NFCI. + +Summary: +This is ground work for the changes to enable coercion in NewGVN. +GVN doesn't care if they end up constant because it eliminates as it goes. +NewGVN cares. + +IRBuilder and ConstantFolder deliberately present the same interface, +so we use this to our advantage to templatize our functions to make +them either constant only or not. + +Reviewers: davide + +Subscribers: llvm-commits, Prazek + +Differential Revision: https://reviews.llvm.org/D30928 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@298262 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + include/llvm/Transforms/Utils/VNCoercion.h | 14 ++- + lib/Transforms/Scalar/GVN.cpp | 2 +- + lib/Transforms/Utils/VNCoercion.cpp | 177 ++++++++++++++++++----------- + 3 files changed, 124 insertions(+), 69 deletions(-) + +diff --git a/include/llvm/Transforms/Utils/VNCoercion.h b/include/llvm/Transforms/Utils/VNCoercion.h +index edc63ca38db..1baa9b66e49 100644 +--- a/include/llvm/Transforms/Utils/VNCoercion.h ++++ b/include/llvm/Transforms/Utils/VNCoercion.h +@@ -76,13 +76,21 @@ int analyzeLoadFromClobberingMemInst(Type *LoadTy, Value *LoadPtr, + /// inserts instructions to do so at InsertPt, and returns the extracted value. + Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, + Instruction *InsertPt, const DataLayout &DL); ++// This is the same as getStoreValueForLoad, except it performs no insertion ++// It only allows constant inputs. ++Constant *getConstantStoreValueForLoad(Constant *SrcVal, unsigned Offset, ++ Type *LoadTy, const DataLayout &DL); + + /// If analyzeLoadFromClobberingLoad returned an offset, this function can be + /// used to actually perform the extraction of the bits from the load, including + /// any necessary load widening. It inserts instructions to do so at InsertPt, + /// and returns the extracted value. + Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, +- Instruction *InsertPt); ++ Instruction *InsertPt, const DataLayout &DL); ++// This is the same as getLoadValueForLoad, except it is given the load value as ++// a constant. It returns nullptr if it would require widening the load. ++Constant *getConstantLoadValueForLoad(Constant *SrcVal, unsigned Offset, ++ Type *LoadTy, const DataLayout &DL); + + /// If analyzeLoadFromClobberingMemInst returned an offset, this function can be + /// used to actually perform the extraction of the bits from the memory +@@ -91,6 +99,10 @@ Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, + Value *getMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, + Type *LoadTy, Instruction *InsertPt, + const DataLayout &DL); ++// This is the same as getStoreValueForLoad, except it performs no insertion. ++// It returns nullptr if it cannot produce a constant. ++Constant *getConstantMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, ++ Type *LoadTy, const DataLayout &DL); + } + } + #endif +diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp +index 7b8948c065b..91118ee7e39 100644 +--- a/lib/Transforms/Scalar/GVN.cpp ++++ b/lib/Transforms/Scalar/GVN.cpp +@@ -748,7 +748,7 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *LI, + if (Load->getType() == LoadTy && Offset == 0) { + Res = Load; + } else { +- Res = getLoadValueForLoad(Load, Offset, LoadTy, InsertPt); ++ Res = getLoadValueForLoad(Load, Offset, LoadTy, InsertPt, DL); + // We would like to use gvn.markInstructionForDeletion here, but we can't + // because the load is already memoized into the leader map table that GVN + // tracks. It is potentially possible to remove the load from the table, +diff --git a/lib/Transforms/Utils/VNCoercion.cpp b/lib/Transforms/Utils/VNCoercion.cpp +index 6fa9aca8436..60d9ede2c48 100644 +--- a/lib/Transforms/Utils/VNCoercion.cpp ++++ b/lib/Transforms/Utils/VNCoercion.cpp +@@ -32,17 +32,12 @@ bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, + return true; + } + +-/// If we saw a store of a value to memory, and +-/// then a load from a must-aliased pointer of a different type, try to coerce +-/// the stored value. LoadedTy is the type of the load we want to replace. +-/// IRB is IRBuilder used to insert new instructions. +-/// +-/// If we can't do it, return null. +-Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, +- IRBuilder<> &IRB, const DataLayout &DL) { ++template ++static T *coerceAvailableValueToLoadTypeHelper(T *StoredVal, Type *LoadedTy, ++ HelperClass &Helper, ++ const DataLayout &DL) { + assert(canCoerceMustAliasedValueToLoad(StoredVal, LoadedTy, DL) && + "precondition violation - materialization can't fail"); +- + if (auto *C = dyn_cast(StoredVal)) + if (auto *FoldedStoredVal = ConstantFoldConstant(C, DL)) + StoredVal = FoldedStoredVal; +@@ -58,12 +53,12 @@ Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, + // Pointer to Pointer -> use bitcast. + if (StoredValTy->getScalarType()->isPointerTy() && + LoadedTy->getScalarType()->isPointerTy()) { +- StoredVal = IRB.CreateBitCast(StoredVal, LoadedTy); ++ StoredVal = Helper.CreateBitCast(StoredVal, LoadedTy); + } else { + // Convert source pointers to integers, which can be bitcast. + if (StoredValTy->getScalarType()->isPointerTy()) { + StoredValTy = DL.getIntPtrType(StoredValTy); +- StoredVal = IRB.CreatePtrToInt(StoredVal, StoredValTy); ++ StoredVal = Helper.CreatePtrToInt(StoredVal, StoredValTy); + } + + Type *TypeToCastTo = LoadedTy; +@@ -71,11 +66,11 @@ Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, + TypeToCastTo = DL.getIntPtrType(TypeToCastTo); + + if (StoredValTy != TypeToCastTo) +- StoredVal = IRB.CreateBitCast(StoredVal, TypeToCastTo); ++ StoredVal = Helper.CreateBitCast(StoredVal, TypeToCastTo); + + // Cast to pointer if the load needs a pointer type. + if (LoadedTy->getScalarType()->isPointerTy()) +- StoredVal = IRB.CreateIntToPtr(StoredVal, LoadedTy); ++ StoredVal = Helper.CreateIntToPtr(StoredVal, LoadedTy); + } + + if (auto *C = dyn_cast(StoredVal)) +@@ -84,7 +79,6 @@ Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, + + return StoredVal; + } +- + // If the loaded value is smaller than the available value, then we can + // extract out a piece from it. If the available value is too small, then we + // can't do anything. +@@ -94,13 +88,13 @@ Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, + // Convert source pointers to integers, which can be manipulated. + if (StoredValTy->getScalarType()->isPointerTy()) { + StoredValTy = DL.getIntPtrType(StoredValTy); +- StoredVal = IRB.CreatePtrToInt(StoredVal, StoredValTy); ++ StoredVal = Helper.CreatePtrToInt(StoredVal, StoredValTy); + } + + // Convert vectors and fp to integer, which can be manipulated. + if (!StoredValTy->isIntegerTy()) { + StoredValTy = IntegerType::get(StoredValTy->getContext(), StoredValSize); +- StoredVal = IRB.CreateBitCast(StoredVal, StoredValTy); ++ StoredVal = Helper.CreateBitCast(StoredVal, StoredValTy); + } + + // If this is a big-endian system, we need to shift the value down to the low +@@ -108,20 +102,21 @@ Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, + if (DL.isBigEndian()) { + uint64_t ShiftAmt = DL.getTypeStoreSizeInBits(StoredValTy) - + DL.getTypeStoreSizeInBits(LoadedTy); +- StoredVal = IRB.CreateLShr(StoredVal, ShiftAmt, "tmp"); ++ StoredVal = Helper.CreateLShr( ++ StoredVal, ConstantInt::get(StoredVal->getType(), ShiftAmt)); + } + + // Truncate the integer to the right size now. + Type *NewIntTy = IntegerType::get(StoredValTy->getContext(), LoadedValSize); +- StoredVal = IRB.CreateTrunc(StoredVal, NewIntTy, "trunc"); ++ StoredVal = Helper.CreateTruncOrBitCast(StoredVal, NewIntTy); + + if (LoadedTy != NewIntTy) { + // If the result is a pointer, inttoptr. + if (LoadedTy->getScalarType()->isPointerTy()) +- StoredVal = IRB.CreateIntToPtr(StoredVal, LoadedTy, "inttoptr"); ++ StoredVal = Helper.CreateIntToPtr(StoredVal, LoadedTy); + else + // Otherwise, bitcast. +- StoredVal = IRB.CreateBitCast(StoredVal, LoadedTy, "bitcast"); ++ StoredVal = Helper.CreateBitCast(StoredVal, LoadedTy); + } + + if (auto *C = dyn_cast(StoredVal)) +@@ -131,10 +126,21 @@ Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, + return StoredVal; + } + +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering memory write (store, +-/// memset, memcpy, memmove). This means that the write *may* provide bits used +-/// by the load but we can't be sure because the pointers don't mustalias. ++/// If we saw a store of a value to memory, and ++/// then a load from a must-aliased pointer of a different type, try to coerce ++/// the stored value. LoadedTy is the type of the load we want to replace. ++/// IRB is IRBuilder used to insert new instructions. ++/// ++/// If we can't do it, return null. ++Value *coerceAvailableValueToLoadType(Value *StoredVal, Type *LoadedTy, ++ IRBuilder<> &IRB, const DataLayout &DL) { ++ return coerceAvailableValueToLoadTypeHelper(StoredVal, LoadedTy, IRB, DL); ++} ++ ++/// This function is called when we have a memdep query of a load that ends up ++/// being a clobbering memory write (store, memset, memcpy, memmove). This ++/// means that the write *may* provide bits used by the load but we can't be ++/// sure because the pointers don't must-alias. + /// + /// Check this case to see if there is anything more we can do before we give + /// up. This returns -1 if we have to give up, or a byte number in the stored +@@ -291,13 +297,10 @@ int analyzeLoadFromClobberingMemInst(Type *LoadTy, Value *LoadPtr, + return -1; + } + +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering store. This means +-/// that the store provides bits used by the load but we the pointers don't +-/// mustalias. Check this case to see if there is anything more we can do +-/// before we give up. +-Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, +- Instruction *InsertPt, const DataLayout &DL) { ++template ++static T *getStoreValueForLoadHelper(T *SrcVal, unsigned Offset, Type *LoadTy, ++ HelperClass &Helper, ++ const DataLayout &DL) { + LLVMContext &Ctx = SrcVal->getType()->getContext(); + + // If two pointers are in the same address space, they have the same size, +@@ -311,17 +314,12 @@ Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, + + uint64_t StoreSize = (DL.getTypeSizeInBits(SrcVal->getType()) + 7) / 8; + uint64_t LoadSize = (DL.getTypeSizeInBits(LoadTy) + 7) / 8; +- +- IRBuilder<> Builder(InsertPt); +- + // Compute which bits of the stored value are being used by the load. Convert + // to an integer type to start with. + if (SrcVal->getType()->getScalarType()->isPointerTy()) +- SrcVal = +- Builder.CreatePtrToInt(SrcVal, DL.getIntPtrType(SrcVal->getType())); ++ SrcVal = Helper.CreatePtrToInt(SrcVal, DL.getIntPtrType(SrcVal->getType())); + if (!SrcVal->getType()->isIntegerTy()) +- SrcVal = +- Builder.CreateBitCast(SrcVal, IntegerType::get(Ctx, StoreSize * 8)); ++ SrcVal = Helper.CreateBitCast(SrcVal, IntegerType::get(Ctx, StoreSize * 8)); + + // Shift the bits to the least significant depending on endianness. + unsigned ShiftAmt; +@@ -329,25 +327,42 @@ Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, + ShiftAmt = Offset * 8; + else + ShiftAmt = (StoreSize - LoadSize - Offset) * 8; +- + if (ShiftAmt) +- SrcVal = Builder.CreateLShr(SrcVal, ShiftAmt); ++ SrcVal = Helper.CreateLShr(SrcVal, ++ ConstantInt::get(SrcVal->getType(), ShiftAmt)); + + if (LoadSize != StoreSize) +- SrcVal = Builder.CreateTrunc(SrcVal, IntegerType::get(Ctx, LoadSize * 8)); ++ SrcVal = Helper.CreateTruncOrBitCast(SrcVal, ++ IntegerType::get(Ctx, LoadSize * 8)); ++ return SrcVal; ++} ++ ++/// This function is called when we have a memdep query of a load that ends up ++/// being a clobbering store. This means that the store provides bits used by ++/// the load but the pointers don't must-alias. Check this case to see if ++/// there is anything more we can do before we give up. ++Value *getStoreValueForLoad(Value *SrcVal, unsigned Offset, Type *LoadTy, ++ Instruction *InsertPt, const DataLayout &DL) { + +- return coerceAvailableValueToLoadType(SrcVal, LoadTy, Builder, DL); ++ IRBuilder<> Builder(InsertPt); ++ SrcVal = getStoreValueForLoadHelper(SrcVal, Offset, LoadTy, Builder, DL); ++ return coerceAvailableValueToLoadTypeHelper(SrcVal, LoadTy, Builder, DL); + } + +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering load. This means +-/// that the load *may* provide bits used by the load but we can't be sure +-/// because the pointers don't mustalias. Check this case to see if there is +-/// anything more we can do before we give up. +-Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, +- Instruction *InsertPt) { ++Constant *getConstantStoreValueForLoad(Constant *SrcVal, unsigned Offset, ++ Type *LoadTy, const DataLayout &DL) { ++ ConstantFolder F; ++ SrcVal = getStoreValueForLoadHelper(SrcVal, Offset, LoadTy, F, DL); ++ return coerceAvailableValueToLoadTypeHelper(SrcVal, LoadTy, F, DL); ++} + +- const DataLayout &DL = SrcVal->getModule()->getDataLayout(); ++/// This function is called when we have a memdep query of a load that ends up ++/// being a clobbering load. This means that the load *may* provide bits used ++/// by the load but we can't be sure because the pointers don't must-alias. ++/// Check this case to see if there is anything more we can do before we give ++/// up. ++Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, ++ Instruction *InsertPt, const DataLayout &DL) { + // If Offset+LoadTy exceeds the size of SrcVal, then we must be wanting to + // widen SrcVal out to a larger load. + unsigned SrcValStoreSize = DL.getTypeStoreSize(SrcVal->getType()); +@@ -362,7 +377,6 @@ Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, + NewLoadSize = NextPowerOf2(NewLoadSize); + + Value *PtrVal = SrcVal->getPointerOperand(); +- + // Insert the new load after the old load. This ensures that subsequent + // memdep queries will find the new load. We can't easily remove the old + // load completely because it is already in the value numbering table. +@@ -393,44 +407,51 @@ Value *getLoadValueForLoad(LoadInst *SrcVal, unsigned Offset, Type *LoadTy, + return getStoreValueForLoad(SrcVal, Offset, LoadTy, InsertPt, DL); + } + +-/// This function is called when we have a +-/// memdep query of a load that ends up being a clobbering mem intrinsic. +-Value *getMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, +- Type *LoadTy, Instruction *InsertPt, +- const DataLayout &DL) { ++Constant *getConstantLoadValueForLoad(Constant *SrcVal, unsigned Offset, ++ Type *LoadTy, const DataLayout &DL) { ++ unsigned SrcValStoreSize = DL.getTypeStoreSize(SrcVal->getType()); ++ unsigned LoadSize = DL.getTypeStoreSize(LoadTy); ++ if (Offset + LoadSize > SrcValStoreSize) ++ return nullptr; ++ return getConstantStoreValueForLoad(SrcVal, Offset, LoadTy, DL); ++} ++ ++template ++T *getMemInstValueForLoadHelper(MemIntrinsic *SrcInst, unsigned Offset, ++ Type *LoadTy, HelperClass &Helper, ++ const DataLayout &DL) { + LLVMContext &Ctx = LoadTy->getContext(); + uint64_t LoadSize = DL.getTypeSizeInBits(LoadTy) / 8; + +- IRBuilder<> Builder(InsertPt); +- + // We know that this method is only called when the mem transfer fully + // provides the bits for the load. + if (MemSetInst *MSI = dyn_cast(SrcInst)) { + // memset(P, 'x', 1234) -> splat('x'), even if x is a variable, and + // independently of what the offset is. +- Value *Val = MSI->getValue(); ++ T *Val = cast(MSI->getValue()); + if (LoadSize != 1) +- Val = Builder.CreateZExt(Val, IntegerType::get(Ctx, LoadSize * 8)); +- +- Value *OneElt = Val; ++ Val = ++ Helper.CreateZExtOrBitCast(Val, IntegerType::get(Ctx, LoadSize * 8)); ++ T *OneElt = Val; + + // Splat the value out to the right number of bits. + for (unsigned NumBytesSet = 1; NumBytesSet != LoadSize;) { + // If we can double the number of bytes set, do it. + if (NumBytesSet * 2 <= LoadSize) { +- Value *ShVal = Builder.CreateShl(Val, NumBytesSet * 8); +- Val = Builder.CreateOr(Val, ShVal); ++ T *ShVal = Helper.CreateShl( ++ Val, ConstantInt::get(Val->getType(), NumBytesSet * 8)); ++ Val = Helper.CreateOr(Val, ShVal); + NumBytesSet <<= 1; + continue; + } + + // Otherwise insert one byte at a time. +- Value *ShVal = Builder.CreateShl(Val, 1 * 8); +- Val = Builder.CreateOr(OneElt, ShVal); ++ T *ShVal = Helper.CreateShl(Val, ConstantInt::get(Val->getType(), 1 * 8)); ++ Val = Helper.CreateOr(OneElt, ShVal); + ++NumBytesSet; + } + +- return coerceAvailableValueToLoadType(Val, LoadTy, Builder, DL); ++ return coerceAvailableValueToLoadTypeHelper(Val, LoadTy, Helper, DL); + } + + // Otherwise, this is a memcpy/memmove from a constant global. +@@ -449,5 +470,27 @@ Value *getMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, + Src = ConstantExpr::getBitCast(Src, PointerType::get(LoadTy, AS)); + return ConstantFoldLoadFromConstPtr(Src, LoadTy, DL); + } ++ ++/// This function is called when we have a ++/// memdep query of a load that ends up being a clobbering mem intrinsic. ++Value *getMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, ++ Type *LoadTy, Instruction *InsertPt, ++ const DataLayout &DL) { ++ IRBuilder<> Builder(InsertPt); ++ return getMemInstValueForLoadHelper>(SrcInst, Offset, ++ LoadTy, Builder, DL); ++} ++ ++Constant *getConstantMemInstValueForLoad(MemIntrinsic *SrcInst, unsigned Offset, ++ Type *LoadTy, const DataLayout &DL) { ++ // The only case analyzeLoadFromClobberingMemInst cannot be converted to a ++ // constant is when it's a memset of a non-constant. ++ if (auto *MSI = dyn_cast(SrcInst)) ++ if (!isa(MSI->getValue())) ++ return nullptr; ++ ConstantFolder F; ++ return getMemInstValueForLoadHelper(SrcInst, Offset, ++ LoadTy, F, DL); ++} + } // namespace VNCoercion + } // namespace llvm +-- +2.13.1 + diff --git a/deps/patches/llvm-Yet-another-fix.patch b/deps/patches/llvm-Yet-another-fix.patch new file mode 100644 index 0000000000000..39823be1cd918 --- /dev/null +++ b/deps/patches/llvm-Yet-another-fix.patch @@ -0,0 +1,40 @@ +From e92be5eb5c60dfdeb5d41d81c82f0aca0c1e4aa9 Mon Sep 17 00:00:00 2001 +From: Yichao Yu +Date: Sat, 17 Jun 2017 17:29:53 -0400 +Subject: [PATCH] 4.0 fix + +--- + lib/CodeGen/CodeGenPrepare.cpp | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp +index 44d6b3e264c..4177819e989 100644 +--- a/lib/CodeGen/CodeGenPrepare.cpp ++++ b/lib/CodeGen/CodeGenPrepare.cpp +@@ -4067,6 +4067,23 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr, + // non-integral pointers, so in that case bail out now. + if (DL->isNonIntegralPointerType(Addr->getType())) + return false; ++ if (AddrMode.BaseReg) { ++ Type *BaseTy = AddrMode.BaseReg->getType(); ++ if (BaseTy->isPointerTy() && DL->isNonIntegralPointerType(BaseTy)) { ++ return false; ++ } ++ } ++ if (AddrMode.Scale) { ++ Type *ScaleTy = AddrMode.ScaledReg->getType(); ++ if (ScaleTy->isPointerTy() && DL->isNonIntegralPointerType(ScaleTy)) { ++ return false; ++ } ++ } ++ if (AddrMode.BaseGV) { ++ if (DL->isNonIntegralPointerType(AddrMode.BaseGV->getType())) { ++ return false; ++ } ++ } + + DEBUG(dbgs() << "CGP: SINKING nonlocal addrmode: " << AddrMode << " for " + << *MemoryInst << "\n"); +-- +2.13.1 +