From c53addf38e24e4dafe992aafb3ae928bfa8fdb0a Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Mon, 22 May 2017 19:44:12 +0000 Subject: [PATCH 01/11] Vendor import of lld trunk r303571: https://llvm.org/svn/llvm-project/lld/trunk@303571 --- COFF/CMakeLists.txt | 2 - COFF/Config.h | 2 - COFF/DLL.cpp | 160 ++++------ COFF/DLL.h | 27 +- COFF/Driver.cpp | 93 +++++- COFF/Driver.h | 7 - COFF/DriverUtils.cpp | 4 +- COFF/InputFiles.cpp | 16 +- COFF/InputFiles.h | 7 +- COFF/Librarian.cpp | 511 ------------------------------ COFF/ModuleDef.cpp | 304 ------------------ COFF/Options.td | 1 - COFF/PDB.cpp | 15 +- COFF/SymbolTable.h | 1 - COFF/Writer.cpp | 52 +-- ELF/InputSection.cpp | 57 +++- ELF/InputSection.h | 2 + ELF/LinkerScript.cpp | 3 - ELF/MapFile.cpp | 18 +- ELF/MapFile.h | 6 +- ELF/Relocations.cpp | 4 + ELF/Relocations.h | 1 + ELF/SyntheticSections.cpp | 31 +- ELF/SyntheticSections.h | 12 +- ELF/Target.cpp | 3 + ELF/Writer.cpp | 41 +-- test/COFF/armnt-imports.test | 2 +- test/COFF/hello32.test | 7 +- test/COFF/imports.test | 8 +- test/COFF/invalid-debug-type.test | 2 +- test/COFF/options.test | 8 +- test/COFF/pdb-none.test | 2 +- test/COFF/pdb-options.test | 20 ++ test/COFF/pdb.test | 2 +- test/ELF/arm-sbrel32.s | 39 +++ 35 files changed, 385 insertions(+), 1085 deletions(-) delete mode 100644 COFF/Librarian.cpp delete mode 100644 COFF/ModuleDef.cpp create mode 100644 test/COFF/pdb-options.test create mode 100644 test/ELF/arm-sbrel32.s diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt index 8f24e36c0eca..14f553e540d9 100644 --- a/COFF/CMakeLists.txt +++ b/COFF/CMakeLists.txt @@ -14,11 +14,9 @@ add_lld_library(lldCOFF Error.cpp ICF.cpp InputFiles.cpp - Librarian.cpp LTO.cpp MapFile.cpp MarkLive.cpp - ModuleDef.cpp PDB.cpp Strings.cpp SymbolTable.cpp diff --git a/COFF/Config.h b/COFF/Config.h index fafd3bcde2e3..d859b1fbb7d9 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -155,7 +155,6 @@ struct Configuration { uint32_t MajorOSVersion = 6; uint32_t MinorOSVersion = 0; bool DynamicBase = true; - bool AllowBind = true; bool NxCompat = true; bool AllowIsolation = true; bool TerminalServerAware = true; @@ -164,7 +163,6 @@ struct Configuration { bool AppContainer = false; // This is for debugging. - bool DebugPdb = false; bool DumpPdb = false; }; diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp index f93dc5cde44c..3ac14e4ea2b0 100644 --- a/COFF/DLL.cpp +++ b/COFF/DLL.cpp @@ -100,13 +100,17 @@ class ImportDirectoryChunk : public Chunk { void writeTo(uint8_t *Buf) const override { auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); - E->ImportLookupTableRVA = LookupTab->getRVA(); E->NameRVA = DLLName->getRVA(); + + // The import descriptor table contains two pointers to + // the tables describing dllimported symbols. But the + // Windows loader actually uses only one. So we create + // only one table and set both fields to its address. + E->ImportLookupTableRVA = AddressTab->getRVA(); E->ImportAddressTableRVA = AddressTab->getRVA(); } Chunk *DLLName; - Chunk *LookupTab; Chunk *AddressTab; }; @@ -136,9 +140,9 @@ binImports(const std::vector &Imports) { M[Sym->getDLLName().lower()].push_back(Sym); std::vector> V; - for (auto &P : M) { + for (auto &KV : M) { // Sort symbols by name for each group. - std::vector &Syms = P.second; + std::vector &Syms = KV.second; std::sort(Syms.begin(), Syms.end(), [](DefinedImportData *A, DefinedImportData *B) { return A->getName() < B->getName(); @@ -383,21 +387,14 @@ uint64_t IdataContents::getIATSize() { // See Microsoft PE/COFF spec 5.4 for details. std::vector IdataContents::getChunks() { create(); - std::vector V; + // The loader assumes a specific order of data. // Add each type in the correct order. - for (std::unique_ptr &C : Dirs) - V.push_back(C.get()); - for (std::unique_ptr &C : Lookups) - V.push_back(C.get()); - for (std::unique_ptr &C : Addresses) - V.push_back(C.get()); - for (std::unique_ptr &C : Hints) - V.push_back(C.get()); - for (auto &P : DLLNames) { - std::unique_ptr &C = P.second; - V.push_back(C.get()); - } + std::vector V; + V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Addresses.begin(), Addresses.end()); + V.insert(V.end(), Hints.begin(), Hints.end()); + V.insert(V.end(), DLLNames.begin(), DLLNames.end()); return V; } @@ -406,65 +403,50 @@ void IdataContents::create() { // Create .idata contents for each DLL. for (std::vector &Syms : V) { - StringRef Name = Syms[0]->getDLLName(); - // Create lookup and address tables. If they have external names, // we need to create HintName chunks to store the names. // If they don't (if they are import-by-ordinals), we store only // ordinal values to the table. - size_t Base = Lookups.size(); + size_t Base = Addresses.size(); for (DefinedImportData *S : Syms) { uint16_t Ord = S->getOrdinal(); if (S->getExternalName().empty()) { - Lookups.push_back(make_unique(Ord)); - Addresses.push_back(make_unique(Ord)); + Addresses.push_back(make(Ord)); continue; } - auto C = make_unique(S->getExternalName(), Ord); - Lookups.push_back(make_unique(C.get())); - Addresses.push_back(make_unique(C.get())); - Hints.push_back(std::move(C)); + auto *C = make(S->getExternalName(), Ord); + Addresses.push_back(make(C)); + Hints.push_back(C); } // Terminate with null values. - Lookups.push_back(make_unique(ptrSize())); - Addresses.push_back(make_unique(ptrSize())); + Addresses.push_back(make(ptrSize())); for (int I = 0, E = Syms.size(); I < E; ++I) - Syms[I]->setLocation(Addresses[Base + I].get()); + Syms[I]->setLocation(Addresses[Base + I]); // Create the import table header. - if (!DLLNames.count(Name)) - DLLNames[Name] = make_unique(Name); - auto Dir = make_unique(DLLNames[Name].get()); - Dir->LookupTab = Lookups[Base].get(); - Dir->AddressTab = Addresses[Base].get(); - Dirs.push_back(std::move(Dir)); + DLLNames.push_back(make(Syms[0]->getDLLName())); + auto *Dir = make(DLLNames.back()); + Dir->AddressTab = Addresses[Base]; + Dirs.push_back(Dir); } // Add null terminator. - Dirs.push_back(make_unique(sizeof(ImportDirectoryTableEntry))); + Dirs.push_back(make(sizeof(ImportDirectoryTableEntry))); } std::vector DelayLoadContents::getChunks() { std::vector V; - for (std::unique_ptr &C : Dirs) - V.push_back(C.get()); - for (std::unique_ptr &C : Names) - V.push_back(C.get()); - for (std::unique_ptr &C : HintNames) - V.push_back(C.get()); - for (auto &P : DLLNames) { - std::unique_ptr &C = P.second; - V.push_back(C.get()); - } + V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Names.begin(), Names.end()); + V.insert(V.end(), HintNames.begin(), HintNames.end()); + V.insert(V.end(), DLLNames.begin(), DLLNames.end()); return V; } std::vector DelayLoadContents::getDataChunks() { std::vector V; - for (std::unique_ptr &C : ModuleHandles) - V.push_back(C.get()); - for (std::unique_ptr &C : Addresses) - V.push_back(C.get()); + V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); + V.insert(V.end(), Addresses.begin(), Addresses.end()); return V; } @@ -478,55 +460,51 @@ void DelayLoadContents::create(Defined *H) { // Create .didat contents for each DLL. for (std::vector &Syms : V) { - StringRef Name = Syms[0]->getDLLName(); - // Create the delay import table header. - if (!DLLNames.count(Name)) - DLLNames[Name] = make_unique(Name); - auto Dir = make_unique(DLLNames[Name].get()); + DLLNames.push_back(make(Syms[0]->getDLLName())); + auto *Dir = make(DLLNames.back()); size_t Base = Addresses.size(); for (DefinedImportData *S : Syms) { - Chunk *T = newThunkChunk(S, Dir.get()); - auto A = make_unique(T); - Addresses.push_back(std::move(A)); - Thunks.push_back(std::unique_ptr(T)); + Chunk *T = newThunkChunk(S, Dir); + auto *A = make(T); + Addresses.push_back(A); + Thunks.push_back(T); StringRef ExtName = S->getExternalName(); if (ExtName.empty()) { - Names.push_back(make_unique(S->getOrdinal())); + Names.push_back(make(S->getOrdinal())); } else { - auto C = make_unique(ExtName, 0); - Names.push_back(make_unique(C.get())); - HintNames.push_back(std::move(C)); + auto *C = make(ExtName, 0); + Names.push_back(make(C)); + HintNames.push_back(C); } } // Terminate with null values. - Addresses.push_back(make_unique(8)); - Names.push_back(make_unique(8)); + Addresses.push_back(make(8)); + Names.push_back(make(8)); for (int I = 0, E = Syms.size(); I < E; ++I) - Syms[I]->setLocation(Addresses[Base + I].get()); - auto *MH = new NullChunk(8); + Syms[I]->setLocation(Addresses[Base + I]); + auto *MH = make(8); MH->setAlign(8); - ModuleHandles.push_back(std::unique_ptr(MH)); + ModuleHandles.push_back(MH); // Fill the delay import table header fields. Dir->ModuleHandle = MH; - Dir->AddressTab = Addresses[Base].get(); - Dir->NameTab = Names[Base].get(); - Dirs.push_back(std::move(Dir)); + Dir->AddressTab = Addresses[Base]; + Dir->NameTab = Names[Base]; + Dirs.push_back(Dir); } // Add null terminator. - Dirs.push_back( - make_unique(sizeof(delay_import_directory_table_entry))); + Dirs.push_back(make(sizeof(delay_import_directory_table_entry))); } Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { switch (Config->Machine) { case AMD64: - return new ThunkChunkX64(S, Dir, Helper); + return make(S, Dir, Helper); case I386: - return new ThunkChunkX86(S, Dir, Helper); + return make(S, Dir, Helper); default: llvm_unreachable("unsupported machine type"); } @@ -537,34 +515,32 @@ EdataContents::EdataContents() { for (Export &E : Config->Exports) MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); - auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile)); - auto *AddressTab = new AddressTableChunk(MaxOrdinal); + auto *DLLName = make(sys::path::filename(Config->OutputFile)); + auto *AddressTab = make(MaxOrdinal); std::vector Names; for (Export &E : Config->Exports) if (!E.Noname) - Names.push_back(new StringChunk(E.ExportName)); + Names.push_back(make(E.ExportName)); std::vector Forwards; for (Export &E : Config->Exports) { if (E.ForwardTo.empty()) continue; - E.ForwardChunk = new StringChunk(E.ForwardTo); + E.ForwardChunk = make(E.ForwardTo); Forwards.push_back(E.ForwardChunk); } - auto *NameTab = new NamePointersChunk(Names); - auto *OrdinalTab = new ExportOrdinalChunk(Names.size()); - auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName, - AddressTab, NameTab, OrdinalTab); - Chunks.push_back(std::unique_ptr(Dir)); - Chunks.push_back(std::unique_ptr(DLLName)); - Chunks.push_back(std::unique_ptr(AddressTab)); - Chunks.push_back(std::unique_ptr(NameTab)); - Chunks.push_back(std::unique_ptr(OrdinalTab)); - for (Chunk *C : Names) - Chunks.push_back(std::unique_ptr(C)); - for (Chunk *C : Forwards) - Chunks.push_back(std::unique_ptr(C)); + auto *NameTab = make(Names); + auto *OrdinalTab = make(Names.size()); + auto *Dir = make(MaxOrdinal, Names.size(), DLLName, + AddressTab, NameTab, OrdinalTab); + Chunks.push_back(Dir); + Chunks.push_back(DLLName); + Chunks.push_back(AddressTab); + Chunks.push_back(NameTab); + Chunks.push_back(OrdinalTab); + Chunks.insert(Chunks.end(), Names.begin(), Names.end()); + Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); } } // namespace coff diff --git a/COFF/DLL.h b/COFF/DLL.h index 83a12df185c2..939771b3290c 100644 --- a/COFF/DLL.h +++ b/COFF/DLL.h @@ -35,11 +35,10 @@ class IdataContents { void create(); std::vector Imports; - std::vector> Dirs; - std::vector> Lookups; - std::vector> Addresses; - std::vector> Hints; - std::map> DLLNames; + std::vector Dirs; + std::vector Addresses; + std::vector Hints; + std::vector DLLNames; }; // Windows-specific. @@ -51,7 +50,7 @@ class DelayLoadContents { void create(Defined *Helper); std::vector getChunks(); std::vector getDataChunks(); - std::vector> &getCodeChunks() { return Thunks; } + ArrayRef getCodeChunks() { return Thunks; } uint64_t getDirRVA() { return Dirs[0]->getRVA(); } uint64_t getDirSize(); @@ -61,13 +60,13 @@ class DelayLoadContents { Defined *Helper; std::vector Imports; - std::vector> Dirs; - std::vector> ModuleHandles; - std::vector> Addresses; - std::vector> Names; - std::vector> HintNames; - std::vector> Thunks; - std::map> DLLNames; + std::vector Dirs; + std::vector ModuleHandles; + std::vector Addresses; + std::vector Names; + std::vector HintNames; + std::vector Thunks; + std::vector DLLNames; }; // Windows-specific. @@ -75,7 +74,7 @@ class DelayLoadContents { class EdataContents { public: EdataContents(); - std::vector> Chunks; + std::vector Chunks; }; } // namespace coff diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 4c0ea44b875e..d871f942737d 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -19,6 +19,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/COFFModuleDefinition.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -35,6 +37,7 @@ #include using namespace llvm; +using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; using llvm::sys::fs::file_magic; @@ -97,12 +100,11 @@ static std::future createFutureForFile(std::string Path) { MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr MB) { MemoryBufferRef MBRef = *MB; - OwningMBs.push_back(std::move(MB)); + make>(std::move(MB)); // take ownership if (Driver->Tar) Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), MBRef.getBuffer()); - return MBRef; } @@ -420,6 +422,84 @@ static std::string getMapFile(const opt::InputArgList &Args) { return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); } +static std::string getImplibPath() { + if (!Config->Implib.empty()) + return Config->Implib; + SmallString<128> Out = StringRef(Config->OutputFile); + sys::path::replace_extension(Out, ".lib"); + return Out.str(); +} + +std::vector createCOFFShortExportFromConfig() { + std::vector Exports; + for (Export &E1 : Config->Exports) { + COFFShortExport E2; + E2.Name = E1.Name; + E2.ExtName = E1.ExtName; + E2.Ordinal = E1.Ordinal; + E2.Noname = E1.Noname; + E2.Data = E1.Data; + E2.Private = E1.Private; + E2.Constant = E1.Constant; + Exports.push_back(E2); + } + return Exports; +} + +static void createImportLibrary() { + std::vector Exports = createCOFFShortExportFromConfig(); + std::string DLLName = sys::path::filename(Config->OutputFile); + std::string Path = getImplibPath(); + writeImportLibrary(DLLName, Path, Exports, Config->Machine); +} + +static void parseModuleDefs(StringRef Path) { + std::unique_ptr MB = check( + MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); + MemoryBufferRef MBRef = MB->getMemBufferRef(); + + Expected Def = + parseCOFFModuleDefinition(MBRef, Config->Machine); + if (!Def) + fatal(errorToErrorCode(Def.takeError()).message()); + + COFFModuleDefinition &M = *Def; + if (Config->OutputFile.empty()) + Config->OutputFile = Saver.save(M.OutputFile); + + if (M.ImageBase) + Config->ImageBase = M.ImageBase; + if (M.StackReserve) + Config->StackReserve = M.StackReserve; + if (M.StackCommit) + Config->StackCommit = M.StackCommit; + if (M.HeapReserve) + Config->HeapReserve = M.HeapReserve; + if (M.HeapCommit) + Config->HeapCommit = M.HeapCommit; + if (M.MajorImageVersion) + Config->MajorImageVersion = M.MajorImageVersion; + if (M.MinorImageVersion) + Config->MinorImageVersion = M.MinorImageVersion; + if (M.MajorOSVersion) + Config->MajorOSVersion = M.MajorOSVersion; + if (M.MinorOSVersion) + Config->MinorOSVersion = M.MinorOSVersion; + + for (COFFShortExport E1 : M.Exports) { + Export E2; + E2.Name = Saver.save(E1.Name); + if (E1.isWeak()) + E2.ExtName = Saver.save(E1.ExtName); + E2.Ordinal = E1.Ordinal; + E2.Noname = E1.Noname; + E2.Data = E1.Data; + E2.Private = E1.Private; + E2.Constant = E1.Constant; + Config->Exports.push_back(E2); + } +} + std::vector getArchiveMembers(Archive *File) { std::vector V; Error Err = Error::success(); @@ -821,8 +901,6 @@ void LinkerDriver::link(ArrayRef ArgsArr) { Config->ManifestInput.push_back(Arg->getValue()); // Handle miscellaneous boolean flags. - if (Args.hasArg(OPT_allowbind_no)) - Config->AllowBind = false; if (Args.hasArg(OPT_allowisolation_no)) Config->AllowIsolation = false; if (Args.hasArg(OPT_dynamicbase_no)) @@ -834,7 +912,6 @@ void LinkerDriver::link(ArrayRef ArgsArr) { if (Args.hasArg(OPT_nosymtab)) Config->WriteSymtab = false; Config->DumpPdb = Args.hasArg(OPT_dumppdb); - Config->DebugPdb = Args.hasArg(OPT_debugpdb); Config->MapFile = getMapFile(Args); @@ -916,9 +993,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { // Handle /def if (auto *Arg = Args.getLastArg(OPT_deffile)) { // parseModuleDefs mutates Config object. - parseModuleDefs( - takeBuffer(check(MemoryBuffer::getFile(Arg->getValue()), - Twine("could not open ") + Arg->getValue()))); + parseModuleDefs(Arg->getValue()); } // Handle /delayload @@ -1038,7 +1113,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { // need to create a .lib file. if (!Config->Exports.empty() || Config->DLL) { fixupExports(); - writeImportLibrary(); + createImportLibrary(); assignExportOrdinals(); } diff --git a/COFF/Driver.h b/COFF/Driver.h index ad725625e030..3eb950cca25c 100644 --- a/COFF/Driver.h +++ b/COFF/Driver.h @@ -119,18 +119,11 @@ class LinkerDriver { void enqueueTask(std::function Task); bool run(); - // Driver is the owner of all opened files. - // InputFiles have MemoryBufferRefs to them. - std::vector> OwningMBs; - std::list> TaskQueue; std::vector FilePaths; std::vector Resources; }; -void parseModuleDefs(MemoryBufferRef MB); -void writeImportLibrary(); - // Functions below this line are defined in DriverUtils.cpp. void printHelp(const char *Argv0); diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index 252590c7d870..ee4bd0f6b22c 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -43,7 +43,7 @@ namespace { class Executor { public: - explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {} + explicit Executor(StringRef S) : Prog(Saver.save(S)) {} void add(StringRef S) { Args.push_back(Saver.save(S)); } void add(std::string &S) { Args.push_back(Saver.save(S)); } void add(Twine S) { Args.push_back(Saver.save(S)); } @@ -67,8 +67,6 @@ class Executor { } private: - BumpPtrAllocator Alloc; - StringSaver Saver; StringRef Prog; std::vector Args; }; diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index df3b6a032cf8..6e6465cd5d62 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -137,13 +137,13 @@ void ObjectFile::initializeChunks() { // CodeView sections are stored to a different vector because they are // not linked in the regular manner. if (Name == ".debug" || Name.startswith(".debug$")) { - DebugChunks.push_back(new (Alloc) SectionChunk(this, Sec)); + DebugChunks.push_back(make(this, Sec)); continue; } if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; - auto *C = new (Alloc) SectionChunk(this, Sec); + auto *C = make(this, Sec); Chunks.push_back(C); SparseChunks[I] = C; } @@ -200,7 +200,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, bool IsFirst) { StringRef Name; if (Sym.isCommon()) { - auto *C = new (Alloc) CommonChunk(Sym); + auto *C = make(Sym); Chunks.push_back(C); COFFObj->getSymbolName(Sym, Name); Symbol *S = @@ -221,7 +221,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, if (Sym.isExternal()) return Symtab->addAbsolute(Name, Sym)->body(); else - return new (Alloc) DefinedAbsolute(Name, Sym); + return make(Name, Sym); } int32_t SectionNumber = Sym.getSectionNumber(); if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) @@ -258,8 +258,8 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC); B = cast(S->body()); } else - B = new (Alloc) DefinedRegular(this, /*Name*/ "", SC->isCOMDAT(), - /*IsExternal*/ false, Sym.getGeneric(), SC); + B = make(this, /*Name*/ "", SC->isCOMDAT(), + /*IsExternal*/ false, Sym.getGeneric(), SC); if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) SC->setSymbol(B); @@ -301,8 +301,8 @@ void ImportFile::parse() { fatal("broken import library"); // Read names and create an __imp_ symbol. - StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr))); - StringRef ImpName = StringAlloc.save("__imp_" + Name); + StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr))); + StringRef ImpName = Saver.save("__imp_" + Name); const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; DLLName = StringRef(NameStart); StringRef ExtName; diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index a2fd3f59ad70..9e32b3b9f9d6 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -130,7 +130,6 @@ class ObjectFile : public InputFile { SymbolBody *createUndefined(COFFSymbolRef Sym); std::unique_ptr COFFObj; - llvm::BumpPtrAllocator Alloc; const coff_section *SXData = nullptr; // List of all chunks defined by this file. This includes both section @@ -162,8 +161,7 @@ class ObjectFile : public InputFile { // for details about the format. class ImportFile : public InputFile { public: - explicit ImportFile(MemoryBufferRef M) - : InputFile(ImportKind, M), StringAlloc(StringAllocAux) {} + explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ImportKind; } DefinedImportData *ImpSym = nullptr; @@ -174,9 +172,6 @@ class ImportFile : public InputFile { private: void parse() override; - llvm::BumpPtrAllocator StringAllocAux; - llvm::StringSaver StringAlloc; - public: StringRef ExternalName; const coff_import_header *Hdr; diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp deleted file mode 100644 index 91316ee6b0c9..000000000000 --- a/COFF/Librarian.cpp +++ /dev/null @@ -1,511 +0,0 @@ -//===- Librarian.cpp ------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains functions for the Librarian. The librarian creates and -// manages libraries of the Common Object File Format (COFF) object files. It -// primarily is used for creating static libraries and import libraries. -// -//===----------------------------------------------------------------------===// - -#include "Config.h" -#include "Driver.h" -#include "Error.h" -#include "Symbols.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/ArchiveWriter.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/Path.h" - -#include - -using namespace lld::coff; -using namespace llvm::COFF; -using namespace llvm::object; -using namespace llvm; - -static bool is32bit() { - switch (Config->Machine) { - default: - llvm_unreachable("unsupported machine"); - case IMAGE_FILE_MACHINE_AMD64: - return false; - case IMAGE_FILE_MACHINE_ARMNT: - case IMAGE_FILE_MACHINE_I386: - return true; - } -} - -static uint16_t getImgRelRelocation() { - switch (Config->Machine) { - default: - llvm_unreachable("unsupported machine"); - case IMAGE_FILE_MACHINE_AMD64: - return IMAGE_REL_AMD64_ADDR32NB; - case IMAGE_FILE_MACHINE_ARMNT: - return IMAGE_REL_ARM_ADDR32NB; - case IMAGE_FILE_MACHINE_I386: - return IMAGE_REL_I386_DIR32NB; - } -} - -template static void append(std::vector &B, const T &Data) { - size_t S = B.size(); - B.resize(S + sizeof(T)); - memcpy(&B[S], &Data, sizeof(T)); -} - -static void writeStringTable(std::vector &B, - ArrayRef Strings) { - // The COFF string table consists of a 4-byte value which is the size of the - // table, including the length field itself. This value is followed by the - // string content itself, which is an array of null-terminated C-style - // strings. The termination is important as they are referenced to by offset - // by the symbol entity in the file format. - - std::vector::size_type Pos = B.size(); - std::vector::size_type Offset = B.size(); - - // Skip over the length field, we will fill it in later as we will have - // computed the length while emitting the string content itself. - Pos += sizeof(uint32_t); - - for (const auto &S : Strings) { - B.resize(Pos + S.length() + 1); - strcpy(reinterpret_cast(&B[Pos]), S.c_str()); - Pos += S.length() + 1; - } - - // Backfill the length of the table now that it has been computed. - support::ulittle32_t Length(B.size() - Offset); - memcpy(&B[Offset], &Length, sizeof(Length)); -} - -static std::string getImplibPath() { - if (!Config->Implib.empty()) - return Config->Implib; - SmallString<128> Out = StringRef(Config->OutputFile); - sys::path::replace_extension(Out, ".lib"); - return Out.str(); -} - -static ImportNameType getNameType(StringRef Sym, StringRef ExtName) { - if (Sym != ExtName) - return IMPORT_NAME_UNDECORATE; - if (Config->Machine == I386 && Sym.startswith("_")) - return IMPORT_NAME_NOPREFIX; - return IMPORT_NAME; -} - -static std::string replace(StringRef S, StringRef From, StringRef To) { - size_t Pos = S.find(From); - - // From and To may be mangled, but substrings in S may not. - if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) { - From = From.substr(1); - To = To.substr(1); - Pos = S.find(From); - } - - if (Pos == StringRef::npos) { - error(S + ": replacing '" + From + "' with '" + To + "' failed"); - return ""; - } - return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); -} - -static const std::string NullImportDescriptorSymbolName = - "__NULL_IMPORT_DESCRIPTOR"; - -namespace { -// This class constructs various small object files necessary to support linking -// symbols imported from a DLL. The contents are pretty strictly defined and -// nearly entirely static. The details of the structures files are defined in -// WINNT.h and the PE/COFF specification. -class ObjectFactory { - using u16 = support::ulittle16_t; - using u32 = support::ulittle32_t; - - BumpPtrAllocator Alloc; - StringRef DLLName; - StringRef Library; - std::string ImportDescriptorSymbolName; - std::string NullThunkSymbolName; - -public: - ObjectFactory(StringRef S) - : DLLName(S), Library(S.drop_back(4)), - ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()), - NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {} - - // Creates an Import Descriptor. This is a small object file which contains a - // reference to the terminators and contains the library name (entry) for the - // import name table. It will force the linker to construct the necessary - // structure to import symbols from the DLL. - NewArchiveMember createImportDescriptor(std::vector &Buffer); - - // Creates a NULL import descriptor. This is a small object file whcih - // contains a NULL import descriptor. It is used to terminate the imports - // from a specific DLL. - NewArchiveMember createNullImportDescriptor(std::vector &Buffer); - - // Create a NULL Thunk Entry. This is a small object file which contains a - // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It - // is used to terminate the IAT and ILT. - NewArchiveMember createNullThunk(std::vector &Buffer); - - // Create a short import file which is described in PE/COFF spec 7. Import - // Library Format. - NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, - ImportType Type, ImportNameType NameType); -}; -} - -NewArchiveMember -ObjectFactory::createImportDescriptor(std::vector &Buffer) { - static const uint32_t NumberOfSections = 2; - static const uint32_t NumberOfSymbols = 7; - static const uint32_t NumberOfRelocations = 3; - - // COFF Header - coff_file_header Header{ - u16(Config->Machine), u16(NumberOfSections), u32(0), - u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + - // .idata$2 - sizeof(coff_import_directory_table_entry) + - NumberOfRelocations * sizeof(coff_relocation) + - // .idata$4 - (DLLName.size() + 1)), - u32(NumberOfSymbols), u16(0), - u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0), - }; - append(Buffer, Header); - - // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { - {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}, - u32(0), - u32(0), - u32(sizeof(coff_import_directory_table_entry)), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + - sizeof(coff_import_directory_table_entry)), - u32(0), - u16(NumberOfRelocations), - u16(0), - u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | - IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, - {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}, - u32(0), - u32(0), - u32(DLLName.size() + 1), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + - sizeof(coff_import_directory_table_entry) + - NumberOfRelocations * sizeof(coff_relocation)), - u32(0), - u32(0), - u16(0), - u16(0), - u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | - IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, - }; - append(Buffer, SectionTable); - - // .idata$2 - static const coff_import_directory_table_entry ImportDescriptor{ - u32(0), u32(0), u32(0), u32(0), u32(0), - }; - append(Buffer, ImportDescriptor); - - static const coff_relocation RelocationTable[NumberOfRelocations] = { - {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2), - u16(getImgRelRelocation())}, - {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)), - u32(3), u16(getImgRelRelocation())}, - {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)), - u32(4), u16(getImgRelRelocation())}, - }; - append(Buffer, RelocationTable); - - // .idata$6 - auto S = Buffer.size(); - Buffer.resize(S + DLLName.size() + 1); - memcpy(&Buffer[S], DLLName.data(), DLLName.size()); - Buffer[S + DLLName.size()] = '\0'; - - // Symbol Table - coff_symbol16 SymbolTable[NumberOfSymbols] = { - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(1), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}}, - u32(0), - u16(1), - u16(0), - IMAGE_SYM_CLASS_SECTION, - 0}, - {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}}, - u32(0), - u16(2), - u16(0), - IMAGE_SYM_CLASS_STATIC, - 0}, - {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}}, - u32(0), - u16(0), - u16(0), - IMAGE_SYM_CLASS_SECTION, - 0}, - {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}}, - u32(0), - u16(0), - u16(0), - IMAGE_SYM_CLASS_SECTION, - 0}, - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(0), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(0), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - }; - reinterpret_cast(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - reinterpret_cast(SymbolTable[5].Name).Offset = - sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1; - reinterpret_cast(SymbolTable[6].Name).Offset = - sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 + - NullImportDescriptorSymbolName.length() + 1; - append(Buffer, SymbolTable); - - // String Table - writeStringTable(Buffer, - {ImportDescriptorSymbolName, NullImportDescriptorSymbolName, - NullThunkSymbolName}); - - StringRef F{reinterpret_cast(Buffer.data()), Buffer.size()}; - return {MemoryBufferRef(F, DLLName)}; -} - -NewArchiveMember -ObjectFactory::createNullImportDescriptor(std::vector &Buffer) { - static const uint32_t NumberOfSections = 1; - static const uint32_t NumberOfSymbols = 1; - - // COFF Header - coff_file_header Header{ - u16(Config->Machine), u16(NumberOfSections), u32(0), - u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + - // .idata$3 - sizeof(coff_import_directory_table_entry)), - u32(NumberOfSymbols), u16(0), - u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0), - }; - append(Buffer, Header); - - // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { - {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'}, - u32(0), - u32(0), - u32(sizeof(coff_import_directory_table_entry)), - u32(sizeof(coff_file_header) + - (NumberOfSections * sizeof(coff_section))), - u32(0), - u32(0), - u16(0), - u16(0), - u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | - IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, - }; - append(Buffer, SectionTable); - - // .idata$3 - static const coff_import_directory_table_entry ImportDescriptor{ - u32(0), u32(0), u32(0), u32(0), u32(0), - }; - append(Buffer, ImportDescriptor); - - // Symbol Table - coff_symbol16 SymbolTable[NumberOfSymbols] = { - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(1), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - }; - reinterpret_cast(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - append(Buffer, SymbolTable); - - // String Table - writeStringTable(Buffer, {NullImportDescriptorSymbolName}); - - StringRef F{reinterpret_cast(Buffer.data()), Buffer.size()}; - return {MemoryBufferRef(F, DLLName)}; -} - -NewArchiveMember ObjectFactory::createNullThunk(std::vector &Buffer) { - static const uint32_t NumberOfSections = 2; - static const uint32_t NumberOfSymbols = 1; - uint32_t VASize = is32bit() ? 4 : 8; - - // COFF Header - coff_file_header Header{ - u16(Config->Machine), u16(NumberOfSections), u32(0), - u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + - // .idata$5 - VASize + - // .idata$4 - VASize), - u32(NumberOfSymbols), u16(0), - u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0), - }; - append(Buffer, Header); - - // Section Header Table - static const coff_section SectionTable[NumberOfSections] = { - {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, - u32(0), - u32(0), - u32(VASize), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), - u32(0), - u32(0), - u16(0), - u16(0), - u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) | - IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | - IMAGE_SCN_MEM_WRITE)}, - {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, - u32(0), - u32(0), - u32(VASize), - u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + - VASize), - u32(0), - u32(0), - u16(0), - u16(0), - u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) | - IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | - IMAGE_SCN_MEM_WRITE)}, - }; - append(Buffer, SectionTable); - - // .idata$5, ILT - append(Buffer, u32(0)); - if (!is32bit()) - append(Buffer, u32(0)); - - // .idata$4, IAT - append(Buffer, u32(0)); - if (!is32bit()) - append(Buffer, u32(0)); - - // Symbol Table - coff_symbol16 SymbolTable[NumberOfSymbols] = { - {{{0, 0, 0, 0, 0, 0, 0, 0}}, - u32(0), - u16(1), - u16(0), - IMAGE_SYM_CLASS_EXTERNAL, - 0}, - }; - reinterpret_cast(SymbolTable[0].Name).Offset = - sizeof(uint32_t); - append(Buffer, SymbolTable); - - // String Table - writeStringTable(Buffer, {NullThunkSymbolName}); - - StringRef F{reinterpret_cast(Buffer.data()), Buffer.size()}; - return {MemoryBufferRef{F, DLLName}}; -} - -NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, - uint16_t Ordinal, - ImportType ImportType, - ImportNameType NameType) { - size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs - size_t Size = sizeof(coff_import_header) + ImpSize; - char *Buf = Alloc.Allocate(Size); - memset(Buf, 0, Size); - char *P = Buf; - - // Write short import library. - auto *Imp = reinterpret_cast(P); - P += sizeof(*Imp); - Imp->Sig2 = 0xFFFF; - Imp->Machine = Config->Machine; - Imp->SizeOfData = ImpSize; - if (Ordinal > 0) - Imp->OrdinalHint = Ordinal; - Imp->TypeInfo = (NameType << 2) | ImportType; - - // Write symbol name and DLL name. - memcpy(P, Sym.data(), Sym.size()); - P += Sym.size() + 1; - memcpy(P, DLLName.data(), DLLName.size()); - - return {MemoryBufferRef(StringRef(Buf, Size), DLLName)}; -} - -// Creates an import library for a DLL. In this function, we first -// create an empty import library using lib.exe and then adds short -// import files to that file. -void lld::coff::writeImportLibrary() { - std::vector Members; - - std::string Path = getImplibPath(); - std::string DLLName = sys::path::filename(Config->OutputFile); - ObjectFactory OF(DLLName); - - std::vector ImportDescriptor; - Members.push_back(OF.createImportDescriptor(ImportDescriptor)); - - std::vector NullImportDescriptor; - Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor)); - - std::vector NullThunk; - Members.push_back(OF.createNullThunk(NullThunk)); - - for (Export &E : Config->Exports) { - if (E.Private) - continue; - - ImportType ImportType = IMPORT_CODE; - if (E.Data) - ImportType = IMPORT_DATA; - if (E.Constant) - ImportType = IMPORT_CONST; - - ImportNameType NameType = getNameType(E.SymbolName, E.Name); - std::string Name = E.ExtName.empty() - ? std::string(E.SymbolName) - : replace(E.SymbolName, E.Name, E.ExtName); - Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, - NameType)); - } - - std::pair Result = - writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU, - /*Deterministic*/ true, /*Thin*/ false); - if (auto EC = Result.second) - fatal(EC, "failed to write " + Path); -} diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp deleted file mode 100644 index 740ce867a7c4..000000000000 --- a/COFF/ModuleDef.cpp +++ /dev/null @@ -1,304 +0,0 @@ -//===- COFF/ModuleDef.cpp -------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Windows-specific. -// A parser for the module-definition file (.def file). -// Parsed results are directly written to Config global variable. -// -// The format of module-definition files are described in this document: -// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx -// -//===----------------------------------------------------------------------===// - -#include "Config.h" -#include "Error.h" -#include "Memory.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/StringSaver.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace llvm; - -namespace lld { -namespace coff { -namespace { - -enum Kind { - Unknown, - Eof, - Identifier, - Comma, - Equal, - KwBase, - KwConstant, - KwData, - KwExports, - KwHeapsize, - KwLibrary, - KwName, - KwNoname, - KwPrivate, - KwStacksize, - KwVersion, -}; - -struct Token { - explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {} - Kind K; - StringRef Value; -}; - -static bool isDecorated(StringRef Sym) { - return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); -} - -class Lexer { -public: - explicit Lexer(StringRef S) : Buf(S) {} - - Token lex() { - Buf = Buf.trim(); - if (Buf.empty()) - return Token(Eof); - - switch (Buf[0]) { - case '\0': - return Token(Eof); - case ';': { - size_t End = Buf.find('\n'); - Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); - return lex(); - } - case '=': - Buf = Buf.drop_front(); - return Token(Equal, "="); - case ',': - Buf = Buf.drop_front(); - return Token(Comma, ","); - case '"': { - StringRef S; - std::tie(S, Buf) = Buf.substr(1).split('"'); - return Token(Identifier, S); - } - default: { - size_t End = Buf.find_first_of("=,\r\n \t\v"); - StringRef Word = Buf.substr(0, End); - Kind K = llvm::StringSwitch(Word) - .Case("BASE", KwBase) - .Case("CONSTANT", KwConstant) - .Case("DATA", KwData) - .Case("EXPORTS", KwExports) - .Case("HEAPSIZE", KwHeapsize) - .Case("LIBRARY", KwLibrary) - .Case("NAME", KwName) - .Case("NONAME", KwNoname) - .Case("PRIVATE", KwPrivate) - .Case("STACKSIZE", KwStacksize) - .Case("VERSION", KwVersion) - .Default(Identifier); - Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); - return Token(K, Word); - } - } - } - -private: - StringRef Buf; -}; - -class Parser { -public: - explicit Parser(StringRef S) : Lex(S) {} - - void parse() { - do { - parseOne(); - } while (Tok.K != Eof); - } - -private: - void read() { - if (Stack.empty()) { - Tok = Lex.lex(); - return; - } - Tok = Stack.back(); - Stack.pop_back(); - } - - void readAsInt(uint64_t *I) { - read(); - if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I)) - fatal("integer expected"); - } - - void expect(Kind Expected, StringRef Msg) { - read(); - if (Tok.K != Expected) - fatal(Msg); - } - - void unget() { Stack.push_back(Tok); } - - void parseOne() { - read(); - switch (Tok.K) { - case Eof: - return; - case KwExports: - for (;;) { - read(); - if (Tok.K != Identifier) { - unget(); - return; - } - parseExport(); - } - case KwHeapsize: - parseNumbers(&Config->HeapReserve, &Config->HeapCommit); - return; - case KwStacksize: - parseNumbers(&Config->StackReserve, &Config->StackCommit); - return; - case KwLibrary: - case KwName: { - bool IsDll = Tok.K == KwLibrary; // Check before parseName. - std::string Name; - parseName(&Name, &Config->ImageBase); - - // Append the appropriate file extension if not already present. - StringRef Ext = IsDll ? ".dll" : ".exe"; - if (!StringRef(Name).endswith_lower(Ext)) - Name += Ext; - - // Set the output file, but don't override /out if it was already passed. - if (Config->OutputFile.empty()) - Config->OutputFile = Name; - return; - } - case KwVersion: - parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion); - return; - default: - fatal("unknown directive: " + Tok.Value); - } - } - - void parseExport() { - Export E; - E.Name = Tok.Value; - read(); - if (Tok.K == Equal) { - read(); - if (Tok.K != Identifier) - fatal("identifier expected, but got " + Tok.Value); - E.ExtName = E.Name; - E.Name = Tok.Value; - } else { - unget(); - } - - if (Config->Machine == I386) { - if (!isDecorated(E.Name)) - E.Name = Saver.save("_" + E.Name); - if (!E.ExtName.empty() && !isDecorated(E.ExtName)) - E.ExtName = Saver.save("_" + E.ExtName); - } - - for (;;) { - read(); - if (Tok.K == Identifier && Tok.Value[0] == '@') { - Tok.Value.drop_front().getAsInteger(10, E.Ordinal); - read(); - if (Tok.K == KwNoname) { - E.Noname = true; - } else { - unget(); - } - continue; - } - if (Tok.K == KwData) { - E.Data = true; - continue; - } - if (Tok.K == KwConstant) { - warn("CONSTANT keyword is obsolete; use DATA"); - E.Constant = true; - continue; - } - if (Tok.K == KwPrivate) { - E.Private = true; - continue; - } - unget(); - Config->Exports.push_back(E); - return; - } - } - - // HEAPSIZE/STACKSIZE reserve[,commit] - void parseNumbers(uint64_t *Reserve, uint64_t *Commit) { - readAsInt(Reserve); - read(); - if (Tok.K != Comma) { - unget(); - Commit = nullptr; - return; - } - readAsInt(Commit); - } - - // NAME outputPath [BASE=address] - void parseName(std::string *Out, uint64_t *Baseaddr) { - read(); - if (Tok.K == Identifier) { - *Out = Tok.Value; - } else { - *Out = ""; - unget(); - return; - } - read(); - if (Tok.K == KwBase) { - expect(Equal, "'=' expected"); - readAsInt(Baseaddr); - } else { - unget(); - *Baseaddr = 0; - } - } - - // VERSION major[.minor] - void parseVersion(uint32_t *Major, uint32_t *Minor) { - read(); - if (Tok.K != Identifier) - fatal("identifier expected, but got " + Tok.Value); - StringRef V1, V2; - std::tie(V1, V2) = Tok.Value.split('.'); - if (V1.getAsInteger(10, *Major)) - fatal("integer expected, but got " + Tok.Value); - if (V2.empty()) - *Minor = 0; - else if (V2.getAsInteger(10, *Minor)) - fatal("integer expected, but got " + Tok.Value); - } - - Lexer Lex; - Token Tok; - std::vector Stack; -}; - -} // anonymous namespace - -void parseModuleDefs(MemoryBufferRef MB) { Parser(MB.getBuffer()).parse(); } - -} // namespace coff -} // namespace lld diff --git a/COFF/Options.td b/COFF/Options.td index 7b5573b31cd3..14a1aa04afd6 100644 --- a/COFF/Options.td +++ b/COFF/Options.td @@ -102,7 +102,6 @@ def nosymtab : F<"nosymtab">; def msvclto : F<"msvclto">; // Flags for debugging -def debugpdb : F<"debugpdb">; def dumppdb : Joined<["/", "-"], "dumppdb">; def lldmap : F<"lldmap">; def lldmap_file : Joined<["/", "-"], "lldmap:">; diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index 61b0c64de3a8..0266148cc6c9 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -14,7 +14,8 @@ #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" @@ -107,6 +108,7 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, BinaryByteStream Stream(Data, support::little); codeview::CVTypeArray Types; BinaryStreamReader Reader(Stream); + SmallVector SourceToDest; // Follow type servers. If the same type server is encountered more than // once for this instance of `PDBTypeServerHandler` (for example if many // object files reference the same TypeServer), the types from the @@ -115,8 +117,8 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); - if (auto Err = - codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types)) + if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest, + &Handler, Types)) fatal(Err, "codeview::mergeTypeStreams failed"); } @@ -133,12 +135,11 @@ static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) { if (Data.empty()) return; - TypeDatabase TDB(0); - TypeDumpVisitor TDV(TDB, &W, false); + LazyRandomTypeCollection Types(Data, 100); + TypeDumpVisitor TDV(Types, &W, false); // Use a default implementation that does not follow type servers and instead // just dumps the contents of the TypeServer2 record. - CVTypeDumper TypeDumper(TDB); - if (auto EC = TypeDumper.dump(Data, TDV)) + if (auto EC = codeview::visitTypeStream(Types, TDV)) fatal(EC, "CVTypeDumper::dump failed"); } diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h index bf8d6618d964..0aa8a4593b5c 100644 --- a/COFF/SymbolTable.h +++ b/COFF/SymbolTable.h @@ -15,7 +15,6 @@ #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" -#include "llvm/Support/Allocator.h" #include "llvm/Support/raw_ostream.h" namespace llvm { diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index 5c9c8375dadc..cf3ad7ef045c 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -48,8 +48,7 @@ namespace { class DebugDirectoryChunk : public Chunk { public: - DebugDirectoryChunk(const std::vector> &R) - : Records(R) {} + DebugDirectoryChunk(const std::vector &R) : Records(R) {} size_t getSize() const override { return Records.size() * sizeof(debug_directory); @@ -58,7 +57,7 @@ class DebugDirectoryChunk : public Chunk { void writeTo(uint8_t *B) const override { auto *D = reinterpret_cast(B + OutputSectionOff); - for (const std::unique_ptr &Record : Records) { + for (const Chunk *Record : Records) { D->Characteristics = 0; D->TimeDateStamp = 0; D->MajorVersion = 0; @@ -74,7 +73,7 @@ class DebugDirectoryChunk : public Chunk { } private: - const std::vector> &Records; + const std::vector &Records; }; class CVDebugRecordChunk : public Chunk { @@ -142,10 +141,10 @@ class Writer { IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; - std::unique_ptr SEHTable; + SEHTableChunk *SEHTable = nullptr; - std::unique_ptr DebugDirectory; - std::vector> DebugRecords; + Chunk *DebugDirectory = nullptr; + std::vector DebugRecords; CVDebugRecordChunk *BuildId = nullptr; ArrayRef SectionTable; @@ -153,8 +152,6 @@ class Writer { uint32_t PointerToSymbolTable = 0; uint64_t SizeOfImage; uint64_t SizeOfHeaders; - - std::vector> Chunks; }; } // anonymous namespace @@ -258,7 +255,7 @@ void Writer::run() { sortExceptionTable(); writeBuildId(); - if (!Config->PDBPath.empty()) { + if (!Config->PDBPath.empty() && Config->Debug) { const llvm::codeview::DebugInfo *DI = nullptr; if (Config->DebugTypes & static_cast(coff::DebugType::CV)) DI = BuildId->DI; @@ -324,19 +321,19 @@ void Writer::createMiscChunks() { // Create Debug Information Chunks if (Config->Debug) { - DebugDirectory = llvm::make_unique(DebugRecords); + DebugDirectory = make(DebugRecords); // TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled if (Config->DebugTypes & static_cast(coff::DebugType::CV)) { - auto Chunk = llvm::make_unique(); + auto *Chunk = make(); - BuildId = Chunk.get(); - DebugRecords.push_back(std::move(Chunk)); + BuildId = Chunk; + DebugRecords.push_back(Chunk); } - RData->addChunk(DebugDirectory.get()); - for (const std::unique_ptr &C : DebugRecords) - RData->addChunk(C.get()); + RData->addChunk(DebugDirectory); + for (Chunk *C : DebugRecords) + RData->addChunk(C); } // Create SEH table. x86-only. @@ -352,8 +349,8 @@ void Writer::createMiscChunks() { Handlers.insert(cast(B)); } - SEHTable.reset(new SEHTableChunk(Handlers)); - RData->addChunk(SEHTable.get()); + SEHTable = make(Handlers); + RData->addChunk(SEHTable); } // Create .idata section for the DLL-imported symbol table. @@ -398,8 +395,8 @@ void Writer::createImportTables() { for (Chunk *C : DelayIdata.getDataChunks()) Sec->addChunk(C); Sec = createSection(".text"); - for (std::unique_ptr &C : DelayIdata.getCodeChunks()) - Sec->addChunk(C.get()); + for (Chunk *C : DelayIdata.getCodeChunks()) + Sec->addChunk(C); } } @@ -407,8 +404,8 @@ void Writer::createExportTable() { if (Config->Exports.empty()) return; OutputSection *Sec = createSection(".edata"); - for (std::unique_ptr &C : Edata.Chunks) - Sec->addChunk(C.get()); + for (Chunk *C : Edata.Chunks) + Sec->addChunk(C); } // The Windows loader doesn't seem to like empty sections, @@ -602,14 +599,19 @@ template void Writer::writeHeader() { PE->SizeOfStackCommit = Config->StackCommit; PE->SizeOfHeapReserve = Config->HeapReserve; PE->SizeOfHeapCommit = Config->HeapCommit; + + // Import Descriptor Tables and Import Address Tables are merged + // in our output. That's not compatible with the Binding feature + // that is sort of prelinking. Setting this flag to make it clear + // that our outputs are not for the Binding. + PE->DLLCharacteristics = IMAGE_DLL_CHARACTERISTICS_NO_BIND; + if (Config->AppContainer) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; if (Config->DynamicBase) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; if (Config->HighEntropyVA) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; - if (!Config->AllowBind) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; if (Config->NxCompat) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; if (!Config->AllowIsolation) diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 87896ec96b29..e8cfd21c4c49 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -390,14 +390,28 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, } } -template -static typename ELFT::uint -getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P, - const SymbolBody &Body, RelExpr Expr) { +// ARM SBREL relocations are of the form S + A - B where B is the static base +// The ARM ABI defines base to be "addressing origin of the output segment +// defining the symbol S". We defined the "addressing origin"/static base to be +// the base of the PT_LOAD segment containing the Body. +// The procedure call standard only defines a Read Write Position Independent +// RWPI variant so in practice we should expect the static base to be the base +// of the RW segment. +static uint64_t getARMStaticBase(const SymbolBody &Body) { + OutputSection *OS = Body.getOutputSection(); + if (!OS || !OS->FirstInPtLoad) + fatal("SBREL relocation to " + Body.getName() + " without static base\n"); + return OS->FirstInPtLoad->Addr; +} + +static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, + const SymbolBody &Body, RelExpr Expr) { switch (Expr) { case R_ABS: case R_RELAX_GOT_PC_NOPIC: return Body.getVA(A); + case R_ARM_SBREL: + return Body.getVA(A) - getARMStaticBase(Body); case R_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: return Body.getGotVA() + A; @@ -518,7 +532,7 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P, case R_NEG_TLS: return Out::TlsPhdr->p_memsz - Body.getVA(A); case R_SIZE: - return Body.getSize() + A; + return A; // Body.getSize was already folded into the addend. case R_TLSDESC: return InX::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: @@ -566,7 +580,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef Rels) { uint64_t SymVA = 0; if (!Sym.isTls() || Out::TlsPhdr) SymVA = SignExtend64( - getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); + getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); Target->relocateOne(BufLoc, Type, SymVA); } } @@ -577,19 +591,28 @@ template elf::ObjectFile *InputSectionBase::getFile() const { template void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { + if (Flags & SHF_ALLOC) + relocateAlloc(Buf, BufEnd); + else + relocateNonAlloc(Buf, BufEnd); +} + +template +void InputSectionBase::relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd) { // scanReloc function in Writer.cpp constructs Relocations // vector only for SHF_ALLOC'ed sections. For other sections, // we handle relocations directly here. - auto *IS = dyn_cast(this); - if (IS && !(IS->Flags & SHF_ALLOC)) { - if (IS->AreRelocsRela) - IS->relocateNonAlloc(Buf, IS->template relas()); - else - IS->relocateNonAlloc(Buf, IS->template rels()); - return; - } + auto *IS = cast(this); + assert(!(IS->Flags & SHF_ALLOC)); + if (IS->AreRelocsRela) + IS->relocateNonAlloc(Buf, IS->template relas()); + else + IS->relocateNonAlloc(Buf, IS->template rels()); +} - const unsigned Bits = sizeof(typename ELFT::uint) * 8; +void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { + assert(Flags & SHF_ALLOC); + const unsigned Bits = Config->Wordsize * 8; for (const Relocation &Rel : Relocations) { uint64_t Offset = getOffset(Rel.Offset); uint8_t *BufLoc = Buf + Offset; @@ -597,8 +620,8 @@ void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; - uint64_t TargetVA = SignExtend64( - getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr)); + uint64_t TargetVA = SignExtend64( + getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); switch (Expr) { case R_RELAX_GOT_PC: diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 57458588b690..303c398b58cd 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -167,6 +167,8 @@ class InputSectionBase : public SectionBase { template std::string getObjMsg(uint64_t Offset); template void relocate(uint8_t *Buf, uint8_t *BufEnd); + void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd); + template void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd); std::vector Relocations; diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 161909abf00d..c303f0524ad4 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -440,9 +440,6 @@ void LinkerScript::fabricateDefaultCommands() { // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections for (OutputSection *Sec : *OutputSections) { - if (!(Sec->Flags & SHF_ALLOC)) - continue; - auto *OSCmd = make(Sec->Name); OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index 23c63e845c9a..7b82eceba02a 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -21,6 +21,8 @@ #include "MapFile.h" #include "InputFiles.h" +#include "LinkerScript.h" +#include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Threads.h" @@ -98,7 +100,7 @@ getSymbolStrings(ArrayRef Syms) { } template -void elf::writeMapFile(ArrayRef OutputSections) { +void elf::writeMapFile(llvm::ArrayRef Script) { if (Config->MapFile.empty()) return; @@ -121,7 +123,11 @@ void elf::writeMapFile(ArrayRef OutputSections) { << " Align Out In Symbol\n"; // Print out file contents. - for (OutputSection *OSec : OutputSections) { + for (BaseCommand *Base : Script) { + auto *Cmd = dyn_cast(Base); + if (!Cmd) + continue; + OutputSection *OSec = Cmd->Sec; writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment); OS << OSec->Name << '\n'; @@ -136,7 +142,7 @@ void elf::writeMapFile(ArrayRef OutputSections) { } } -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(ArrayRef); diff --git a/ELF/MapFile.h b/ELF/MapFile.h index 24d636890e53..f50ef00061ff 100644 --- a/ELF/MapFile.h +++ b/ELF/MapFile.h @@ -10,12 +10,12 @@ #ifndef LLD_ELF_MAPFILE_H #define LLD_ELF_MAPFILE_H -#include "OutputSections.h" +#include namespace lld { namespace elf { -template -void writeMapFile(llvm::ArrayRef OutputSections); +struct BaseCommand; +template void writeMapFile(llvm::ArrayRef Script); } } diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index c505a14f3c64..5564ea246eeb 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -935,6 +935,10 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef Rels) { bool IsConstant = isStaticLinkTimeConstant(Expr, Type, Body, Sec, Rel.r_offset); + // The size is not going to change, so we fold it in here. + if (Expr == R_SIZE) + Addend += Body.getSize(); + // If the output being produced is position independent, the final value // is still not known. In that case we still need some help from the // dynamic linker. We can however do better than just copying the incoming diff --git a/ELF/Relocations.h b/ELF/Relocations.h index f3512e0a89fc..206f0d9423c9 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -27,6 +27,7 @@ class OutputSection; // doesn't have to know about architecture-specific details. enum RelExpr { R_ABS, + R_ARM_SBREL, R_GOT, R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 5a2c2c37efd8..599f1441a47f 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -600,7 +600,7 @@ template void EhFrameSection::writeTo(uint8_t *Buf) { } for (EhInputSection *S : Sections) - S->template relocate(Buf, nullptr); + S->relocateAlloc(Buf, nullptr); // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table // to get a FDE from an address to which FDE is applied. So here @@ -617,16 +617,16 @@ template void EhFrameSection::writeTo(uint8_t *Buf) { } } -GotBaseSection::GotBaseSection() +GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotEntrySize, ".got") {} -void GotBaseSection::addEntry(SymbolBody &Sym) { +void GotSection::addEntry(SymbolBody &Sym) { Sym.GotIndex = NumEntries; ++NumEntries; } -bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) { +bool GotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = NumEntries; @@ -637,7 +637,7 @@ bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) { // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. -bool GotBaseSection::addTlsIndex() { +bool GotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = NumEntries * Config->Wordsize; @@ -645,27 +645,23 @@ bool GotBaseSection::addTlsIndex() { return true; } -uint64_t GotBaseSection::getGlobalDynAddr(const SymbolBody &B) const { +uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const { return this->getVA() + B.GlobalDynIndex * Config->Wordsize; } -uint64_t GotBaseSection::getGlobalDynOffset(const SymbolBody &B) const { +uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * Config->Wordsize; } -void GotBaseSection::finalizeContents() { - Size = NumEntries * Config->Wordsize; -} +void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; } -bool GotBaseSection::empty() const { +bool GotSection::empty() const { // If we have a relocation that is relative to GOT (such as GOTOFFREL), // we need to emit a GOT even if it's empty. return NumEntries == 0 && !HasGotOffRel; } -template void GotSection::writeTo(uint8_t *Buf) { - this->template relocate(Buf, Buf + Size); -} +void GotSection::writeTo(uint8_t *Buf) { relocateAlloc(Buf, Buf + Size); } MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, @@ -2242,7 +2238,7 @@ StringTableSection *InX::DynStrTab; SymbolTableBaseSection *InX::DynSymTab; InputSection *InX::Interp; GdbIndexSection *InX::GdbIndex; -GotBaseSection *InX::Got; +GotSection *InX::Got; GotPltSection *InX::GotPlt; GnuHashTableSection *InX::GnuHashTab; IgotPltSection *InX::IgotPlt; @@ -2284,11 +2280,6 @@ template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; -template class elf::GotSection; -template class elf::GotSection; -template class elf::GotSection; -template class elf::GotSection; - template class elf::DynamicSection; template class elf::DynamicSection; template class elf::DynamicSection; diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index 0477c601a7df..c5ffb88c1366 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -104,12 +104,13 @@ template class EhFrameSection final : public SyntheticSection { llvm::DenseMap, SymbolBody *>, CieRecord> CieMap; }; -class GotBaseSection : public SyntheticSection { +class GotSection : public SyntheticSection { public: - GotBaseSection(); + GotSection(); size_t getSize() const override { return Size; } void finalizeContents() override; bool empty() const override; + void writeTo(uint8_t *Buf) override; void addEntry(SymbolBody &Sym); bool addDynTlsEntry(SymbolBody &Sym); @@ -130,11 +131,6 @@ class GotBaseSection : public SyntheticSection { uint64_t Size = 0; }; -template class GotSection final : public GotBaseSection { -public: - void writeTo(uint8_t *Buf) override; -}; - // .note.gnu.build-id section. class BuildIdSection : public SyntheticSection { // First 16 bytes are a header. @@ -764,7 +760,7 @@ struct InX { static GnuHashTableSection *GnuHashTab; static InputSection *Interp; static GdbIndexSection *GdbIndex; - static GotBaseSection *Got; + static GotSection *Got; static GotPltSection *GotPlt; static IgotPltSection *IgotPlt; static MipsGotSection *MipsGot; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index 781d7fe3bc3f..cf7d912ad829 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -1693,6 +1693,8 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, case R_ARM_TLS_IE32: // GOT(S) + A - P return R_GOT_PC; + case R_ARM_SBREL32: + return R_ARM_SBREL; case R_ARM_TARGET1: return Config->Target1Rel ? R_PC : R_ABS; case R_ARM_TARGET2: @@ -1832,6 +1834,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_RELATIVE: + case R_ARM_SBREL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 4be6fe53c18b..7a21d2b9f13d 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -288,8 +288,13 @@ template void Writer::run() { if (ErrorCount) return; + // Clear the OutputSections to make sure it is not used anymore. Any + // code from this point on should be using the linker script + // commands. + OutputSections.clear(); + // Handle -Map option. - writeMapFile(OutputSections); + writeMapFile(Script->Opt.Commands); if (ErrorCount) return; @@ -403,7 +408,7 @@ template void Writer::createSyntheticSections() { InX::MipsGot = make(); Add(InX::MipsGot); } else { - InX::Got = make>(); + InX::Got = make(); Add(InX::Got); } @@ -626,22 +631,22 @@ bool elf::isRelroSection(const OutputSection *Sec) { // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { - RF_NOT_ADDR_SET = 1 << 16, - RF_NOT_INTERP = 1 << 15, - RF_NOT_ALLOC = 1 << 14, - RF_WRITE = 1 << 13, - RF_EXEC = 1 << 12, - RF_NON_TLS_BSS = 1 << 11, - RF_NON_TLS_BSS_RO = 1 << 10, - RF_NOT_TLS = 1 << 9, - RF_BSS = 1 << 8, - RF_PPC_NOT_TOCBSS = 1 << 7, - RF_PPC_OPD = 1 << 6, - RF_PPC_TOCL = 1 << 5, - RF_PPC_TOC = 1 << 4, - RF_PPC_BRANCH_LT = 1 << 3, - RF_MIPS_GPREL = 1 << 2, - RF_MIPS_NOT_GOT = 1 << 1 + RF_NOT_ADDR_SET = 1 << 15, + RF_NOT_INTERP = 1 << 14, + RF_NOT_ALLOC = 1 << 13, + RF_WRITE = 1 << 12, + RF_EXEC = 1 << 11, + RF_NON_TLS_BSS = 1 << 10, + RF_NON_TLS_BSS_RO = 1 << 9, + RF_NOT_TLS = 1 << 8, + RF_BSS = 1 << 7, + RF_PPC_NOT_TOCBSS = 1 << 6, + RF_PPC_OPD = 1 << 5, + RF_PPC_TOCL = 1 << 4, + RF_PPC_TOC = 1 << 3, + RF_PPC_BRANCH_LT = 1 << 2, + RF_MIPS_GPREL = 1 << 1, + RF_MIPS_NOT_GOT = 1 << 0 }; static unsigned getSectionRank(const OutputSection *Sec) { diff --git a/test/COFF/armnt-imports.test b/test/COFF/armnt-imports.test index 519886eb0c06..f0aaebd3f293 100644 --- a/test/COFF/armnt-imports.test +++ b/test/COFF/armnt-imports.test @@ -6,7 +6,7 @@ # CHECK: Import { # CHECK: Name: library.dll # CHECK: ImportLookupTableRVA: 0x2028 -# CHECK: ImportAddressTableRVA: 0x2030 +# CHECK: ImportAddressTableRVA: 0x2028 # CHECK: Symbol: function (0) # CHECK: } diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test index b7bc887d46eb..b7c5f28c3534 100644 --- a/test/COFF/hello32.test +++ b/test/COFF/hello32.test @@ -41,9 +41,10 @@ HEADER-NEXT: MinorSubsystemVersion: 0 HEADER-NEXT: SizeOfImage: 16896 HEADER-NEXT: SizeOfHeaders: 512 HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) -HEADER-NEXT: Characteristics [ (0x9140) +HEADER-NEXT: Characteristics [ (0x9940) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40) +HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_BIND (0x800) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000) HEADER-NEXT: ] @@ -77,7 +78,7 @@ HEADER-NEXT: LoadConfigTableRVA: 0x0 HEADER-NEXT: LoadConfigTableSize: 0x0 HEADER-NEXT: BoundImportRVA: 0x0 HEADER-NEXT: BoundImportSize: 0x0 -HEADER-NEXT: IATRVA: 0x3034 +HEADER-NEXT: IATRVA: 0x3028 HEADER-NEXT: IATSize: 0xC HEADER-NEXT: DelayImportDescriptorRVA: 0x0 HEADER-NEXT: DelayImportDescriptorSize: 0x0 @@ -113,7 +114,7 @@ IMPORTS: AddressSize: 32bit IMPORTS: Import { IMPORTS: Name: std32.dll IMPORTS: ImportLookupTableRVA: 0x3028 -IMPORTS: ImportAddressTableRVA: 0x3034 +IMPORTS: ImportAddressTableRVA: 0x3028 IMPORTS: Symbol: ExitProcess (0) IMPORTS: Symbol: MessageBoxA (1) IMPORTS: } diff --git a/test/COFF/imports.test b/test/COFF/imports.test index 584c24eb1b76..4df6d492ff28 100644 --- a/test/COFF/imports.test +++ b/test/COFF/imports.test @@ -21,14 +21,14 @@ TEXT-NEXT: callq 60 TEXT-NEXT: movl $0, %ecx TEXT-NEXT: callq 18 TEXT-NEXT: callq 29 -TEXT: jmpq *4098(%rip) -TEXT: jmpq *4090(%rip) -TEXT: jmpq *4082(%rip) +TEXT: jmpq *4066(%rip) +TEXT: jmpq *4058(%rip) +TEXT: jmpq *4050(%rip) IMPORT: Import { IMPORT-NEXT: Name: std64.dll IMPORT-NEXT: ImportLookupTableRVA: 0x3028 -IMPORT-NEXT: ImportAddressTableRVA: 0x3048 +IMPORT-NEXT: ImportAddressTableRVA: 0x3028 IMPORT-NEXT: Symbol: ExitProcess (0) IMPORT-NEXT: Symbol: (50) IMPORT-NEXT: Symbol: MessageBoxA (1) diff --git a/test/COFF/invalid-debug-type.test b/test/COFF/invalid-debug-type.test index e48b3fdd2e06..10264180314d 100644 --- a/test/COFF/invalid-debug-type.test +++ b/test/COFF/invalid-debug-type.test @@ -1,5 +1,5 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ -# RUN: /debugpdb %t1.obj %t2.obj +# RUN: %t1.obj %t2.obj diff --git a/test/COFF/options.test b/test/COFF/options.test index 39f944beddbc..a23da1971d15 100644 --- a/test/COFF/options.test +++ b/test/COFF/options.test @@ -2,13 +2,7 @@ # RUN: lld-link /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s -# RUN: lld-link /allowbind /out:%t.exe /entry:main %t.obj -# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s -BIND-NOT: IMAGE_DLL_CHARACTERISTICS_NO_BIND - -# RUN: lld-link /allowbind:no /out:%t.exe /entry:main %t.obj -# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOBIND %s -NOBIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND +BIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND # RUN: lld-link /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s diff --git a/test/COFF/pdb-none.test b/test/COFF/pdb-none.test index 480ff2a4ace3..7e428693aec4 100644 --- a/test/COFF/pdb-none.test +++ b/test/COFF/pdb-none.test @@ -1,7 +1,7 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: lld-link /debug /debugtype:pdata /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ -# RUN: /debugpdb %t1.obj %t2.obj +# RUN: %t1.obj %t2.obj # RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.pdb | FileCheck %s diff --git a/test/COFF/pdb-options.test b/test/COFF/pdb-options.test new file mode 100644 index 000000000000..1cc4b3abda7c --- /dev/null +++ b/test/COFF/pdb-options.test @@ -0,0 +1,20 @@ +# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj +# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj + +; If /DEBUG is not specified, /pdb is ignored. +# RUN: lld-link /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj +# RUN: not ls %t.pdb + +; If /DEBUG and /pdb are specified, it uses the specified name. +# RUN: lld-link /DEBUG /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj +# RUN: ls %t.pdb +# RUN: rm %t.pdb + +; If /DEBUG is specified but not /pdb, it uses a default name in the current +; directory. This is a bit hacky since but we need to be IN our test specific +; temporary directory when we run this command or we can't test this +# RUN: cd %T +# RUN: lld-link /DEBUG /entry:main /nodefaultlib %t1.obj %t2.obj +# RUN: ls %t1.pdb +# RUN: rm %t* +# RUN: cd %T/.. diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test index aa14d290c737..f1fa4ec7c2b6 100644 --- a/test/COFF/pdb.test +++ b/test/COFF/pdb.test @@ -1,7 +1,7 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ -# RUN: /debugpdb %t1.obj %t2.obj +# RUN: %t1.obj %t2.obj # RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream \ # RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s diff --git a/test/ELF/arm-sbrel32.s b/test/ELF/arm-sbrel32.s new file mode 100644 index 000000000000..7f12717195a9 --- /dev/null +++ b/test/ELF/arm-sbrel32.s @@ -0,0 +1,39 @@ +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o %t2 2>&1 +// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s +// REQUIRES: arm + +// Test the R_ARM_SBREL32 relocation which calculates the offset of the Symbol +// from the static base. We define the static base to be the address of the +// segment containing the symbol + .text + .syntax unified + + .globl _start + .p2align 2 + .type _start,%function +_start: + .fnstart + bx lr + + .long foo(sbrel) + .long foo2(sbrel) + .long foo3(sbrel) + .long foo4(sbrel) +// RW segment starts here + .data + .p2align 4 +foo: .word 10 +foo2: .word 20 + + .bss +foo3: .space 4 +foo4: .space 4 + +// CHECK: Disassembly of section .text: +// CHECK-NEXT: _start: +// CHECK-NEXT: 11000: 1e ff 2f e1 bx lr +// CHECK: 11004: 00 00 00 00 .word 0x00000000 +// CHECK-NEXT: 11008: 04 00 00 00 .word 0x00000004 +// CHECK-NEXT: 1100c: 08 00 00 00 .word 0x00000008 +// CHECK-NEXT: 11010: 0c 00 00 00 .word 0x0000000c From bef2946c219dc621608bcc9e47f8b973e5ef5c70 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Mon, 29 May 2017 16:26:20 +0000 Subject: [PATCH 02/11] Vendor import of lld trunk r304149: https://llvm.org/svn/llvm-project/lld/trunk@304149 --- COFF/ICF.cpp | 37 ++-- COFF/InputFiles.cpp | 21 ++- COFF/InputFiles.h | 13 +- COFF/MarkLive.cpp | 17 +- COFF/PDB.cpp | 15 +- COFF/Symbols.cpp | 19 +- COFF/Symbols.h | 3 +- COFF/Writer.cpp | 55 ++++-- ELF/Config.h | 1 + ELF/Driver.cpp | 9 +- ELF/ICF.cpp | 4 +- ELF/InputFiles.cpp | 32 ++-- ELF/InputSection.cpp | 31 +++- ELF/InputSection.h | 5 +- ELF/LTO.cpp | 7 +- ELF/LinkerScript.cpp | 98 +++++++--- ELF/LinkerScript.h | 11 +- ELF/MapFile.cpp | 17 +- ELF/Options.td | 1 + ELF/OutputSections.cpp | 93 +++------- ELF/OutputSections.h | 2 - ELF/SyntheticSections.cpp | 44 ++--- ELF/SyntheticSections.h | 6 +- ELF/Writer.cpp | 188 +++++++++++++------- ELF/Writer.h | 2 +- test/COFF/Inputs/delayimports-error.yaml | 29 +++ test/COFF/Inputs/import.yaml | 9 +- test/COFF/Inputs/oldname.yaml | 26 +++ test/COFF/delayimports-error.test | 46 +++++ test/COFF/dllimport-gc.test | 58 ++++++ test/ELF/Inputs/rodynamic.s | 4 + test/ELF/amdgpu-globals.s | 26 +-- test/ELF/build-id.s | 4 + test/ELF/gc-sections.s | 12 +- test/ELF/gdb-index-dup-types.s | 60 +++++++ test/ELF/i386-tls-ie-shared.s | 68 +++---- test/ELF/linkerscript/arm-lscript.s | 9 + test/ELF/linkerscript/sections-constraint.s | 2 +- test/ELF/lto/Inputs/relocation-model-pic.ll | 11 ++ test/ELF/lto/relocation-model.ll | 46 +++++ test/ELF/relocatable-comdat.s | 45 +++++ test/ELF/relocation-size-shared.s | 72 ++++---- test/ELF/relocation-size.s | 132 +++++++------- test/ELF/reproduce.s | 2 +- test/ELF/rodynamic.s | 35 ++++ test/ELF/section-layout.s | 7 +- test/ELF/tls-i686.s | 48 ++--- 47 files changed, 1008 insertions(+), 474 deletions(-) create mode 100644 test/COFF/Inputs/delayimports-error.yaml create mode 100644 test/COFF/Inputs/oldname.yaml create mode 100644 test/COFF/delayimports-error.test create mode 100644 test/COFF/dllimport-gc.test create mode 100644 test/ELF/Inputs/rodynamic.s create mode 100644 test/ELF/gdb-index-dup-types.s create mode 100644 test/ELF/linkerscript/arm-lscript.s create mode 100644 test/ELF/lto/Inputs/relocation-model-pic.ll create mode 100644 test/ELF/lto/relocation-model.ll create mode 100644 test/ELF/relocatable-comdat.s create mode 100644 test/ELF/rodynamic.s diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp index 3b7cc424f0a2..da8ca360542a 100644 --- a/COFF/ICF.cpp +++ b/COFF/ICF.cpp @@ -56,7 +56,6 @@ class ICF { std::vector Chunks; int Cnt = 0; - std::atomic NextId = {1}; std::atomic Repeat = {false}; }; @@ -98,10 +97,10 @@ void ICF::segregate(size_t Begin, size_t End, bool Constant) { }); size_t Mid = Bound - Chunks.begin(); - // Split [Begin, End) into [Begin, Mid) and [Mid, End). - uint32_t Id = NextId++; + // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an + // equivalence class ID because every group ends with a unique index. for (size_t I = Begin; I < Mid; ++I) - Chunks[I]->Class[(Cnt + 1) % 2] = Id; + Chunks[I]->Class[(Cnt + 1) % 2] = Mid; // If we created a group, we need to iterate the main loop again. if (Mid != End) @@ -186,6 +185,7 @@ void ICF::forEachClass(std::function Fn) { // call Fn sequentially. if (Chunks.size() < 1024) { forEachClassRange(0, Chunks.size(), Fn); + ++Cnt; return; } @@ -193,9 +193,10 @@ void ICF::forEachClass(std::function Fn) { size_t NumShards = 256; size_t Step = Chunks.size() / NumShards; for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) { - forEachClassRange(I * Step, (I + 1) * Step, Fn); + size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step; + forEachClassRange(I * Step, End, Fn); }); - forEachClassRange(Step * NumShards, Chunks.size(), Fn); + ++Cnt; } // Merge identical COMDAT sections. @@ -203,22 +204,20 @@ void ICF::forEachClass(std::function Fn) { // contents and relocations are all the same. void ICF::run(const std::vector &Vec) { // Collect only mergeable sections and group by hash value. + uint32_t NextId = 1; for (Chunk *C : Vec) { - auto *SC = dyn_cast(C); - if (!SC) - continue; - - if (isEligible(SC)) { - // Set MSB to 1 to avoid collisions with non-hash classs. - SC->Class[0] = getHash(SC) | (1 << 31); - Chunks.push_back(SC); - } else { - SC->Class[0] = NextId++; + if (auto *SC = dyn_cast(C)) { + if (isEligible(SC)) + Chunks.push_back(SC); + else + SC->Class[0] = NextId++; } } - if (Chunks.empty()) - return; + // Initially, we use hash values to partition sections. + for (SectionChunk *SC : Chunks) + // Set MSB to 1 to avoid collisions with non-hash classs. + SC->Class[0] = getHash(SC) | (1 << 31); // From now on, sections in Chunks are ordered so that sections in // the same group are consecutive in the vector. @@ -229,14 +228,12 @@ void ICF::run(const std::vector &Vec) { // Compare static contents and assign unique IDs for each static content. forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); - ++Cnt; // Split groups by comparing relocations until convergence is obtained. do { Repeat = false; forEachClass( [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); - ++Cnt; } while (Repeat); log("ICF needed " + Twine(Cnt) + " iterations"); diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index 6e6465cd5d62..258d9fd74b4d 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -48,13 +48,11 @@ namespace coff { /// alias to Target. static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, SymbolBody *Source, SymbolBody *Target) { - auto *U = dyn_cast(Source); - if (!U) - return; - else if (!U->WeakAlias) + if (auto *U = dyn_cast(Source)) { + if (U->WeakAlias && U->WeakAlias != Target) + Symtab->reportDuplicate(Source->symbol(), F); U->WeakAlias = Target; - else if (U->WeakAlias != Target) - Symtab->reportDuplicate(Source->symbol(), F); + } } ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} @@ -153,8 +151,10 @@ void ObjectFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); SymbolBodies.reserve(NumSymbols); SparseSymbolBodies.resize(NumSymbols); + SmallVector, 8> WeakAliases; int32_t LastSectionNumber = 0; + for (uint32_t I = 0; I < NumSymbols; ++I) { // Get a COFFSymbolRef object. ErrorOr SymOrErr = COFFObj->getSymbol(I); @@ -185,9 +185,12 @@ void ObjectFile::initializeSymbols() { I += Sym.getNumberOfAuxSymbols(); LastSectionNumber = Sym.getSectionNumber(); } - for (auto WeakAlias : WeakAliases) - checkAndSetWeakAlias(Symtab, this, WeakAlias.first, - SparseSymbolBodies[WeakAlias.second]); + + for (auto &KV : WeakAliases) { + SymbolBody *Sym = KV.first; + uint32_t Idx = KV.second; + checkAndSetWeakAlias(Symtab, this, Sym, SparseSymbolBodies[Idx]); + } } SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index 9e32b3b9f9d6..9449f24ac241 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -10,6 +10,7 @@ #ifndef LLD_COFF_INPUT_FILES_H #define LLD_COFF_INPUT_FILES_H +#include "Config.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" @@ -161,7 +162,9 @@ class ObjectFile : public InputFile { // for details about the format. class ImportFile : public InputFile { public: - explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} + explicit ImportFile(MemoryBufferRef M) + : InputFile(ImportKind, M), Live(!Config->DoGC) {} + static bool classof(const InputFile *F) { return F->kind() == ImportKind; } DefinedImportData *ImpSym = nullptr; @@ -176,6 +179,14 @@ class ImportFile : public InputFile { StringRef ExternalName; const coff_import_header *Hdr; Chunk *Location = nullptr; + + // We want to eliminate dllimported symbols if no one actually refers them. + // This "Live" bit is used to keep track of which import library members + // are actually in use. + // + // If the Live bit is turned off by MarkLive, Writer will ignore dllimported + // symbols provided by this import library member. + bool Live; }; // Used for LTO. diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp index 0156d238b672..25e5cc350673 100644 --- a/COFF/MarkLive.cpp +++ b/COFF/MarkLive.cpp @@ -37,19 +37,26 @@ void markLive(const std::vector &Chunks) { Worklist.push_back(C); }; + auto AddSym = [&](SymbolBody *B) { + if (auto *Sym = dyn_cast(B)) + Enqueue(Sym->getChunk()); + else if (auto *Sym = dyn_cast(B)) + Sym->File->Live = true; + else if (auto *Sym = dyn_cast(B)) + Sym->WrappedSym->File->Live = true; + }; + // Add GC root chunks. for (SymbolBody *B : Config->GCRoot) - if (auto *D = dyn_cast(B)) - Enqueue(D->getChunk()); + AddSym(B); while (!Worklist.empty()) { SectionChunk *SC = Worklist.pop_back_val(); assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); // Mark all symbols listed in the relocation table for this section. - for (SymbolBody *S : SC->symbols()) - if (auto *D = dyn_cast(S)) - Enqueue(D->getChunk()); + for (SymbolBody *B : SC->symbols()) + AddSym(B); // Mark associative sections if any. for (SectionChunk *C : SC->children()) diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index 0266148cc6c9..a3b3ab7bbab0 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -99,6 +99,12 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, codeview::TypeTableBuilder &TypeTable, codeview::TypeTableBuilder &IDTable) { + // Follow type servers. If the same type server is encountered more than + // once for this instance of `PDBTypeServerHandler` (for example if many + // object files reference the same TypeServer), the types from the + // TypeServer will only be visited once. + pdb::PDBTypeServerHandler Handler; + // Visit all .debug$T sections to add them to Builder. for (ObjectFile *File : Symtab->ObjectFiles) { ArrayRef Data = getDebugSection(File, ".debug$T"); @@ -109,16 +115,11 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, codeview::CVTypeArray Types; BinaryStreamReader Reader(Stream); SmallVector SourceToDest; - // Follow type servers. If the same type server is encountered more than - // once for this instance of `PDBTypeServerHandler` (for example if many - // object files reference the same TypeServer), the types from the - // TypeServer will only be visited once. - pdb::PDBTypeServerHandler Handler; Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); - if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest, - &Handler, Types)) + if (auto Err = codeview::mergeTypeAndIdRecords( + IDTable, TypeTable, SourceToDest, &Handler, Types)) fatal(Err, "codeview::mergeTypeStreams failed"); } diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp index 993e920ce7f7..5c185a511dd7 100644 --- a/COFF/Symbols.cpp +++ b/COFF/Symbols.cpp @@ -61,16 +61,19 @@ COFFSymbolRef DefinedCOFF::getCOFFSymbol() { return COFFSymbolRef(reinterpret_cast(Sym)); } +static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { + if (Machine == AMD64) + return make(S); + if (Machine == I386) + return make(S); + assert(Machine == ARMNT); + return make(S); +} + DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine) - : Defined(DefinedImportThunkKind, Name) { - switch (Machine) { - case AMD64: Data = make(S); return; - case I386: Data = make(S); return; - case ARMNT: Data = make(S); return; - default: llvm_unreachable("unknown machine type"); - } -} + : Defined(DefinedImportThunkKind, Name), WrappedSym(S), + Data(makeImportThunk(S, Machine)) {} Defined *Undefined::getWeakAlias() { // A weak alias may be a weak alias to another symbol, so check recursively. diff --git a/COFF/Symbols.h b/COFF/Symbols.h index 1b83f73ff20c..801fc87f91d9 100644 --- a/COFF/Symbols.h +++ b/COFF/Symbols.h @@ -300,7 +300,6 @@ class DefinedImportData : public Defined { void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } -private: ImportFile *File; }; @@ -320,6 +319,8 @@ class DefinedImportThunk : public Defined { uint64_t getRVA() { return Data->getRVA(); } Chunk *getChunk() { return Data; } + DefinedImportData *WrappedSym; + private: Chunk *Data; }; diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index cf3ad7ef045c..fb1f3cae5bb2 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -365,6 +365,9 @@ void Writer::createImportTables() { // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) for (ImportFile *File : Symtab->ImportFiles) { + if (!File->Live) + continue; + std::string DLL = StringRef(File->DLLName).lower(); if (Config->DLLOrder.count(DLL) == 0) Config->DLLOrder[DLL] = Config->DLLOrder.size(); @@ -372,19 +375,28 @@ void Writer::createImportTables() { OutputSection *Text = createSection(".text"); for (ImportFile *File : Symtab->ImportFiles) { + if (!File->Live) + continue; + if (DefinedImportThunk *Thunk = File->ThunkSym) Text->addChunk(Thunk->getChunk()); + if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { + if (!File->ThunkSym) + fatal("cannot delay-load " + toString(File) + + " due to import of data: " + toString(*File->ImpSym)); DelayIdata.add(File->ImpSym); } else { Idata.add(File->ImpSym); } } + if (!Idata.empty()) { OutputSection *Sec = createSection(".idata"); for (Chunk *C : Idata.getChunks()) Sec->addChunk(C); } + if (!DelayIdata.empty()) { Defined *Helper = cast(Config->DelayLoadHelper); DelayIdata.create(Helper); @@ -437,6 +449,14 @@ Optional Writer::createSymbol(Defined *Def) { if (!D->getChunk()->isLive()) return None; + if (auto *Sym = dyn_cast(Def)) + if (!Sym->File->Live) + return None; + + if (auto *Sym = dyn_cast(Def)) + if (!Sym->WrappedSym->File->Live) + return None; + coff_symbol16 Sym; StringRef Name = Def->getName(); if (Name.size() > COFF::NameSize) { @@ -491,14 +511,17 @@ void Writer::createSymbolAndStringTable() { Sec->setStringTableOff(addEntryToStringTable(Name)); } - for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) - for (SymbolBody *B : File->getSymbols()) - if (auto *D = dyn_cast(B)) - if (!D->WrittenToSymtab) { - D->WrittenToSymtab = true; - if (Optional Sym = createSymbol(D)) - OutputSymtab.push_back(*Sym); - } + for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { + for (SymbolBody *B : File->getSymbols()) { + auto *D = dyn_cast(B); + if (!D || D->WrittenToSymtab) + continue; + D->WrittenToSymtab = true; + + if (Optional Sym = createSymbol(D)) + OutputSymtab.push_back(*Sym); + } + } OutputSection *LastSection = OutputSections.back(); // We position the symbol table to be adjacent to the end of the last section. @@ -782,19 +805,15 @@ void Writer::writeBuildId() { if (BuildId == nullptr) return; - MD5 Hash; - MD5::MD5Result Res; - - Hash.update(ArrayRef{Buffer->getBufferStart(), - Buffer->getBufferEnd()}); - Hash.final(Res); - assert(BuildId->DI->Signature.CVSignature == OMF::Signature::PDB70 && "only PDB 7.0 is supported"); - assert(sizeof(Res) == sizeof(BuildId->DI->PDB70.Signature) && + assert(sizeof(BuildId->DI->PDB70.Signature) == 16 && "signature size mismatch"); - memcpy(BuildId->DI->PDB70.Signature, Res.Bytes.data(), - sizeof(codeview::PDB70DebugInfo::Signature)); + + // Compute an MD5 hash. + ArrayRef Buf(Buffer->getBufferStart(), Buffer->getBufferEnd()); + memcpy(BuildId->DI->PDB70.Signature, MD5::hash(Buf).data(), 16); + // TODO(compnerd) track the Age BuildId->DI->PDB70.Age = 1; } diff --git a/ELF/Config.h b/ELF/Config.h index 57a0e5a5ec73..54f6dc2acc7c 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -145,6 +145,7 @@ struct Configuration { bool ZNow; bool ZOrigin; bool ZRelro; + bool ZRodynamic; bool ZText; bool ExitEarly; bool ZWxneeded; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 737c6a6bf114..325404447b24 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -572,10 +572,14 @@ static std::pair getHashStyle(opt::InputArgList &Args) { // -build-id=sha1 are actually tree hashes for performance reasons. static std::pair> getBuildId(opt::InputArgList &Args) { - if (Args.hasArg(OPT_build_id)) + auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq); + if (!Arg) + return {BuildIdKind::None, {}}; + + if (Arg->getOption().getID() == OPT_build_id) return {BuildIdKind::Fast, {}}; - StringRef S = getString(Args, OPT_build_id_eq, "none"); + StringRef S = Arg->getValue(); if (S == "md5") return {BuildIdKind::Md5, {}}; if (S == "sha1" || S == "tree") @@ -688,6 +692,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); + Config->ZRodynamic = hasZOption(Args, "rodynamic"); Config->ZStackSize = getZOptionValue(Args, "stack-size", 0); Config->ZText = !hasZOption(Args, "notext"); Config->ZWxneeded = hasZOption(Args, "wxneeded"); diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp index 3722d4e3ed2f..419ae6816328 100644 --- a/ELF/ICF.cpp +++ b/ELF/ICF.cpp @@ -326,9 +326,9 @@ void ICF::forEachClass(std::function Fn) { size_t NumShards = 256; size_t Step = Sections.size() / NumShards; parallelForEachN(0, NumShards, [&](size_t I) { - forEachClassRange(I * Step, (I + 1) * Step, Fn); + size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step; + forEachClassRange(I * Step, End, Fn); }); - forEachClassRange(Step * NumShards, Sections.size(), Fn); ++Cnt; } diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index fe036a644f41..98189825ccbf 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -281,18 +281,20 @@ bool elf::ObjectFile::shouldMerge(const Elf_Shdr &Sec) { template void elf::ObjectFile::initializeSections( DenseSet &ComdatGroups) { + const ELFFile &Obj = this->getObj(); + ArrayRef ObjSections = check(this->getObj().sections(), toString(this)); - const ELFFile &Obj = this->getObj(); uint64_t Size = ObjSections.size(); this->Sections.resize(Size); - unsigned I = -1; + StringRef SectionStringTable = check(Obj.getSectionStringTable(ObjSections), toString(this)); - for (const Elf_Shdr &Sec : ObjSections) { - ++I; + + for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) continue; + const Elf_Shdr &Sec = ObjSections[I]; // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. @@ -303,13 +305,22 @@ void elf::ObjectFile::initializeSections( } switch (Sec.sh_type) { - case SHT_GROUP: - this->Sections[I] = &InputSection::Discarded; - if (ComdatGroups - .insert( - CachedHashStringRef(getShtGroupSignature(ObjSections, Sec))) - .second) + case SHT_GROUP: { + // We discard comdat sections usually. When -r we should not do that. We + // still do deduplication in this case to simplify implementation, because + // otherwise merging group sections together would requre additional + // regeneration of its contents. + bool New = ComdatGroups + .insert(CachedHashStringRef( + getShtGroupSignature(ObjSections, Sec))) + .second; + if (New && Config->Relocatable) + this->Sections[I] = createInputSection(Sec, SectionStringTable); + else + this->Sections[I] = &InputSection::Discarded; + if (New) continue; + for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(toString(this) + @@ -317,6 +328,7 @@ void elf::ObjectFile::initializeSections( this->Sections[SecIndex] = &InputSection::Discarded; } break; + } case SHT_SYMTAB: this->initSymtab(ObjSections, &Sec); break; diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index e8cfd21c4c49..466656efbf08 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Threading.h" #include using namespace llvm; @@ -172,7 +173,8 @@ void InputSectionBase::uncompress() { if (Error E = Dec.decompress({OutputBuf, Size})) fatal(toString(this) + ": decompress failed: " + llvm::toString(std::move(E))); - Data = ArrayRef((uint8_t *)OutputBuf, Size); + this->Data = ArrayRef((uint8_t *)OutputBuf, Size); + this->Flags &= ~(uint64_t)SHF_COMPRESSED; } uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const { @@ -293,6 +295,24 @@ bool InputSectionBase::classof(const SectionBase *S) { return S->kind() != Output; } +void InputSection::copyShtGroup(uint8_t *Buf) { + assert(this->Type == SHT_GROUP); + + ArrayRef From = getDataAs(); + uint32_t *To = reinterpret_cast(Buf); + + // First entry is a flag word, we leave it unchanged. + *To++ = From[0]; + + // Here we adjust indices of sections that belong to group as it + // might change during linking. + ArrayRef Sections = this->File->getSections(); + for (uint32_t Val : From.slice(1)) { + uint32_t Index = read32(&Val, Config->Endianness); + write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness); + } +} + InputSectionBase *InputSection::getRelocatedSection() { assert(this->Type == SHT_RELA || this->Type == SHT_REL); ArrayRef Sections = this->File->getSections(); @@ -678,6 +698,13 @@ template void InputSection::writeTo(uint8_t *Buf) { return; } + // If -r is given, linker should keep SHT_GROUP sections. We should fixup + // them, see copyShtGroup(). + if (this->Type == SHT_GROUP) { + copyShtGroup(Buf + OutSecOff); + return; + } + // Copy section contents from source object file to output file // and then apply relocations. memcpy(Buf + OutSecOff, Data.data(), Data.size()); @@ -866,7 +893,7 @@ const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const { // it is not just an addition to a base output offset. uint64_t MergeInputSection::getOffset(uint64_t Offset) const { // Initialize OffsetMap lazily. - std::call_once(InitOffsetMap, [&] { + llvm::call_once(InitOffsetMap, [&] { OffsetMap.reserve(Pieces.size()); for (const SectionPiece &Piece : Pieces) OffsetMap[Piece.InputOff] = Piece.OutputOff; diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 303c398b58cd..4ef4328e8a5d 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" +#include "llvm/Support/Threading.h" #include namespace lld { @@ -248,7 +249,7 @@ class MergeInputSection : public InputSectionBase { std::vector Hashes; mutable llvm::DenseMap OffsetMap; - mutable std::once_flag InitOffsetMap; + mutable llvm::once_flag InitOffsetMap; llvm::DenseSet LiveOffsets; }; @@ -318,6 +319,8 @@ class InputSection : public InputSectionBase { private: template void copyRelocations(uint8_t *Buf, llvm::ArrayRef Rels); + + void copyShtGroup(uint8_t *Buf); }; // The list of all input sections. diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp index dd435173101a..6915d9713891 100644 --- a/ELF/LTO.cpp +++ b/ELF/LTO.cpp @@ -73,7 +73,12 @@ static std::unique_ptr createLTO() { Conf.Options = InitTargetOptionsFromCodeGenFlags(); Conf.Options.RelaxELFRelocations = true; - Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static; + if (Config->Relocatable) + Conf.RelocModel = None; + else if (Config->Pic) + Conf.RelocModel = Reloc::PIC_; + else + Conf.RelocModel = Reloc::Static; Conf.CodeModel = GetCodeModelFromCMModel(); Conf.DisableVerify = Config->DisableVerify; Conf.DiagHandler = diagnosticHandler; diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index c303f0524ad4..492b81c1fa76 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -20,6 +20,8 @@ #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "Target.h" +#include "Threads.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -198,6 +200,15 @@ bool OutputSectionCommand::classof(const BaseCommand *C) { return C->Kind == OutputSectionKind; } +// Fill [Buf, Buf + Size) with Filler. +// This is used for linker script "=fillexp" command. +static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { + size_t I = 0; + for (; I + 4 < Size; I += 4) + memcpy(Buf + I, &Filler, 4); + memcpy(Buf + I, &Filler, Size - I); +} + bool InputSectionDescription::classof(const BaseCommand *C) { return C->Kind == InputSectionKind; } @@ -263,16 +274,16 @@ static bool matchConstraints(ArrayRef Sections, (!IsRW && Kind == ConstraintKind::ReadOnly); } -static void sortSections(InputSectionBase **Begin, InputSectionBase **End, +static void sortSections(InputSection **Begin, InputSection **End, SortSectionPolicy K) { if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None) std::stable_sort(Begin, End, getComparator(K)); } // Compute and remember which sections the InputSectionDescription matches. -std::vector +std::vector LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { - std::vector Ret; + std::vector Ret; // Collects all sections that satisfy constraints of Cmd. for (const SectionPattern &Pat : Cmd->SectionPatterns) { @@ -294,7 +305,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { !Pat.SectionPat.match(Sec->Name)) continue; - Ret.push_back(Sec); + Ret.push_back(cast(Sec)); Sec->Assigned = true; } @@ -309,8 +320,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { // --sort-section is handled as an inner SORT command. // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. - InputSectionBase **Begin = Ret.data() + SizeBefore; - InputSectionBase **End = Ret.data() + Ret.size(); + InputSection **Begin = Ret.data() + SizeBefore; + InputSection **End = Ret.data() + Ret.size(); if (Pat.SortOuter != SortSectionPolicy::None) { if (Pat.SortInner == SortSectionPolicy::Default) sortSections(Begin, End, Config->SortSection); @@ -493,7 +504,7 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { Sec->SectionIndex = Index; } auto *ISD = make(""); - ISD->Sections.push_back(S); + ISD->Sections.push_back(cast(S)); Cmd->Commands.push_back(ISD); } } @@ -684,7 +695,6 @@ void LinkerScript::adjustSectionsBeforeSorting() { // '.' is assigned to, but creating these section should not have any bad // consequeces and gives us a section to put the symbol in. uint64_t Flags = SHF_ALLOC; - uint32_t Type = SHT_PROGBITS; for (int I = 0, E = Opt.Commands.size(); I != E; ++I) { auto *Cmd = dyn_cast(Opt.Commands[I]); @@ -692,14 +702,13 @@ void LinkerScript::adjustSectionsBeforeSorting() { continue; if (OutputSection *Sec = Cmd->Sec) { Flags = Sec->Flags; - Type = Sec->Type; continue; } if (isAllSectionDescription(*Cmd)) continue; - auto *OutSec = make(Cmd->Name, Type, Flags); + auto *OutSec = make(Cmd->Name, SHT_PROGBITS, Flags); OutSec->SectionIndex = I; OutputSections->push_back(OutSec); Cmd->Sec = OutSec; @@ -875,20 +884,20 @@ void LinkerScript::synchronize() { if (!Cmd) continue; ArrayRef Sections = Cmd->Sec->Sections; - std::vector ScriptSections; - DenseSet ScriptSectionsSet; + std::vector ScriptSections; + DenseSet ScriptSectionsSet; for (BaseCommand *Base : Cmd->Commands) { auto *ISD = dyn_cast(Base); if (!ISD) continue; - for (InputSectionBase *&IS : ISD->Sections) { + for (InputSection *&IS : ISD->Sections) { if (IS->Live) { ScriptSections.push_back(&IS); ScriptSectionsSet.insert(IS); } } } - std::vector Missing; + std::vector Missing; for (InputSection *IS : Sections) if (!ScriptSectionsSet.count(IS)) Missing.push_back(IS); @@ -896,7 +905,7 @@ void LinkerScript::synchronize() { auto ISD = make(""); ISD->Sections = Missing; Cmd->Commands.push_back(ISD); - for (InputSectionBase *&IS : ISD->Sections) + for (InputSection *&IS : ISD->Sections) if (IS->Live) ScriptSections.push_back(&IS); } @@ -1034,10 +1043,12 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { return I->second; } -Optional LinkerScript::getFiller(OutputSection *Sec) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) - return Cmd->Filler; - return None; +uint32_t OutputSectionCommand::getFiller() { + if (Filler) + return *Filler; + if (Sec->Flags & SHF_EXECINSTR) + return Target->TrapInstr; + return 0; } static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { @@ -1053,11 +1064,45 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { llvm_unreachable("unsupported Size argument"); } -void LinkerScript::writeDataBytes(OutputSection *Sec, uint8_t *Buf) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) - for (BaseCommand *Base : Cmd->Commands) - if (auto *Data = dyn_cast(Base)) - writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); +template void OutputSectionCommand::writeTo(uint8_t *Buf) { + Sec->Loc = Buf; + + // We may have already rendered compressed content when using + // -compress-debug-sections option. Write it together with header. + if (!Sec->CompressedData.empty()) { + memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); + memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), + Sec->CompressedData.size()); + return; + } + + // Write leading padding. + ArrayRef Sections = Sec->Sections; + uint32_t Filler = getFiller(); + if (Filler) + fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler); + + parallelForEachN(0, Sections.size(), [=](size_t I) { + InputSection *IS = Sections[I]; + IS->writeTo(Buf); + + // Fill gaps between sections. + if (Filler) { + uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); + uint8_t *End; + if (I + 1 == Sections.size()) + End = Buf + Sec->Size; + else + End = Buf + Sections[I + 1]->OutSecOff; + fill(Start, End - Start, Filler); + } + }); + + // Linker scripts may have BYTE()-family commands with which you + // can write arbitrary bytes to the output. Process them if any. + for (BaseCommand *Base : Commands) + if (auto *Data = dyn_cast(Base)) + writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); } bool LinkerScript::hasLMA(OutputSection *Sec) { @@ -1104,3 +1149,8 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); return 0; } + +template void OutputSectionCommand::writeTo(uint8_t *Buf); +template void OutputSectionCommand::writeTo(uint8_t *Buf); +template void OutputSectionCommand::writeTo(uint8_t *Buf); +template void OutputSectionCommand::writeTo(uint8_t *Buf); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index d0a4d83d72b0..e56e569d4e72 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -130,6 +130,9 @@ struct OutputSectionCommand : BaseCommand { ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; + + template void writeTo(uint8_t *Buf); + uint32_t getFiller(); }; // This struct represents one section match pattern in SECTIONS() command. @@ -157,7 +160,7 @@ struct InputSectionDescription : BaseCommand { // will be associated with this InputSectionDescription. std::vector SectionPatterns; - std::vector Sections; + std::vector Sections; }; // Represents an ASSERT(). @@ -213,11 +216,10 @@ struct ScriptConfiguration { class LinkerScript final { llvm::DenseMap SecToCommand; - OutputSectionCommand *getCmd(OutputSection *Sec) const; void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); - std::vector + std::vector computeInputSections(const InputSectionDescription *); std::vector @@ -244,6 +246,7 @@ class LinkerScript final { MemoryRegion *CurMemRegion = nullptr; public: + OutputSectionCommand *getCmd(OutputSection *Sec) const; bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } OutputSection *getOutputSection(const Twine &Loc, StringRef S); @@ -263,7 +266,6 @@ class LinkerScript final { std::vector createPhdrs(); bool ignoreInterpSection(); - llvm::Optional getFiller(OutputSection *Sec); bool hasLMA(OutputSection *Sec); bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); @@ -272,7 +274,6 @@ class LinkerScript final { void synchronize(); void assignAddresses(std::vector &Phdrs); - void writeDataBytes(OutputSection *Sec, uint8_t *Buf); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index 7b82eceba02a..806e99e3d9dd 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -132,12 +132,17 @@ void elf::writeMapFile(llvm::ArrayRef Script) { OS << OSec->Name << '\n'; // Dump symbols for each input section. - for (InputSection *IS : OSec->Sections) { - writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), - IS->Alignment); - OS << indent(1) << toString(IS) << '\n'; - for (DefinedRegular *Sym : SectionSyms[IS]) - OS << SymStr[Sym] << '\n'; + for (BaseCommand *Base : Cmd->Commands) { + auto *ISD = dyn_cast(Base); + if (!ISD) + continue; + for (InputSection *IS : ISD->Sections) { + writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), + IS->Alignment); + OS << indent(1) << toString(IS) << '\n'; + for (DefinedRegular *Sym : SectionSyms[IS]) + OS << SymStr[Sym] << '\n'; + } } } } diff --git a/ELF/Options.td b/ELF/Options.td index 65a0e72d2320..335c7ade6db2 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -313,6 +313,7 @@ def alias_o_output2 : Separate<["--"], "output">, Alias; def alias_pie_pic_executable: F<"pic-executable">, Alias; def alias_print_map_M: Flag<["-"], "M">, Alias; def alias_relocatable_r: Flag<["-"], "r">, Alias; +def alias_reproduce_eq: J<"reproduce=">, Alias; def alias_retain_symbols_file: S<"retain-symbols-file">, Alias; def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias; def alias_rpath_rpath: J<"rpath=">, Alias; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index dcefd03766d7..d82fdcdc31ba 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -103,7 +103,7 @@ template void OutputSection::maybeCompress() { // Write section contents to a temporary buffer and compress it. std::vector Buf(Size); - writeTo(Buf.data()); + Script->getCmd(this)->writeTo(Buf.data()); if (Error E = zlib::compress(toStringRef(Buf), CompressedData)) fatal("compress failed: " + llvm::toString(std::move(E))); @@ -112,6 +112,19 @@ template void OutputSection::maybeCompress() { Flags |= SHF_COMPRESSED; } +template static void finalizeShtGroup(OutputSection *Sec) { + // sh_link field for SHT_GROUP sections should contain the section index of + // the symbol table. + Sec->Link = InX::SymTab->OutSec->SectionIndex; + + // sh_link then contain index of an entry in symbol table section which + // provides signature of the section group. + elf::ObjectFile *Obj = Sec->Sections[0]->getFile(); + assert(Config->Relocatable && Sec->Sections.size() == 1); + ArrayRef Symbols = Obj->getSymbols(); + Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]); +} + template void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { std::sort(Sections.begin(), Sections.end(), compareByFilePosition); @@ -126,6 +139,11 @@ template void OutputSection::finalize() { } uint32_t Type = this->Type; + if (Type == SHT_GROUP) { + finalizeShtGroup(this); + return; + } + if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) return; @@ -259,69 +277,6 @@ void OutputSection::sortCtorsDtors() { std::stable_sort(Sections.begin(), Sections.end(), compCtors); } -// Fill [Buf, Buf + Size) with Filler. -// This is used for linker script "=fillexp" command. -static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { - size_t I = 0; - for (; I + 4 < Size; I += 4) - memcpy(Buf + I, &Filler, 4); - memcpy(Buf + I, &Filler, Size - I); -} - -uint32_t OutputSection::getFiller() { - // Determine what to fill gaps between InputSections with, as specified by the - // linker script. If nothing is specified and this is an executable section, - // fall back to trap instructions to prevent bad diassembly and detect invalid - // jumps to padding. - if (Optional Filler = Script->getFiller(this)) - return *Filler; - if (Flags & SHF_EXECINSTR) - return Target->TrapInstr; - return 0; -} - -template void OutputSection::writeTo(uint8_t *Buf) { - Loc = Buf; - - // We may have already rendered compressed content when using - // -compress-debug-sections option. Write it together with header. - if (!CompressedData.empty()) { - memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size()); - memcpy(Buf + ZDebugHeader.size(), CompressedData.data(), - CompressedData.size()); - return; - } - - // Write leading padding. - uint32_t Filler = getFiller(); - if (Filler) - fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler); - - parallelForEachN(0, Sections.size(), [=](size_t I) { - InputSection *Sec = Sections[I]; - Sec->writeTo(Buf); - - // Fill gaps between sections. - if (Filler) { - uint8_t *Start = Buf + Sec->OutSecOff + Sec->getSize(); - uint8_t *End; - if (I + 1 == Sections.size()) - End = Buf + Size; - else - End = Buf + Sections[I + 1]->OutSecOff; - fill(Start, End - Start, Filler); - } - }); - - // Linker scripts may have BYTE()-family commands with which you - // can write arbitrary bytes to the output. Process them if any. - Script->writeDataBytes(this, Buf); -} - -static uint64_t getOutFlags(InputSectionBase *S) { - return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED; -} - static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { // The ELF spec just says // ---------------------------------------------------------------- @@ -418,7 +373,10 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, return; } - uint64_t Flags = getOutFlags(IS); + uint64_t Flags = IS->Flags; + if (!Config->Relocatable) + Flags &= ~(uint64_t)SHF_GROUP; + if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) error("incompatible section flags for " + Sec->Name + @@ -484,8 +442,3 @@ template void OutputSection::maybeCompress(); template void OutputSection::maybeCompress(); template void OutputSection::maybeCompress(); template void OutputSection::maybeCompress(); - -template void OutputSection::writeTo(uint8_t *Buf); -template void OutputSection::writeTo(uint8_t *Buf); -template void OutputSection::writeTo(uint8_t *Buf); -template void OutputSection::writeTo(uint8_t *Buf); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 413871b60cf7..08655a9ed67b 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -82,8 +82,6 @@ class OutputSection final : public SectionBase { void sort(std::function Order); void sortInitFini(); void sortCtorsDtors(); - uint32_t getFiller(); - template void writeTo(uint8_t *Buf); template void finalize(); template void maybeCompress(); void assignOffsets(); diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 599f1441a47f..d3db32613a8a 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1005,10 +1005,11 @@ DynamicSection::DynamicSection() ".dynamic") { this->Entsize = ELFT::Is64Bits ? 16 : 8; - // .dynamic section is not writable on MIPS. + // .dynamic section is not writable on MIPS and on Fuchsia OS + // which passes -z rodynamic. // See "Special Section" in Chapter 4 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Config->EMachine == EM_MIPS) + if (Config->EMachine == EM_MIPS || Config->ZRodynamic) this->Flags = SHF_ALLOC; addEntries(); @@ -1053,7 +1054,15 @@ template void DynamicSection::addEntries() { if (DtFlags1) add({DT_FLAGS_1, DtFlags1}); - if (!Config->Shared && !Config->Relocatable) + // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We + // need it for each process, so we don't write it for DSOs. The loader writes + // the pointer into this entry. + // + // DT_DEBUG is the only .dynamic entry that needs to be written to. Some + // systems (currently only Fuchsia OS) provide other means to give the + // debugger this information. Such systems may choose make .dynamic read-only. + // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. + if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) add({DT_DEBUG, (uint64_t)0}); } @@ -1778,11 +1787,10 @@ void GdbIndexSection::readDwarf(InputSection *Sec) { std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); if (IsNew) { Sym->CuVectorIndex = CuVectors.size(); - CuVectors.push_back({{CuId, Pair.second}}); - continue; + CuVectors.resize(CuVectors.size() + 1); } - CuVectors[Sym->CuVectorIndex].push_back({CuId, Pair.second}); + CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId); } } @@ -1806,7 +1814,7 @@ void GdbIndexSection::finalizeContents() { ConstantPoolOffset = SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; - for (std::vector> &CuVec : CuVectors) { + for (std::set &CuVec : CuVectors) { CuVectorsOffset.push_back(CuVectorsSize); CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1); } @@ -1859,14 +1867,11 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { } // Write the CU vectors into the constant pool. - for (std::vector> &CuVec : CuVectors) { + for (std::set &CuVec : CuVectors) { write32le(Buf, CuVec.size()); Buf += 4; - for (std::pair &P : CuVec) { - uint32_t Index = P.first; - uint8_t Flags = P.second; - Index |= Flags << 24; - write32le(Buf, Index); + for (uint32_t Val : CuVec) { + write32le(Buf, Val); Buf += 4; } } @@ -2173,17 +2178,6 @@ MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, ".rld_map") {} -void MipsRldMapSection::writeTo(uint8_t *Buf) { - // Apply filler from linker script. - Optional Fill = Script->getFiller(this->OutSec); - if (!Fill || *Fill == 0) - return; - - uint64_t Filler = *Fill; - Filler = (Filler << 32) | Filler; - memcpy(Buf, &Filler, getSize()); -} - ARMExidxSentinelSection::ARMExidxSentinelSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, Config->Wordsize, ".ARM.exidx") {} @@ -2194,7 +2188,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection() // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // Get the InputSection before us, we are by definition last - auto RI = cast(this->OutSec)->Sections.rbegin(); + auto RI = this->OutSec->Sections.rbegin(); InputSection *LE = *(++RI); InputSection *LC = cast(LE->getLinkOrderDep()); uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index c5ffb88c1366..61cc03de222e 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -27,6 +27,8 @@ #include "llvm/ADT/MapVector.h" #include "llvm/MC/StringTableBuilder.h" +#include + namespace lld { namespace elf { @@ -515,7 +517,7 @@ class GdbIndexSection final : public SyntheticSection { GdbHashTab SymbolTable; // The CU vector portion of the constant pool. - std::vector>> CuVectors; + std::vector> CuVectors; std::vector AddressArea; @@ -709,7 +711,7 @@ class MipsRldMapSection : public SyntheticSection { public: MipsRldMapSection(); size_t getSize() const override { return Config->Wordsize; } - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *Buf) override {} }; class ARMExidxSentinelSection : public SyntheticSection { diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 7a21d2b9f13d..e539d8ffce6e 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -46,6 +46,7 @@ template class Writer { void run(); private: + void clearOutputSections(); void createSyntheticSections(); void copyLocalSymbols(); void addSectionSymbols(); @@ -80,6 +81,8 @@ template class Writer { void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); OutputSection *findSection(StringRef Name); + OutputSection *findSectionInScript(StringRef Name); + OutputSectionCommand *findSectionCommand(StringRef Name); std::vector Phdrs; @@ -161,7 +164,7 @@ static void combineMergableSections() { continue; StringRef OutsecName = getOutputSectionName(MS->Name); - uint64_t Flags = MS->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED); + uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP; uint32_t Alignment = std::max(MS->Alignment, MS->Entsize); auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { @@ -198,6 +201,15 @@ template static void combineEhFrameSections() { V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } +template void Writer::clearOutputSections() { + // Clear the OutputSections to make sure it is not used anymore. Any + // code from this point on should be using the linker script + // commands. + for (OutputSection *Sec : OutputSections) + Sec->Sections.clear(); + OutputSections.clear(); +} + // The main function of the writer. template void Writer::run() { // Create linker-synthesized sections such as .got or .plt. @@ -244,13 +256,21 @@ template void Writer::run() { if (ErrorCount) return; + if (!Script->Opt.HasSections) { + if (!Config->Relocatable) + fixSectionAlignments(); + Script->fabricateDefaultCommands(); + } + + // If -compressed-debug-sections is specified, we need to compress + // .debug_* sections. Do it right now because it changes the size of + // output sections. + parallelForEach(OutputSections.begin(), OutputSections.end(), + [](OutputSection *S) { S->maybeCompress(); }); + if (Config->Relocatable) { assignFileOffsets(); } else { - if (!Script->Opt.HasSections) { - fixSectionAlignments(); - Script->fabricateDefaultCommands(); - } Script->synchronize(); Script->assignAddresses(Phdrs); @@ -281,6 +301,7 @@ template void Writer::run() { } else { writeSectionsBinary(); } + clearOutputSections(); // Backfill .note.gnu.build-id section content. This is done at last // because the content is usually a hash value of the entire output file. @@ -288,10 +309,6 @@ template void Writer::run() { if (ErrorCount) return; - // Clear the OutputSections to make sure it is not used anymore. Any - // code from this point on should be using the linker script - // commands. - OutputSections.clear(); // Handle -Map option. writeMapFile(Script->Opt.Commands); @@ -631,10 +648,11 @@ bool elf::isRelroSection(const OutputSection *Sec) { // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { - RF_NOT_ADDR_SET = 1 << 15, - RF_NOT_INTERP = 1 << 14, - RF_NOT_ALLOC = 1 << 13, - RF_WRITE = 1 << 12, + RF_NOT_ADDR_SET = 1 << 16, + RF_NOT_INTERP = 1 << 15, + RF_NOT_ALLOC = 1 << 14, + RF_WRITE = 1 << 13, + RF_EXEC_WRITE = 1 << 12, RF_EXEC = 1 << 11, RF_NON_TLS_BSS = 1 << 10, RF_NON_TLS_BSS_RO = 1 << 9, @@ -669,19 +687,29 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return Rank | RF_NOT_ALLOC; - // We want the read only sections first so that they go in the PT_LOAD - // covering the program headers at the start of the file. - if (Sec->Flags & SHF_WRITE) - Rank |= RF_WRITE; + // Sort sections based on their access permission in the following + // order: R, RX, RWX, RW. This order is based on the following + // considerations: + // * Read-only sections come first such that they go in the + // PT_LOAD covering the program headers at the start of the file. + // * Read-only, executable sections come next, unless the + // -no-rosegment option is used. + // * Writable, executable sections follow such that .plt on + // architectures where it needs to be writable will be placed + // between .text and .data. + // * Writable sections come last, such that .bss lands at the very + // end of the last PT_LOAD. + bool IsExec = Sec->Flags & SHF_EXECINSTR; + bool IsWrite = Sec->Flags & SHF_WRITE; - if (Sec->Flags & SHF_EXECINSTR) { - // For a corresponding reason, put non exec sections first (the program - // header PT_LOAD is not executable). - // We only do that if we are not using linker scripts, since with linker - // scripts ro and rx sections are in the same PT_LOAD, so their relative - // order is not important. The same applies for -no-rosegment. - if ((Rank & RF_WRITE) || !Config->SingleRoRx) + if (IsExec) { + if (IsWrite) + Rank |= RF_EXEC_WRITE; + else if (!Config->SingleRoRx) Rank |= RF_EXEC; + } else { + if (IsWrite) + Rank |= RF_WRITE; } // If we got here we know that both A and B are in the same PT_LOAD. @@ -778,12 +806,6 @@ static bool compareSections(const OutputSection *A, const OutputSection *B) { return compareSectionsNonScript(A, B); } -// Program header entry -PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) { - p_type = Type; - p_flags = Flags; -} - void PhdrEntry::add(OutputSection *Sec) { Last = Sec; if (!First) @@ -1239,12 +1261,6 @@ template void Writer::finalizeSections() { for (OutputSection *Sec : OutputSections) Sec->finalize(); - // If -compressed-debug-sections is specified, we need to compress - // .debug_* sections. Do it right now because it changes the size of - // output sections. - parallelForEach(OutputSections.begin(), OutputSections.end(), - [](OutputSection *S) { S->maybeCompress(); }); - // createThunks may have added local symbols to the static symbol table applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, [](SyntheticSection *SS) { SS->postThunkContents(); }); @@ -1297,6 +1313,21 @@ void Writer::addStartStopSymbols(OutputSection *Sec) { addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } +template +OutputSectionCommand *Writer::findSectionCommand(StringRef Name) { + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast(Base)) + if (Cmd->Name == Name) + return Cmd; + return nullptr; +} + +template OutputSection *Writer::findSectionInScript(StringRef Name) { + if (OutputSectionCommand *Cmd = findSectionCommand(Name)) + return Cmd->Sec; + return nullptr; +} + template OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) @@ -1583,7 +1614,7 @@ template uint64_t Writer::getEntryAddr() { return Addr; // Case 4 - if (OutputSection *Sec = findSection(".text")) { + if (OutputSection *Sec = findSectionInScript(".text")) { if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" + utohexstr(Sec->Addr)); @@ -1609,18 +1640,6 @@ static uint16_t getELFType() { // to each section. This function fixes some predefined // symbol values that depend on section address and size. template void Writer::fixPredefinedSymbols() { - auto Set = [](DefinedRegular *S1, DefinedRegular *S2, OutputSection *Sec, - uint64_t Value) { - if (S1) { - S1->Section = Sec; - S1->Value = Value; - } - if (S2) { - S2->Section = Sec; - S2->Value = Value; - } - }; - // _etext is the first location after the last read-only loadable segment. // _edata is the first location after the last read-write loadable segment. // _end is the first location after the uninitialized data region. @@ -1636,15 +1655,29 @@ template void Writer::fixPredefinedSymbols() { else LastRO = &P; } - if (Last) - Set(ElfSym::End1, ElfSym::End2, Last->First, Last->p_memsz); - if (LastRO) - Set(ElfSym::Etext1, ElfSym::Etext2, LastRO->First, LastRO->p_filesz); - if (LastRW) - Set(ElfSym::Edata1, ElfSym::Edata2, LastRW->First, LastRW->p_filesz); + + auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) { + if (S) { + S->Section = Sec; + S->Value = Value; + } + }; + + if (Last) { + Set(ElfSym::End1, Last->First, Last->p_memsz); + Set(ElfSym::End2, Last->First, Last->p_memsz); + } + if (LastRO) { + Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz); + Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz); + } + if (LastRW) { + Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz); + Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz); + } if (ElfSym::Bss) - ElfSym::Bss->Section = findSection(".bss"); + ElfSym::Bss->Section = findSectionInScript(".bss"); // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. @@ -1736,9 +1769,14 @@ template void Writer::openFile() { template void Writer::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); - for (OutputSection *Sec : OutputSections) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast(Base); + if (!Cmd) + continue; + OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) - Sec->writeTo(Buf + Sec->Offset); + Cmd->writeTo(Buf + Sec->Offset); + } } // Write section contents to a mmap'ed file. @@ -1747,31 +1785,45 @@ template void Writer::writeSections() { // PPC64 needs to process relocations in the .opd section // before processing relocations in code-containing sections. - Out::Opd = findSection(".opd"); - if (Out::Opd) { + if (auto *OpdCmd = findSectionCommand(".opd")) { + Out::Opd = OpdCmd->Sec; Out::OpdBuf = Buf + Out::Opd->Offset; - Out::Opd->template writeTo(Buf + Out::Opd->Offset); + OpdCmd->template writeTo(Buf + Out::Opd->Offset); } OutputSection *EhFrameHdr = - In::EhFrameHdr ? In::EhFrameHdr->OutSec : nullptr; + (In::EhFrameHdr && !In::EhFrameHdr->empty()) + ? In::EhFrameHdr->OutSec + : nullptr; // In -r or -emit-relocs mode, write the relocation sections first as in // ELf_Rel targets we might find out that we need to modify the relocated // section while doing it. - for (OutputSection *Sec : OutputSections) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast(Base); + if (!Cmd) + continue; + OutputSection *Sec = Cmd->Sec; if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) - Sec->writeTo(Buf + Sec->Offset); + Cmd->writeTo(Buf + Sec->Offset); + } - for (OutputSection *Sec : OutputSections) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast(Base); + if (!Cmd) + continue; + OutputSection *Sec = Cmd->Sec; if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) - Sec->writeTo(Buf + Sec->Offset); + Cmd->writeTo(Buf + Sec->Offset); + } // The .eh_frame_hdr depends on .eh_frame section contents, therefore // it should be written after .eh_frame is written. - if (EhFrameHdr && !EhFrameHdr->Sections.empty()) - EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset); + if (EhFrameHdr) { + OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr); + Cmd->writeTo(Buf + EhFrameHdr->Offset); + } } template void Writer::writeBuildId() { diff --git a/ELF/Writer.h b/ELF/Writer.h index 17fbda394a20..e935b6419de6 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -30,7 +30,7 @@ bool isRelroSection(const OutputSection *Sec); // Each contains type, access flags and range of output sections that will be // placed in it. struct PhdrEntry { - PhdrEntry(unsigned Type, unsigned Flags); + PhdrEntry(unsigned Type, unsigned Flags) : p_type(Type), p_flags(Flags) {} void add(OutputSection *Sec); uint64_t p_paddr = 0; diff --git a/test/COFF/Inputs/delayimports-error.yaml b/test/COFF/Inputs/delayimports-error.yaml new file mode 100644 index 000000000000..60b395938dfd --- /dev/null +++ b/test/COFF/Inputs/delayimports-error.yaml @@ -0,0 +1,29 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: 0000000000000000 +symbols: + - Name: .data + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: datasym + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/Inputs/import.yaml b/test/COFF/Inputs/import.yaml index 493400143d6c..b7ae026de29b 100644 --- a/test/COFF/Inputs/import.yaml +++ b/test/COFF/Inputs/import.yaml @@ -7,6 +7,13 @@ sections: Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 0000000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: exportfn1 + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: exportfn2 + Type: IMAGE_REL_AMD64_ADDR32NB symbols: - Name: .text Value: 0 @@ -16,7 +23,7 @@ symbols: StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 8 - NumberOfRelocations: 0 + NumberOfRelocations: 2 NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 diff --git a/test/COFF/Inputs/oldname.yaml b/test/COFF/Inputs/oldname.yaml new file mode 100644 index 000000000000..42ee5b2269bd --- /dev/null +++ b/test/COFF/Inputs/oldname.yaml @@ -0,0 +1,26 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_UNKNOWN + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: '' +symbols: + - Name: exportfn1 + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn1_alias + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_WEAK_EXTERNAL + WeakExternal: + TagIndex: 0 + Characteristics: IMAGE_WEAK_EXTERN_SEARCH_ALIAS +... diff --git a/test/COFF/delayimports-error.test b/test/COFF/delayimports-error.test new file mode 100644 index 000000000000..3fea1bc099c2 --- /dev/null +++ b/test/COFF/delayimports-error.test @@ -0,0 +1,46 @@ +# RUN: mkdir -p %t.dir +# RUN: yaml2obj < %p/Inputs/delayimports-error.yaml > %t1.obj +# RUN: lld-link /out:%t.dir/foo.dll /dll %t1.obj /export:datasym,DATA /noentry + +# RUN: yaml2obj < %s > %t2.obj +# RUN: not lld-link /out:%t.exe /entry:main %t2.obj %t.dir/foo.lib /delayload:foo.dll \ +# RUN: /alternatename:__delayLoadHelper2=main /opt:noref >& %t.log +# RUN: FileCheck %s < %t.log + +# CHECK: cannot delay-load foo.dll due to import of data: __imp_datasym + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 0000000000000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __imp_datasym + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/dllimport-gc.test b/test/COFF/dllimport-gc.test new file mode 100644 index 000000000000..54ae773e793f --- /dev/null +++ b/test/COFF/dllimport-gc.test @@ -0,0 +1,58 @@ +# REQUIRES: winres + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t-lib.obj +# RUN: lld-link /out:%t.dll /dll %t-lib.obj /implib:%t.lib /export:exportfn1 + +# RUN: yaml2obj < %p/Inputs/oldname.yaml > %t-oldname.obj + +# RUN: yaml2obj < %s > %t.obj + +# RUN: lld-link /out:%t1.exe /entry:main %t.obj %t-oldname.obj %t.lib +# RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=REF %s +# REF-NOT: Symbol: exportfn1 + +# RUN: lld-link /out:%t2.exe /entry:main %t.obj %t-oldname.obj %t.lib /opt:noref +# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=NOREF %s +# NOREF: Symbol: exportfn1 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 0000000000000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn1 + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn1_alias + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/ELF/Inputs/rodynamic.s b/test/ELF/Inputs/rodynamic.s new file mode 100644 index 000000000000..a06f4bef0084 --- /dev/null +++ b/test/ELF/Inputs/rodynamic.s @@ -0,0 +1,4 @@ +.global foo +.type foo, @function +foo: + ret diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s index f30c0ed40157..17dfc82ef8f3 100644 --- a/test/ELF/amdgpu-globals.s +++ b/test/ELF/amdgpu-globals.s @@ -40,6 +40,19 @@ module_global_readonly: program_global_readonly: .long 0 ; 0x0 +# CHECK: Section { +# CHECK: Name: .hsatext +# CHECK: Type: SHT_PROGBITS +# CHECK: Flags [ (0xC00007) +# CHECK: SHF_ALLOC (0x2) +# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) +# CHECK: SHF_AMDGPU_HSA_CODE (0x400000) +# CHECK: SHF_EXECINSTR (0x4) +# CHECK: SHF_WRITE (0x1) +# CHECK: ] +# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]] +# CHECK: } + # CHECK: Section { # CHECK: Name: .hsadata_global_program # CHECK: Type: SHT_PROGBITS (0x1) @@ -62,19 +75,6 @@ program_global_readonly: # CHECK: ] # CHECK: } -# CHECK: Section { -# CHECK: Name: .hsatext -# CHECK: Type: SHT_PROGBITS -# CHECK: Flags [ (0xC00007) -# CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) -# CHECK: SHF_AMDGPU_HSA_CODE (0x400000) -# CHECK: SHF_EXECINSTR (0x4) -# CHECK: SHF_WRITE (0x1) -# CHECK: ] -# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]] -# CHECK: } - # CHECK: Symbol { # CHECK: Name: module_global_agent # CHECK: Value: diff --git a/test/ELF/build-id.s b/test/ELF/build-id.s index ffd8d7744f70..2d193478df71 100644 --- a/test/ELF/build-id.s +++ b/test/ELF/build-id.s @@ -33,6 +33,10 @@ # RUN: ld.lld --build-id=md5 --build-id=none %t -o %t2 # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s +# RUN: ld.lld --build-id --build-id=none %t -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s +# RUN: ld.lld --build-id=none --build-id %t -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s .globl _start _start: diff --git a/test/ELF/gc-sections.s b/test/ELF/gc-sections.s index f100153ec358..0ae6fa4f06de 100644 --- a/test/ELF/gc-sections.s +++ b/test/ELF/gc-sections.s @@ -10,10 +10,10 @@ # NOGC: Name: .eh_frame # NOGC: Name: .text -# NOGC: Name: .ctors -# NOGC: Name: .dtors # NOGC: Name: .init # NOGC: Name: .fini +# NOGC: Name: .ctors +# NOGC: Name: .dtors # NOGC: Name: .debug_pubtypes # NOGC: Name: .comment # NOGC: Name: a @@ -25,10 +25,10 @@ # GC1: Name: .eh_frame # GC1: Name: .text -# GC1: Name: .ctors -# GC1: Name: .dtors # GC1: Name: .init # GC1: Name: .fini +# GC1: Name: .ctors +# GC1: Name: .dtors # GC1: Name: .debug_pubtypes # GC1: Name: .comment # GC1: Name: a @@ -40,10 +40,10 @@ # GC2: Name: .eh_frame # GC2: Name: .text -# GC2: Name: .ctors -# GC2: Name: .dtors # GC2: Name: .init # GC2: Name: .fini +# GC2: Name: .ctors +# GC2: Name: .dtors # GC2: Name: .debug_pubtypes # GC2: Name: .comment # GC2: Name: a diff --git a/test/ELF/gdb-index-dup-types.s b/test/ELF/gdb-index-dup-types.s new file mode 100644 index 000000000000..e0bed33eed4d --- /dev/null +++ b/test/ELF/gdb-index-dup-types.s @@ -0,0 +1,60 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld --gdb-index %t.o -o %t +# RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s + +## Testcase is based on output produced by gcc version 5.4.1 20160904 +## it has duplicate entries in .debug_gnu_pubtypes which seems to be +## compiler bug. In that case it is useless to have them in .gdb_index +## and we filter such entries out to reduce size of .gdb_index. + +## CHECK: Constant pool offset = {{.*}}, has 1 CU vectors: +## CHECK-NOT: 0(0x0): 0x90000000 0x90000000 + +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .ascii "\260B" # DW_AT_GNU_dwo_name + .byte 14 # DW_FORM_strp + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .ascii "\263B" # DW_AT_GNU_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + +.section .debug_info,"",@progbits +.Lcu_begin0: + .long 32 # Length of Unit + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x19 DW_TAG_compile_unit + .long 0 # DW_AT_stmt_list + .long 0 # DW_AT_GNU_dwo_name + .long 0 # DW_AT_comp_dir + .quad 0 # DW_AT_GNU_dwo_id + .long 0 # DW_AT_GNU_addr_base + +.section .debug_gnu_pubtypes,"",@progbits +.long .LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info +.LpubTypes_begin0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 36 # Compilation Unit Length + .long 36 # DIE offset + .byte 144 # Kind: TYPE, STATIC + .asciz "int" # External Name + .long 36 # DIE offset + .byte 144 # Kind: TYPE, STATIC + .asciz "int" # External Name + .long 0 # End Mark +.LpubTypes_end0: diff --git a/test/ELF/i386-tls-ie-shared.s b/test/ELF/i386-tls-ie-shared.s index 8becc3199f95..f419eb45dfb9 100644 --- a/test/ELF/i386-tls-ie-shared.s +++ b/test/ELF/i386-tls-ie-shared.s @@ -13,8 +13,8 @@ // GOTRELSHARED-NEXT: SHF_ALLOC // GOTRELSHARED-NEXT: SHF_WRITE // GOTRELSHARED-NEXT: ] -// GOTRELSHARED-NEXT: Address: 0x1058 -// GOTRELSHARED-NEXT: Offset: 0x1058 +// GOTRELSHARED-NEXT: Address: 0x2058 +// GOTRELSHARED-NEXT: Offset: 0x2058 // GOTRELSHARED-NEXT: Size: 16 // GOTRELSHARED-NEXT: Link: 0 // GOTRELSHARED-NEXT: Info: 0 @@ -23,44 +23,44 @@ // GOTRELSHARED-NEXT: } // GOTRELSHARED: Relocations [ // GOTRELSHARED-NEXT: Section ({{.*}}) .rel.dyn { -// GOTRELSHARED-NEXT: 0x2002 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x200A R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x2013 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x201C R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x2024 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x202D R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x2036 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x203F R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x1058 R_386_TLS_TPOFF tlslocal0 0x0 -// GOTRELSHARED-NEXT: 0x105C R_386_TLS_TPOFF tlslocal1 0x0 -// GOTRELSHARED-NEXT: 0x1060 R_386_TLS_TPOFF tlsshared0 0x0 -// GOTRELSHARED-NEXT: 0x1064 R_386_TLS_TPOFF tlsshared1 0x0 +// GOTRELSHARED-NEXT: 0x1002 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x100A R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x1013 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x101C R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x1024 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x102D R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x1036 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x103F R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x2058 R_386_TLS_TPOFF tlslocal0 0x0 +// GOTRELSHARED-NEXT: 0x205C R_386_TLS_TPOFF tlslocal1 0x0 +// GOTRELSHARED-NEXT: 0x2060 R_386_TLS_TPOFF tlsshared0 0x0 +// GOTRELSHARED-NEXT: 0x2064 R_386_TLS_TPOFF tlsshared1 0x0 // GOTRELSHARED-NEXT: } // GOTRELSHARED-NEXT: ] // GOTRELSHARED: 0x6FFFFFFA RELCOUNT 8 // DISASMSHARED: Disassembly of section test: // DISASMSHARED-NEXT: _start: -// (.got)[0] = 0x2050 = 8272 -// (.got)[1] = 0x2054 = 8276 -// (.got)[2] = 0x2058 = 8280 -// (.got)[3] = 0x205C = 8284 -// DISASMSHARED-NEXT: 2000: 8b 0d 58 10 00 00 movl 4184, %ecx -// DISASMSHARED-NEXT: 2006: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 2009: a1 58 10 00 00 movl 4184, %eax -// DISASMSHARED-NEXT: 200e: 65 8b 00 movl %gs:(%eax), %eax -// DISASMSHARED-NEXT: 2011: 03 0d 58 10 00 00 addl 4184, %ecx -// DISASMSHARED-NEXT: 2017: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 201a: 8b 0d 5c 10 00 00 movl 4188, %ecx -// DISASMSHARED-NEXT: 2020: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 2023: a1 5c 10 00 00 movl 4188, %eax -// DISASMSHARED-NEXT: 2028: 65 8b 00 movl %gs:(%eax), %eax -// DISASMSHARED-NEXT: 202b: 03 0d 5c 10 00 00 addl 4188, %ecx -// DISASMSHARED-NEXT: 2031: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 2034: 8b 0d 60 10 00 00 movl 4192, %ecx -// DISASMSHARED-NEXT: 203a: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 203d: 03 0d 64 10 00 00 addl 4196, %ecx -// DISASMSHARED-NEXT: 2043: 65 8b 01 movl %gs:(%ecx), %eax +// (.got)[0] = 0x2058 = 8280 +// (.got)[1] = 0x205C = 8284 +// (.got)[2] = 0x2060 = 8288 +// (.got)[3] = 0x2064 = 8292 +// DISASMSHARED-NEXT: 1000: 8b 0d 58 20 00 00 movl 8280, %ecx +// DISASMSHARED-NEXT: 1006: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 1009: a1 58 20 00 00 movl 8280, %eax +// DISASMSHARED-NEXT: 100e: 65 8b 00 movl %gs:(%eax), %eax +// DISASMSHARED-NEXT: 1011: 03 0d 58 20 00 00 addl 8280, %ecx +// DISASMSHARED-NEXT: 1017: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 101a: 8b 0d 5c 20 00 00 movl 8284, %ecx +// DISASMSHARED-NEXT: 1020: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 1023: a1 5c 20 00 00 movl 8284, %eax +// DISASMSHARED-NEXT: 1028: 65 8b 00 movl %gs:(%eax), %eax +// DISASMSHARED-NEXT: 102b: 03 0d 5c 20 00 00 addl 8284, %ecx +// DISASMSHARED-NEXT: 1031: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 1034: 8b 0d 60 20 00 00 movl 8288, %ecx +// DISASMSHARED-NEXT: 103a: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 103d: 03 0d 64 20 00 00 addl 8292, %ecx +// DISASMSHARED-NEXT: 1043: 65 8b 01 movl %gs:(%ecx), %eax .type tlslocal0,@object .section .tbss,"awT",@nobits diff --git a/test/ELF/linkerscript/arm-lscript.s b/test/ELF/linkerscript/arm-lscript.s new file mode 100644 index 000000000000..c377764e9776 --- /dev/null +++ b/test/ELF/linkerscript/arm-lscript.s @@ -0,0 +1,9 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: echo "SECTIONS { \ +// RUN: .rel.dyn : { } \ +// RUN: .zed : { PROVIDE_HIDDEN (foobar = .); } \ +// RUN: }" > %t.script +// This is a test case for PR33029. Making sure that linker can digest +// the above script without dumping core. +// RUN: ld.lld -emit-relocs -T %t.script %t.o -shared -o %t.so diff --git a/test/ELF/linkerscript/sections-constraint.s b/test/ELF/linkerscript/sections-constraint.s index 796240627170..4d95ec18336c 100644 --- a/test/ELF/linkerscript/sections-constraint.s +++ b/test/ELF/linkerscript/sections-constraint.s @@ -24,8 +24,8 @@ # NO1-NEXT: 0 00000000 # NO1: .writable 00000004 # NO1: .foo.2 00000004 -# NO1: .foo.1 00000004 # NO1: .readable 00000004 +# NO1: .foo.1 00000004 .global _start _start: diff --git a/test/ELF/lto/Inputs/relocation-model-pic.ll b/test/ELF/lto/Inputs/relocation-model-pic.ll new file mode 100644 index 000000000000..e76605435e87 --- /dev/null +++ b/test/ELF/lto/Inputs/relocation-model-pic.ll @@ -0,0 +1,11 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = external global i32 +define i32 @main() { + %t = load i32, i32* @foo + ret i32 %t +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"PIC Level", i32 2} diff --git a/test/ELF/lto/relocation-model.ll b/test/ELF/lto/relocation-model.ll new file mode 100644 index 000000000000..78334dd5cd2c --- /dev/null +++ b/test/ELF/lto/relocation-model.ll @@ -0,0 +1,46 @@ +; REQUIRES: x86 + +; RUN: llvm-as %s -o %t.o +; RUN: llvm-as %p/Inputs/relocation-model-pic.ll -o %t.pic.o + +;; Non-PIC source. + +; RUN: ld.lld %t.o -o %t-out -save-temps -shared +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.o -o %t-out -save-temps --export-dynamic --noinhibit-exec -pie +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.o -o %t-out -save-temps --export-dynamic --noinhibit-exec +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + +; RUN: ld.lld %t.o -o %t-out -save-temps -r --export-dynamic +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + + +;; PIC source. + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps -shared +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps --export-dynamic --noinhibit-exec -pie +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps --export-dynamic --noinhibit-exec +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps -r --export-dynamic +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + + +; PIC: R_X86_64_REX_GOTPCRELX foo +; STATIC: R_X86_64_PC32 foo + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = external global i32 +define i32 @main() { + %t = load i32, i32* @foo + ret i32 %t +} diff --git a/test/ELF/relocatable-comdat.s b/test/ELF/relocatable-comdat.s new file mode 100644 index 000000000000..24504d23884f --- /dev/null +++ b/test/ELF/relocatable-comdat.s @@ -0,0 +1,45 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -r %t.o %t.o -o %t +# RUN: llvm-readobj -elf-section-groups -sections %t | FileCheck %s + +# CHECK: Name: .text.bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_GROUP +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 8 +# CHECK: Section { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .text.foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_GROUP +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 4 + +# CHECK: Groups { +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: abc +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .text.bar +# CHECK-NEXT: .text.foo +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } + +.section .text.bar,"axG",@progbits,abc,comdat +.quad 42 +.section .text.foo,"axG",@progbits,abc,comdat +.long 42 diff --git a/test/ELF/relocation-size-shared.s b/test/ELF/relocation-size-shared.s index 7b700ad74401..cea9e64d58ed 100644 --- a/test/ELF/relocation-size-shared.s +++ b/test/ELF/relocation-size-shared.s @@ -7,48 +7,48 @@ // RELOCSHARED: Relocations [ // RELOCSHARED-NEXT: Section ({{.*}}) .rela.dyn { -// RELOCSHARED-NEXT: 0x203018 R_X86_64_SIZE64 fooshared 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT: 0x203020 R_X86_64_SIZE64 fooshared 0x0 -// RELOCSHARED-NEXT: 0x203028 R_X86_64_SIZE64 fooshared 0x1 -// RELOCSHARED-NEXT: 0x203048 R_X86_64_SIZE32 fooshared 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT: 0x20304F R_X86_64_SIZE32 fooshared 0x0 -// RELOCSHARED-NEXT: 0x203056 R_X86_64_SIZE32 fooshared 0x1 +// RELOCSHARED-NEXT: 0x201018 R_X86_64_SIZE64 fooshared 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT: 0x201020 R_X86_64_SIZE64 fooshared 0x0 +// RELOCSHARED-NEXT: 0x201028 R_X86_64_SIZE64 fooshared 0x1 +// RELOCSHARED-NEXT: 0x201048 R_X86_64_SIZE32 fooshared 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT: 0x20104F R_X86_64_SIZE32 fooshared 0x0 +// RELOCSHARED-NEXT: 0x201056 R_X86_64_SIZE32 fooshared 0x1 // RELOCSHARED-NEXT: } // RELOCSHARED-NEXT:] // DISASM: Disassembly of section test // DISASM: _data: -// DISASM-NEXT: 203000: 19 00 -// DISASM-NEXT: 203002: 00 00 -// DISASM-NEXT: 203004: 00 00 -// DISASM-NEXT: 203006: 00 00 -// DISASM-NEXT: 203008: 1a 00 -// DISASM-NEXT: 20300a: 00 00 -// DISASM-NEXT: 20300c: 00 00 -// DISASM-NEXT: 20300e: 00 00 -// DISASM-NEXT: 203010: 1b 00 -// DISASM-NEXT: 203012: 00 00 -// DISASM-NEXT: 203014: 00 00 -// DISASM-NEXT: 203016: 00 00 -// DISASM-NEXT: 203018: 00 00 -// DISASM-NEXT: 20301a: 00 00 -// DISASM-NEXT: 20301c: 00 00 -// DISASM-NEXT: 20301e: 00 00 -// DISASM-NEXT: 203020: 00 00 -// DISASM-NEXT: 203022: 00 00 -// DISASM-NEXT: 203024: 00 00 -// DISASM-NEXT: 203026: 00 00 -// DISASM-NEXT: 203028: 00 00 -// DISASM-NEXT: 20302a: 00 00 -// DISASM-NEXT: 20302c: 00 00 -// DISASM-NEXT: 20302e: 00 00 +// DISASM-NEXT: 201000: 19 00 +// DISASM-NEXT: 201002: 00 00 +// DISASM-NEXT: 201004: 00 00 +// DISASM-NEXT: 201006: 00 00 +// DISASM-NEXT: 201008: 1a 00 +// DISASM-NEXT: 20100a: 00 00 +// DISASM-NEXT: 20100c: 00 00 +// DISASM-NEXT: 20100e: 00 00 +// DISASM-NEXT: 201010: 1b 00 +// DISASM-NEXT: 201012: 00 00 +// DISASM-NEXT: 201014: 00 00 +// DISASM-NEXT: 201016: 00 00 +// DISASM-NEXT: 201018: 00 00 +// DISASM-NEXT: 20101a: 00 00 +// DISASM-NEXT: 20101c: 00 00 +// DISASM-NEXT: 20101e: 00 00 +// DISASM-NEXT: 201020: 00 00 +// DISASM-NEXT: 201022: 00 00 +// DISASM-NEXT: 201024: 00 00 +// DISASM-NEXT: 201026: 00 00 +// DISASM-NEXT: 201028: 00 00 +// DISASM-NEXT: 20102a: 00 00 +// DISASM-NEXT: 20102c: 00 00 +// DISASM-NEXT: 20102e: 00 00 // DISASM: _start: -// DISASM-NEXT: 203030: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 203037: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 20303e: 8b 04 25 1b 00 00 00 movl 27, %eax -// DISASM-NEXT: 203045: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASM-NEXT: 20304c: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASM-NEXT: 203053: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 201037: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 20103e: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201045: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 20104c: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 201053: 8b 04 25 00 00 00 00 movl 0, %eax .data .global foo diff --git a/test/ELF/relocation-size.s b/test/ELF/relocation-size.s index 2256be67df06..419b8a17fad9 100644 --- a/test/ELF/relocation-size.s +++ b/test/ELF/relocation-size.s @@ -11,82 +11,82 @@ // DISASM: Disassembly of section test: // DISASM-NEXT: _data: -// DISASM-NEXT: 202000: 19 00 -// DISASM-NEXT: 202002: 00 00 -// DISASM-NEXT: 202004: 00 00 -// DISASM-NEXT: 202006: 00 00 -// DISASM-NEXT: 202008: 1a 00 -// DISASM-NEXT: 20200a: 00 00 -// DISASM-NEXT: 20200c: 00 00 -// DISASM-NEXT: 20200e: 00 00 -// DISASM-NEXT: 202010: 1b 00 -// DISASM-NEXT: 202012: 00 00 -// DISASM-NEXT: 202014: 00 00 -// DISASM-NEXT: 202016: 00 00 -// DISASM-NEXT: 202018: 19 00 -// DISASM-NEXT: 20201a: 00 00 -// DISASM-NEXT: 20201c: 00 00 -// DISASM-NEXT: 20201e: 00 00 -// DISASM-NEXT: 202020: 1a 00 -// DISASM-NEXT: 202022: 00 00 -// DISASM-NEXT: 202024: 00 00 -// DISASM-NEXT: 202026: 00 00 -// DISASM-NEXT: 202028: 1b 00 -// DISASM-NEXT: 20202a: 00 00 -// DISASM-NEXT: 20202c: 00 00 -// DISASM-NEXT: 20202e: 00 00 +// DISASM-NEXT: 201000: 19 00 +// DISASM-NEXT: 201002: 00 00 +// DISASM-NEXT: 201004: 00 00 +// DISASM-NEXT: 201006: 00 00 +// DISASM-NEXT: 201008: 1a 00 +// DISASM-NEXT: 20100a: 00 00 +// DISASM-NEXT: 20100c: 00 00 +// DISASM-NEXT: 20100e: 00 00 +// DISASM-NEXT: 201010: 1b 00 +// DISASM-NEXT: 201012: 00 00 +// DISASM-NEXT: 201014: 00 00 +// DISASM-NEXT: 201016: 00 00 +// DISASM-NEXT: 201018: 19 00 +// DISASM-NEXT: 20101a: 00 00 +// DISASM-NEXT: 20101c: 00 00 +// DISASM-NEXT: 20101e: 00 00 +// DISASM-NEXT: 201020: 1a 00 +// DISASM-NEXT: 201022: 00 00 +// DISASM-NEXT: 201024: 00 00 +// DISASM-NEXT: 201026: 00 00 +// DISASM-NEXT: 201028: 1b 00 +// DISASM-NEXT: 20102a: 00 00 +// DISASM-NEXT: 20102c: 00 00 +// DISASM-NEXT: 20102e: 00 00 // DISASM: _start: -// DISASM-NEXT: 202030: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 202037: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 20203e: 8b 04 25 1b 00 00 00 movl 27, %eax -// DISASM-NEXT: 202045: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 20204c: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 202053: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 201037: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 20103e: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201045: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 20104c: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 201053: 8b 04 25 1b 00 00 00 movl 27, %eax // RELOCSHARED: Relocations [ // RELOCSHARED-NEXT: Section ({{.*}}) .rela.dyn { -// RELOCSHARED-NEXT: 0x3000 R_X86_64_SIZE64 foo 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT: 0x3008 R_X86_64_SIZE64 foo 0x0 -// RELOCSHARED-NEXT: 0x3010 R_X86_64_SIZE64 foo 0x1 -// RELOCSHARED-NEXT: 0x3033 R_X86_64_SIZE32 foo 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT: 0x303A R_X86_64_SIZE32 foo 0x0 -// RELOCSHARED-NEXT: 0x3041 R_X86_64_SIZE32 foo 0x1 +// RELOCSHARED-NEXT: 0x1000 R_X86_64_SIZE64 foo 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT: 0x1008 R_X86_64_SIZE64 foo 0x0 +// RELOCSHARED-NEXT: 0x1010 R_X86_64_SIZE64 foo 0x1 +// RELOCSHARED-NEXT: 0x1033 R_X86_64_SIZE32 foo 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT: 0x103A R_X86_64_SIZE32 foo 0x0 +// RELOCSHARED-NEXT: 0x1041 R_X86_64_SIZE32 foo 0x1 // RELOCSHARED-NEXT: } // RELOCSHARED-NEXT: ] // DISASMSHARED: Disassembly of section test: // DISASMSHARED-NEXT: _data: -// DISASMSHARED-NEXT: 3000: 00 00 -// DISASMSHARED-NEXT: 3002: 00 00 -// DISASMSHARED-NEXT: 3004: 00 00 -// DISASMSHARED-NEXT: 3006: 00 00 -// DISASMSHARED-NEXT: 3008: 00 00 -// DISASMSHARED-NEXT: 300a: 00 00 -// DISASMSHARED-NEXT: 300c: 00 00 -// DISASMSHARED-NEXT: 300e: 00 00 -// DISASMSHARED-NEXT: 3010: 00 00 -// DISASMSHARED-NEXT: 3012: 00 00 -// DISASMSHARED-NEXT: 3014: 00 00 -// DISASMSHARED-NEXT: 3016: 00 00 -// DISASMSHARED-NEXT: 3018: 19 00 -// DISASMSHARED-NEXT: 301a: 00 00 -// DISASMSHARED-NEXT: 301c: 00 00 -// DISASMSHARED-NEXT: 301e: 00 00 -// DISASMSHARED-NEXT: 3020: 1a 00 -// DISASMSHARED-NEXT: 3022: 00 00 -// DISASMSHARED-NEXT: 3024: 00 00 -// DISASMSHARED-NEXT: 3026: 00 00 -// DISASMSHARED-NEXT: 3028: 1b 00 -// DISASMSHARED-NEXT: 302a: 00 00 -// DISASMSHARED-NEXT: 302c: 00 00 -// DISASMSHARED-NEXT: 302e: 00 00 +// DISASMSHARED-NEXT: 1000: 00 00 +// DISASMSHARED-NEXT: 1002: 00 00 +// DISASMSHARED-NEXT: 1004: 00 00 +// DISASMSHARED-NEXT: 1006: 00 00 +// DISASMSHARED-NEXT: 1008: 00 00 +// DISASMSHARED-NEXT: 100a: 00 00 +// DISASMSHARED-NEXT: 100c: 00 00 +// DISASMSHARED-NEXT: 100e: 00 00 +// DISASMSHARED-NEXT: 1010: 00 00 +// DISASMSHARED-NEXT: 1012: 00 00 +// DISASMSHARED-NEXT: 1014: 00 00 +// DISASMSHARED-NEXT: 1016: 00 00 +// DISASMSHARED-NEXT: 1018: 19 00 +// DISASMSHARED-NEXT: 101a: 00 00 +// DISASMSHARED-NEXT: 101c: 00 00 +// DISASMSHARED-NEXT: 101e: 00 00 +// DISASMSHARED-NEXT: 1020: 1a 00 +// DISASMSHARED-NEXT: 1022: 00 00 +// DISASMSHARED-NEXT: 1024: 00 00 +// DISASMSHARED-NEXT: 1026: 00 00 +// DISASMSHARED-NEXT: 1028: 1b 00 +// DISASMSHARED-NEXT: 102a: 00 00 +// DISASMSHARED-NEXT: 102c: 00 00 +// DISASMSHARED-NEXT: 102e: 00 00 // DISASMSHARED: _start: -// DISASMSHARED-NEXT: 3030: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 3037: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 303e: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 3045: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASMSHARED-NEXT: 304c: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASMSHARED-NEXT: 3053: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASMSHARED-NEXT: 1030: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 1037: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 103e: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 1045: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASMSHARED-NEXT: 104c: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASMSHARED-NEXT: 1053: 8b 04 25 1b 00 00 00 movl 27, %eax .data .global foo diff --git a/test/ELF/reproduce.s b/test/ELF/reproduce.s index 94823d6d377f..0a93be08d040 100644 --- a/test/ELF/reproduce.s +++ b/test/ELF/reproduce.s @@ -63,7 +63,7 @@ ## Check that directory path is stripped from -o # RUN: mkdir -p %t.dir/build3/a/b/c # RUN: cd %t.dir -# RUN: ld.lld build1/foo.o -o build3/a/b/c/bar -shared --as-needed --reproduce repro3.tar +# RUN: ld.lld build1/foo.o -o build3/a/b/c/bar -shared --as-needed --reproduce=repro3.tar # RUN: tar xf repro3.tar # RUN: FileCheck %s --check-prefix=RSP3 < repro3/response.txt # RSP3: -o bar diff --git a/test/ELF/rodynamic.s b/test/ELF/rodynamic.s new file mode 100644 index 000000000000..441e5c395e7c --- /dev/null +++ b/test/ELF/rodynamic.s @@ -0,0 +1,35 @@ +# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux +# RUN: llvm-mc %p/Inputs/rodynamic.s -o %t.so.o -filetype=obj -triple=x86_64-pc-linux + +# RUN: ld.lld -shared %t.so.o -o %t.so +# RUN: ld.lld %t.o %t.so -o %t.exe +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=DEFDEBUG %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=DEFSEC %s + +# RUN: ld.lld -shared -z rodynamic %t.so.o -o %t.so +# RUN: ld.lld -z rodynamic %t.o %t.so -o %t.exe +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=RODEBUG %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=ROSEC %s + +.globl _start +_start: + call foo + +# DEFDEBUG: DEBUG + +# DEFSEC: Section { +# DEFSEC: Name: .dynamic +# DEFSEC-NEXT: Type: SHT_DYNAMIC +# DEFSEC-NEXT: Flags [ +# DEFSEC-NEXT: SHF_ALLOC +# DEFSEC-NEXT: SHF_WRITE +# DEFSEC-NEXT: ] + +# RODEBUG-NOT: DEBUG + +# ROSEC: Section { +# ROSEC: Name: .dynamic +# ROSEC-NEXT: Type: SHT_DYNAMIC +# ROSEC-NEXT: Flags [ +# ROSEC-NEXT: SHF_ALLOC +# ROSEC-NEXT: ] diff --git a/test/ELF/section-layout.s b/test/ELF/section-layout.s index f63066e0d926..7febec85a629 100644 --- a/test/ELF/section-layout.s +++ b/test/ELF/section-layout.s @@ -34,6 +34,11 @@ _start: // CHECK: Name: c // CHECK: Name: d +// Sections that are both writable and executable appear before +// sections that are only writable. +// CHECK: Name: k +// CHECK: Name: l + // Writable sections appear before TLS and other relro sections. // CHECK: Name: i @@ -42,8 +47,6 @@ _start: // CHECK: Name: g // CHECK: Name: j -// CHECK: Name: k -// CHECK: Name: l // Non allocated sections are in input order. // CHECK: Name: t diff --git a/test/ELF/tls-i686.s b/test/ELF/tls-i686.s index 2a04a555865a..7f2dd605cacd 100644 --- a/test/ELF/tls-i686.s +++ b/test/ELF/tls-i686.s @@ -32,38 +32,38 @@ _start: // DIS: Disassembly of section test: // DIS-NEXT: _start: -// DIS-NEXT: 12000: ba 08 00 00 00 movl $8, %edx -// DIS-NEXT: 12005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 1200c: 29 d0 subl %edx, %eax -// DIS-NEXT: 1200e: ba 04 00 00 00 movl $4, %edx -// DIS-NEXT: 12013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 1201a: 29 d0 subl %edx, %eax -// DIS-NEXT: 1201c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 12023: 8d 81 f8 ff ff ff leal -8(%ecx), %eax -// DIS-NEXT: 12029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 12030: 8d 81 77 00 00 00 leal 119(%ecx), %eax +// DIS-NEXT: 11000: ba 08 00 00 00 movl $8, %edx +// DIS-NEXT: 11005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 1100c: 29 d0 subl %edx, %eax +// DIS-NEXT: 1100e: ba 04 00 00 00 movl $4, %edx +// DIS-NEXT: 11013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 1101a: 29 d0 subl %edx, %eax +// DIS-NEXT: 1101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 11023: 8d 81 f8 ff ff ff leal -8(%ecx), %eax +// DIS-NEXT: 11029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 11030: 8d 81 77 00 00 00 leal 119(%ecx), %eax // RELOC: Relocations [ // RELOC-NEXT: ] // DISSHARED: Disassembly of section test: // DISSHARED-NEXT: _start: -// DISSHARED-NEXT: 2000: ba 00 00 00 00 movl $0, %edx -// DISSHARED-NEXT: 2005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DISSHARED-NEXT: 200c: 29 d0 subl %edx, %eax -// DISSHARED-NEXT: 200e: ba 00 00 00 00 movl $0, %edx -// DISSHARED-NEXT: 2013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DISSHARED-NEXT: 201a: 29 d0 subl %edx, %eax -// DISSHARED-NEXT: 201c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DISSHARED-NEXT: 2023: 8d 81 00 00 00 00 leal (%ecx), %eax -// DISSHARED-NEXT: 2029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DISSHARED-NEXT: 2030: 8d 81 7b 00 00 00 leal 123(%ecx), %eax +// DISSHARED-NEXT: 1000: ba 00 00 00 00 movl $0, %edx +// DISSHARED-NEXT: 1005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 100c: 29 d0 subl %edx, %eax +// DISSHARED-NEXT: 100e: ba 00 00 00 00 movl $0, %edx +// DISSHARED-NEXT: 1013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 101a: 29 d0 subl %edx, %eax +// DISSHARED-NEXT: 101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 1023: 8d 81 00 00 00 00 leal (%ecx), %eax +// DISSHARED-NEXT: 1029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 1030: 8d 81 7b 00 00 00 leal 123(%ecx), %eax // RELOCSHARED: Relocations [ // RELOCSHARED-NEXT: Section (4) .rel.dyn { -// RELOCSHARED-NEXT: 0x2001 R_386_TLS_TPOFF32 var 0x0 -// RELOCSHARED-NEXT: 0x2025 R_386_TLS_TPOFF var 0x0 -// RELOCSHARED-NEXT: 0x200F R_386_TLS_TPOFF32 var1 0x0 -// RELOCSHARED-NEXT: 0x2032 R_386_TLS_TPOFF var1 0x0 +// RELOCSHARED-NEXT: 0x1001 R_386_TLS_TPOFF32 var 0x0 +// RELOCSHARED-NEXT: 0x1025 R_386_TLS_TPOFF var 0x0 +// RELOCSHARED-NEXT: 0x100F R_386_TLS_TPOFF32 var1 0x0 +// RELOCSHARED-NEXT: 0x1032 R_386_TLS_TPOFF var1 0x0 // RELOCSHARED-NEXT: } // RELOCSHARED-NEXT: ] From cbb560c9ba3c378189c7a438bed9977b482410fb Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Tue, 30 May 2017 17:38:04 +0000 Subject: [PATCH 03/11] Vendor import of lld trunk r304222: https://llvm.org/svn/llvm-project/lld/trunk@304222 --- ELF/LinkerScript.cpp | 13 ++++-- ELF/LinkerScript.h | 5 +++ ELF/MapFile.cpp | 15 +++---- ELF/MapFile.h | 5 ++- ELF/OutputSections.cpp | 2 +- ELF/ScriptParser.cpp | 6 ++- ELF/Writer.cpp | 53 ++++++++++++++----------- test/ELF/linkerscript/align.s | 2 +- test/ELF/linkerscript/bss-fill.s | 7 ++++ test/ELF/linkerscript/merge-sections.s | 10 +++++ test/ELF/linkerscript/symbol-reserved.s | 6 +++ 11 files changed, 83 insertions(+), 41 deletions(-) create mode 100644 test/ELF/linkerscript/bss-fill.s diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 492b81c1fa76..99c464e3714c 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -52,11 +52,12 @@ LinkerScript *elf::Script; uint64_t ExprValue::getValue() const { if (Sec) { if (Sec->getOutputSection()) - return Sec->getOffset(Val) + Sec->getOutputSection()->Addr; + return alignTo(Sec->getOffset(Val) + Sec->getOutputSection()->Addr, + Alignment); error("unable to evaluate expression: input section " + Sec->Name + " has no output section assigned"); } - return Val; + return alignTo(Val, Alignment); } uint64_t ExprValue::getSecAddr() const { @@ -143,7 +144,7 @@ void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { } else { Sym->Section = V.Sec; if (Sym->Section->Flags & SHF_ALLOC) - Sym->Value = V.Val; + Sym->Value = alignTo(V.Val, V.Alignment); else Sym->Value = V.getValue(); } @@ -290,6 +291,9 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { size_t SizeBefore = Ret.size(); for (InputSectionBase *Sec : InputSections) { + if (!isa(Sec)) + continue; + if (Sec->Assigned) continue; @@ -1076,6 +1080,9 @@ template void OutputSectionCommand::writeTo(uint8_t *Buf) { return; } + if (Sec->Type == SHT_NOBITS) + return; + // Write leading padding. ArrayRef Sections = Sec->Sections; uint32_t Filler = getFiller(); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index e56e569d4e72..08f60f4517a7 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -41,7 +41,12 @@ struct ExprValue { SectionBase *Sec; uint64_t Val; bool ForceAbsolute; + uint64_t Alignment = 1; + ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val, + uint64_t Alignment) + : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Alignment(Alignment) { + } ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val) : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute) {} ExprValue(SectionBase *Sec, uint64_t Val) : ExprValue(Sec, false, Val) {} diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index 806e99e3d9dd..e0c7d8cd8b1b 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -100,7 +100,7 @@ getSymbolStrings(ArrayRef Syms) { } template -void elf::writeMapFile(llvm::ArrayRef Script) { +void elf::writeMapFile(llvm::ArrayRef Script) { if (Config->MapFile.empty()) return; @@ -123,10 +123,7 @@ void elf::writeMapFile(llvm::ArrayRef Script) { << " Align Out In Symbol\n"; // Print out file contents. - for (BaseCommand *Base : Script) { - auto *Cmd = dyn_cast(Base); - if (!Cmd) - continue; + for (OutputSectionCommand *Cmd : Script) { OutputSection *OSec = Cmd->Sec; writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment); OS << OSec->Name << '\n'; @@ -147,7 +144,7 @@ void elf::writeMapFile(llvm::ArrayRef Script) { } } -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(ArrayRef); diff --git a/ELF/MapFile.h b/ELF/MapFile.h index f50ef00061ff..68d8ba8d4a04 100644 --- a/ELF/MapFile.h +++ b/ELF/MapFile.h @@ -14,8 +14,9 @@ namespace lld { namespace elf { -struct BaseCommand; -template void writeMapFile(llvm::ArrayRef Script); +struct OutputSectionCommand; +template +void writeMapFile(llvm::ArrayRef Script); } } diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index d82fdcdc31ba..f117690c3828 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -117,7 +117,7 @@ template static void finalizeShtGroup(OutputSection *Sec) { // the symbol table. Sec->Link = InX::SymTab->OutSec->SectionIndex; - // sh_link then contain index of an entry in symbol table section which + // sh_info then contain index of an entry in symbol table section which // provides signature of the section group. elf::ObjectFile *Obj = Sec->Sections[0]->getFile(); assert(Config->Relocatable && Sec->Sections.size() == 1); diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index f1bc245c9256..4b77e35b9bae 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -859,7 +859,11 @@ Expr ScriptParser::readPrimary() { expect(","); Expr E2 = readExpr(); expect(")"); - return [=] { return alignTo(E().getValue(), E2().getValue()); }; + return [=] { + ExprValue V = E(); + V.Alignment = E2().getValue(); + return V; + }; } if (Tok == "ALIGNOF") { StringRef Name = readParenLiteral(); diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index e539d8ffce6e..77d6412f80ad 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -74,6 +74,7 @@ template class Writer { std::unique_ptr Buffer; std::vector OutputSections; + std::vector OutputSectionCommands; OutputSectionFactory Factory{OutputSections}; void addRelIpltSymbols(); @@ -262,6 +263,10 @@ template void Writer::run() { Script->fabricateDefaultCommands(); } + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast(Base)) + OutputSectionCommands.push_back(Cmd); + // If -compressed-debug-sections is specified, we need to compress // .debug_* sections. Do it right now because it changes the size of // output sections. @@ -311,7 +316,7 @@ template void Writer::run() { // Handle -Map option. - writeMapFile(Script->Opt.Commands); + writeMapFile(OutputSectionCommands); if (ErrorCount) return; @@ -1201,8 +1206,6 @@ template void Writer::finalizeSections() { if (ErrorCount) return; - // So far we have added sections from input object files. - // This function adds linker-created Out::* sections. addPredefinedSections(); removeUnusedSyntheticSections(OutputSections); @@ -1270,8 +1273,20 @@ template void Writer::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. auto *OS = dyn_cast_or_null(findSection(".ARM.exidx")); - if (OS && !OS->Sections.empty() && !Config->Relocatable) - OS->addSection(make()); + if (!OS || OS->Sections.empty() || Config->Relocatable) + return; + + auto *Sentinel = make(); + OS->addSection(Sentinel); + // If there are linker script commands existing at this point then add the + // sentinel to the last of these too. + if (OutputSectionCommand *C = Script->getCmd(OS)) { + auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), + [](const BaseCommand *Base) { + return isa(Base); + }); + cast(*ISD)->Sections.push_back(Sentinel); + } } // The linker is expected to define SECNAME_start and SECNAME_end @@ -1315,10 +1330,9 @@ void Writer::addStartStopSymbols(OutputSection *Sec) { template OutputSectionCommand *Writer::findSectionCommand(StringRef Name) { - for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast(Base)) - if (Cmd->Name == Name) - return Cmd; + for (OutputSectionCommand *Cmd : OutputSectionCommands) + if (Cmd->Name == Name) + return Cmd; return nullptr; } @@ -1713,7 +1727,7 @@ template void Writer::writeHeader() { EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); - EHdr->e_shnum = OutputSections.size() + 1; + EHdr->e_shnum = OutputSectionCommands.size() + 1; EHdr->e_shstrndx = InX::ShStrTab->OutSec->SectionIndex; if (Config->EMachine == EM_ARM) @@ -1745,8 +1759,8 @@ template void Writer::writeHeader() { // Write the section header table. Note that the first table entry is null. auto *SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); - for (OutputSection *Sec : OutputSections) - Sec->writeHeaderTo(++SHdrs); + for (OutputSectionCommand *Cmd : OutputSectionCommands) + Cmd->Sec->writeHeaderTo(++SHdrs); } // Open a result file. @@ -1769,10 +1783,7 @@ template void Writer::openFile() { template void Writer::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); - for (BaseCommand *Base : Script->Opt.Commands) { - auto *Cmd = dyn_cast(Base); - if (!Cmd) - continue; + for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) Cmd->writeTo(Buf + Sec->Offset); @@ -1799,19 +1810,13 @@ template void Writer::writeSections() { // In -r or -emit-relocs mode, write the relocation sections first as in // ELf_Rel targets we might find out that we need to modify the relocated // section while doing it. - for (BaseCommand *Base : Script->Opt.Commands) { - auto *Cmd = dyn_cast(Base); - if (!Cmd) - continue; + for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) Cmd->writeTo(Buf + Sec->Offset); } - for (BaseCommand *Base : Script->Opt.Commands) { - auto *Cmd = dyn_cast(Base); - if (!Cmd) - continue; + for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) diff --git a/test/ELF/linkerscript/align.s b/test/ELF/linkerscript/align.s index ffeb1acbd027..357f54ce1ca5 100644 --- a/test/ELF/linkerscript/align.s +++ b/test/ELF/linkerscript/align.s @@ -64,7 +64,7 @@ # SYMBOLS-NEXT: 0000000000010000 *ABS* 00000000 __code_base__ # SYMBOLS-NEXT: 0000000000001000 *ABS* 00000000 VAR # SYMBOLS-NEXT: 0000000000011000 .bbb 00000000 __start_bbb -# SYMBOLS-NEXT: 0000000000012000 *ABS* 00000000 __end_bbb +# SYMBOLS-NEXT: 0000000000012000 .bbb 00000000 __end_bbb .global _start _start: diff --git a/test/ELF/linkerscript/bss-fill.s b/test/ELF/linkerscript/bss-fill.s new file mode 100644 index 000000000000..92f9fdf56190 --- /dev/null +++ b/test/ELF/linkerscript/bss-fill.s @@ -0,0 +1,7 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { .bss : { . += 0x10000; *(.bss) } =0xFF };" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o + +.section .bss,"",@nobits +.short 0 diff --git a/test/ELF/linkerscript/merge-sections.s b/test/ELF/linkerscript/merge-sections.s index ae53ebc4d400..950d822ec403 100644 --- a/test/ELF/linkerscript/merge-sections.s +++ b/test/ELF/linkerscript/merge-sections.s @@ -31,6 +31,16 @@ # 0x19E = begin + sizeof(.foo) = 0x190 + 0xE # CHECK-NEXT: Value: 0x19E +# Check that we don't crash with --gc-sections +# RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared +# RUN: llvm-readobj -s -t %t2 | FileCheck %s --check-prefix=GC + +# GC: Name: .foo +# GC-NEXT: Type: SHT_PROGBITS +# GC-NEXT: Flags [ +# GC-NEXT: SHF_ALLOC +# GC-NEXT: ] + .section .foo.1a,"aMS",@progbits,1 .asciz "foo" diff --git a/test/ELF/linkerscript/symbol-reserved.s b/test/ELF/linkerscript/symbol-reserved.s index ccbe761738ba..e0b259597381 100644 --- a/test/ELF/linkerscript/symbol-reserved.s +++ b/test/ELF/linkerscript/symbol-reserved.s @@ -11,6 +11,12 @@ # SHARED: 0000000000000005 .dynsym 00000000 .hidden newsym +# RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(__ehdr_start, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script +# RUN: ld.lld -o %t1 %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=ALIGNED %s + +# ALIGNED: 0000000000200005 .text 00000000 .hidden newsym + .global _start _start: lea newsym(%rip),%rax From 80350c116f86dbb87e055a630b1b2be0c66b244b Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Thu, 1 Jun 2017 20:59:20 +0000 Subject: [PATCH 04/11] Vendor import of lld trunk r304460: https://llvm.org/svn/llvm-project/lld/trunk@304460 --- ELF/InputSection.cpp | 50 +++++++++---- ELF/InputSection.h | 19 +++-- ELF/LinkerScript.cpp | 129 +++++++++++++++++++++----------- ELF/LinkerScript.h | 14 +++- ELF/MarkLive.cpp | 3 +- ELF/OutputSections.cpp | 53 +++---------- ELF/OutputSections.h | 2 +- ELF/Relocations.cpp | 8 +- ELF/ScriptParser.cpp | 32 ++++++-- ELF/Symbols.cpp | 8 +- ELF/SyntheticSections.cpp | 97 +++++++++++++----------- ELF/SyntheticSections.h | 2 +- ELF/Target.cpp | 4 +- ELF/Writer.cpp | 82 ++++++++++---------- test/ELF/gc-absolute.s | 7 ++ test/ELF/i386-gotpc-dynamic.s | 32 ++++++++ test/ELF/mips64-eh-abs-reloc.s | 38 ++++++++++ test/ELF/section-metadata-err.s | 15 ++++ 18 files changed, 380 insertions(+), 215 deletions(-) create mode 100644 test/ELF/gc-absolute.s create mode 100644 test/ELF/i386-gotpc-dynamic.s create mode 100644 test/ELF/mips64-eh-abs-reloc.s create mode 100644 test/ELF/section-metadata-err.s diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 466656efbf08..4af05c1a187b 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -139,21 +139,24 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const { return Offset; case Merge: const MergeInputSection *MS = cast(this); - if (MS->MergeSec) - return MS->MergeSec->OutSecOff + MS->getOffset(Offset); + if (InputSection *IS = MS->getParent()) + return IS->OutSecOff + MS->getOffset(Offset); return MS->getOffset(Offset); } llvm_unreachable("invalid section kind"); } OutputSection *SectionBase::getOutputSection() { + InputSection *Sec; if (auto *IS = dyn_cast(this)) - return IS->OutSec; - if (auto *MS = dyn_cast(this)) - return MS->MergeSec ? MS->MergeSec->OutSec : nullptr; - if (auto *EH = dyn_cast(this)) - return EH->EHSec->OutSec; - return cast(this); + Sec = IS; + else if (auto *MS = dyn_cast(this)) + Sec = MS->getParent(); + else if (auto *EH = dyn_cast(this)) + Sec = EH->getParent(); + else + return cast(this); + return Sec ? Sec->getParent() : nullptr; } // Uncompress section contents. Note that this function is called @@ -181,9 +184,15 @@ uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const { return getOffset(Sym.Value); } -InputSectionBase *InputSectionBase::getLinkOrderDep() const { - if ((Flags & SHF_LINK_ORDER) && Link != 0) - return File->getSections()[Link]; +InputSection *InputSectionBase::getLinkOrderDep() const { + if ((Flags & SHF_LINK_ORDER) && Link != 0) { + InputSectionBase *L = File->getSections()[Link]; + if (auto *IS = dyn_cast(L)) + return IS; + error( + "Merge and .eh_frame sections are not supported with SHF_LINK_ORDER " + + toString(L)); + } return nullptr; } @@ -295,6 +304,10 @@ bool InputSectionBase::classof(const SectionBase *S) { return S->kind() != Output; } +OutputSection *InputSection::getParent() const { + return cast_or_null(Parent); +} + void InputSection::copyShtGroup(uint8_t *Buf) { assert(this->Type == SHT_GROUP); @@ -309,7 +322,8 @@ void InputSection::copyShtGroup(uint8_t *Buf) { ArrayRef Sections = this->File->getSections(); for (uint32_t Val : From.slice(1)) { uint32_t Index = read32(&Val, Config->Endianness); - write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness); + write32(To++, Sections[Index]->getOutputSection()->SectionIndex, + Config->Endianness); } } @@ -342,7 +356,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef Rels) { // Output section VA is zero for -r, so r_offset is an offset within the // section, but for --emit-relocs it is an virtual address. - P->r_offset = RelocatedSection->OutSec->Addr + + P->r_offset = RelocatedSection->getOutputSection()->Addr + RelocatedSection->getOffset(Rel.r_offset); P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Body), Type, Config->IsMips64EL); @@ -596,7 +610,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef Rels) { return; } - uint64_t AddrLoc = this->OutSec->Addr + Offset; + uint64_t AddrLoc = getParent()->Addr + Offset; uint64_t SymVA = 0; if (!Sym.isTls() || Out::TlsPhdr) SymVA = SignExtend64( @@ -729,6 +743,10 @@ EhInputSection::EhInputSection(elf::ObjectFile *F, this->Live = true; } +SyntheticSection *EhInputSection::getParent() const { + return cast_or_null(Parent); +} + bool EhInputSection::classof(const SectionBase *S) { return S->kind() == InputSectionBase::EHFrame; } @@ -797,6 +815,10 @@ static size_t findNull(ArrayRef A, size_t EntSize) { return StringRef::npos; } +SyntheticSection *MergeInputSection::getParent() const { + return cast_or_null(Parent); +} + // Split SHF_STRINGS section. Such section is a sequence of // null-terminated strings. void MergeInputSection::splitStrings(ArrayRef Data, size_t EntSize) { diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 4ef4328e8a5d..97ca2133f905 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -120,7 +120,12 @@ class InputSectionBase : public SectionBase { uint64_t Entsize, uint32_t Link, uint32_t Info, uint32_t Alignment, ArrayRef Data, StringRef Name, Kind SectionKind); - OutputSection *OutSec = nullptr; + + // Input sections are part of an output section. Special sections + // like .eh_frame and merge sections are first combined into a + // synthetic section that is then added to an output section. In all + // cases this points one level up. + SectionBase *Parent = nullptr; // Relocations that refer to this section. const void *FirstRelocation = nullptr; @@ -158,7 +163,7 @@ class InputSectionBase : public SectionBase { return getFile()->getObj(); } - InputSectionBase *getLinkOrderDep() const; + InputSection *getLinkOrderDep() const; void uncompress(); @@ -237,10 +242,7 @@ class MergeInputSection : public InputSectionBase { SectionPiece *getSectionPiece(uint64_t Offset); const SectionPiece *getSectionPiece(uint64_t Offset) const; - // MergeInputSections are aggregated to a synthetic input sections, - // and then added to an OutputSection. This pointer points to a - // synthetic MergeSyntheticSection which this section belongs to. - MergeSyntheticSection *MergeSec = nullptr; + SyntheticSection *getParent() const; private: void splitStrings(ArrayRef A, size_t Size); @@ -280,7 +282,8 @@ class EhInputSection : public InputSectionBase { // Splittable sections are handled as a sequence of data // rather than a single large blob of data. std::vector Pieces; - SyntheticSection *EHSec = nullptr; + + SyntheticSection *getParent() const; }; // This is a section that is added directly to an output section @@ -299,6 +302,8 @@ class InputSection : public InputSectionBase { // beginning of the output section. template void writeTo(uint8_t *Buf); + OutputSection *getParent() const; + // The offset from beginning of the output sections this section was assigned // to. The writer sets a value. uint64_t OutSecOff = 0; diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 99c464e3714c..75df2cd4bd5c 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" @@ -51,9 +52,8 @@ LinkerScript *elf::Script; uint64_t ExprValue::getValue() const { if (Sec) { - if (Sec->getOutputSection()) - return alignTo(Sec->getOffset(Val) + Sec->getOutputSection()->Addr, - Alignment); + if (OutputSection *OS = Sec->getOutputSection()) + return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment); error("unable to evaluate expression: input section " + Sec->Name + " has no output section assigned"); } @@ -85,29 +85,28 @@ template static SymbolBody *addRegular(SymbolAssignment *Cmd) { return Sym->body(); } -OutputSection *LinkerScript::getOutputSection(const Twine &Loc, - StringRef Name) { - for (OutputSection *Sec : *OutputSections) - if (Sec->Name == Name) - return Sec; - - static OutputSection Dummy("", 0, 0); - if (ErrorOnMissingSection) - error(Loc + ": undefined section " + Name); - return &Dummy; +OutputSectionCommand * +LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) { + OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; + OutputSectionCommand *Cmd; + if (CmdRef && CmdRef->Location.empty()) { + // There was a forward reference. + Cmd = CmdRef; + } else { + Cmd = make(Name); + if (!CmdRef) + CmdRef = Cmd; + } + Cmd->Location = Location; + return Cmd; } -// This function is essentially the same as getOutputSection(Name)->Size, -// but it won't print out an error message if a given section is not found. -// -// Linker script does not create an output section if its content is empty. -// We want to allow SIZEOF(.foo) where .foo is a section which happened to -// be empty. That is why this function is different from getOutputSection(). -uint64_t LinkerScript::getOutputSectionSize(StringRef Name) { - for (OutputSection *Sec : *OutputSections) - if (Sec->Name == Name) - return Sec->Size; - return 0; +OutputSectionCommand * +LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { + OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; + if (!CmdRef) + CmdRef = make(Name); + return CmdRef; } void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { @@ -291,12 +290,14 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { size_t SizeBefore = Ret.size(); for (InputSectionBase *Sec : InputSections) { - if (!isa(Sec)) - continue; - if (Sec->Assigned) continue; + if (!Sec->Live) { + reportDiscarded(Sec); + continue; + } + // For -emit-relocs we have to ignore entries like // .rela.dyn : { *(.rela.data) } // which are common because they are in the default bfd script. @@ -455,7 +456,7 @@ void LinkerScript::fabricateDefaultCommands() { // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections for (OutputSection *Sec : *OutputSections) { - auto *OSCmd = make(Sec->Name); + auto *OSCmd = createOutputSectionCommand(Sec->Name, ""); OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; @@ -487,7 +488,7 @@ void LinkerScript::fabricateDefaultCommands() { // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { for (InputSectionBase *S : InputSections) { - if (!S->Live || S->OutSec) + if (!S->Live || S->Parent) continue; StringRef Name = getOutputSectionName(S->Name); auto I = std::find_if( @@ -590,7 +591,7 @@ void LinkerScript::process(BaseCommand &Base) { // It calculates and assigns the offsets for each section and also // updates the output section size. auto &Cmd = cast(Base); - for (InputSectionBase *Sec : Cmd.Sections) { + for (InputSection *Sec : Cmd.Sections) { // We tentatively added all synthetic sections at the beginning and removed // empty ones afterwards (because there is no way to know whether they were // going be empty or not other than actually running linker scripts.) @@ -601,8 +602,8 @@ void LinkerScript::process(BaseCommand &Base) { if (!Sec->Live) continue; - assert(CurOutSec == Sec->OutSec); - output(cast(Sec)); + assert(CurOutSec == Sec->getParent()); + output(Sec); } } @@ -842,7 +843,7 @@ void LinkerScript::placeOrphanSections() { // representations agree on which input sections to use. OutputSectionCommand *Cmd = getCmd(Sec); if (!Cmd) { - Cmd = make(Name); + Cmd = createOutputSectionCommand(Name, ""); Opt.Commands.insert(CmdIter, Cmd); ++CmdIndex; @@ -919,9 +920,10 @@ void LinkerScript::synchronize() { } } -static bool allocateHeaders(std::vector &Phdrs, - ArrayRef OutputSections, - uint64_t Min) { +static bool +allocateHeaders(std::vector &Phdrs, + ArrayRef OutputSectionCommands, + uint64_t Min) { auto FirstPTLoad = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); @@ -938,16 +940,19 @@ static bool allocateHeaders(std::vector &Phdrs, assert(FirstPTLoad->First == Out::ElfHeader); OutputSection *ActualFirst = nullptr; - for (OutputSection *Sec : OutputSections) { + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; if (Sec->FirstInPtLoad == Out::ElfHeader) { ActualFirst = Sec; break; } } if (ActualFirst) { - for (OutputSection *Sec : OutputSections) + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; if (Sec->FirstInPtLoad == Out::ElfHeader) Sec->FirstInPtLoad = ActualFirst; + } FirstPTLoad->First = ActualFirst; } else { Phdrs.erase(FirstPTLoad); @@ -961,7 +966,9 @@ static bool allocateHeaders(std::vector &Phdrs, return false; } -void LinkerScript::assignAddresses(std::vector &Phdrs) { +void LinkerScript::assignAddresses( + std::vector &Phdrs, + ArrayRef OutputSectionCommands) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; ErrorOnMissingSection = true; @@ -983,14 +990,15 @@ void LinkerScript::assignAddresses(std::vector &Phdrs) { } uint64_t MinVA = std::numeric_limits::max(); - for (OutputSection *Sec : *OutputSections) { + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) MinVA = std::min(MinVA, Sec->Addr); else Sec->Addr = 0; } - allocateHeaders(Phdrs, *OutputSections, MinVA); + allocateHeaders(Phdrs, OutputSectionCommands, MinVA); } // Creates program headers as instructed by PHDRS linker script command. @@ -1068,6 +1076,33 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { llvm_unreachable("unsupported Size argument"); } +// Compress section contents if this section contains debug info. +template void OutputSectionCommand::maybeCompress() { + typedef typename ELFT::Chdr Elf_Chdr; + + // Compress only DWARF debug sections. + if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) || + !Name.startswith(".debug_")) + return; + + // Create a section header. + Sec->ZDebugHeader.resize(sizeof(Elf_Chdr)); + auto *Hdr = reinterpret_cast(Sec->ZDebugHeader.data()); + Hdr->ch_type = ELFCOMPRESS_ZLIB; + Hdr->ch_size = Sec->Size; + Hdr->ch_addralign = Sec->Alignment; + + // Write section contents to a temporary buffer and compress it. + std::vector Buf(Sec->Size); + writeTo(Buf.data()); + if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData)) + fatal("compress failed: " + llvm::toString(std::move(E))); + + // Update section headers. + Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size(); + Sec->Flags |= SHF_COMPRESSED; +} + template void OutputSectionCommand::writeTo(uint8_t *Buf) { Sec->Loc = Buf; @@ -1084,7 +1119,12 @@ template void OutputSectionCommand::writeTo(uint8_t *Buf) { return; // Write leading padding. - ArrayRef Sections = Sec->Sections; + std::vector Sections; + for (BaseCommand *Cmd : Commands) + if (auto *ISD = dyn_cast(Cmd)) + for (InputSection *IS : ISD->Sections) + if (IS->Live) + Sections.push_back(IS); uint32_t Filler = getFiller(); if (Filler) fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler); @@ -1161,3 +1201,8 @@ template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); + +template void OutputSectionCommand::maybeCompress(); +template void OutputSectionCommand::maybeCompress(); +template void OutputSectionCommand::maybeCompress(); +template void OutputSectionCommand::maybeCompress(); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index 08f60f4517a7..a708ea7f61d5 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -137,6 +137,7 @@ struct OutputSectionCommand : BaseCommand { std::string MemoryRegionName; template void writeTo(uint8_t *Buf); + template void maybeCompress(); uint32_t getFiller(); }; @@ -221,6 +222,8 @@ struct ScriptConfiguration { class LinkerScript final { llvm::DenseMap SecToCommand; + llvm::DenseMap NameToOutputSectionCommand; + void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); @@ -241,7 +244,6 @@ class LinkerScript final { void process(BaseCommand &Base); OutputSection *Aether; - bool ErrorOnMissingSection = false; uint64_t Dot; uint64_t ThreadBssOffset = 0; @@ -251,11 +253,14 @@ class LinkerScript final { MemoryRegion *CurMemRegion = nullptr; public: + bool ErrorOnMissingSection = false; + OutputSectionCommand *createOutputSectionCommand(StringRef Name, + StringRef Location); + OutputSectionCommand *getOrCreateOutputSectionCommand(StringRef Name); + OutputSectionCommand *getCmd(OutputSection *Sec) const; bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } - OutputSection *getOutputSection(const Twine &Loc, StringRef S); - uint64_t getOutputSectionSize(StringRef S); void discard(ArrayRef V); ExprValue getSymbolValue(const Twine &Loc, StringRef S); @@ -277,7 +282,8 @@ class LinkerScript final { void placeOrphanSections(); void processNonSectionCommands(); void synchronize(); - void assignAddresses(std::vector &Phdrs); + void assignAddresses(std::vector &Phdrs, + ArrayRef OutputSectionCommands); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp index ee499265886e..b77c84ff75a0 100644 --- a/ELF/MarkLive.cpp +++ b/ELF/MarkLive.cpp @@ -220,7 +220,8 @@ template void elf::markLive() { auto MarkSymbol = [&](const SymbolBody *Sym) { if (auto *D = dyn_cast_or_null(Sym)) - Enqueue({cast(D->Section), D->Value}); + if (auto *IS = cast_or_null(D->Section)) + Enqueue({IS, D->Value}); }; // Add GC root symbols. diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index f117690c3828..4f8906a32081 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -16,7 +16,6 @@ #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" -#include "llvm/Support/Compression.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" @@ -76,46 +75,19 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) { if (A->kind() == InputSectionBase::Synthetic || B->kind() == InputSectionBase::Synthetic) return false; - auto *LA = cast(A->getLinkOrderDep()); - auto *LB = cast(B->getLinkOrderDep()); - OutputSection *AOut = LA->OutSec; - OutputSection *BOut = LB->OutSec; + InputSection *LA = A->getLinkOrderDep(); + InputSection *LB = B->getLinkOrderDep(); + OutputSection *AOut = LA->getParent(); + OutputSection *BOut = LB->getParent(); if (AOut != BOut) return AOut->SectionIndex < BOut->SectionIndex; return LA->OutSecOff < LB->OutSecOff; } -// Compress section contents if this section contains debug info. -template void OutputSection::maybeCompress() { - typedef typename ELFT::Chdr Elf_Chdr; - - // Compress only DWARF debug sections. - if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) || - !Name.startswith(".debug_")) - return; - - // Create a section header. - ZDebugHeader.resize(sizeof(Elf_Chdr)); - auto *Hdr = reinterpret_cast(ZDebugHeader.data()); - Hdr->ch_type = ELFCOMPRESS_ZLIB; - Hdr->ch_size = Size; - Hdr->ch_addralign = Alignment; - - // Write section contents to a temporary buffer and compress it. - std::vector Buf(Size); - Script->getCmd(this)->writeTo(Buf.data()); - if (Error E = zlib::compress(toStringRef(Buf), CompressedData)) - fatal("compress failed: " + llvm::toString(std::move(E))); - - // Update section headers. - Size = sizeof(Elf_Chdr) + CompressedData.size(); - Flags |= SHF_COMPRESSED; -} - template static void finalizeShtGroup(OutputSection *Sec) { // sh_link field for SHT_GROUP sections should contain the section index of // the symbol table. - Sec->Link = InX::SymTab->OutSec->SectionIndex; + Sec->Link = InX::SymTab->getParent()->SectionIndex; // sh_info then contain index of an entry in symbol table section which // provides signature of the section group. @@ -135,7 +107,7 @@ template void OutputSection::finalize() { // need to translate the InputSection sh_link to the OutputSection sh_link, // all InputSections in the OutputSection have the same dependency. if (auto *D = this->Sections.front()->getLinkOrderDep()) - this->Link = D->OutSec->SectionIndex; + this->Link = D->getParent()->SectionIndex; } uint32_t Type = this->Type; @@ -151,11 +123,11 @@ template void OutputSection::finalize() { if (isa(First)) return; - this->Link = InX::SymTab->OutSec->SectionIndex; + this->Link = InX::SymTab->getParent()->SectionIndex; // sh_info for SHT_REL[A] sections should contain the section header index of // the section to which the relocation applies. InputSectionBase *S = First->getRelocatedSection(); - this->Info = S->OutSec->SectionIndex; + Info = S->getOutputSection()->SectionIndex; } static uint64_t updateOffset(uint64_t Off, InputSection *S) { @@ -167,7 +139,7 @@ static uint64_t updateOffset(uint64_t Off, InputSection *S) { void OutputSection::addSection(InputSection *S) { assert(S->Live); Sections.push_back(S); - S->OutSec = this; + S->Parent = this; this->updateAlignment(S->Alignment); // The actual offsets will be computed by assignAddresses. For now, use @@ -351,7 +323,7 @@ static bool canMergeToProgbits(unsigned Type) { Type == SHT_NOTE; } -static void reportDiscarded(InputSectionBase *IS) { +void elf::reportDiscarded(InputSectionBase *IS) { if (!Config->PrintGcSections) return; message("removing unused section from '" + IS->Name + "' in file '" + @@ -437,8 +409,3 @@ template void OutputSection::finalize(); template void OutputSection::finalize(); template void OutputSection::finalize(); template void OutputSection::finalize(); - -template void OutputSection::maybeCompress(); -template void OutputSection::maybeCompress(); -template void OutputSection::maybeCompress(); -template void OutputSection::maybeCompress(); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 08655a9ed67b..326348cd5a20 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -83,7 +83,6 @@ class OutputSection final : public SectionBase { void sortInitFini(); void sortCtorsDtors(); template void finalize(); - template void maybeCompress(); void assignOffsets(); std::vector Sections; @@ -149,6 +148,7 @@ class OutputSectionFactory { }; uint64_t getHeaderSize(); +void reportDiscarded(InputSectionBase *IS); } // namespace elf } // namespace lld diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 5564ea246eeb..54cc6dd89d46 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -360,9 +360,9 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, // These expressions always compute a constant if (isRelExprOneOf(E)) + R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, + R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD, + R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E)) return true; // These never do, except if the entire file is position dependent or if @@ -1015,7 +1015,7 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) { ThunkSection *TS = ThunkedSections.lookup(IS); if (TS) return TS; - auto *TOS = cast(IS->OutSec); + auto *TOS = IS->getParent(); TS = make(TOS, IS->OutSecOff); ThunkSections[TOS].push_back(TS); ThunkedSections[IS] = TS; diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index 4b77e35b9bae..02212fa8ba14 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -55,6 +55,7 @@ class ScriptParser final : ScriptLexer { private: void addFile(StringRef Path); + OutputSection *checkSection(OutputSectionCommand *Cmd, StringRef Loccation); void readAsNeeded(); void readEntry(); @@ -564,8 +565,8 @@ uint32_t ScriptParser::readFill() { OutputSectionCommand * ScriptParser::readOutputSectionDescription(StringRef OutSec) { - OutputSectionCommand *Cmd = make(OutSec); - Cmd->Location = getCurrentLocation(); + OutputSectionCommand *Cmd = + Script->createOutputSectionCommand(OutSec, getCurrentLocation()); // Read an address expression. // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html @@ -819,6 +820,16 @@ StringRef ScriptParser::readParenLiteral() { return Tok; } +OutputSection *ScriptParser::checkSection(OutputSectionCommand *Cmd, + StringRef Location) { + if (Cmd->Location.empty() && Script->ErrorOnMissingSection) + error(Location + ": undefined section " + Cmd->Name); + if (Cmd->Sec) + return Cmd->Sec; + static OutputSection Dummy("", 0, 0); + return &Dummy; +} + Expr ScriptParser::readPrimary() { if (peek() == "(") return readParenExpr(); @@ -847,9 +858,8 @@ Expr ScriptParser::readPrimary() { } if (Tok == "ADDR") { StringRef Name = readParenLiteral(); - return [=]() -> ExprValue { - return {Script->getOutputSection(Location, Name), 0}; - }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=]() -> ExprValue { return {checkSection(Cmd, Location), 0}; }; } if (Tok == "ALIGN") { expect("("); @@ -867,7 +877,8 @@ Expr ScriptParser::readPrimary() { } if (Tok == "ALIGNOF") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSection(Location, Name)->Alignment; }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=] { return checkSection(Cmd, Location)->Alignment; }; } if (Tok == "ASSERT") return readAssertExpr(); @@ -912,7 +923,8 @@ Expr ScriptParser::readPrimary() { } if (Tok == "LOADADDR") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSection(Location, Name)->getLMA(); }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=] { return checkSection(Cmd, Location)->getLMA(); }; } if (Tok == "ORIGIN") { StringRef Name = readParenLiteral(); @@ -930,7 +942,11 @@ Expr ScriptParser::readPrimary() { } if (Tok == "SIZEOF") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSectionSize(Name); }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + // Linker script does not create an output section if its content is empty. + // We want to allow SIZEOF(.foo) where .foo is a section which happened to + // be empty. + return [=] { return Cmd->Sec ? Cmd->Sec->Size : 0; }; } if (Tok == "SIZEOF_HEADERS") return [=] { return elf::getHeaderSize(); }; diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 7ce1f5354b1b..67e57d9c8f00 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -101,12 +101,12 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { case SymbolBody::DefinedCommonKind: if (!Config->DefineCommon) return 0; - return InX::Common->OutSec->Addr + InX::Common->OutSecOff + + return InX::Common->getParent()->Addr + InX::Common->OutSecOff + cast(Body).Offset; case SymbolBody::SharedKind: { auto &SS = cast(Body); if (SS.NeedsCopy) - return SS.CopyRelSec->OutSec->Addr + SS.CopyRelSec->OutSecOff + + return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff + SS.CopyRelSecOff; if (SS.NeedsPltAddr) return Body.getPltVA(); @@ -207,13 +207,13 @@ OutputSection *SymbolBody::getOutputSection() const { if (auto *S = dyn_cast(this)) { if (S->NeedsCopy) - return S->CopyRelSec->OutSec; + return S->CopyRelSec->getParent(); return nullptr; } if (isa(this)) { if (Config->DefineCommon) - return InX::Common->OutSec; + return InX::Common->getParent(); return nullptr; } diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index d3db32613a8a..223fc9a0fd07 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -48,8 +48,8 @@ using namespace lld; using namespace lld::elf; uint64_t SyntheticSection::getVA() const { - if (this->OutSec) - return this->OutSec->Addr + this->OutSecOff; + if (OutputSection *Sec = getParent()) + return Sec->Addr + OutSecOff; return 0; } @@ -367,8 +367,8 @@ BssSection::BssSection(StringRef Name) : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, Name) {} size_t BssSection::reserveSpace(uint64_t Size, uint32_t Alignment) { - if (OutSec) - OutSec->updateAlignment(Alignment); + if (OutputSection *Sec = getParent()) + Sec->updateAlignment(Alignment); this->Size = alignTo(this->Size, Alignment) + Size; this->Alignment = std::max(this->Alignment, Alignment); return this->Size - Size; @@ -494,7 +494,7 @@ void EhFrameSection::addSectionAux(EhInputSection *Sec, template void EhFrameSection::addSection(InputSectionBase *C) { auto *Sec = cast(C); - Sec->EHSec = this; + Sec->Parent = this; updateAlignment(Sec->Alignment); Sections.push_back(Sec); for (auto *DS : Sec->DependentSections) @@ -579,7 +579,7 @@ uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff, if ((Enc & 0x70) == DW_EH_PE_absptr) return Addr; if ((Enc & 0x70) == DW_EH_PE_pcrel) - return Addr + this->OutSec->Addr + Off; + return Addr + getParent()->Addr + Off; fatal("unknown FDE size relative encoding"); } @@ -610,7 +610,7 @@ template void EhFrameSection::writeTo(uint8_t *Buf) { uint8_t Enc = getFdeEncoding(Cie->Piece); for (SectionPiece *Fde : Cie->FdePieces) { uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); - uint64_t FdeVA = this->OutSec->Addr + Fde->OutputOff; + uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; In::EhFrameHdr->addFde(Pc, FdeVA); } } @@ -698,8 +698,7 @@ void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) { // sections referenced by GOT relocations. Then later in the `finalize` // method calculate number of "pages" required to cover all saved output // section and allocate appropriate number of GOT entries. - auto *DefSym = cast(&Sym); - PageIndexMap.insert({DefSym->Section->getOutputSection(), 0}); + PageIndexMap.insert({Sym.getOutputSection(), 0}); return; } if (Sym.isTls()) { @@ -766,8 +765,7 @@ static uint64_t getMipsPageCount(uint64_t Size) { uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B, int64_t Addend) const { - const OutputSection *OutSec = - cast(&B)->Section->getOutputSection(); + const OutputSection *OutSec = B.getOutputSection(); uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend)); uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; @@ -1071,11 +1069,11 @@ template void DynamicSection::finalizeContents() { if (this->Size) return; // Already finalized. - this->Link = InX::DynStrTab->OutSec->SectionIndex; - if (In::RelaDyn->OutSec->Size > 0) { + this->Link = InX::DynStrTab->getParent()->SectionIndex; + if (In::RelaDyn->getParent()->Size > 0) { bool IsRela = Config->IsRela; add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); - add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->OutSec->Size}); + add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->getParent()->Size}); add({IsRela ? DT_RELAENT : DT_RELENT, uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); @@ -1088,9 +1086,9 @@ template void DynamicSection::finalizeContents() { add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } - if (In::RelaPlt->OutSec->Size > 0) { + if (In::RelaPlt->getParent()->Size > 0) { add({DT_JMPREL, In::RelaPlt}); - add({DT_PLTRELSZ, In::RelaPlt->OutSec->Size}); + add({DT_PLTRELSZ, In::RelaPlt->getParent()->Size}); add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, InX::GotPlt}); add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)}); @@ -1152,7 +1150,7 @@ template void DynamicSection::finalizeContents() { add({DT_MIPS_RLD_MAP, InX::MipsRldMap}); } - this->OutSec->Link = this->Link; + getParent()->Link = this->Link; // +1 for DT_NULL this->Size = (Entries.size() + 1) * this->Entsize; @@ -1168,7 +1166,7 @@ template void DynamicSection::writeTo(uint8_t *Buf) { P->d_un.d_ptr = E.OutSec->Addr; break; case Entry::InSecAddr: - P->d_un.d_ptr = E.InSec->OutSec->Addr + E.InSec->OutSecOff; + P->d_un.d_ptr = E.InSec->getParent()->Addr + E.InSec->OutSecOff; break; case Entry::SecSize: P->d_un.d_val = E.OutSec->Size; @@ -1185,7 +1183,7 @@ template void DynamicSection::writeTo(uint8_t *Buf) { } uint64_t DynamicReloc::getOffset() const { - return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec); + return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec); } int64_t DynamicReloc::getAddend() const { @@ -1258,11 +1256,11 @@ template unsigned RelocationSection::getRelocOffset() { } template void RelocationSection::finalizeContents() { - this->Link = InX::DynSymTab ? InX::DynSymTab->OutSec->SectionIndex - : InX::SymTab->OutSec->SectionIndex; + this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex + : InX::SymTab->getParent()->SectionIndex; // Set required output section properties. - this->OutSec->Link = this->Link; + getParent()->Link = this->Link; } SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) @@ -1293,14 +1291,14 @@ static bool sortMipsSymbols(const SymbolTableEntry &L, // function. (For .dynsym, we don't do that because symbols for // dynamic linking are inherently all globals.) void SymbolTableBaseSection::finalizeContents() { - this->OutSec->Link = StrTabSec.OutSec->SectionIndex; + getParent()->Link = StrTabSec.getParent()->SectionIndex; // If it is a .dynsym, there should be no local symbols, but we need // to do a few things for the dynamic linker. if (this->Type == SHT_DYNSYM) { // Section's Info field has the index of the first non-local symbol. // Because the first symbol entry is a null entry, 1 is the first. - this->OutSec->Info = 1; + getParent()->Info = 1; if (InX::GnuHashTab) { // NB: It also sorts Symbols to meet the GNU hash table requirements. @@ -1326,7 +1324,7 @@ void SymbolTableBaseSection::postThunkContents() { S.Symbol->symbol()->computeBinding() == STB_LOCAL; }); size_t NumLocals = It - Symbols.begin(); - this->OutSec->Info = NumLocals + 1; + getParent()->Info = NumLocals + 1; } void SymbolTableBaseSection::addSymbol(SymbolBody *B) { @@ -1344,8 +1342,7 @@ size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) { // This is used for -r, so we have to handle multiple section // symbols being combined. if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION) - return cast(Body)->Section->getOutputSection() == - cast(E.Symbol)->Section->getOutputSection(); + return Body->getOutputSection() == E.Symbol->getOutputSection(); return false; }); if (I == Symbols.end()) @@ -1456,7 +1453,7 @@ GnuHashTableSection::GnuHashTableSection() } void GnuHashTableSection::finalizeContents() { - this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex; + getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; // Computes bloom filter size in word size. We want to allocate 8 // bits for each symbol. It must be a power of two. @@ -1590,7 +1587,7 @@ HashTableSection::HashTableSection() } template void HashTableSection::finalizeContents() { - this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex; + getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; unsigned NumEntries = 2; // nbucket and nchain. NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries. @@ -1801,7 +1798,7 @@ void GdbIndexSection::finalizeContents() { for (InputSectionBase *S : InputSections) if (InputSection *IS = dyn_cast(S)) - if (IS->OutSec && IS->Name == ".debug_info") + if (IS->getParent() && IS->Name == ".debug_info") readDwarf(IS); SymbolTable.finalizeContents(); @@ -1846,7 +1843,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { // Write the address area. for (AddressEntry &E : AddressArea) { - uint64_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0); + uint64_t BaseAddr = E.Section->getParent()->Addr + E.Section->getOffset(0); write64le(Buf, BaseAddr + E.LowAddress); write64le(Buf + 8, BaseAddr + E.HighAddress); write32le(Buf + 16, E.CuIndex); @@ -1906,7 +1903,7 @@ template void EhFrameHeader::writeTo(uint8_t *Buf) { Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; Buf[2] = DW_EH_PE_udata4; Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; - write32(Buf + 4, In::EhFrame->OutSec->Addr - this->getVA() - 4); + write32(Buf + 4, In::EhFrame->getParent()->Addr - this->getVA() - 4); write32(Buf + 8, Fdes.size()); Buf += 12; @@ -1948,12 +1945,12 @@ template void VersionDefinitionSection::finalizeContents() { for (VersionDefinition &V : Config->VersionDefinitions) V.NameOff = InX::DynStrTab->addString(V.Name); - this->OutSec->Link = InX::DynStrTab->OutSec->SectionIndex; + getParent()->Link = InX::DynStrTab->getParent()->SectionIndex; // sh_info should be set to the number of definitions. This fact is missed in // documentation, but confirmed by binutils community: // https://sourceware.org/ml/binutils/2014-11/msg00355.html - this->OutSec->Info = getVerDefNum(); + getParent()->Info = getVerDefNum(); } template @@ -2001,7 +1998,7 @@ VersionTableSection::VersionTableSection() template void VersionTableSection::finalizeContents() { // At the moment of june 2016 GNU docs does not mention that sh_link field // should be set, but Sun docs do. Also readelf relies on this field. - this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex; + getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; } template size_t VersionTableSection::getSize() const { @@ -2093,8 +2090,8 @@ template void VersionNeedSection::writeTo(uint8_t *Buf) { } template void VersionNeedSection::finalizeContents() { - this->OutSec->Link = InX::DynStrTab->OutSec->SectionIndex; - this->OutSec->Info = Needed.size(); + getParent()->Link = InX::DynStrTab->getParent()->SectionIndex; + getParent()->Info = Needed.size(); } template size_t VersionNeedSection::getSize() const { @@ -2115,7 +2112,7 @@ MergeSyntheticSection::MergeSyntheticSection(StringRef Name, uint32_t Type, void MergeSyntheticSection::addSection(MergeInputSection *MS) { assert(!Finalized); - MS->MergeSec = this; + MS->Parent = this; Sections.push_back(MS); } @@ -2186,13 +2183,23 @@ ARMExidxSentinelSection::ARMExidxSentinelSection() // This section will have been sorted last in the .ARM.exidx table. // This table entry will have the form: // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | +// The sentinel must have the PREL31 value of an address higher than any +// address described by any other table entry. void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { - // Get the InputSection before us, we are by definition last - auto RI = this->OutSec->Sections.rbegin(); - InputSection *LE = *(++RI); - InputSection *LC = cast(LE->getLinkOrderDep()); - uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); - uint64_t P = this->getVA(); + // The Sections are sorted in order of ascending PREL31 address with the + // sentinel last. We need to find the InputSection that precedes the + // sentinel. By construction the Sentinel is in the last + // InputSectionDescription as the InputSection that precedes it. + OutputSectionCommand *C = Script->getCmd(getParent()); + auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), + [](const BaseCommand *Base) { + return isa(Base); + }); + auto L = cast(*ISD); + InputSection *Highest = L->Sections[L->Sections.size() - 2]; + InputSection *LS = Highest->getLinkOrderDep(); + uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize()); + uint64_t P = getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 0x1); } @@ -2200,7 +2207,7 @@ void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, Config->Wordsize, ".text.thunk") { - this->OutSec = OS; + this->Parent = OS; this->OutSecOff = Off; } diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index 61cc03de222e..b47d2fab24ec 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -53,7 +53,7 @@ class SyntheticSection : public InputSection { virtual bool empty() const { return false; } uint64_t getVA() const; - static bool classof(const InputSectionBase *D) { + static bool classof(const SectionBase *D) { return D->kind() == InputSectionBase::Synthetic; } }; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index cf7d912ad829..b6c6e7089365 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -62,10 +62,10 @@ static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); } template static std::string getErrorLoc(const uint8_t *Loc) { for (InputSectionBase *D : InputSections) { auto *IS = dyn_cast_or_null(D); - if (!IS || !IS->OutSec) + if (!IS || !IS->getParent()) continue; - uint8_t *ISLoc = cast(IS->OutSec)->Loc + IS->OutSecOff; + uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff; if (ISLoc <= Loc && Loc < ISLoc + IS->getSize()) return IS->template getLocation(Loc - ISLoc) + ": "; } diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 77d6412f80ad..258d5e26ef7f 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -261,23 +261,26 @@ template void Writer::run() { if (!Config->Relocatable) fixSectionAlignments(); Script->fabricateDefaultCommands(); + } else { + Script->synchronize(); } for (BaseCommand *Base : Script->Opt.Commands) if (auto *Cmd = dyn_cast(Base)) OutputSectionCommands.push_back(Cmd); + clearOutputSections(); // If -compressed-debug-sections is specified, we need to compress // .debug_* sections. Do it right now because it changes the size of // output sections. - parallelForEach(OutputSections.begin(), OutputSections.end(), - [](OutputSection *S) { S->maybeCompress(); }); + parallelForEach( + OutputSectionCommands.begin(), OutputSectionCommands.end(), + [](OutputSectionCommand *Cmd) { Cmd->maybeCompress(); }); if (Config->Relocatable) { assignFileOffsets(); } else { - Script->synchronize(); - Script->assignAddresses(Phdrs); + Script->assignAddresses(Phdrs, OutputSectionCommands); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses @@ -300,13 +303,13 @@ template void Writer::run() { openFile(); if (ErrorCount) return; + if (!Config->OFormatBinary) { writeHeader(); writeSections(); } else { writeSectionsBinary(); } - clearOutputSections(); // Backfill .note.gnu.build-id section content. This is done at last // because the content is usually a hash value of the entire output file. @@ -613,27 +616,27 @@ bool elf::isRelroSection(const OutputSection *Sec) { // .got contains pointers to external symbols. They are resolved by // the dynamic linker when a module is loaded into memory, and after // that they are not expected to change. So, it can be in RELRO. - if (InX::Got && Sec == InX::Got->OutSec) + if (InX::Got && Sec == InX::Got->getParent()) return true; // .got.plt contains pointers to external function symbols. They are // by default resolved lazily, so we usually cannot put it into RELRO. // However, if "-z now" is given, the lazy symbol resolution is // disabled, which enables us to put it into RELRO. - if (Sec == InX::GotPlt->OutSec) + if (Sec == InX::GotPlt->getParent()) return Config->ZNow; // .dynamic section contains data for the dynamic linker, and // there's no need to write to it at runtime, so it's better to put // it into RELRO. - if (Sec == InX::Dynamic->OutSec) + if (Sec == InX::Dynamic->getParent()) return true; // .bss.rel.ro is used for copy relocations for read-only symbols. // Since the dynamic linker needs to process copy relocations, the // section cannot be read-only, but once initialized, they shouldn't // change. - if (Sec == InX::BssRelRo->OutSec) + if (Sec == InX::BssRelRo->getParent()) return true; // Sections with some special names are put into RELRO. This is a @@ -1112,9 +1115,9 @@ template void Writer::sortSections() { static void applySynthetic(const std::vector &Sections, std::function Fn) { for (SyntheticSection *SS : Sections) - if (SS && SS->OutSec && !SS->empty()) { + if (SS && SS->getParent() && !SS->empty()) { Fn(SS); - SS->OutSec->assignOffsets(); + SS->getParent()->assignOffsets(); } } @@ -1130,16 +1133,15 @@ static void removeUnusedSyntheticSections(std::vector &V) { SyntheticSection *SS = dyn_cast(S); if (!SS) return; - if (!SS->empty() || !SS->OutSec) + OutputSection *OS = SS->getParent(); + if (!SS->empty() || !OS) continue; - - SS->OutSec->Sections.erase(std::find(SS->OutSec->Sections.begin(), - SS->OutSec->Sections.end(), SS)); + OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS)); SS->Live = false; // If there are no other sections in the output section, remove it from the // output. - if (SS->OutSec->Sections.empty()) - V.erase(std::find(V.begin(), V.end(), SS->OutSec)); + if (OS->Sections.empty()) + V.erase(std::find(V.begin(), V.end(), OS)); } } @@ -1427,8 +1429,8 @@ template std::vector Writer::createPhdrs() { // Add an entry for .dynamic. if (InX::DynSymTab) - AddHdr(PT_DYNAMIC, InX::Dynamic->OutSec->getPhdrFlags()) - ->add(InX::Dynamic->OutSec); + AddHdr(PT_DYNAMIC, InX::Dynamic->getParent()->getPhdrFlags()) + ->add(InX::Dynamic->getParent()); // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. @@ -1441,9 +1443,9 @@ template std::vector Writer::createPhdrs() { // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. if (!In::EhFrame->empty() && In::EhFrameHdr && - In::EhFrame->OutSec && In::EhFrameHdr->OutSec) - AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->OutSec->getPhdrFlags()) - ->add(In::EhFrameHdr->OutSec); + In::EhFrame->getParent() && In::EhFrameHdr->getParent()) + AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->getParent()->getPhdrFlags()) + ->add(In::EhFrameHdr->getParent()); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. @@ -1556,9 +1558,11 @@ static uint64_t setOffset(OutputSection *Sec, uint64_t Off) { template void Writer::assignFileOffsetsBinary() { uint64_t Off = 0; - for (OutputSection *Sec : OutputSections) + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) Off = setOffset(Sec, Off); + } FileSize = alignTo(Off, Config->Wordsize); } @@ -1568,11 +1572,12 @@ template void Writer::assignFileOffsets() { Off = setOffset(Out::ElfHeader, Off); Off = setOffset(Out::ProgramHeaders, Off); - for (OutputSection *Sec : OutputSections) - Off = setOffset(Sec, Off); + for (OutputSectionCommand *Cmd : OutputSectionCommands) + Off = setOffset(Cmd->Sec, Off); SectionHeaderOff = alignTo(Off, Config->Wordsize); - FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); + FileSize = + SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr); } // Finalize the program headers. We call this function after we assign @@ -1695,16 +1700,15 @@ template void Writer::fixPredefinedSymbols() { // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. - if (Config->EMachine == EM_MIPS) { - if (!ElfSym::MipsGp->Value) { - // Find GP-relative section with the lowest address - // and use this address to calculate default _gp value. - uint64_t Gp = -1; - for (const OutputSection *OS : OutputSections) - if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp) - Gp = OS->Addr; - if (Gp != (uint64_t)-1) - ElfSym::MipsGp->Value = Gp + 0x7ff0; + if (Config->EMachine == EM_MIPS && !ElfSym::MipsGp->Value) { + // Find GP-relative section with the lowest address + // and use this address to calculate default _gp value. + for (const OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *OS = Cmd->Sec; + if (OS->Flags & SHF_MIPS_GPREL) { + ElfSym::MipsGp->Value = OS->Addr + 0x7ff0; + break; + } } } } @@ -1728,7 +1732,7 @@ template void Writer::writeHeader() { EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = OutputSectionCommands.size() + 1; - EHdr->e_shstrndx = InX::ShStrTab->OutSec->SectionIndex; + EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex; if (Config->EMachine == EM_ARM) // We don't currently use any features incompatible with EF_ARM_EABI_VER5, @@ -1804,7 +1808,7 @@ template void Writer::writeSections() { OutputSection *EhFrameHdr = (In::EhFrameHdr && !In::EhFrameHdr->empty()) - ? In::EhFrameHdr->OutSec + ? In::EhFrameHdr->getParent() : nullptr; // In -r or -emit-relocs mode, write the relocation sections first as in @@ -1832,7 +1836,7 @@ template void Writer::writeSections() { } template void Writer::writeBuildId() { - if (!InX::BuildId || !InX::BuildId->OutSec) + if (!InX::BuildId || !InX::BuildId->getParent()) return; // Compute a hash of all sections of the output file. diff --git a/test/ELF/gc-absolute.s b/test/ELF/gc-absolute.s new file mode 100644 index 000000000000..29e671678ee7 --- /dev/null +++ b/test/ELF/gc-absolute.s @@ -0,0 +1,7 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 -shared --gc-sections + +.global foo +foo = 0x123 diff --git a/test/ELF/i386-gotpc-dynamic.s b/test/ELF/i386-gotpc-dynamic.s new file mode 100644 index 000000000000..da8a607d5753 --- /dev/null +++ b/test/ELF/i386-gotpc-dynamic.s @@ -0,0 +1,32 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.so -shared +# RUN: llvm-readobj -s %t.so | FileCheck %s +# RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s + +# CHECK: Section { +# CHECK: Index: 7 +# CHECK-NEXT: Name: .got +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2030 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: } + +## 0x1000 + 4144 = 0x2030 +# DISASM: 1000: {{.*}} movl $4144, %eax + +.section .foo,"ax",@progbits +foo: + movl $bar@got-., %eax # R_386_GOTPC + +.local bar +bar: diff --git a/test/ELF/mips64-eh-abs-reloc.s b/test/ELF/mips64-eh-abs-reloc.s new file mode 100644 index 000000000000..7bc500137992 --- /dev/null +++ b/test/ELF/mips64-eh-abs-reloc.s @@ -0,0 +1,38 @@ +# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD +# REQUIRES: mips +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o +# RUN: llvm-readobj -r %t.o | FileCheck %s -check-prefix OBJ +# RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o +# RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix PIC-RELOCS + +# Linking this as a PIE executable would also previously crash +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %S/Inputs/archive2.s -o %t-foo.o +# -pie needs -z notext because of the R_MIPS_64 relocation +# RUN: ld.lld --eh-frame-hdr -Bdynamic -pie -z notext -o %t-pie-dynamic.exe %t.o %t-foo.o +# RUN: llvm-readobj -r %t-pie-dynamic.exe | FileCheck %s -check-prefix PIC-RELOCS + + +# OBJ: Section ({{.*}}) .rela.text { +# OBJ-NEXT: 0x0 R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 foo 0x0 +# OBJ-NEXT: } +# OBJ-NEXT: Section ({{.*}}) .rela.eh_frame { +# OBJ-NEXT: 0x1C R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x0 +# OBJ-NEXT: } + +# PIC-RELOCS: Relocations [ +# PIC-RELOCS-NEXT: Section (7) .rela.dyn { +# PIC-RELOCS-NEXT: {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x10000 +# PIC-RELOCS-NEXT: } +# PIC-RELOCS-NEXT:] + + +.globl foo + +bar: +.cfi_startproc +lui $11, %hi(%neg(%gp_rel(foo))) +.cfi_endproc + +.globl __start +__start: +b bar diff --git a/test/ELF/section-metadata-err.s b/test/ELF/section-metadata-err.s new file mode 100644 index 000000000000..f3b5842945cb --- /dev/null +++ b/test/ELF/section-metadata-err.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s + +# CHECK: error: Merge and .eh_frame sections are not supported with SHF_LINK_ORDER {{.*}}section-metadata-err.s.tmp.o:(.foo) + +.global _start +_start: +.quad .foo + +.section .foo,"aM",@progbits,8 +.quad 0 + +.section bar,"ao",@progbits,.foo From 7c5c4ef25000522f341d2edb21344a2fe2b881ad Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 3 Jun 2017 15:21:10 +0000 Subject: [PATCH 05/11] Vendor import of libc++ trunk r304659: https://llvm.org/svn/llvm-project/libcxx/trunk@304659 --- include/__hash_table | 2 +- .../containers/unord/next_pow2.pass.cpp | 88 +++++++++++++++++++ .../coroutine.handle.completion/done.pass.cpp | 2 +- .../end.to.end/await_result.pass.cpp | 4 +- .../end.to.end/bool_await_suspend.pass.cpp | 5 +- .../end.to.end/generator.pass.cpp | 3 + .../end.to.end/oneshot_func.pass.cpp | 4 +- 7 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 test/libcxx/containers/unord/next_pow2.pass.cpp diff --git a/include/__hash_table b/include/__hash_table index 79336ff793ec..3f430af1283e 100644 --- a/include/__hash_table +++ b/include/__hash_table @@ -137,7 +137,7 @@ inline _LIBCPP_INLINE_VISIBILITY size_t __next_hash_pow2(size_t __n) { - return size_t(1) << (std::numeric_limits::digits - __clz(__n-1)); + return __n < 2 ? __n : (size_t(1) << (std::numeric_limits::digits - __clz(__n-1))); } diff --git a/test/libcxx/containers/unord/next_pow2.pass.cpp b/test/libcxx/containers/unord/next_pow2.pass.cpp new file mode 100644 index 000000000000..3784eb87cebb --- /dev/null +++ b/test/libcxx/containers/unord/next_pow2.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// REQUIRES: long_tests +// UNSUPPORTED: c++98, c++03 + +// Not a portable test + +// <__hash_table> + +// size_t __next_hash_pow2(size_t n); + +// If n <= 1, return n. If n is a power of 2, return n. +// Otherwise, return the next power of 2. + +#include <__hash_table> +#include +#include + +#include + +bool +is_power_of_two(unsigned long n) +{ + return __builtin_popcount(n) == 1; +} + +void test_next_pow2_val(size_t n) +{ + std::size_t npow2 = std::__next_hash_pow2(n); + assert(is_power_of_two(npow2) && npow2 > n); +} + +void +test_next_pow2() +{ + assert(!is_power_of_two(0)); + assert(is_power_of_two(1)); + assert(is_power_of_two(2)); + assert(!is_power_of_two(3)); + + assert(std::__next_hash_pow2(0) == 0); + assert(std::__next_hash_pow2(1) == 1); + + for (std::size_t n = 2; n < (sizeof(std::size_t) * 8 - 1); ++n) + { + std::size_t pow2 = 1ULL << n; + assert(std::__next_hash_pow2(pow2) == pow2); + } + + test_next_pow2_val(3); + test_next_pow2_val(7); + test_next_pow2_val(9); + test_next_pow2_val(15); + test_next_pow2_val(127); + test_next_pow2_val(129); +} + +// Note: this is only really useful when run with -fsanitize=undefined. +void +fuzz_unordered_map_reserve(unsigned num_inserts, + unsigned num_reserve1, + unsigned num_reserve2) +{ + std::unordered_map m; + m.reserve(num_reserve1); + for (unsigned I = 0; I < num_inserts; ++I) m[I] = 0; + m.reserve(num_reserve2); + assert(m.bucket_count() >= num_reserve2); +} + +int main() +{ + test_next_pow2(); + + for (unsigned num_inserts = 0; num_inserts <= 64; ++num_inserts) + for (unsigned num_reserve1 = 1; num_reserve1 <= 64; ++num_reserve1) + for (unsigned num_reserve2 = 1; num_reserve2 <= 64; ++num_reserve2) + fuzz_unordered_map_reserve(num_inserts, num_reserve1, num_reserve2); + + return 0; +} diff --git a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp index 74a9e7bda04e..240d9324507c 100644 --- a/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp +++ b/test/std/experimental/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp @@ -33,7 +33,7 @@ void do_test(coro::coroutine_handle const& H) { // FIXME Add a runtime test { ASSERT_SAME_TYPE(decltype(H.done()), bool); - ASSERT_NOT_NOEXCEPT(H.done()); + LIBCPP_ASSERT_NOT_NOEXCEPT(H.done()); } } diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.pass.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.pass.cpp index 769a825df001..b8606317ae56 100644 --- a/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.pass.cpp +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.pass.cpp @@ -23,7 +23,7 @@ struct coro_t { } suspend_never initial_suspend() { return {}; } suspend_never final_suspend() { return {}; } - void return_void(){} + void return_void() {} static void unhandled_exception() {} }; }; @@ -37,7 +37,7 @@ struct B { struct A { - ~A(){} + ~A() {} bool await_ready() { return true; } int await_resume() { return 42; } template void await_suspend(F) {} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.pass.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.pass.cpp index 9c3becffc0ac..12ab92ff3004 100644 --- a/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.pass.cpp +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.pass.cpp @@ -10,6 +10,9 @@ // UNSUPPORTED: c++98, c++03, c++11 +// See https://bugs.llvm.org/show_bug.cgi?id=33271 +// UNSUPPORTED: ubsan + #include #include @@ -22,7 +25,7 @@ struct coro_t { } suspend_never initial_suspend() { return {}; } suspend_never final_suspend() { return {}; } - void return_void(){} + void return_void() {} void unhandled_exception() {} }; coro_t(coroutine_handle hh) : h(hh) {} diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/generator.pass.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/generator.pass.cpp index 9200fae91576..c92e26184ff6 100644 --- a/test/std/experimental/language.support/support.coroutines/end.to.end/generator.pass.cpp +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/generator.pass.cpp @@ -10,6 +10,9 @@ // UNSUPPORTED: c++98, c++03, c++11 +// See https://bugs.llvm.org/show_bug.cgi?id=33271 +// UNSUPPORTED: ubsan + #include #include #include diff --git a/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.pass.cpp b/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.pass.cpp index d5f2c40e2a79..ae0a950dc686 100644 --- a/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.pass.cpp +++ b/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.pass.cpp @@ -68,10 +68,10 @@ template struct func { std::vector yielded_values = {}; int yield(int x) { yielded_values.push_back(x); return x + 1; } -float fyield(int x) { yielded_values.push_back(x); return x + 2; } +float fyield(int x) { yielded_values.push_back(x); return static_cast(x + 2); } void Do1(func f) { yield(f()); } -void Do2(func f) { yield(f()); } +void Do2(func f) { yield(static_cast(f())); } int main() { Do1([] { return yield(43); }); From b9a1baec33e911ca24f51abf882d454e62047ea6 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 3 Jun 2017 15:21:18 +0000 Subject: [PATCH 06/11] Vendor import of lld trunk r304659: https://llvm.org/svn/llvm-project/lld/trunk@304659 --- COFF/DLL.cpp | 15 ++++++++------- COFF/DLL.h | 1 + COFF/Driver.cpp | 3 ++- COFF/PDB.cpp | 3 ++- ELF/LinkerScript.cpp | 7 +------ ELF/OutputSections.cpp | 1 + ELF/OutputSections.h | 4 ---- ELF/Writer.cpp | 32 +++++++++++++++++++++----------- test/COFF/armnt-imports.test | 2 +- test/COFF/def-export-stdcall.s | 25 +++++++++++++++++++++++++ test/COFF/hello32.test | 4 ++-- test/COFF/imports.test | 8 ++++---- test/ELF/emit-relocs.s | 13 ++++++++++--- 13 files changed, 78 insertions(+), 40 deletions(-) create mode 100644 test/COFF/def-export-stdcall.s diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp index 3ac14e4ea2b0..d76410b67471 100644 --- a/COFF/DLL.cpp +++ b/COFF/DLL.cpp @@ -100,17 +100,13 @@ class ImportDirectoryChunk : public Chunk { void writeTo(uint8_t *Buf) const override { auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); + E->ImportLookupTableRVA = LookupTab->getRVA(); E->NameRVA = DLLName->getRVA(); - - // The import descriptor table contains two pointers to - // the tables describing dllimported symbols. But the - // Windows loader actually uses only one. So we create - // only one table and set both fields to its address. - E->ImportLookupTableRVA = AddressTab->getRVA(); E->ImportAddressTableRVA = AddressTab->getRVA(); } Chunk *DLLName; + Chunk *LookupTab; Chunk *AddressTab; }; @@ -392,6 +388,7 @@ std::vector IdataContents::getChunks() { // Add each type in the correct order. std::vector V; V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Lookups.begin(), Lookups.end()); V.insert(V.end(), Addresses.begin(), Addresses.end()); V.insert(V.end(), Hints.begin(), Hints.end()); V.insert(V.end(), DLLNames.begin(), DLLNames.end()); @@ -407,18 +404,21 @@ void IdataContents::create() { // we need to create HintName chunks to store the names. // If they don't (if they are import-by-ordinals), we store only // ordinal values to the table. - size_t Base = Addresses.size(); + size_t Base = Lookups.size(); for (DefinedImportData *S : Syms) { uint16_t Ord = S->getOrdinal(); if (S->getExternalName().empty()) { + Lookups.push_back(make(Ord)); Addresses.push_back(make(Ord)); continue; } auto *C = make(S->getExternalName(), Ord); + Lookups.push_back(make(C)); Addresses.push_back(make(C)); Hints.push_back(C); } // Terminate with null values. + Lookups.push_back(make(ptrSize())); Addresses.push_back(make(ptrSize())); for (int I = 0, E = Syms.size(); I < E; ++I) @@ -427,6 +427,7 @@ void IdataContents::create() { // Create the import table header. DLLNames.push_back(make(Syms[0]->getDLLName())); auto *Dir = make(DLLNames.back()); + Dir->LookupTab = Lookups[Base]; Dir->AddressTab = Addresses[Base]; Dirs.push_back(Dir); } diff --git a/COFF/DLL.h b/COFF/DLL.h index 939771b3290c..ad312789edf1 100644 --- a/COFF/DLL.h +++ b/COFF/DLL.h @@ -36,6 +36,7 @@ class IdataContents { std::vector Imports; std::vector Dirs; + std::vector Lookups; std::vector Addresses; std::vector Hints; std::vector DLLNames; diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index d871f942737d..96c328b30518 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -434,7 +434,8 @@ std::vector createCOFFShortExportFromConfig() { std::vector Exports; for (Export &E1 : Config->Exports) { COFFShortExport E2; - E2.Name = E1.Name; + // Use SymbolName, which will have any stdcall or fastcall qualifiers. + E2.Name = E1.SymbolName; E2.ExtName = E1.ExtName; E2.Ordinal = E1.Ordinal; E2.Noname = E1.Noname; diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index a3b3ab7bbab0..eb8c3820412d 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -157,7 +157,8 @@ static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) { fatal(EC, "StreamReader.readArray failed"); TypeDatabase TDB(0); - CVSymbolDumper SymbolDumper(W, TDB, nullptr, false); + CVSymbolDumper SymbolDumper(W, TDB, CodeViewContainer::ObjectFile, nullptr, + false); if (auto EC = SymbolDumper.dump(Symbols)) fatal(EC, "CVSymbolDumper::dump failed"); } diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 75df2cd4bd5c..1ced3e8e8d71 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -463,12 +463,7 @@ void LinkerScript::fabricateDefaultCommands() { // Prefer user supplied address over additional alignment constraint auto I = Config->SectionStartMap.find(Sec->Name); if (I != Config->SectionStartMap.end()) - Commands.push_back( - make(".", [=] { return I->second; }, "")); - else if (Sec->PageAlign) - OSCmd->AddrExpr = [=] { - return alignTo(Script->getDot(), Config->MaxPageSize); - }; + OSCmd->AddrExpr = [=] { return I->second; }; Commands.push_back(OSCmd); if (Sec->Sections.size()) { diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index 4f8906a32081..8357d6b03bb1 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -128,6 +128,7 @@ template void OutputSection::finalize() { // the section to which the relocation applies. InputSectionBase *S = First->getRelocatedSection(); Info = S->getOutputSection()->SectionIndex; + Flags |= SHF_INFO_LINK; } static uint64_t updateOffset(uint64_t Off, InputSection *S) { diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 326348cd5a20..0f2fe68ca708 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -59,10 +59,6 @@ class OutputSection final : public SectionBase { Alignment = Val; } - // If true, this section will be page aligned on disk. - // Typically the first section of each PT_LOAD segment has this flag. - bool PageAlign = false; - // Pointer to the first section in PT_LOAD segment, which this section // also resides in. This field is used to correctly compute file offset // of a section. When two sections share the same load segment, difference diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 258d5e26ef7f..f68e07fc69d7 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -257,19 +257,20 @@ template void Writer::run() { if (ErrorCount) return; - if (!Script->Opt.HasSections) { - if (!Config->Relocatable) - fixSectionAlignments(); + if (!Script->Opt.HasSections) Script->fabricateDefaultCommands(); - } else { + else Script->synchronize(); - } for (BaseCommand *Base : Script->Opt.Commands) if (auto *Cmd = dyn_cast(Base)) OutputSectionCommands.push_back(Cmd); clearOutputSections(); + + if (!Script->Opt.HasSections &&!Config->Relocatable) + fixSectionAlignments(); + // If -compressed-debug-sections is specified, we need to compress // .debug_* sections. Do it right now because it changes the size of // output sections. @@ -1504,24 +1505,33 @@ void Writer::addPtArmExid(std::vector &Phdrs) { // first section after PT_GNU_RELRO have to be page aligned so that the dynamic // linker can set the permissions. template void Writer::fixSectionAlignments() { + auto PageAlign = [](OutputSection *Sec) { + OutputSectionCommand *Cmd = Script->getCmd(Sec); + if (Cmd && !Cmd->AddrExpr) + Cmd->AddrExpr = [=] { + return alignTo(Script->getDot(), Config->MaxPageSize); + }; + }; + for (const PhdrEntry &P : Phdrs) if (P.p_type == PT_LOAD && P.First) - P.First->PageAlign = true; + PageAlign(P.First); for (const PhdrEntry &P : Phdrs) { if (P.p_type != PT_GNU_RELRO) continue; if (P.First) - P.First->PageAlign = true; + PageAlign(P.First); // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we // have to align it to a page. - auto End = OutputSections.end(); - auto I = std::find(OutputSections.begin(), End, P.Last); + auto End = OutputSectionCommands.end(); + auto I = + std::find(OutputSectionCommands.begin(), End, Script->getCmd(P.Last)); if (I == End || (I + 1) == End) continue; - OutputSection *Sec = *(I + 1); + OutputSection *Sec = (*(I + 1))->Sec; if (needsPtLoad(Sec)) - Sec->PageAlign = true; + PageAlign(Sec); } } diff --git a/test/COFF/armnt-imports.test b/test/COFF/armnt-imports.test index f0aaebd3f293..519886eb0c06 100644 --- a/test/COFF/armnt-imports.test +++ b/test/COFF/armnt-imports.test @@ -6,7 +6,7 @@ # CHECK: Import { # CHECK: Name: library.dll # CHECK: ImportLookupTableRVA: 0x2028 -# CHECK: ImportAddressTableRVA: 0x2028 +# CHECK: ImportAddressTableRVA: 0x2030 # CHECK: Symbol: function (0) # CHECK: } diff --git a/test/COFF/def-export-stdcall.s b/test/COFF/def-export-stdcall.s new file mode 100644 index 000000000000..cdca7ae76acf --- /dev/null +++ b/test/COFF/def-export-stdcall.s @@ -0,0 +1,25 @@ +# RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o %t.obj +# RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall" > %t.def +# RUN: lld-link -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib +# RUN: llvm-nm %t.lib | FileCheck %s +# CHECK: __imp__stdcall@8 +# CHECK: _stdcall@8 + + .def _stdcall@8; + .scl 2; + .type 32; + .endef + .globl _stdcall@8 +_stdcall@8: + movl 8(%esp), %eax + addl 4(%esp), %eax + retl $8 + + .def _dllmain; + .scl 2; + .type 32; + .endef + .globl _dllmain +_dllmain: + retl + diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test index b7c5f28c3534..66b52378aaa3 100644 --- a/test/COFF/hello32.test +++ b/test/COFF/hello32.test @@ -78,7 +78,7 @@ HEADER-NEXT: LoadConfigTableRVA: 0x0 HEADER-NEXT: LoadConfigTableSize: 0x0 HEADER-NEXT: BoundImportRVA: 0x0 HEADER-NEXT: BoundImportSize: 0x0 -HEADER-NEXT: IATRVA: 0x3028 +HEADER-NEXT: IATRVA: 0x3034 HEADER-NEXT: IATSize: 0xC HEADER-NEXT: DelayImportDescriptorRVA: 0x0 HEADER-NEXT: DelayImportDescriptorSize: 0x0 @@ -114,7 +114,7 @@ IMPORTS: AddressSize: 32bit IMPORTS: Import { IMPORTS: Name: std32.dll IMPORTS: ImportLookupTableRVA: 0x3028 -IMPORTS: ImportAddressTableRVA: 0x3028 +IMPORTS: ImportAddressTableRVA: 0x3034 IMPORTS: Symbol: ExitProcess (0) IMPORTS: Symbol: MessageBoxA (1) IMPORTS: } diff --git a/test/COFF/imports.test b/test/COFF/imports.test index 4df6d492ff28..584c24eb1b76 100644 --- a/test/COFF/imports.test +++ b/test/COFF/imports.test @@ -21,14 +21,14 @@ TEXT-NEXT: callq 60 TEXT-NEXT: movl $0, %ecx TEXT-NEXT: callq 18 TEXT-NEXT: callq 29 -TEXT: jmpq *4066(%rip) -TEXT: jmpq *4058(%rip) -TEXT: jmpq *4050(%rip) +TEXT: jmpq *4098(%rip) +TEXT: jmpq *4090(%rip) +TEXT: jmpq *4082(%rip) IMPORT: Import { IMPORT-NEXT: Name: std64.dll IMPORT-NEXT: ImportLookupTableRVA: 0x3028 -IMPORT-NEXT: ImportAddressTableRVA: 0x3028 +IMPORT-NEXT: ImportAddressTableRVA: 0x3048 IMPORT-NEXT: Symbol: ExitProcess (0) IMPORT-NEXT: Symbol: (50) IMPORT-NEXT: Symbol: MessageBoxA (1) diff --git a/test/ELF/emit-relocs.s b/test/ELF/emit-relocs.s index dfe20589e97b..fd9722f13ab0 100644 --- a/test/ELF/emit-relocs.s +++ b/test/ELF/emit-relocs.s @@ -1,16 +1,23 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o # RUN: ld.lld --emit-relocs %t1.o -o %t -# RUN: llvm-readobj -t -r %t | FileCheck %s +# RUN: llvm-readobj -t -r -s %t | FileCheck %s ## Check single dash form. # RUN: ld.lld -emit-relocs %t1.o -o %t1 -# RUN: llvm-readobj -t -r %t1 | FileCheck %s +# RUN: llvm-readobj -t -r -s %t1 | FileCheck %s ## Check alias. # RUN: ld.lld -q %t1.o -o %t2 -# RUN: llvm-readobj -t -r %t2 | FileCheck %s +# RUN: llvm-readobj -t -r -s %t2 | FileCheck %s +# CHECK: Section { +# CHECK: Index: 2 +# CHECK-NEXT: Name: .rela.text +# CHECK-NEXT: Type: SHT_RELA +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_INFO_LINK +# CHECK-NEXT: ] # CHECK: Relocations [ # CHECK-NEXT: Section ({{.*}}) .rela.text { # CHECK-NEXT: 0x201002 R_X86_64_32 .text 0x1 From 74c4bc8d0eddcb4786594f1c6b598094fac43859 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 10 Jun 2017 13:44:41 +0000 Subject: [PATCH 07/11] Vendor import of libc++ trunk r305145: https://llvm.org/svn/llvm-project/libcxx/trunk@305145 --- include/__mutex_base | 5 +- include/mutex | 1 - include/numeric | 71 +++++ include/optional | 2 +- include/tuple | 10 + include/variant | 21 +- .../variant.assign/copy.pass.cpp | 209 --------------- .../variant.assign/move.pass.cpp | 197 -------------- .../variant.ctor/copy.pass.cpp | 120 --------- .../variant.ctor/move.pass.cpp | 153 ----------- .../locale.codecvt.byname/ctor_char.pass.cpp | 10 +- .../exclusive_scan_iter_iter_iter.pass.cpp | 97 +++++++ ...usive_scan_iter_iter_iter_init_op.pass.cpp | 87 ++++++ ..._scan_iter_iter_iter_init_bop_uop.pass.cpp | 154 +++++++++++ .../thread.mutex.class/default.pass.cpp | 2 + .../optional.object.mod/reset.pass.cpp | 2 - .../optional.object.observe/value_or.pass.cpp | 20 +- .../implicit_deduction_guides.pass.cpp | 155 +++++++++++ .../variant.variant/variant.assign/T.pass.cpp | 34 ++- .../variant.assign/copy.pass.cpp | 248 ++++++++++++++++-- .../variant.assign/move.pass.cpp | 199 +++++++++++++- .../variant.ctor/copy.pass.cpp | 101 ++++++- .../variant.ctor/move.pass.cpp | 134 +++++++++- test/support/msvc_stdlib_force_include.hpp | 8 +- test/support/platform_support.h | 15 +- ...xx_empty_parameter_pack_expansion.pass.cpp | 49 ---- test/support/test_workarounds.h | 1 - test/support/uses_alloc_types.hpp | 7 - test/support/variant_test_helpers.hpp | 4 +- www/cxx1z_status.html | 4 +- 30 files changed, 1288 insertions(+), 832 deletions(-) delete mode 100644 test/libcxx/utilities/variant/variant.variant/variant.assign/copy.pass.cpp delete mode 100644 test/libcxx/utilities/variant/variant.variant/variant.assign/move.pass.cpp delete mode 100644 test/libcxx/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp delete mode 100644 test/libcxx/utilities/variant/variant.variant/variant.ctor/move.pass.cpp create mode 100644 test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter.pass.cpp create mode 100644 test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter_init_op.pass.cpp create mode 100644 test/std/numerics/numeric.ops/transform.exclusive.scan/transform_exclusive_scan_iter_iter_iter_init_bop_uop.pass.cpp create mode 100644 test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp delete mode 100644 test/support/test.workarounds/c1xx_empty_parameter_pack_expansion.pass.cpp diff --git a/include/__mutex_base b/include/__mutex_base index 159acd626618..3b2453f1ba1a 100644 --- a/include/__mutex_base +++ b/include/__mutex_base @@ -48,7 +48,7 @@ class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mut public: _LIBCPP_INLINE_VISIBILITY #ifndef _LIBCPP_CXX03_LANG - constexpr mutex() _NOEXCEPT = default; + constexpr mutex() = default; #else mutex() _NOEXCEPT {__m_ = (__libcpp_mutex_t)_LIBCPP_MUTEX_INITIALIZER;} #endif @@ -67,6 +67,9 @@ public: _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;} }; +static_assert(is_nothrow_default_constructible::value, + "the default constructor for std::mutex must be nothrow"); + struct _LIBCPP_TYPE_VIS defer_lock_t {}; struct _LIBCPP_TYPE_VIS try_to_lock_t {}; struct _LIBCPP_TYPE_VIS adopt_lock_t {}; diff --git a/include/mutex b/include/mutex index 55380882044d..1557ed8770d7 100644 --- a/include/mutex +++ b/include/mutex @@ -502,7 +502,6 @@ public: _LIBCPP_INLINE_VISIBILITY explicit scoped_lock(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m)) : __m_(__m) {} - scoped_lock(scoped_lock const&) = delete; scoped_lock& operator=(scoped_lock const&) = delete; diff --git a/include/numeric b/include/numeric index 0e53ba33c3c7..a84fb862b667 100644 --- a/include/numeric +++ b/include/numeric @@ -42,6 +42,23 @@ template OutputIterator partial_sum(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op); +template + OutputIterator + exclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, T init); // C++17 + +template + OutputIterator + exclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, T init, BinaryOperation binary_op); // C++17 + +template + OutputIterator + transform_exclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, T init, + BinaryOperation binary_op, UnaryOperation unary_op); // C++17 + template OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result); @@ -66,6 +83,7 @@ template #include <__config> #include #include // for numeric_limits +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -154,6 +172,59 @@ partial_sum(_InputIterator __first, _InputIterator __last, _OutputIterator __res return __result; } +#if _LIBCPP_STD_VER > 14 +template +inline _LIBCPP_INLINE_VISIBILITY +_OutputIterator +exclusive_scan(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _Tp __init, _BinaryOp __b) +{ + if (__first != __last) + { + _Tp __saved = __init; + do + { + __init = __b(__init, *__first); + *__result = __saved; + __saved = __init; + ++__result; + } while (++__first != __last); + } + return __result; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_OutputIterator +exclusive_scan(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _Tp __init) +{ + return _VSTD::exclusive_scan(__first, __last, __result, __init, _VSTD::plus<>()); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_OutputIterator +transform_exclusive_scan(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _Tp __init, + _BinaryOp __b, _UnaryOp __u) +{ + if (__first != __last) + { + _Tp __saved = __init; + do + { + __init = __b(__init, __u(*__first)); + *__result = __saved; + __saved = __init; + ++__result; + } while (++__first != __last); + } + return __result; +} +#endif + template inline _LIBCPP_INLINE_VISIBILITY _OutputIterator diff --git a/include/optional b/include/optional index 8c8ee76b1411..c0fd0e7bc49f 100644 --- a/include/optional +++ b/include/optional @@ -897,7 +897,7 @@ public: template _LIBCPP_INLINE_VISIBILITY - value_type value_or(_Up&& __v) && + constexpr value_type value_or(_Up&& __v) && { static_assert(is_move_constructible_v, "optional::value_or: T must be move constructible"); diff --git a/include/tuple b/include/tuple index aa4713faf06f..a52b934aaca7 100644 --- a/include/tuple +++ b/include/tuple @@ -929,6 +929,16 @@ public: void swap(tuple&) _NOEXCEPT {} }; +#ifdef __cpp_deduction_guides +// NOTE: These are not yet standardized, but are required to simulate the +// implicit deduction guide that should be generated had libc++ declared the +// tuple-like constructors "correctly" +template +tuple(allocator_arg_t, const _Alloc&, tuple<_Args...> const&) -> tuple<_Args...>; +template +tuple(allocator_arg_t, const _Alloc&, tuple<_Args...>&&) -> tuple<_Args...>; +#endif + template inline _LIBCPP_INLINE_VISIBILITY typename enable_if diff --git a/include/variant b/include/variant index ba15ed8c4a14..8505f3262a18 100644 --- a/include/variant +++ b/include/variant @@ -358,7 +358,6 @@ struct __traits { static constexpr _Trait __copy_assignable_trait = __common_trait( {__copy_constructible_trait, - __move_constructible_trait, __trait<_Types, is_trivially_copy_assignable, is_copy_assignable>...}); static constexpr _Trait __move_assignable_trait = __common_trait( @@ -877,25 +876,24 @@ public: } protected: - template + template inline _LIBCPP_INLINE_VISIBILITY - void __assign_alt(__alt<_Ip, _Tp>& __a, - _Arg&& __arg, - bool_constant<_CopyAssign> __tag) { + void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) { if (this->index() == _Ip) { __a.__value = _VSTD::forward<_Arg>(__arg); } else { struct { void operator()(true_type) const { - __this->__emplace<_Ip>(_Tp(_VSTD::forward<_Arg>(__arg))); + __this->__emplace<_Ip>(_VSTD::forward<_Arg>(__arg)); } void operator()(false_type) const { - __this->__emplace<_Ip>(_VSTD::forward<_Arg>(__arg)); + __this->__emplace<_Ip>(_Tp(_VSTD::forward<_Arg>(__arg))); } __assignment* __this; _Arg&& __arg; } __impl{this, _VSTD::forward<_Arg>(__arg)}; - __impl(__tag); + __impl(bool_constant || + !is_nothrow_move_constructible_v<_Tp>>{}); } } @@ -912,8 +910,7 @@ protected: [this](auto& __this_alt, auto&& __that_alt) { this->__assign_alt( __this_alt, - _VSTD::forward(__that_alt).__value, - is_lvalue_reference<_That>{}); + _VSTD::forward(__that_alt).__value); }, *this, _VSTD::forward<_That>(__that)); } @@ -1013,8 +1010,7 @@ public: inline _LIBCPP_INLINE_VISIBILITY void __assign(_Arg&& __arg) { this->__assign_alt(__access::__base::__get_alt<_Ip>(*this), - _VSTD::forward<_Arg>(__arg), - false_type{}); + _VSTD::forward<_Arg>(__arg)); } inline _LIBCPP_INLINE_VISIBILITY @@ -1088,7 +1084,6 @@ class _LIBCPP_TEMPLATE_VIS variant __all...>::value>, private __sfinae_assign_base< __all<(is_copy_constructible_v<_Types> && - is_move_constructible_v<_Types> && is_copy_assignable_v<_Types>)...>::value, __all<(is_move_constructible_v<_Types> && is_move_assignable_v<_Types>)...>::value> { diff --git a/test/libcxx/utilities/variant/variant.variant/variant.assign/copy.pass.cpp b/test/libcxx/utilities/variant/variant.variant/variant.assign/copy.pass.cpp deleted file mode 100644 index 26556c6eb047..000000000000 --- a/test/libcxx/utilities/variant/variant.variant/variant.assign/copy.pass.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// The following compilers don't generate constexpr special members correctly. -// XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8 -// XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0 - -// - -// template class variant; - -// variant& operator=(variant const&); - -#include -#include - -#include "test_macros.h" - -struct NTCopyAssign { - constexpr NTCopyAssign(int v) : value(v) {} - NTCopyAssign(const NTCopyAssign &) = default; - NTCopyAssign(NTCopyAssign &&) = default; - NTCopyAssign &operator=(const NTCopyAssign &that) { - value = that.value; - return *this; - }; - NTCopyAssign &operator=(NTCopyAssign &&) = delete; - int value; -}; - -static_assert(!std::is_trivially_copy_assignable::value, ""); -static_assert(std::is_copy_assignable::value, ""); - -struct TCopyAssign { - constexpr TCopyAssign(int v) : value(v) {} - TCopyAssign(const TCopyAssign &) = default; - TCopyAssign(TCopyAssign &&) = default; - TCopyAssign &operator=(const TCopyAssign &) = default; - TCopyAssign &operator=(TCopyAssign &&) = delete; - int value; -}; - -static_assert(std::is_trivially_copy_assignable::value, ""); - -struct TCopyAssignNTMoveAssign { - constexpr TCopyAssignNTMoveAssign(int v) : value(v) {} - TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign &) = default; - TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign &&) = default; - TCopyAssignNTMoveAssign &operator=(const TCopyAssignNTMoveAssign &) = default; - TCopyAssignNTMoveAssign &operator=(TCopyAssignNTMoveAssign &&that) { - value = that.value; - that.value = -1; - return *this; - } - int value; -}; - -static_assert(std::is_trivially_copy_assignable_v, ""); - -void test_copy_assignment_sfinae() { - { - using V = std::variant; - static_assert(std::is_trivially_copy_assignable::value, ""); - } - { - using V = std::variant; - static_assert(!std::is_trivially_copy_assignable::value, ""); - static_assert(std::is_copy_assignable::value, ""); - } - { - using V = std::variant; - static_assert(std::is_trivially_copy_assignable::value, ""); - } - { - using V = std::variant; - static_assert(std::is_trivially_copy_assignable::value, ""); - } -} - -template struct Result { size_t index; T value; }; - -void test_copy_assignment_same_index() { - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(43); - V v2(42); - v = v2; - return {v.index(), std::get<0>(v)}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 0, ""); - static_assert(result.value == 42, ""); - } - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(43l); - V v2(42l); - v = v2; - return {v.index(), std::get<1>(v)}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42l, ""); - } - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(std::in_place_type, 43); - V v2(std::in_place_type, 42); - v = v2; - return {v.index(), std::get<1>(v).value}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42, ""); - } - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(std::in_place_type, 43); - V v2(std::in_place_type, 42); - v = v2; - return {v.index(), std::get<1>(v).value}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42, ""); - } -} - -void test_copy_assignment_different_index() { - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(43); - V v2(42l); - v = v2; - return {v.index(), std::get<1>(v)}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42l, ""); - } - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(std::in_place_type, 43); - V v2(std::in_place_type, 42); - v = v2; - return {v.index(), std::get<1>(v).value}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42, ""); - } -} - -template -constexpr bool test_constexpr_assign_extension_imp( - std::variant&& v, ValueType&& new_value) -{ - const std::variant cp( - std::forward(new_value)); - v = cp; - return v.index() == NewIdx && - std::get(v) == std::get(cp); -} - -void test_constexpr_copy_assignment_extension() { -#ifdef _LIBCPP_VERSION - using V = std::variant; - static_assert(std::is_trivially_copyable::value, ""); - static_assert(std::is_trivially_copy_assignable::value, ""); - static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); - static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); - static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); - static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); -#endif -} - -int main() { - test_copy_assignment_same_index(); - test_copy_assignment_different_index(); - test_copy_assignment_sfinae(); - test_constexpr_copy_assignment_extension(); -} diff --git a/test/libcxx/utilities/variant/variant.variant/variant.assign/move.pass.cpp b/test/libcxx/utilities/variant/variant.variant/variant.assign/move.pass.cpp deleted file mode 100644 index fb6907dc5627..000000000000 --- a/test/libcxx/utilities/variant/variant.variant/variant.assign/move.pass.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// The following compilers don't generate constexpr special members correctly. -// XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8 -// XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0 - -// - -// template class variant; - -// variant& operator=(variant&&) noexcept(see below); - -#include -#include - -#include "test_macros.h" - -struct NTMoveAssign { - constexpr NTMoveAssign(int v) : value(v) {} - NTMoveAssign(const NTMoveAssign &) = default; - NTMoveAssign(NTMoveAssign &&) = default; - NTMoveAssign &operator=(const NTMoveAssign &that) = default; - NTMoveAssign &operator=(NTMoveAssign &&that) { - value = that.value; - that.value = -1; - return *this; - }; - int value; -}; - -static_assert(!std::is_trivially_move_assignable::value, ""); -static_assert(std::is_move_assignable::value, ""); - -struct TMoveAssign { - constexpr TMoveAssign(int v) : value(v) {} - TMoveAssign(const TMoveAssign &) = delete; - TMoveAssign(TMoveAssign &&) = default; - TMoveAssign &operator=(const TMoveAssign &) = delete; - TMoveAssign &operator=(TMoveAssign &&) = default; - int value; -}; - -static_assert(std::is_trivially_move_assignable::value, ""); - -struct TMoveAssignNTCopyAssign { - constexpr TMoveAssignNTCopyAssign(int v) : value(v) {} - TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default; - TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default; - TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) { - value = that.value; - return *this; - } - TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default; - int value; -}; - -static_assert(std::is_trivially_move_assignable_v, ""); - -void test_move_assignment_sfinae() { - { - using V = std::variant; - static_assert(std::is_trivially_move_assignable::value, ""); - } - { - using V = std::variant; - static_assert(!std::is_trivially_move_assignable::value, ""); - static_assert(std::is_move_assignable::value, ""); - } - { - using V = std::variant; - static_assert(std::is_trivially_move_assignable::value, ""); - } - { - using V = std::variant; - static_assert(std::is_trivially_move_assignable::value, ""); - } -} - -template struct Result { size_t index; T value; }; - -void test_move_assignment_same_index() { - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(43); - V v2(42); - v = std::move(v2); - return {v.index(), std::get<0>(v)}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 0, ""); - static_assert(result.value == 42, ""); - } - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(43l); - V v2(42l); - v = std::move(v2); - return {v.index(), std::get<1>(v)}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42l, ""); - } - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(std::in_place_type, 43); - V v2(std::in_place_type, 42); - v = std::move(v2); - return {v.index(), std::get<1>(v).value}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42, ""); - } -} - -void test_move_assignment_different_index() { - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(43); - V v2(42l); - v = std::move(v2); - return {v.index(), std::get<1>(v)}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42l, ""); - } - { - struct { - constexpr Result operator()() const { - using V = std::variant; - V v(std::in_place_type, 43); - V v2(std::in_place_type, 42); - v = std::move(v2); - return {v.index(), std::get<1>(v).value}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42, ""); - } -} - - -template -constexpr bool test_constexpr_assign_extension_imp( - std::variant&& v, ValueType&& new_value) -{ - std::variant v2( - std::forward(new_value)); - const auto cp = v2; - v = std::move(v2); - return v.index() == NewIdx && - std::get(v) == std::get(cp); -} - -void test_constexpr_move_assignment_extension() { -#ifdef _LIBCPP_VERSION - using V = std::variant; - static_assert(std::is_trivially_copyable::value, ""); - static_assert(std::is_trivially_move_assignable::value, ""); - static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); - static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); - static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); - static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); -#endif -} - -int main() { - test_move_assignment_same_index(); - test_move_assignment_different_index(); - test_move_assignment_sfinae(); - test_constexpr_move_assignment_extension(); -} diff --git a/test/libcxx/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp b/test/libcxx/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp deleted file mode 100644 index 0d30a78a48ac..000000000000 --- a/test/libcxx/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// - -// template class variant; - -// variant(variant const&); - -#include -#include - -#include "test_macros.h" - -struct NTCopy { - constexpr NTCopy(int v) : value(v) {} - NTCopy(const NTCopy &that) : value(that.value) {} - NTCopy(NTCopy &&) = delete; - int value; -}; - -static_assert(!std::is_trivially_copy_constructible::value, ""); -static_assert(std::is_copy_constructible::value, ""); - -struct TCopy { - constexpr TCopy(int v) : value(v) {} - TCopy(TCopy const &) = default; - TCopy(TCopy &&) = delete; - int value; -}; - -static_assert(std::is_trivially_copy_constructible::value, ""); - -struct TCopyNTMove { - constexpr TCopyNTMove(int v) : value(v) {} - TCopyNTMove(const TCopyNTMove&) = default; - TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; } - int value; -}; - -static_assert(std::is_trivially_copy_constructible::value, ""); - -void test_copy_ctor_sfinae() { - { - using V = std::variant; - static_assert(std::is_trivially_copy_constructible::value, ""); - } - { - using V = std::variant; - static_assert(!std::is_trivially_copy_constructible::value, ""); - static_assert(std::is_copy_constructible::value, ""); - } - { - using V = std::variant; - static_assert(std::is_trivially_copy_constructible::value, ""); - } - { - using V = std::variant; - static_assert(std::is_trivially_copy_constructible::value, ""); - } -} - -void test_copy_ctor_basic() { - { - constexpr std::variant v(std::in_place_index<0>, 42); - static_assert(v.index() == 0, ""); - constexpr std::variant v2 = v; - static_assert(v2.index() == 0, ""); - static_assert(std::get<0>(v2) == 42, ""); - } - { - constexpr std::variant v(std::in_place_index<1>, 42); - static_assert(v.index() == 1, ""); - constexpr std::variant v2 = v; - static_assert(v2.index() == 1, ""); - static_assert(std::get<1>(v2) == 42, ""); - } - { - constexpr std::variant v(std::in_place_index<0>, 42); - static_assert(v.index() == 0, ""); - constexpr std::variant v2(v); - static_assert(v2.index() == 0, ""); - static_assert(std::get<0>(v2).value == 42, ""); - } - { - constexpr std::variant v(std::in_place_index<1>, 42); - static_assert(v.index() == 1, ""); - constexpr std::variant v2(v); - static_assert(v2.index() == 1, ""); - static_assert(std::get<1>(v2).value == 42, ""); - } - { - constexpr std::variant v(std::in_place_index<0>, 42); - static_assert(v.index() == 0, ""); - constexpr std::variant v2(v); - static_assert(v2.index() == 0, ""); - static_assert(std::get<0>(v2).value == 42, ""); - } - { - constexpr std::variant v(std::in_place_index<1>, 42); - static_assert(v.index() == 1, ""); - constexpr std::variant v2(v); - static_assert(v2.index() == 1, ""); - static_assert(std::get<1>(v2).value == 42, ""); - } -} - -int main() { - test_copy_ctor_basic(); - test_copy_ctor_sfinae(); -} diff --git a/test/libcxx/utilities/variant/variant.variant/variant.ctor/move.pass.cpp b/test/libcxx/utilities/variant/variant.variant/variant.ctor/move.pass.cpp deleted file mode 100644 index 91e8c194d144..000000000000 --- a/test/libcxx/utilities/variant/variant.variant/variant.ctor/move.pass.cpp +++ /dev/null @@ -1,153 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03, c++11, c++14 - -// - -// template class variant; - -// variant(variant&&) noexcept(see below); - -#include -#include - -#include "test_macros.h" - -struct NTMove { - constexpr NTMove(int v) : value(v) {} - NTMove(const NTMove &) = delete; - NTMove(NTMove &&that) : value(that.value) { that.value = -1; } - int value; -}; - -static_assert(!std::is_trivially_move_constructible::value, ""); -static_assert(std::is_move_constructible::value, ""); - -struct TMove { - constexpr TMove(int v) : value(v) {} - TMove(const TMove &) = delete; - TMove(TMove &&) = default; - int value; -}; - -static_assert(std::is_trivially_move_constructible::value, ""); - -struct TMoveNTCopy { - constexpr TMoveNTCopy(int v) : value(v) {} - TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {} - TMoveNTCopy(TMoveNTCopy&&) = default; - int value; -}; - -static_assert(std::is_trivially_move_constructible::value, ""); - -void test_move_ctor_sfinae() { - { - using V = std::variant; - static_assert(std::is_trivially_move_constructible::value, ""); - } - { - using V = std::variant; - static_assert(!std::is_trivially_move_constructible::value, ""); - static_assert(std::is_move_constructible::value, ""); - } - { - using V = std::variant; - static_assert(std::is_trivially_move_constructible::value, ""); - } - { - using V = std::variant; - static_assert(std::is_trivially_move_constructible::value, ""); - } -} - -template -struct Result { size_t index; T value; }; - -void test_move_ctor_basic() { - { - struct { - constexpr Result operator()() const { - std::variant v(std::in_place_index<0>, 42); - std::variant v2 = std::move(v); - return {v2.index(), std::get<0>(std::move(v2))}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 0, ""); - static_assert(result.value == 42, ""); - } - { - struct { - constexpr Result operator()() const { - std::variant v(std::in_place_index<1>, 42); - std::variant v2 = std::move(v); - return {v2.index(), std::get<1>(std::move(v2))}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value == 42, ""); - } - { - struct { - constexpr Result operator()() const { - std::variant v(std::in_place_index<0>, 42); - std::variant v2(std::move(v)); - return {v2.index(), std::get<0>(std::move(v2))}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 0, ""); - static_assert(result.value.value == 42, ""); - } - { - struct { - constexpr Result operator()() const { - std::variant v(std::in_place_index<1>, 42); - std::variant v2(std::move(v)); - return {v2.index(), std::get<1>(std::move(v2))}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value.value == 42, ""); - } - { - struct { - constexpr Result operator()() const { - std::variant v(std::in_place_index<0>, 42); - std::variant v2(std::move(v)); - return {v2.index(), std::get<0>(std::move(v2))}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 0, ""); - static_assert(result.value.value == 42, ""); - } - { - struct { - constexpr Result operator()() const { - std::variant v(std::in_place_index<1>, 42); - std::variant v2(std::move(v)); - return {v2.index(), std::get<1>(std::move(v2))}; - } - } test; - constexpr auto result = test(); - static_assert(result.index == 1, ""); - static_assert(result.value.value == 42, ""); - } -} - -int main() { - test_move_ctor_basic(); - test_move_ctor_sfinae(); -} diff --git a/test/std/localization/locale.categories/category.ctype/locale.codecvt.byname/ctor_char.pass.cpp b/test/std/localization/locale.categories/category.ctype/locale.codecvt.byname/ctor_char.pass.cpp index 349577835ec6..24c2f23f0db7 100644 --- a/test/std/localization/locale.categories/category.ctype/locale.codecvt.byname/ctor_char.pass.cpp +++ b/test/std/localization/locale.categories/category.ctype/locale.codecvt.byname/ctor_char.pass.cpp @@ -17,6 +17,8 @@ #include #include +#include "platform_support.h" + typedef std::codecvt_byname F; class my_facet @@ -38,12 +40,12 @@ int my_facet::count = 0; int main() { { - std::locale l(std::locale::classic(), new my_facet("en_US")); + std::locale l(std::locale::classic(), new my_facet(LOCALE_en_US)); assert(my_facet::count == 1); } assert(my_facet::count == 0); { - my_facet f("en_US", 1); + my_facet f(LOCALE_en_US, 1); assert(my_facet::count == 1); { std::locale l(std::locale::classic(), &f); @@ -53,12 +55,12 @@ int main() } assert(my_facet::count == 0); { - std::locale l(std::locale::classic(), new my_facet(std::string("en_US"))); + std::locale l(std::locale::classic(), new my_facet(std::string(LOCALE_en_US))); assert(my_facet::count == 1); } assert(my_facet::count == 0); { - my_facet f(std::string("en_US"), 1); + my_facet f(std::string(LOCALE_en_US), 1); assert(my_facet::count == 1); { std::locale l(std::locale::classic(), &f); diff --git a/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter.pass.cpp b/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter.pass.cpp new file mode 100644 index 000000000000..6fdd288e2d6a --- /dev/null +++ b/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// template +// OutputIterator exclusive_scan(InputIterator first, InputIterator last, +// OutputIterator result, T init); +// + +#include +#include +#include + +#include "test_iterators.h" + +template +void +test(Iter1 first, Iter1 last, T init, Iter2 rFirst, Iter2 rLast) +{ + std::vector::value_type> v; + +// Not in place + std::exclusive_scan(first, last, std::back_inserter(v), init); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); + +// In place + v.clear(); + v.assign(first, last); + std::exclusive_scan(v.begin(), v.end(), v.begin(), init); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); +} + + +template +void +test() +{ + int ia[] = {1, 3, 5, 7, 9}; + const int pRes[] = {0, 1, 4, 9, 16}; + const unsigned sa = sizeof(ia) / sizeof(ia[0]); + static_assert(sa == sizeof(pRes) / sizeof(pRes[0])); // just to be sure + + for (unsigned int i = 0; i < sa; ++i ) + test(Iter(ia), Iter(ia + i), 0, pRes, pRes + i); +} + +int triangle(int n) { return n*(n+1)/2; } + +// Basic sanity +void basic_tests() +{ + { + std::vector v(10); + std::fill(v.begin(), v.end(), 3); + std::exclusive_scan(v.begin(), v.end(), v.begin(), 50); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 50 + (int) i * 3); + } + + { + std::vector v(10); + std::iota(v.begin(), v.end(), 0); + std::exclusive_scan(v.begin(), v.end(), v.begin(), 30); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 30 + triangle(i-1)); + } + + { + std::vector v(10); + std::iota(v.begin(), v.end(), 1); + std::exclusive_scan(v.begin(), v.end(), v.begin(), 40); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 40 + triangle(i)); + } + +} + +int main() +{ + basic_tests(); + +// All the iterator categories + test >(); + test >(); + test >(); + test >(); + test(); + test< int*>(); +} diff --git a/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter_init_op.pass.cpp b/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter_init_op.pass.cpp new file mode 100644 index 000000000000..ba1673fe467f --- /dev/null +++ b/test/std/numerics/numeric.ops/exclusive.scan/exclusive_scan_iter_iter_iter_init_op.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// template +// OutputIterator +// exclusive_scan(InputIterator first, InputIterator last, +// OutputIterator result, +// T init, BinaryOperation binary_op); // C++17 + +#include +#include +#include + +#include "test_iterators.h" + +template +void +test(Iter1 first, Iter1 last, T init, Op op, Iter2 rFirst, Iter2 rLast) +{ + std::vector::value_type> v; + +// Not in place + std::exclusive_scan(first, last, std::back_inserter(v), init, op); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); + +// In place + v.clear(); + v.assign(first, last); + std::exclusive_scan(v.begin(), v.end(), v.begin(), init, op); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); +} + + +template +void +test() +{ + int ia[] = {1, 3, 5, 7, 9}; + const int pRes[] = {0, 1, 4, 9, 16}; + const int mRes[] = {1, 1, 3, 15, 105}; + const unsigned sa = sizeof(ia) / sizeof(ia[0]); + static_assert(sa == sizeof(pRes) / sizeof(pRes[0])); // just to be sure + static_assert(sa == sizeof(mRes) / sizeof(mRes[0])); // just to be sure + + for (unsigned int i = 0; i < sa; ++i ) { + test(Iter(ia), Iter(ia + i), 0, std::plus<>(), pRes, pRes + i); + test(Iter(ia), Iter(ia + i), 1, std::multiplies<>(), mRes, mRes + i); + } +} + +int main() +{ +// All the iterator categories + test >(); + test >(); + test >(); + test >(); + test(); + test< int*>(); + +// Make sure that the calculations are done using the init typedef + { + std::vector v(10); + std::iota(v.begin(), v.end(), 1); + std::vector res; + std::exclusive_scan(v.begin(), v.end(), std::back_inserter(res), 1, std::multiplies<>()); + + assert(res.size() == 10); + int j = 1; + assert(res[0] == 1); + for (size_t i = 1; i < v.size(); ++i) + { + j *= i; + assert(res[i] == j); + } + } +} + \ No newline at end of file diff --git a/test/std/numerics/numeric.ops/transform.exclusive.scan/transform_exclusive_scan_iter_iter_iter_init_bop_uop.pass.cpp b/test/std/numerics/numeric.ops/transform.exclusive.scan/transform_exclusive_scan_iter_iter_iter_init_bop_uop.pass.cpp new file mode 100644 index 000000000000..3bfb336a03f9 --- /dev/null +++ b/test/std/numerics/numeric.ops/transform.exclusive.scan/transform_exclusive_scan_iter_iter_iter_init_bop_uop.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// template +// OutputIterator transform_exclusive_scan(InputIterator first, InputIterator last, +// OutputIterator result, T init, +// BinaryOperation binary_op, +// UnaryOperation unary_op); + + +#include +#include +#include +#include + +#include "test_iterators.h" + +template +struct identity : std::unary_function<_Tp, _Tp> +{ + constexpr const _Tp& operator()(const _Tp& __x) const { return __x;} +}; + +template <> +struct identity +{ + template + constexpr auto operator()(_Tp&& __x) const + _NOEXCEPT_(noexcept(_VSTD::forward<_Tp>(__x))) + -> decltype (_VSTD::forward<_Tp>(__x)) + { return _VSTD::forward<_Tp>(__x); } +}; + +template +void +test(Iter1 first, Iter1 last, BOp bop, UOp uop, T init, Iter2 rFirst, Iter2 rLast) +{ + std::vector::value_type> v; +// Test not in-place + std::transform_exclusive_scan(first, last, std::back_inserter(v), init, bop, uop); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); + +// Test in-place + v.clear(); + v.assign(first, last); + std::transform_exclusive_scan(v.begin(), v.end(), v.begin(), init, bop, uop); + assert(std::equal(v.begin(), v.end(), rFirst, rLast)); +} + + +template +void +test() +{ + int ia[] = { 1, 3, 5, 7, 9}; + const int pResI0[] = { 0, 1, 4, 9, 16}; // with identity + const int mResI0[] = { 0, 0, 0, 0, 0}; + const int pResN0[] = { 0, -1, -4, -9, -16}; // with negate + const int mResN0[] = { 0, 0, 0, 0, 0}; + const int pResI2[] = { 2, 3, 6, 11, 18}; // with identity + const int mResI2[] = { 2, 2, 6, 30, 210}; + const int pResN2[] = { 2, 1, -2, -7, -14}; // with negate + const int mResN2[] = { 2, -2, 6, -30, 210}; + const unsigned sa = sizeof(ia) / sizeof(ia[0]); + static_assert(sa == sizeof(pResI0) / sizeof(pResI0[0])); // just to be sure + static_assert(sa == sizeof(mResI0) / sizeof(mResI0[0])); // just to be sure + static_assert(sa == sizeof(pResN0) / sizeof(pResN0[0])); // just to be sure + static_assert(sa == sizeof(mResN0) / sizeof(mResN0[0])); // just to be sure + static_assert(sa == sizeof(pResI2) / sizeof(pResI2[0])); // just to be sure + static_assert(sa == sizeof(mResI2) / sizeof(mResI2[0])); // just to be sure + static_assert(sa == sizeof(pResN2) / sizeof(pResN2[0])); // just to be sure + static_assert(sa == sizeof(mResN2) / sizeof(mResN2[0])); // just to be sure + + for (unsigned int i = 0; i < sa; ++i ) { + test(Iter(ia), Iter(ia + i), std::plus<>(), identity<>(), 0, pResI0, pResI0 + i); + test(Iter(ia), Iter(ia + i), std::multiplies<>(), identity<>(), 0, mResI0, mResI0 + i); + test(Iter(ia), Iter(ia + i), std::plus<>(), std::negate<>(), 0, pResN0, pResN0 + i); + test(Iter(ia), Iter(ia + i), std::multiplies<>(), std::negate<>(), 0, mResN0, mResN0 + i); + test(Iter(ia), Iter(ia + i), std::plus<>(), identity<>(), 2, pResI2, pResI2 + i); + test(Iter(ia), Iter(ia + i), std::multiplies<>(), identity<>(), 2, mResI2, mResI2 + i); + test(Iter(ia), Iter(ia + i), std::plus<>(), std::negate<>(), 2, pResN2, pResN2 + i); + test(Iter(ia), Iter(ia + i), std::multiplies<>(), std::negate<>(), 2, mResN2, mResN2 + i); + } +} + +int triangle(int n) { return n*(n+1)/2; } + +// Basic sanity +void basic_tests() +{ + { + std::vector v(10); + std::fill(v.begin(), v.end(), 3); + std::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 50, std::plus<>(), identity<>()); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 50 + (int) i * 3); + } + + { + std::vector v(10); + std::iota(v.begin(), v.end(), 0); + std::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 30, std::plus<>(), identity<>()); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 30 + triangle(i-1)); + } + + { + std::vector v(10); + std::iota(v.begin(), v.end(), 1); + std::transform_exclusive_scan(v.begin(), v.end(), v.begin(), 40, std::plus<>(), identity<>()); + for (size_t i = 0; i < v.size(); ++i) + assert(v[i] == 40 + triangle(i)); + } + +// Make sure that the calculations are done using the init typedef + { + std::vector v(10); + std::iota(v.begin(), v.end(), 1); + std::vector res; + std::transform_exclusive_scan(v.begin(), v.end(), std::back_inserter(res), 1, std::multiplies<>(), identity<>()); + + assert(res.size() == 10); + int j = 1; + assert(res[0] == 1); + for (size_t i = 1; i < res.size(); ++i) + { + j *= i; + assert(res[i] == j); + } + } +} + +int main() +{ + basic_tests(); + +// All the iterator categories + test >(); + test >(); + test >(); + test >(); + test(); + test< int*>(); +} diff --git a/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp b/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp index 4de42fbd0243..48c3a73a06cc 100644 --- a/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp +++ b/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/default.pass.cpp @@ -16,8 +16,10 @@ // mutex(); #include +#include int main() { + static_assert(std::is_nothrow_default_constructible::value, ""); std::mutex m; } diff --git a/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp b/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp index cee73da849b6..8fcd1860843d 100644 --- a/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp +++ b/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp @@ -48,7 +48,6 @@ int main() assert(X::dtor_called == false); assert(static_cast(opt) == false); } - assert(X::dtor_called == false); // TRANSITION, Clang/C2 VSO#239997 { optional opt(X{}); X::dtor_called = false; @@ -57,5 +56,4 @@ int main() assert(static_cast(opt) == false); X::dtor_called = false; } - assert(X::dtor_called == false); // TRANSITION, Clang/C2 VSO#239997 } diff --git a/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp b/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp index c219e9704716..f94dcabde513 100644 --- a/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp +++ b/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp @@ -10,7 +10,7 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 // -// template T optional::value_or(U&& v) &&; +// template constexpr T optional::value_or(U&& v) &&; #include #include @@ -26,22 +26,22 @@ struct Y { int i_; - Y(int i) : i_(i) {} + constexpr Y(int i) : i_(i) {} }; struct X { int i_; - X(int i) : i_(i) {} - X(X&& x) : i_(x.i_) {x.i_ = 0;} - X(const Y& y) : i_(y.i_) {} - X(Y&& y) : i_(y.i_+1) {} + constexpr X(int i) : i_(i) {} + constexpr X(X&& x) : i_(x.i_) {x.i_ = 0;} + constexpr X(const Y& y) : i_(y.i_) {} + constexpr X(Y&& y) : i_(y.i_+1) {} friend constexpr bool operator==(const X& x, const X& y) {return x.i_ == y.i_;} }; -int main() +constexpr int test() { { optional opt(in_place, 2); @@ -65,4 +65,10 @@ int main() assert(std::move(opt).value_or(Y(3)) == 4); assert(!opt); } + return 0; +} + +int main() +{ + static_assert(test() == 0); } diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp new file mode 100644 index 000000000000..7b9c061b3ae8 --- /dev/null +++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/implicit_deduction_guides.pass.cpp @@ -0,0 +1,155 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// UNSUPPORTED: libcpp-no-deduction-guides + +// GCC's implementation of class template deduction is still immature and runs +// into issues with libc++. However GCC accepts this code when compiling +// against libstdc++. +// XFAIL: gcc + +// + +// Test that the constructors offered by std::basic_string are formulated +// so they're compatible with implicit deduction guides. + +#include +#include +#include + +#include "test_macros.h" +#include "archetypes.hpp" + + +// Overloads +// using A = Allocator +// using AT = std::allocator_arg_t +// --------------- +// (1) tuple(const Types&...) -> tuple +// (2) explicit tuple(const Types&...) -> tuple +// (3) tuple(AT, A const&, Types const&...) -> tuple +// (4) explicit tuple(AT, A const&, Types const&...) -> tuple +// (5) tuple(tuple const& t) -> decltype(t) +// (6) tuple(tuple&& t) -> decltype(t) +// (7) tuple(AT, A const&, tuple const& t) -> decltype(t) +// (8) tuple(AT, A const&, tuple&& t) -> decltype(t) +void test_primary_template() +{ + const std::allocator A; + const auto AT = std::allocator_arg; + { // Testing (1) + int x = 101; + std::tuple t1(42); + ASSERT_SAME_TYPE(decltype(t1), std::tuple); + std::tuple t2(x, 0.0, nullptr); + ASSERT_SAME_TYPE(decltype(t2), std::tuple); + } + { // Testing (2) + using T = ExplicitTestTypes::TestType; + static_assert(!std::is_convertible::value, ""); + + std::tuple t1(T{}); + ASSERT_SAME_TYPE(decltype(t1), std::tuple); + + const T v{}; + std::tuple t2(T{}, 101l, v); + ASSERT_SAME_TYPE(decltype(t2), std::tuple); + } + { // Testing (3) + int x = 101; + std::tuple t1(AT, A, 42); + ASSERT_SAME_TYPE(decltype(t1), std::tuple); + + std::tuple t2(AT, A, 42, 0.0, x); + ASSERT_SAME_TYPE(decltype(t2), std::tuple); + } + { // Testing (4) + using T = ExplicitTestTypes::TestType; + static_assert(!std::is_convertible::value, ""); + + std::tuple t1(AT, A, T{}); + ASSERT_SAME_TYPE(decltype(t1), std::tuple); + + const T v{}; + std::tuple t2(AT, A, T{}, 101l, v); + ASSERT_SAME_TYPE(decltype(t2), std::tuple); + } + { // Testing (5) + using Tup = std::tuple; + const Tup t(42, nullptr); + + std::tuple t1(t); + ASSERT_SAME_TYPE(decltype(t1), Tup); + } + { // Testing (6) + using Tup = std::tuple; + std::tuple t1(Tup(nullptr, 42, 'a')); + ASSERT_SAME_TYPE(decltype(t1), Tup); + } + { // Testing (7) + using Tup = std::tuple; + const Tup t(42, nullptr); + + std::tuple t1(AT, A, t); + ASSERT_SAME_TYPE(decltype(t1), Tup); + } + { // Testing (8) + using Tup = std::tuple; + std::tuple t1(AT, A, Tup(nullptr, 42, 'a')); + ASSERT_SAME_TYPE(decltype(t1), Tup); + } +} + +// Overloads +// using A = Allocator +// using AT = std::allocator_arg_t +// --------------- +// (1) tuple() -> tuple<> +// (2) tuple(AT, A const&) -> tuple<> +// (3) tuple(tuple const&) -> tuple<> +// (4) tuple(tuple&&) -> tuple<> +// (5) tuple(AT, A const&, tuple const&) -> tuple<> +// (6) tuple(AT, A const&, tuple&&) -> tuple<> +void test_empty_specialization() +{ + std::allocator A; + const auto AT = std::allocator_arg; + { // Testing (1) + std::tuple t1{}; + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (2) + std::tuple t1{AT, A}; + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (3) + const std::tuple<> t{}; + std::tuple t1(t); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (4) + std::tuple t1(std::tuple<>{}); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (5) + const std::tuple<> t{}; + std::tuple t1(AT, A, t); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } + { // Testing (6) + std::tuple t1(AT, A, std::tuple<>{}); + ASSERT_SAME_TYPE(decltype(t1), std::tuple<>); + } +} + +int main() { + test_primary_template(); + test_empty_specialization(); +} diff --git a/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp b/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp index dd5880ea6635..29228e562d69 100644 --- a/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -68,6 +68,28 @@ struct ThrowsCtorT { } }; +struct MoveCrashes { + int value; + MoveCrashes(int v = 0) noexcept : value{v} {} + MoveCrashes(MoveCrashes &&) noexcept { assert(false); } + MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; } + MoveCrashes &operator=(int v) noexcept { + value = v; + return *this; + } +}; + +struct ThrowsCtorTandMove { + int value; + ThrowsCtorTandMove() : value(0) {} + ThrowsCtorTandMove(int) noexcept(false) { throw 42; } + ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); } + ThrowsCtorTandMove &operator=(int v) noexcept { + value = v; + return *this; + } +}; + struct ThrowsAssignT { int value; ThrowsAssignT() : value(0) {} @@ -126,7 +148,7 @@ void test_T_assignment_sfinae() { using V = std::variant; static_assert(!std::is_assignable::value, "ambiguous"); } -#endif +#endif // TEST_VARIANT_HAS_NO_REFERENCES } void test_T_assignment_basic() { @@ -163,7 +185,7 @@ void test_T_assignment_basic() { assert(v.index() == 2); assert(std::get<2>(v) == 42); } -#endif +#endif // TEST_VARIANT_HAS_NO_REFERENCES } void test_T_assignment_performs_construction() { @@ -174,9 +196,11 @@ void test_T_assignment_performs_construction() { V v(std::in_place_type, "hello"); try { v = 42; + assert(false); } catch (...) { /* ... */ } - assert(v.valueless_by_exception()); + assert(v.index() == 0); + assert(std::get<0>(v) == "hello"); } { using V = std::variant; @@ -185,7 +209,7 @@ void test_T_assignment_performs_construction() { assert(v.index() == 0); assert(std::get<0>(v).value == 42); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_T_assignment_performs_assignment() { @@ -227,7 +251,7 @@ void test_T_assignment_performs_assignment() { assert(v.index() == 1); assert(std::get<1>(v).value == 100); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } int main() { diff --git a/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp b/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp index 4f0009d9d620..068b9a201566 100644 --- a/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp @@ -10,6 +10,10 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 +// The following compilers don't generate constexpr special members correctly. +// XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8 +// XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0 + // XFAIL: with_system_cxx_lib=macosx10.12 // XFAIL: with_system_cxx_lib=macosx10.11 // XFAIL: with_system_cxx_lib=macosx10.10 @@ -35,11 +39,6 @@ struct NoCopy { NoCopy &operator=(const NoCopy &) = default; }; -struct NothrowCopy { - NothrowCopy(const NothrowCopy &) noexcept = default; - NothrowCopy &operator=(const NothrowCopy &) noexcept = default; -}; - struct CopyOnly { CopyOnly(const CopyOnly &) = default; CopyOnly(CopyOnly &&) = delete; @@ -73,7 +72,7 @@ struct CopyAssign { ++alive; ++copy_construct; } - CopyAssign(CopyAssign &&o) : value(o.value) { + CopyAssign(CopyAssign &&o) noexcept : value(o.value) { o.value = -1; ++alive; ++move_construct; @@ -83,7 +82,7 @@ struct CopyAssign { ++copy_assign; return *this; } - CopyAssign &operator=(CopyAssign &&o) { + CopyAssign &operator=(CopyAssign &&o) noexcept { value = o.value; o.value = -1; ++move_assign; @@ -108,6 +107,48 @@ struct CopyDoesThrow { CopyDoesThrow &operator=(const CopyDoesThrow &) noexcept(false); }; + +struct NTCopyAssign { + constexpr NTCopyAssign(int v) : value(v) {} + NTCopyAssign(const NTCopyAssign &) = default; + NTCopyAssign(NTCopyAssign &&) = default; + NTCopyAssign &operator=(const NTCopyAssign &that) { + value = that.value; + return *this; + }; + NTCopyAssign &operator=(NTCopyAssign &&) = delete; + int value; +}; + +static_assert(!std::is_trivially_copy_assignable::value, ""); +static_assert(std::is_copy_assignable::value, ""); + +struct TCopyAssign { + constexpr TCopyAssign(int v) : value(v) {} + TCopyAssign(const TCopyAssign &) = default; + TCopyAssign(TCopyAssign &&) = default; + TCopyAssign &operator=(const TCopyAssign &) = default; + TCopyAssign &operator=(TCopyAssign &&) = delete; + int value; +}; + +static_assert(std::is_trivially_copy_assignable::value, ""); + +struct TCopyAssignNTMoveAssign { + constexpr TCopyAssignNTMoveAssign(int v) : value(v) {} + TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign &) = default; + TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign &&) = default; + TCopyAssignNTMoveAssign &operator=(const TCopyAssignNTMoveAssign &) = default; + TCopyAssignNTMoveAssign &operator=(TCopyAssignNTMoveAssign &&that) { + value = that.value; + that.value = -1; + return *this; + } + int value; +}; + +static_assert(std::is_trivially_copy_assignable_v, ""); + #ifndef TEST_HAS_NO_EXCEPTIONS struct CopyThrows { CopyThrows() = default; @@ -115,6 +156,17 @@ struct CopyThrows { CopyThrows &operator=(const CopyThrows &) { throw 42; } }; +struct CopyCannotThrow { + static int alive; + CopyCannotThrow() { ++alive; } + CopyCannotThrow(const CopyCannotThrow &) noexcept { ++alive; } + CopyCannotThrow(CopyCannotThrow &&) noexcept { assert(false); } + CopyCannotThrow &operator=(const CopyCannotThrow &) noexcept = default; + CopyCannotThrow &operator=(CopyCannotThrow &&) noexcept { assert(false); return *this; } +}; + +int CopyCannotThrow::alive = 0; + struct MoveThrows { static int alive; MoveThrows() { ++alive; } @@ -146,7 +198,7 @@ int MakeEmptyT::alive = 0; template void makeEmpty(Variant &v) { Variant v2(std::in_place_type); try { - v = v2; + v = std::move(v2); assert(false); } catch (...) { assert(v.valueless_by_exception()); @@ -171,10 +223,8 @@ void test_copy_assignment_sfinae() { static_assert(std::is_copy_assignable::value, ""); } { - // variant only provides copy assignment when both the copy and move - // constructors are well formed using V = std::variant; - static_assert(!std::is_copy_assignable::value, ""); + static_assert(std::is_copy_assignable::value, ""); } { using V = std::variant; @@ -188,6 +238,29 @@ void test_copy_assignment_sfinae() { using V = std::variant; static_assert(!std::is_copy_assignable::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant; + static_assert(std::is_trivially_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_trivially_copy_assignable::value, ""); + static_assert(std::is_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_copy_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_copy_assignable::value, ""); + } } void test_copy_assignment_empty_empty() { @@ -204,7 +277,7 @@ void test_copy_assignment_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_copy_assignment_non_empty_empty() { @@ -230,7 +303,7 @@ void test_copy_assignment_non_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_copy_assignment_empty_non_empty() { @@ -256,9 +329,11 @@ void test_copy_assignment_empty_non_empty() { assert(v1.index() == 2); assert(std::get<2>(v1) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } +template struct Result { size_t index; T value; }; + void test_copy_assignment_same_index() { { using V = std::variant; @@ -306,7 +381,65 @@ void test_copy_assignment_same_index() { assert(v1.index() == 1); assert(&std::get<1>(v1) == &mref); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(43); + V v2(42); + v = v2; + return {v.index(), std::get<0>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(43l); + V v2(42l); + v = v2; + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(std::in_place_type, 43); + V v2(std::in_place_type, 42); + v = v2; + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(std::in_place_type, 43); + V v2(std::in_place_type, 42); + v = v2; + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } } void test_copy_assignment_different_index() { @@ -338,8 +471,6 @@ void test_copy_assignment_different_index() { } #ifndef TEST_HAS_NO_EXCEPTIONS { - // Test that if copy construction throws then original value is - // unchanged. using V = std::variant; V v1(std::in_place_type, "hello"); V v2(std::in_place_type); @@ -348,24 +479,31 @@ void test_copy_assignment_different_index() { assert(false); } catch (...) { /* ... */ } - assert(v1.index() == 2); - assert(std::get<2>(v1) == "hello"); + // Test that copy construction is used directly if move construction may throw, + // resulting in a valueless variant if copy throws. + assert(v1.valueless_by_exception()); } { - // Test that if move construction throws then the variant is left - // valueless by exception. using V = std::variant; V v1(std::in_place_type, "hello"); V v2(std::in_place_type); assert(MoveThrows::alive == 1); - try { - v1 = v2; - assert(false); - } catch (...) { /* ... */ - } - assert(v1.valueless_by_exception()); + // Test that copy construction is used directly if move construction may throw. + v1 = v2; + assert(v1.index() == 1); assert(v2.index() == 1); - assert(MoveThrows::alive == 1); + assert(MoveThrows::alive == 2); + } + { + // Test that direct copy construction is preferred when it cannot throw. + using V = std::variant; + V v1(std::in_place_type, "hello"); + V v2(std::in_place_type); + assert(CopyCannotThrow::alive == 1); + v1 = v2; + assert(v1.index() == 1); + assert(v2.index() == 1); + assert(CopyCannotThrow::alive == 2); } { using V = std::variant; @@ -389,9 +527,60 @@ void test_copy_assignment_different_index() { assert(v2.index() == 2); assert(std::get<2>(v2) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(43); + V v2(42l); + v = v2; + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(std::in_place_type, 43); + V v2(std::in_place_type, 42); + v = v2; + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } } +template +constexpr bool test_constexpr_assign_extension_imp( + std::variant&& v, ValueType&& new_value) +{ + const std::variant cp( + std::forward(new_value)); + v = cp; + return v.index() == NewIdx && + std::get(v) == std::get(cp); +} + +void test_constexpr_copy_assignment_extension() { + // The following tests are for not-yet-standardized behavior (P0602): + using V = std::variant; + static_assert(std::is_trivially_copyable::value, ""); + static_assert(std::is_trivially_copy_assignable::value, ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); +} int main() { test_copy_assignment_empty_empty(); @@ -401,4 +590,5 @@ int main() { test_copy_assignment_different_index(); test_copy_assignment_sfinae(); test_copy_assignment_not_noexcept(); + test_constexpr_copy_assignment_extension(); } diff --git a/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp b/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp index c1ba87be76d1..c410b4b8f3ef 100644 --- a/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp @@ -10,6 +10,10 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 +// The following compilers don't generate constexpr special members correctly. +// XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8 +// XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0 + // XFAIL: with_system_cxx_lib=macosx10.12 // XFAIL: with_system_cxx_lib=macosx10.11 // XFAIL: with_system_cxx_lib=macosx10.10 @@ -91,6 +95,60 @@ struct MoveAssign { int MoveAssign::move_construct = 0; int MoveAssign::move_assign = 0; +struct NTMoveAssign { + constexpr NTMoveAssign(int v) : value(v) {} + NTMoveAssign(const NTMoveAssign &) = default; + NTMoveAssign(NTMoveAssign &&) = default; + NTMoveAssign &operator=(const NTMoveAssign &that) = default; + NTMoveAssign &operator=(NTMoveAssign &&that) { + value = that.value; + that.value = -1; + return *this; + }; + int value; +}; + +static_assert(!std::is_trivially_move_assignable::value, ""); +static_assert(std::is_move_assignable::value, ""); + +struct TMoveAssign { + constexpr TMoveAssign(int v) : value(v) {} + TMoveAssign(const TMoveAssign &) = delete; + TMoveAssign(TMoveAssign &&) = default; + TMoveAssign &operator=(const TMoveAssign &) = delete; + TMoveAssign &operator=(TMoveAssign &&) = default; + int value; +}; + +static_assert(std::is_trivially_move_assignable::value, ""); + +struct TMoveAssignNTCopyAssign { + constexpr TMoveAssignNTCopyAssign(int v) : value(v) {} + TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default; + TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default; + TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) { + value = that.value; + return *this; + } + TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default; + int value; +}; + +static_assert(std::is_trivially_move_assignable_v, ""); + +struct TrivialCopyNontrivialMove { + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default; + TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {} + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default; + TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept { + return *this; + } +}; + +static_assert(std::is_trivially_copy_assignable_v, ""); +static_assert(!std::is_trivially_move_assignable_v, ""); + + void test_move_assignment_noexcept() { { using V = std::variant; @@ -124,10 +182,8 @@ void test_move_assignment_sfinae() { static_assert(std::is_move_assignable::value, ""); } { - // variant only provides move assignment when both the move constructor - // and move assignment operator are well formed. using V = std::variant; - static_assert(!std::is_move_assignable::value, ""); + static_assert(std::is_move_assignable::value, ""); } { using V = std::variant; @@ -147,6 +203,33 @@ void test_move_assignment_sfinae() { using V = std::variant; static_assert(!std::is_move_assignable::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant; + static_assert(std::is_trivially_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_trivially_move_assignable::value, ""); + static_assert(std::is_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_trivially_move_assignable::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_move_assignable::value, ""); + } } void test_move_assignment_empty_empty() { @@ -163,7 +246,7 @@ void test_move_assignment_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_move_assignment_non_empty_empty() { @@ -189,7 +272,7 @@ void test_move_assignment_non_empty_empty() { assert(v1.valueless_by_exception()); assert(v1.index() == std::variant_npos); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } void test_move_assignment_empty_non_empty() { @@ -215,9 +298,11 @@ void test_move_assignment_empty_non_empty() { assert(v1.index() == 2); assert(std::get<2>(v1) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } +template struct Result { size_t index; T value; }; + void test_move_assignment_same_index() { { using V = std::variant; @@ -264,7 +349,51 @@ void test_move_assignment_same_index() { assert(v1.index() == 1); assert(&std::get<1>(v1) == &mref); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(43); + V v2(42); + v = std::move(v2); + return {v.index(), std::get<0>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(43l); + V v2(42l); + v = std::move(v2); + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(std::in_place_type, 43); + V v2(std::in_place_type, 42); + v = std::move(v2); + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } } void test_move_assignment_different_index() { @@ -312,7 +441,60 @@ void test_move_assignment_different_index() { assert(v1.index() == 2); assert(std::get<2>(v1) == "hello"); } -#endif +#endif // TEST_HAS_NO_EXCEPTIONS + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(43); + V v2(42l); + v = std::move(v2); + return {v.index(), std::get<1>(v)}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42l, ""); + } + { + struct { + constexpr Result operator()() const { + using V = std::variant; + V v(std::in_place_type, 43); + V v2(std::in_place_type, 42); + v = std::move(v2); + return {v.index(), std::get<1>(v).value}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } +} + +template +constexpr bool test_constexpr_assign_extension_imp( + std::variant&& v, ValueType&& new_value) +{ + std::variant v2( + std::forward(new_value)); + const auto cp = v2; + v = std::move(v2); + return v.index() == NewIdx && + std::get(v) == std::get(cp); +} + +void test_constexpr_move_assignment_extension() { + // The following tests are for not-yet-standardized behavior (P0602): + using V = std::variant; + static_assert(std::is_trivially_copyable::value, ""); + static_assert(std::is_trivially_move_assignable::value, ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); } int main() { @@ -323,4 +505,5 @@ int main() { test_move_assignment_different_index(); test_move_assignment_sfinae(); test_move_assignment_noexcept(); + test_constexpr_move_assignment_extension(); } diff --git a/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp b/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp index 3b20c369c638..f3113435f3ce 100644 --- a/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -51,6 +51,34 @@ struct MoveOnlyNT { MoveOnlyNT(MoveOnlyNT &&) {} }; +struct NTCopy { + constexpr NTCopy(int v) : value(v) {} + NTCopy(const NTCopy &that) : value(that.value) {} + NTCopy(NTCopy &&) = delete; + int value; +}; + +static_assert(!std::is_trivially_copy_constructible::value, ""); +static_assert(std::is_copy_constructible::value, ""); + +struct TCopy { + constexpr TCopy(int v) : value(v) {} + TCopy(TCopy const &) = default; + TCopy(TCopy &&) = delete; + int value; +}; + +static_assert(std::is_trivially_copy_constructible::value, ""); + +struct TCopyNTMove { + constexpr TCopyNTMove(int v) : value(v) {} + TCopyNTMove(const TCopyNTMove&) = default; + TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; } + int value; +}; + +static_assert(std::is_trivially_copy_constructible::value, ""); + #ifndef TEST_HAS_NO_EXCEPTIONS struct MakeEmptyT { static int alive; @@ -71,7 +99,7 @@ int MakeEmptyT::alive = 0; template void makeEmpty(Variant &v) { Variant v2(std::in_place_type); try { - v = v2; + v = std::move(v2); assert(false); } catch (...) { assert(v.valueless_by_exception()); @@ -96,6 +124,25 @@ void test_copy_ctor_sfinae() { using V = std::variant; static_assert(!std::is_copy_constructible::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant; + static_assert(std::is_trivially_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_trivially_copy_constructible::value, ""); + static_assert(std::is_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_copy_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_copy_constructible::value, ""); + } } void test_copy_ctor_basic() { @@ -125,6 +172,50 @@ void test_copy_ctor_basic() { assert(v2.index() == 1); assert(std::get<1>(v2).value == 42); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + constexpr std::variant v(std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr std::variant v2 = v; + static_assert(v2.index() == 0, ""); + static_assert(std::get<0>(v2) == 42, ""); + } + { + constexpr std::variant v(std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr std::variant v2 = v; + static_assert(v2.index() == 1, ""); + static_assert(std::get<1>(v2) == 42, ""); + } + { + constexpr std::variant v(std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr std::variant v2(v); + static_assert(v2.index() == 0, ""); + static_assert(std::get<0>(v2).value == 42, ""); + } + { + constexpr std::variant v(std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr std::variant v2(v); + static_assert(v2.index() == 1, ""); + static_assert(std::get<1>(v2).value == 42, ""); + } + { + constexpr std::variant v(std::in_place_index<0>, 42); + static_assert(v.index() == 0, ""); + constexpr std::variant v2(v); + static_assert(v2.index() == 0, ""); + static_assert(std::get<0>(v2).value == 42, ""); + } + { + constexpr std::variant v(std::in_place_index<1>, 42); + static_assert(v.index() == 1, ""); + constexpr std::variant v2(v); + static_assert(v2.index() == 1, ""); + static_assert(std::get<1>(v2).value == 42, ""); + } } void test_copy_ctor_valueless_by_exception() { @@ -135,7 +226,7 @@ void test_copy_ctor_valueless_by_exception() { const V &cv1 = v1; V v(cv1); assert(v.valueless_by_exception()); -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } template @@ -149,7 +240,7 @@ constexpr bool test_constexpr_copy_ctor_extension_imp( } void test_constexpr_copy_ctor_extension() { - // NOTE: This test is for not yet standardized behavior. + // NOTE: This test is for not yet standardized behavior. (P0602) using V = std::variant; #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible::value, ""); @@ -157,9 +248,9 @@ void test_constexpr_copy_ctor_extension() { static_assert(std::is_trivially_move_constructible::value, ""); static_assert(!std::is_copy_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); -#else +#else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable::value, ""); -#endif +#endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), ""); static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), ""); static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), ""); diff --git a/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp b/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp index a5de1f77334e..6b392068d5a9 100644 --- a/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp @@ -53,6 +53,34 @@ struct MoveOnlyNT { MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; } }; +struct NTMove { + constexpr NTMove(int v) : value(v) {} + NTMove(const NTMove &) = delete; + NTMove(NTMove &&that) : value(that.value) { that.value = -1; } + int value; +}; + +static_assert(!std::is_trivially_move_constructible::value, ""); +static_assert(std::is_move_constructible::value, ""); + +struct TMove { + constexpr TMove(int v) : value(v) {} + TMove(const TMove &) = delete; + TMove(TMove &&) = default; + int value; +}; + +static_assert(std::is_trivially_move_constructible::value, ""); + +struct TMoveNTCopy { + constexpr TMoveNTCopy(int v) : value(v) {} + TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {} + TMoveNTCopy(TMoveNTCopy&&) = default; + int value; +}; + +static_assert(std::is_trivially_move_constructible::value, ""); + #ifndef TEST_HAS_NO_EXCEPTIONS struct MakeEmptyT { static int alive; @@ -73,7 +101,7 @@ int MakeEmptyT::alive = 0; template void makeEmpty(Variant &v) { Variant v2(std::in_place_type); try { - v = v2; + v = std::move(v2); assert(false); } catch (...) { assert(v.valueless_by_exception()); @@ -117,8 +145,30 @@ void test_move_ctor_sfinae() { using V = std::variant; static_assert(!std::is_move_constructible::value, ""); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + using V = std::variant; + static_assert(std::is_trivially_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(!std::is_trivially_move_constructible::value, ""); + static_assert(std::is_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_move_constructible::value, ""); + } + { + using V = std::variant; + static_assert(std::is_trivially_move_constructible::value, ""); + } } +template +struct Result { size_t index; T value; }; + void test_move_ctor_basic() { { std::variant v(std::in_place_index<0>, 42); @@ -162,6 +212,80 @@ void test_move_ctor_basic() { assert(std::get<1>(v).value == -1); assert(std::get<1>(v2).value == 42); } + + // The following tests are for not-yet-standardized behavior (P0602): + { + struct { + constexpr Result operator()() const { + std::variant v(std::in_place_index<0>, 42); + std::variant v2 = std::move(v); + return {v2.index(), std::get<0>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result operator()() const { + std::variant v(std::in_place_index<1>, 42); + std::variant v2 = std::move(v); + return {v2.index(), std::get<1>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value == 42, ""); + } + { + struct { + constexpr Result operator()() const { + std::variant v(std::in_place_index<0>, 42); + std::variant v2(std::move(v)); + return {v2.index(), std::get<0>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + constexpr Result operator()() const { + std::variant v(std::in_place_index<1>, 42); + std::variant v2(std::move(v)); + return {v2.index(), std::get<1>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + constexpr Result operator()() const { + std::variant v(std::in_place_index<0>, 42); + std::variant v2(std::move(v)); + return {v2.index(), std::get<0>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 0, ""); + static_assert(result.value.value == 42, ""); + } + { + struct { + constexpr Result operator()() const { + std::variant v(std::in_place_index<1>, 42); + std::variant v2(std::move(v)); + return {v2.index(), std::get<1>(std::move(v2))}; + } + } test; + constexpr auto result = test(); + static_assert(result.index == 1, ""); + static_assert(result.value.value == 42, ""); + } } void test_move_ctor_valueless_by_exception() { @@ -171,7 +295,7 @@ void test_move_ctor_valueless_by_exception() { makeEmpty(v1); V v(std::move(v1)); assert(v.valueless_by_exception()); -#endif +#endif // TEST_HAS_NO_EXCEPTIONS } template @@ -186,7 +310,7 @@ constexpr bool test_constexpr_ctor_extension_imp( } void test_constexpr_move_ctor_extension() { - // NOTE: This test is for not yet standardized behavior. + // NOTE: This test is for not yet standardized behavior. (P0602) using V = std::variant; #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible::value, ""); @@ -194,9 +318,9 @@ void test_constexpr_move_ctor_extension() { static_assert(std::is_trivially_move_constructible::value, ""); static_assert(!std::is_copy_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); -#else +#else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable::value, ""); -#endif +#endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_move_constructible::value, ""); static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), ""); static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), ""); diff --git a/test/support/msvc_stdlib_force_include.hpp b/test/support/msvc_stdlib_force_include.hpp index 6bcc97952199..954cf513ef2d 100644 --- a/test/support/msvc_stdlib_force_include.hpp +++ b/test/support/msvc_stdlib_force_include.hpp @@ -28,11 +28,6 @@ #error This header may not be used when targeting libc++ #endif -// Indicates that we are using the MSVC standard library. -#ifndef _MSVC_STL_VER - #define _MSVC_STL_VER 42 -#endif - #ifndef _LIBCXX_IN_DEVCRT struct AssertionDialogAvoider { AssertionDialogAvoider() { @@ -81,6 +76,9 @@ const AssertionDialogAvoider assertion_dialog_avoider{}; // Silence warnings about raw pointers and other unchecked iterators. #define _SCL_SECURE_NO_WARNINGS + + // Silence warnings about features that are deprecated in C++17. + #define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS #endif // _LIBCXX_IN_DEVCRT #include diff --git a/test/support/platform_support.h b/test/support/platform_support.h index 737e5d7a01ce..a9b5b98a3668 100644 --- a/test/support/platform_support.h +++ b/test/support/platform_support.h @@ -19,16 +19,18 @@ #ifdef _WIN32 // WARNING: Windows does not support UTF-8 codepages. // Locales are "converted" using http://docs.moodle.org/dev/Table_of_locales -#define LOCALE_en_US_UTF_8 "English_United States.1252" -#define LOCALE_cs_CZ_ISO8859_2 "Czech_Czech Republic.1250" -#define LOCALE_fr_FR_UTF_8 "French_France.1252" -#define LOCALE_fr_CA_ISO8859_1 "French_Canada.1252" -#define LOCALE_ru_RU_UTF_8 "Russian_Russia.1251" -#define LOCALE_zh_CN_UTF_8 "Chinese_China.936" +#define LOCALE_en_US "en-US" +#define LOCALE_en_US_UTF_8 "en-US" +#define LOCALE_cs_CZ_ISO8859_2 "cs-CZ" +#define LOCALE_fr_FR_UTF_8 "fr-FR" +#define LOCALE_fr_CA_ISO8859_1 "fr-CA" +#define LOCALE_ru_RU_UTF_8 "ru-RU" +#define LOCALE_zh_CN_UTF_8 "zh-CN" #elif defined(__CloudABI__) // Timezones are integrated into locales through LC_TIMEZONE_MASK on // CloudABI. LC_ALL_MASK can only be used if a timezone has also been // provided. UTC should be all right. +#define LOCALE_en_US "en_US" #define LOCALE_en_US_UTF_8 "en_US.UTF-8@UTC" #define LOCALE_fr_FR_UTF_8 "fr_FR.UTF-8@UTC" #define LOCALE_fr_CA_ISO8859_1 "fr_CA.ISO-8859-1@UTC" @@ -36,6 +38,7 @@ #define LOCALE_ru_RU_UTF_8 "ru_RU.UTF-8@UTC" #define LOCALE_zh_CN_UTF_8 "zh_CN.UTF-8@UTC" #else +#define LOCALE_en_US "en_US" #define LOCALE_en_US_UTF_8 "en_US.UTF-8" #define LOCALE_fr_FR_UTF_8 "fr_FR.UTF-8" #ifdef __linux__ diff --git a/test/support/test.workarounds/c1xx_empty_parameter_pack_expansion.pass.cpp b/test/support/test.workarounds/c1xx_empty_parameter_pack_expansion.pass.cpp deleted file mode 100644 index f25a9c9984cc..000000000000 --- a/test/support/test.workarounds/c1xx_empty_parameter_pack_expansion.pass.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03 - -// Verify TEST_WORKAROUND_C1XX_EMPTY_PARAMETER_PACK_EXPANSION. - -#include - -#include "test_workarounds.h" - -template -struct identity { - using type = T; -}; - -template struct list {}; - -// C1XX believes this function template is not viable when LArgs is an empty -// parameter pack. -template -int f2(typename identity::type..., int i) { - return i; -} - -#ifdef TEST_WORKAROUND_C1XX_EMPTY_PARAMETER_PACK_EXPANSION -// C1XX believes this function template *is* viable when LArgs is an empty -// parameter pack. Conforming compilers believe the two overloads are -// ambiguous when LArgs is an empty pack. -template -int f2(int i) { - return i; -} -#endif - -template -int f1(list, Args&&... args) { - return f2(args...); -} - -int main() { - f1(list<>{}, 42); -} diff --git a/test/support/test_workarounds.h b/test/support/test_workarounds.h index ae123d7e41d0..e88a14957d31 100644 --- a/test/support/test_workarounds.h +++ b/test/support/test_workarounds.h @@ -19,7 +19,6 @@ #if defined(TEST_COMPILER_C1XX) # define TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE // VSO#117743 -# define TEST_WORKAROUND_C1XX_EMPTY_PARAMETER_PACK_EXPANSION // VSO#109062 # ifndef _MSC_EXTENSIONS # define TEST_WORKAROUND_C1XX_BROKEN_ZA_CTOR_CHECK // VSO#119998 # endif diff --git a/test/support/uses_alloc_types.hpp b/test/support/uses_alloc_types.hpp index 7f92f0fd19c7..426d2583ef80 100644 --- a/test/support/uses_alloc_types.hpp +++ b/test/support/uses_alloc_types.hpp @@ -257,13 +257,6 @@ struct UsesAllocatorTestBase { return alloc; } -#ifdef TEST_WORKAROUND_C1XX_EMPTY_PARAMETER_PACK_EXPANSION - template - static CtorAlloc getAllocatorFromPackImp(CtorAlloc const& alloc) { - return alloc; - } -#endif - bool has_alloc() const { return alloc_store.get_allocator() != nullptr; } const CtorAlloc *get_alloc() const { return alloc_store.get_allocator(); } public: diff --git a/test/support/variant_test_helpers.hpp b/test/support/variant_test_helpers.hpp index 277167233714..75981546467b 100644 --- a/test/support/variant_test_helpers.hpp +++ b/test/support/variant_test_helpers.hpp @@ -69,9 +69,9 @@ template void makeEmpty(Variant& v) { Variant v2(std::in_place_type); try { - v = v2; + v = std::move(v2); assert(false); - } catch (...) { + } catch (...) { assert(v.valueless_by_exception()); } } diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html index 80b53021c1f0..bd33b6e3c574 100644 --- a/www/cxx1z_status.html +++ b/www/cxx1z_status.html @@ -46,7 +46,7 @@
  • SG1 - Study group #1 (Concurrency working group)
  • - +

    Paper Status

    @@ -477,7 +477,7 @@ - + From 2079716dfb3fb7e4e24b8b2e85eb6780b981a0af Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 10 Jun 2017 13:44:49 +0000 Subject: [PATCH 08/11] Vendor import of lld trunk r305145: https://llvm.org/svn/llvm-project/lld/trunk@305145 --- COFF/CMakeLists.txt | 1 + COFF/Chunks.cpp | 2 +- COFF/Driver.cpp | 13 +- COFF/InputFiles.cpp | 2 +- ELF/CMakeLists.txt | 1 + ELF/Config.h | 9 +- ELF/Driver.cpp | 18 +- ELF/EhFrame.cpp | 2 +- ELF/GdbIndex.h | 25 +- ELF/ICF.cpp | 2 +- ELF/InputFiles.cpp | 30 ++- ELF/InputSection.cpp | 44 +-- ELF/InputSection.h | 2 +- ELF/LTO.cpp | 3 +- ELF/LinkerScript.cpp | 153 +++++++---- ELF/LinkerScript.h | 16 +- ELF/Mips.cpp | 2 +- ELF/OutputSections.cpp | 108 +++----- ELF/OutputSections.h | 6 +- ELF/Relocations.cpp | 158 ++++++----- ELF/Relocations.h | 19 +- ELF/ScriptParser.cpp | 51 +++- ELF/SymbolTable.cpp | 38 ++- ELF/SymbolTable.h | 5 +- ELF/Symbols.cpp | 11 +- ELF/SyntheticSections.cpp | 174 ++++++------ ELF/SyntheticSections.h | 19 +- ELF/Target.cpp | 20 +- ELF/Thunks.cpp | 8 +- ELF/Writer.cpp | 101 ++++--- include/lld/Core/Reader.h | 5 +- .../lld/ReaderWriter/MachOLinkingContext.h | 2 +- lib/Core/CMakeLists.txt | 3 +- lib/Core/Reader.cpp | 6 +- lib/Core/SymbolTable.cpp | 2 +- lib/Driver/DarwinLdDriver.cpp | 8 +- lib/ReaderWriter/FileArchive.cpp | 15 +- lib/ReaderWriter/MachO/ExecutableAtoms.h | 2 +- .../MachO/MachOLinkingContext.cpp | 2 +- lib/ReaderWriter/MachO/MachONormalizedFile.h | 2 +- .../MachO/MachONormalizedFileBinaryReader.cpp | 15 +- .../MachO/MachONormalizedFileBinaryUtils.h | 2 +- .../MachO/MachONormalizedFileBinaryWriter.cpp | 6 +- .../MachO/MachONormalizedFileFromAtoms.cpp | 5 +- .../MachO/MachONormalizedFileToAtoms.cpp | 6 +- .../MachO/MachONormalizedFileYAML.cpp | 3 +- lib/ReaderWriter/MachO/WriterMachO.cpp | 2 +- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 2 + test/CMakeLists.txt | 2 +- test/COFF/pdb-none.test | 2 +- test/COFF/pdb.test | 4 +- test/ELF/Inputs/relocatable-comdat-multiple.s | 2 + test/ELF/aarch64-undefined-weak.s | 20 +- test/ELF/amdgpu-globals.s | 146 +++------- test/ELF/amdgpu-kernels.s | 16 +- test/ELF/arm-icf-exidx.s | 4 +- test/ELF/arm-thumb-no-undefined-thunk.s | 6 +- test/ELF/arm-thumb-thunk-symbols.s | 42 +++ test/ELF/arm-thumb-undefined-weak.s | 12 +- test/ELF/arm-undefined-weak.s | 12 +- test/ELF/dso_handle.s | 19 ++ test/ELF/ehdr_start.s | 11 + test/ELF/emit-relocs-merge.s | 2 +- test/ELF/gdb-index-empty.s | 168 +++++------- test/ELF/i386-reloc-large-addend.s | 15 ++ test/ELF/i386-reloc-range.s | 22 ++ test/ELF/icf-comdat.s | 23 ++ test/ELF/linkerscript/early-assign-symbol.s | 2 +- test/ELF/linkerscript/emit-relocs-multiple.s | 20 ++ test/ELF/linkerscript/expr-invalid-sec.s | 2 +- test/ELF/linkerscript/noload.s | 46 ++++ test/ELF/lto/Inputs/defsym-bar.ll | 21 ++ test/ELF/lto/Inputs/wrap-bar.ll | 14 + test/ELF/lto/defsym.ll | 28 ++ test/ELF/lto/wrap-1.ll | 35 +++ test/ELF/lto/wrap-2.ll | 36 +++ test/ELF/mips-npic-call-pic-script.s | 255 ++++++++++++++++++ test/ELF/relocatable-comdat-multiple.s | 31 +++ test/ELF/relocatable-compressed-input.s | 45 ++++ test/ELF/relocatable-empty-archive.s | 10 + unittests/DriverTests/DarwinLdDriverTest.cpp | 2 +- .../MachONormalizedFileBinaryReaderTests.cpp | 4 +- .../MachONormalizedFileBinaryWriterTests.cpp | 4 +- .../MachONormalizedFileToAtomsTests.cpp | 4 +- .../MachONormalizedFileYAMLTests.cpp | 6 +- 85 files changed, 1485 insertions(+), 739 deletions(-) create mode 100644 test/ELF/Inputs/relocatable-comdat-multiple.s create mode 100644 test/ELF/arm-thumb-thunk-symbols.s create mode 100644 test/ELF/dso_handle.s create mode 100644 test/ELF/i386-reloc-large-addend.s create mode 100644 test/ELF/i386-reloc-range.s create mode 100644 test/ELF/icf-comdat.s create mode 100644 test/ELF/linkerscript/emit-relocs-multiple.s create mode 100644 test/ELF/linkerscript/noload.s create mode 100644 test/ELF/lto/Inputs/defsym-bar.ll create mode 100644 test/ELF/lto/Inputs/wrap-bar.ll create mode 100644 test/ELF/lto/defsym.ll create mode 100644 test/ELF/lto/wrap-1.ll create mode 100644 test/ELF/lto/wrap-2.ll create mode 100644 test/ELF/mips-npic-call-pic-script.s create mode 100644 test/ELF/relocatable-comdat-multiple.s create mode 100644 test/ELF/relocatable-compressed-input.s create mode 100644 test/ELF/relocatable-empty-archive.s diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt index 14f553e540d9..e56593497000 100644 --- a/COFF/CMakeLists.txt +++ b/COFF/CMakeLists.txt @@ -25,6 +25,7 @@ add_lld_library(lldCOFF LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + BinaryFormat BitReader Core DebugInfoCodeView diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 791d96ee92a5..359dbe69559f 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -12,8 +12,8 @@ #include "InputFiles.h" #include "Symbols.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" -#include "llvm/Support/COFF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 96c328b30518..27b1c48ce3e5 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -18,6 +18,7 @@ #include "lld/Driver/Driver.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/COFFModuleDefinition.h" @@ -40,8 +41,6 @@ using namespace llvm; using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; -using llvm::sys::fs::file_magic; -using llvm::sys::fs::identify_magic; namespace lld { namespace coff { @@ -457,17 +456,11 @@ static void createImportLibrary() { static void parseModuleDefs(StringRef Path) { std::unique_ptr MB = check( MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); - MemoryBufferRef MBRef = MB->getMemBufferRef(); + COFFModuleDefinition M = + check(parseCOFFModuleDefinition(MB->getMemBufferRef(), Config->Machine)); - Expected Def = - parseCOFFModuleDefinition(MBRef, Config->Machine); - if (!Def) - fatal(errorToErrorCode(Def.takeError()).message()); - - COFFModuleDefinition &M = *Def; if (Config->OutputFile.empty()) Config->OutputFile = Saver.save(M.OutputFile); - if (M.ImageBase) Config->ImageBase = M.ImageBase; if (M.StackReserve) diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index 258d9fd74b4d..58e8dd329f1f 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -19,9 +19,9 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" -#include "llvm/Support/COFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt index 41da497abe26..c852198bb240 100644 --- a/ELF/CMakeLists.txt +++ b/ELF/CMakeLists.txt @@ -36,6 +36,7 @@ add_lld_library(lldELF LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Analysis + BinaryFormat BitReader BitWriter Codegen diff --git a/ELF/Config.h b/ELF/Config.h index 54f6dc2acc7c..9c73b4c9c068 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -13,9 +13,9 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/CachePruning.h" #include "llvm/Support/CodeGen.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include @@ -67,6 +67,12 @@ struct VersionDefinition { size_t NameOff = 0; // Offset in the string table }; +// Structure for mapping renamed symbols +struct RenamedSymbol { + Symbol *Target; + uint8_t OrigBinding; +}; + // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. @@ -98,6 +104,7 @@ struct Configuration { std::vector VersionScriptGlobals; std::vector VersionScriptLocals; std::vector BuildIdVector; + llvm::MapVector RenamedSymbols; bool AllowMultipleDefinition; bool AsNeeded = false; bool Bsymbolic; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 325404447b24..f3943b5cf655 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -185,7 +185,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { // is attempting LTO and using a default ar command that doesn't // understand the LLVM bitcode file. It is a pretty common error, so // we'll handle it as if it had a symbol table. - if (!File->hasSymbolTable()) { + if (!File->isEmpty() && !File->hasSymbolTable()) { for (const auto &P : getArchiveMembers(MBRef)) Files.push_back(make(P.first, Path, P.second)); return; @@ -970,6 +970,14 @@ template void LinkerDriver::link(opt::InputArgList &Args) { Symtab.scanShlibUndefined(); Symtab.scanVersionScript(); + // Create wrapped symbols for -wrap option. + for (auto *Arg : Args.filtered(OPT_wrap)) + Symtab.addSymbolWrap(Arg->getValue()); + + // Create alias symbols for -defsym option. + for (std::pair &Def : getDefsym(Args)) + Symtab.addSymbolAlias(Def.first, Def.second); + Symtab.addCombinedLTOObject(); if (ErrorCount) return; @@ -979,12 +987,8 @@ template void LinkerDriver::link(opt::InputArgList &Args) { for (StringRef Sym : Script->Opt.ReferencedSymbols) Symtab.addUndefined(Sym); - for (auto *Arg : Args.filtered(OPT_wrap)) - Symtab.wrap(Arg->getValue()); - - // Handle --defsym=sym=alias option. - for (std::pair &Def : getDefsym(Args)) - Symtab.alias(Def.first, Def.second); + // Apply symbol renames for -wrap and -defsym + Symtab.applySymbolRenames(); // Now that we have a complete list of input files. // Beyond this point, no new files are added. diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp index 90be30a5f0f9..c4e3f65c730e 100644 --- a/ELF/EhFrame.cpp +++ b/ELF/EhFrame.cpp @@ -22,8 +22,8 @@ #include "Relocations.h" #include "Strings.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/Dwarf.h" #include "llvm/Support/Endian.h" using namespace llvm; diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h index 03fec64f9bd5..527667f7280e 100644 --- a/ELF/GdbIndex.h +++ b/ELF/GdbIndex.h @@ -24,7 +24,30 @@ struct AddressEntry { InputSection *Section; uint64_t LowAddress; uint64_t HighAddress; - size_t CuIndex; + uint32_t CuIndex; +}; + +// Struct represents single entry of compilation units list area of gdb index. +// It consist of CU offset in .debug_info section and it's size. +struct CompilationUnitEntry { + uint64_t CuOffset; + uint64_t CuLength; +}; + +// Represents data about symbol and type names which are used +// to build symbol table and constant pool area of gdb index. +struct NameTypeEntry { + StringRef Name; + uint8_t Type; +}; + +// We fill one GdbIndexDataChunk for each object where scan of +// debug information performed. That information futher used +// for filling gdb index section areas. +struct GdbIndexChunk { + std::vector AddressArea; + std::vector CompilationUnits; + std::vector NamesAndTypes; }; // Element of GdbHashTab hash table. diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp index 419ae6816328..536032bdc3a8 100644 --- a/ELF/ICF.cpp +++ b/ELF/ICF.cpp @@ -78,8 +78,8 @@ #include "SymbolTable.h" #include "Threads.h" #include "llvm/ADT/Hashing.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" #include #include diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 98189825ccbf..524246ed1d17 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -306,21 +306,23 @@ void elf::ObjectFile::initializeSections( switch (Sec.sh_type) { case SHT_GROUP: { - // We discard comdat sections usually. When -r we should not do that. We - // still do deduplication in this case to simplify implementation, because - // otherwise merging group sections together would requre additional - // regeneration of its contents. - bool New = ComdatGroups - .insert(CachedHashStringRef( - getShtGroupSignature(ObjSections, Sec))) - .second; - if (New && Config->Relocatable) - this->Sections[I] = createInputSection(Sec, SectionStringTable); - else - this->Sections[I] = &InputSection::Discarded; - if (New) - continue; + // De-duplicate section groups by their signatures. + StringRef Signature = getShtGroupSignature(ObjSections, Sec); + bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second; + this->Sections[I] = &InputSection::Discarded; + // If it is a new section group, we want to keep group members. + // Group leader sections, which contain indices of group members, are + // discarded because they are useless beyond this point. The only + // exception is the -r option because in order to produce re-linkable + // object files, we want to pass through basically everything. + if (IsNew) { + if (Config->Relocatable) + this->Sections[I] = createInputSection(Sec, SectionStringTable); + continue; + } + + // Otherwise, discard group members. for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(toString(this) + diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 4af05c1a187b..e82f8c3016fa 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -20,6 +20,7 @@ #include "Target.h" #include "Thunks.h" #include "llvm/Object/Decompressor.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" @@ -72,6 +73,16 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, this->Alignment = V; } +// Drop SHF_GROUP bit unless we are producing a re-linkable object file. +// SHF_GROUP is a marker that a section belongs to some comdat group. +// That flag doesn't make sense in an executable. +static uint64_t getFlags(uint64_t Flags) { + Flags &= ~(uint64_t)SHF_INFO_LINK; + if (!Config->Relocatable) + Flags &= ~(uint64_t)SHF_GROUP; + return Flags; +} + // GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of // March 2017) fail to infer section types for sections starting with // ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of @@ -94,7 +105,7 @@ template InputSectionBase::InputSectionBase(elf::ObjectFile *File, const typename ELFT::Shdr *Hdr, StringRef Name, Kind SectionKind) - : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK, + : InputSectionBase(File, getFlags(Hdr->sh_flags), getType(Hdr->sh_type, Name), Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign, getSectionContents(File, Hdr), Name, SectionKind) { @@ -308,23 +319,21 @@ OutputSection *InputSection::getParent() const { return cast_or_null(Parent); } -void InputSection::copyShtGroup(uint8_t *Buf) { - assert(this->Type == SHT_GROUP); +// Copy SHT_GROUP section contents. Used only for the -r option. +template void InputSection::copyShtGroup(uint8_t *Buf) { + // ELFT::Word is the 32-bit integral type in the target endianness. + typedef typename ELFT::Word u32; + ArrayRef From = getDataAs(); + auto *To = reinterpret_cast(Buf); - ArrayRef From = getDataAs(); - uint32_t *To = reinterpret_cast(Buf); - - // First entry is a flag word, we leave it unchanged. + // The first entry is not a section number but a flag. *To++ = From[0]; - // Here we adjust indices of sections that belong to group as it - // might change during linking. + // Adjust section numbers because section numbers in an input object + // files are different in the output. ArrayRef Sections = this->File->getSections(); - for (uint32_t Val : From.slice(1)) { - uint32_t Index = read32(&Val, Config->Endianness); - write32(To++, Sections[Index]->getOutputSection()->SectionIndex, - Config->Endianness); - } + for (uint32_t Idx : From.slice(1)) + *To++ = Sections[Idx]->getOutputSection()->SectionIndex; } InputSectionBase *InputSection::getRelocatedSection() { @@ -682,7 +691,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { // Patch a nop (0x60000000) to a ld. if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000) write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) - // fallthrough + LLVM_FALLTHROUGH; default: Target->relocateOne(BufLoc, Type, TargetVA); break; @@ -712,10 +721,9 @@ template void InputSection::writeTo(uint8_t *Buf) { return; } - // If -r is given, linker should keep SHT_GROUP sections. We should fixup - // them, see copyShtGroup(). + // If -r is given, we may have a SHT_GROUP section. if (this->Type == SHT_GROUP) { - copyShtGroup(Buf + OutSecOff); + copyShtGroup(Buf + OutSecOff); return; } diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 97ca2133f905..d262b589219a 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -325,7 +325,7 @@ class InputSection : public InputSectionBase { template void copyRelocations(uint8_t *Buf, llvm::ArrayRef Rels); - void copyShtGroup(uint8_t *Buf); + template void copyShtGroup(uint8_t *Buf); }; // The list of all input sections. diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp index 6915d9713891..3a536271db4c 100644 --- a/ELF/LTO.cpp +++ b/ELF/LTO.cpp @@ -17,13 +17,13 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Caching.h" #include "llvm/LTO/Config.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/CodeGen.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -136,6 +136,7 @@ void BitcodeCompiler::add(BitcodeFile &F) { Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); if (R.Prevailing) undefine(Sym); + R.LinkerRedefined = Config->RenamedSymbols.count(Sym); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 1ced3e8e8d71..9dd7ba52be19 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -25,9 +25,9 @@ #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -54,7 +54,7 @@ uint64_t ExprValue::getValue() const { if (Sec) { if (OutputSection *OS = Sec->getOutputSection()) return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment); - error("unable to evaluate expression: input section " + Sec->Name + + error(Loc + ": unable to evaluate expression: input section " + Sec->Name + " has no output section assigned"); } return alignTo(Val, Alignment); @@ -431,6 +431,8 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { if (OutputSection *Sec = Cmd->Sec) { assert(Sec->SectionIndex == INT_MAX); Sec->SectionIndex = I; + if (Cmd->Noload) + Sec->Type = SHT_NOBITS; SecToCommand[Sec] = Cmd; } } @@ -442,7 +444,7 @@ void LinkerScript::fabricateDefaultCommands() { std::vector Commands; // Define start address - uint64_t StartAddr = Config->ImageBase + elf::getHeaderSize(); + uint64_t StartAddr = -1; // The Sections with -T
    have been sorted in order of ascending // address. We must lower StartAddr if the lowest -T
    as @@ -450,8 +452,12 @@ void LinkerScript::fabricateDefaultCommands() { for (auto& KV : Config->SectionStartMap) StartAddr = std::min(StartAddr, KV.second); - Commands.push_back( - make(".", [=] { return StartAddr; }, "")); + Commands.push_back(make( + ".", + [=] { + return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize()); + }, + "")); // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections @@ -870,51 +876,6 @@ void LinkerScript::processNonSectionCommands() { } } -// Do a last effort at synchronizing the linker script "AST" and the section -// list. This is needed to account for last minute changes, like adding a -// .ARM.exidx terminator and sorting SHF_LINK_ORDER sections. -// -// FIXME: We should instead create the "AST" earlier and the above changes would -// be done directly in the "AST". -// -// This can only handle new sections being added and sections being reordered. -void LinkerScript::synchronize() { - for (BaseCommand *Base : Opt.Commands) { - auto *Cmd = dyn_cast(Base); - if (!Cmd) - continue; - ArrayRef Sections = Cmd->Sec->Sections; - std::vector ScriptSections; - DenseSet ScriptSectionsSet; - for (BaseCommand *Base : Cmd->Commands) { - auto *ISD = dyn_cast(Base); - if (!ISD) - continue; - for (InputSection *&IS : ISD->Sections) { - if (IS->Live) { - ScriptSections.push_back(&IS); - ScriptSectionsSet.insert(IS); - } - } - } - std::vector Missing; - for (InputSection *IS : Sections) - if (!ScriptSectionsSet.count(IS)) - Missing.push_back(IS); - if (!Missing.empty()) { - auto ISD = make(""); - ISD->Sections = Missing; - Cmd->Commands.push_back(ISD); - for (InputSection *&IS : ISD->Sections) - if (IS->Live) - ScriptSections.push_back(&IS); - } - assert(ScriptSections.size() == Sections.size()); - for (int I = 0, N = Sections.size(); I < N; ++I) - *ScriptSections[I] = Sections[I]; - } -} - static bool allocateHeaders(std::vector &Phdrs, ArrayRef OutputSectionCommands, @@ -1071,6 +1032,81 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { llvm_unreachable("unsupported Size argument"); } +static bool compareByFilePosition(InputSection *A, InputSection *B) { + // Synthetic doesn't have link order dependecy, stable_sort will keep it last + if (A->kind() == InputSectionBase::Synthetic || + B->kind() == InputSectionBase::Synthetic) + return false; + InputSection *LA = A->getLinkOrderDep(); + InputSection *LB = B->getLinkOrderDep(); + OutputSection *AOut = LA->getParent(); + OutputSection *BOut = LB->getParent(); + if (AOut != BOut) + return AOut->SectionIndex < BOut->SectionIndex; + return LA->OutSecOff < LB->OutSecOff; +} + +template +static void finalizeShtGroup(OutputSection *OS, + ArrayRef Sections) { + // sh_link field for SHT_GROUP sections should contain the section index of + // the symbol table. + OS->Link = InX::SymTab->getParent()->SectionIndex; + + // sh_info then contain index of an entry in symbol table section which + // provides signature of the section group. + elf::ObjectFile *Obj = Sections[0]->getFile(); + assert(Config->Relocatable && Sections.size() == 1); + ArrayRef Symbols = Obj->getSymbols(); + OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]); +} + +template void OutputSectionCommand::finalize() { + // Link order may be distributed across several InputSectionDescriptions + // but sort must consider them all at once. + std::vector ScriptSections; + std::vector Sections; + for (BaseCommand *Base : Commands) + if (auto *ISD = dyn_cast(Base)) + for (InputSection *&IS : ISD->Sections) { + ScriptSections.push_back(&IS); + Sections.push_back(IS); + } + + if ((Sec->Flags & SHF_LINK_ORDER)) { + std::sort(Sections.begin(), Sections.end(), compareByFilePosition); + for (int I = 0, N = Sections.size(); I < N; ++I) + *ScriptSections[I] = Sections[I]; + + // We must preserve the link order dependency of sections with the + // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We + // need to translate the InputSection sh_link to the OutputSection sh_link, + // all InputSections in the OutputSection have the same dependency. + if (auto *D = Sections.front()->getLinkOrderDep()) + Sec->Link = D->getParent()->SectionIndex; + } + + uint32_t Type = Sec->Type; + if (Type == SHT_GROUP) { + finalizeShtGroup(Sec, Sections); + return; + } + + if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) + return; + + InputSection *First = Sections[0]; + if (isa(First)) + return; + + Sec->Link = InX::SymTab->getParent()->SectionIndex; + // sh_info for SHT_REL[A] sections should contain the section header index of + // the section to which the relocation applies. + InputSectionBase *S = First->getRelocatedSection(); + Sec->Info = S->getOutputSection()->SectionIndex; + Sec->Flags |= SHF_INFO_LINK; +} + // Compress section contents if this section contains debug info. template void OutputSectionCommand::maybeCompress() { typedef typename ELFT::Chdr Elf_Chdr; @@ -1099,6 +1135,9 @@ template void OutputSectionCommand::maybeCompress() { } template void OutputSectionCommand::writeTo(uint8_t *Buf) { + if (Sec->Type == SHT_NOBITS) + return; + Sec->Loc = Buf; // We may have already rendered compressed content when using @@ -1110,9 +1149,6 @@ template void OutputSectionCommand::writeTo(uint8_t *Buf) { return; } - if (Sec->Type == SHT_NOBITS) - return; - // Write leading padding. std::vector Sections; for (BaseCommand *Cmd : Commands) @@ -1156,12 +1192,12 @@ bool LinkerScript::hasLMA(OutputSection *Sec) { ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") - return {CurOutSec, Dot - CurOutSec->Addr}; + return {CurOutSec, Dot - CurOutSec->Addr, Loc}; if (SymbolBody *B = findSymbol(S)) { if (auto *D = dyn_cast(B)) - return {D->Section, D->Value}; + return {D->Section, D->Value, Loc}; if (auto *C = dyn_cast(B)) - return {InX::Common, C->Offset}; + return {InX::Common, C->Offset, Loc}; } error(Loc + ": symbol not found: " + S); return 0; @@ -1201,3 +1237,8 @@ template void OutputSectionCommand::maybeCompress(); template void OutputSectionCommand::maybeCompress(); template void OutputSectionCommand::maybeCompress(); template void OutputSectionCommand::maybeCompress(); + +template void OutputSectionCommand::finalize(); +template void OutputSectionCommand::finalize(); +template void OutputSectionCommand::finalize(); +template void OutputSectionCommand::finalize(); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index a708ea7f61d5..1d4c736763fb 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -42,15 +42,14 @@ struct ExprValue { uint64_t Val; bool ForceAbsolute; uint64_t Alignment = 1; + std::string Loc; ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val, - uint64_t Alignment) - : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Alignment(Alignment) { - } - ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val) - : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute) {} - ExprValue(SectionBase *Sec, uint64_t Val) : ExprValue(Sec, false, Val) {} - ExprValue(uint64_t Val) : ExprValue(nullptr, Val) {} + const Twine &Loc) + : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Loc(Loc.str()) {} + ExprValue(SectionBase *Sec, uint64_t Val, const Twine &Loc) + : ExprValue(Sec, false, Val, Loc) {} + ExprValue(uint64_t Val) : ExprValue(nullptr, Val, "") {} bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; } uint64_t getValue() const; uint64_t getSecAddr() const; @@ -135,7 +134,9 @@ struct OutputSectionCommand : BaseCommand { ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; + bool Noload = false; + template void finalize(); template void writeTo(uint8_t *Buf); template void maybeCompress(); uint32_t getFiller(); @@ -281,7 +282,6 @@ class LinkerScript final { void assignOffsets(OutputSectionCommand *Cmd); void placeOrphanSections(); void processNonSectionCommands(); - void synchronize(); void assignAddresses(std::vector &Phdrs, ArrayRef OutputSectionCommands); diff --git a/ELF/Mips.cpp b/ELF/Mips.cpp index ac65672b70fc..af92fb9d24fd 100644 --- a/ELF/Mips.cpp +++ b/ELF/Mips.cpp @@ -16,8 +16,8 @@ #include "SymbolTable.h" #include "Writer.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/MipsABIFlags.h" using namespace llvm; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index 8357d6b03bb1..008871fd3889 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -16,7 +16,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SHA1.h" @@ -70,67 +70,6 @@ OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) /*Link*/ 0), SectionIndex(INT_MAX) {} -static bool compareByFilePosition(InputSection *A, InputSection *B) { - // Synthetic doesn't have link order dependecy, stable_sort will keep it last - if (A->kind() == InputSectionBase::Synthetic || - B->kind() == InputSectionBase::Synthetic) - return false; - InputSection *LA = A->getLinkOrderDep(); - InputSection *LB = B->getLinkOrderDep(); - OutputSection *AOut = LA->getParent(); - OutputSection *BOut = LB->getParent(); - if (AOut != BOut) - return AOut->SectionIndex < BOut->SectionIndex; - return LA->OutSecOff < LB->OutSecOff; -} - -template static void finalizeShtGroup(OutputSection *Sec) { - // sh_link field for SHT_GROUP sections should contain the section index of - // the symbol table. - Sec->Link = InX::SymTab->getParent()->SectionIndex; - - // sh_info then contain index of an entry in symbol table section which - // provides signature of the section group. - elf::ObjectFile *Obj = Sec->Sections[0]->getFile(); - assert(Config->Relocatable && Sec->Sections.size() == 1); - ArrayRef Symbols = Obj->getSymbols(); - Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]); -} - -template void OutputSection::finalize() { - if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { - std::sort(Sections.begin(), Sections.end(), compareByFilePosition); - assignOffsets(); - - // We must preserve the link order dependency of sections with the - // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We - // need to translate the InputSection sh_link to the OutputSection sh_link, - // all InputSections in the OutputSection have the same dependency. - if (auto *D = this->Sections.front()->getLinkOrderDep()) - this->Link = D->getParent()->SectionIndex; - } - - uint32_t Type = this->Type; - if (Type == SHT_GROUP) { - finalizeShtGroup(this); - return; - } - - if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) - return; - - InputSection *First = Sections[0]; - if (isa(First)) - return; - - this->Link = InX::SymTab->getParent()->SectionIndex; - // sh_info for SHT_REL[A] sections should contain the section header index of - // the section to which the relocation applies. - InputSectionBase *S = First->getRelocatedSection(); - Info = S->getOutputSection()->SectionIndex; - Flags |= SHF_INFO_LINK; -} - static uint64_t updateOffset(uint64_t Off, InputSection *S) { Off = alignTo(Off, S->Alignment); S->OutSecOff = Off; @@ -162,9 +101,12 @@ void OutputSection::addSection(InputSection *S) { // This function is called after we sort input sections // and scan relocations to setup sections' offsets. void OutputSection::assignOffsets() { + OutputSectionCommand *Cmd = Script->getCmd(this); uint64_t Off = 0; - for (InputSection *S : Sections) - Off = updateOffset(Off, S); + for (BaseCommand *Base : Cmd->Commands) + if (auto *ISD = dyn_cast(Base)) + for (InputSection *S : ISD->Sections) + Off = updateOffset(Off, S); this->Size = Off; } @@ -333,6 +275,31 @@ void elf::reportDiscarded(InputSectionBase *IS) { void OutputSectionFactory::addInputSec(InputSectionBase *IS, StringRef OutsecName) { + // Sections with the SHT_GROUP attribute reach here only when the - r option + // is given. Such sections define "section groups", and InputFiles.cpp has + // dedup'ed section groups by their signatures. For the -r, we want to pass + // through all SHT_GROUP sections without merging them because merging them + // creates broken section contents. + if (IS->Type == SHT_GROUP) { + OutputSection *Out = nullptr; + addInputSec(IS, OutsecName, Out); + return; + } + + // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have + // relocation sections .rela.foo and .rela.bar for example. Most tools do + // not allow multiple REL[A] sections for output section. Hence we + // should combine these relocation sections into single output. + // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any + // other REL[A] sections created by linker itself. + if (!isa(IS) && + (IS->Type == SHT_REL || IS->Type == SHT_RELA)) { + auto *Sec = cast(IS); + OutputSection *Out = Sec->getRelocatedSection()->getOutputSection(); + addInputSec(IS, OutsecName, Out->RelocationSection); + return; + } + SectionKey Key = createKey(IS, OutsecName); OutputSection *&Sec = Map[Key]; return addInputSec(IS, OutsecName, Sec); @@ -346,10 +313,6 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, return; } - uint64_t Flags = IS->Flags; - if (!Config->Relocatable) - Flags &= ~(uint64_t)SHF_GROUP; - if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) error("incompatible section flags for " + Sec->Name + @@ -366,9 +329,9 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, "\n>>> output section " + Sec->Name + ": " + getELFSectionTypeName(Config->EMachine, Sec->Type)); } - Sec->Flags |= Flags; + Sec->Flags |= IS->Flags; } else { - Sec = make(OutsecName, IS->Type, Flags); + Sec = make(OutsecName, IS->Type, IS->Flags); OutputSections.push_back(Sec); } @@ -405,8 +368,3 @@ template void OutputSection::writeHeaderTo(ELF32LE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF32BE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64LE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64BE::Shdr *Shdr); - -template void OutputSection::finalize(); -template void OutputSection::finalize(); -template void OutputSection::finalize(); -template void OutputSection::finalize(); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 0f2fe68ca708..7b093fb9dee7 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -67,6 +67,11 @@ class OutputSection final : public SectionBase { // formula: Off = Off_first + VA - VA_first. OutputSection *FirstInPtLoad = nullptr; + // Pointer to a relocation section for this section. Usually nullptr because + // we consume relocations, but if --emit-relocs is specified (which is rare), + // it may have a non-null value. + OutputSection *RelocationSection = nullptr; + // The following fields correspond to Elf_Shdr members. uint64_t Size = 0; uint64_t Offset = 0; @@ -78,7 +83,6 @@ class OutputSection final : public SectionBase { void sort(std::function Order); void sortInitFini(); void sortCtorsDtors(); - template void finalize(); void assignOffsets(); std::vector Sections; diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 54cc6dd89d46..98c1349a2f0d 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -43,6 +43,7 @@ #include "Relocations.h" #include "Config.h" +#include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" @@ -967,48 +968,51 @@ template void elf::scanRelocations(InputSectionBase &S) { // in the Sections vector, and recalculate the InputSection output section // offsets. // This may invalidate any output section offsets stored outside of InputSection -void ThunkCreator::mergeThunks(OutputSection *OS, - std::vector &Thunks) { - // Order Thunks in ascending OutSecOff - auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) { - return A->OutSecOff < B->OutSecOff; - }; - std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp); +void ThunkCreator::mergeThunks() { + for (auto &KV : ThunkSections) { + std::vector *ISR = KV.first; + std::vector &Thunks = KV.second; - // Merge sorted vectors of Thunks and InputSections by OutSecOff - std::vector Tmp; - Tmp.reserve(OS->Sections.size() + Thunks.size()); - auto MergeCmp = [](const InputSection *A, const InputSection *B) { - // std::merge requires a strict weak ordering. - if (A->OutSecOff < B->OutSecOff) - return true; - if (A->OutSecOff == B->OutSecOff) - // Check if Thunk is immediately before any specific Target InputSection - // for example Mips LA25 Thunks. - if (auto *TA = dyn_cast(A)) - if (TA && TA->getTargetInputSection() == B) - return true; - return false; - }; - std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(), - Thunks.end(), std::back_inserter(Tmp), MergeCmp); - OS->Sections = std::move(Tmp); - OS->assignOffsets(); + // Order Thunks in ascending OutSecOff + auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) { + return A->OutSecOff < B->OutSecOff; + }; + std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp); + + // Merge sorted vectors of Thunks and InputSections by OutSecOff + std::vector Tmp; + Tmp.reserve(ISR->size() + Thunks.size()); + auto MergeCmp = [](const InputSection *A, const InputSection *B) { + // std::merge requires a strict weak ordering. + if (A->OutSecOff < B->OutSecOff) + return true; + if (A->OutSecOff == B->OutSecOff) + // Check if Thunk is immediately before any specific Target InputSection + // for example Mips LA25 Thunks. + if (auto *TA = dyn_cast(A)) + if (TA && TA->getTargetInputSection() == B) + return true; + return false; + }; + std::merge(ISR->begin(), ISR->end(), Thunks.begin(), Thunks.end(), + std::back_inserter(Tmp), MergeCmp); + *ISR = std::move(Tmp); + } } -ThunkSection *ThunkCreator::getOSThunkSec(ThunkSection *&TS, - OutputSection *OS) { - if (TS == nullptr) { +ThunkSection *ThunkCreator::getOSThunkSec(OutputSection *OS, + std::vector *ISR) { + if (CurTS == nullptr) { uint32_t Off = 0; for (auto *IS : OS->Sections) { Off = IS->OutSecOff + IS->getSize(); if ((IS->Flags & SHF_EXECINSTR) == 0) break; } - TS = make(OS, Off); - ThunkSections[OS].push_back(TS); + CurTS = make(OS, Off); + ThunkSections[ISR].push_back(CurTS); } - return TS; + return CurTS; } ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) { @@ -1017,7 +1021,21 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) { return TS; auto *TOS = IS->getParent(); TS = make(TOS, IS->OutSecOff); - ThunkSections[TOS].push_back(TS); + + // Find InputSectionRange within TOS that IS is in + OutputSectionCommand *C = Script->getCmd(TOS); + std::vector *Range = nullptr; + for (BaseCommand *BC : C->Commands) + if (auto *ISD = dyn_cast (BC)) { + InputSection *first = ISD->Sections.front(); + InputSection *last = ISD->Sections.back(); + if (IS->OutSecOff >= first->OutSecOff && + IS->OutSecOff <= last->OutSecOff) { + Range = &ISD->Sections; + break; + } + } + ThunkSections[Range].push_back(TS); ThunkedSections[IS] = TS; return TS; } @@ -1030,6 +1048,27 @@ std::pair ThunkCreator::getThunk(SymbolBody &Body, return std::make_pair(res.first->second, res.second); } +// Call Fn on every executable InputSection accessed via the linker script +// InputSectionDescription::Sections. +void ThunkCreator::forEachExecInputSection( + ArrayRef OutputSections, + std::function *, + InputSection *)> + Fn) { + for (OutputSectionCommand *Cmd : OutputSections) { + OutputSection *OS = Cmd->Sec; + if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) + continue; + if (OutputSectionCommand *C = Script->getCmd(OS)) + for (BaseCommand *BC : C->Commands) + if (auto *ISD = dyn_cast(BC)) { + CurTS = nullptr; + for (InputSection* IS : ISD->Sections) + Fn(OS, &ISD->Sections, IS); + } + } +} + // Process all relocations from the InputSections that have been assigned // to OutputSections and redirect through Thunks if needed. // @@ -1040,42 +1079,41 @@ std::pair ThunkCreator::getThunk(SymbolBody &Body, // // FIXME: All Thunks are assumed to be in range of the relocation. Range // extension Thunks are not yet supported. -bool ThunkCreator::createThunks(ArrayRef OutputSections) { +bool ThunkCreator::createThunks( + ArrayRef OutputSections) { // Create all the Thunks and insert them into synthetic ThunkSections. The // ThunkSections are later inserted back into the OutputSection. // We separate the creation of ThunkSections from the insertion of the // ThunkSections back into the OutputSection as ThunkSections are not always // inserted into the same OutputSection as the caller. - for (OutputSection *OS : OutputSections) { - ThunkSection *OSTS = nullptr; - for (InputSection *IS : OS->Sections) { - for (Relocation &Rel : IS->Relocations) { - SymbolBody &Body = *Rel.Sym; - if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body)) - continue; - Thunk *T; - bool IsNew; - std::tie(T, IsNew) = getThunk(Body, Rel.Type); - if (IsNew) { - // Find or create a ThunkSection for the new Thunk - ThunkSection *TS; - if (auto *TIS = T->getTargetInputSection()) - TS = getISThunkSec(TIS, OS); - else - TS = getOSThunkSec(OSTS, OS); - TS->addThunk(T); + forEachExecInputSection( + OutputSections, [=](OutputSection *OS, std::vector *ISR, + InputSection *IS) { + for (Relocation &Rel : IS->Relocations) { + SymbolBody &Body = *Rel.Sym; + if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body)) + continue; + Thunk *T; + bool IsNew; + std::tie(T, IsNew) = getThunk(Body, Rel.Type); + if (IsNew) { + // Find or create a ThunkSection for the new Thunk + ThunkSection *TS; + if (auto *TIS = T->getTargetInputSection()) + TS = getISThunkSec(TIS, OS); + else + TS = getOSThunkSec(OS, ISR); + TS->addThunk(T); + } + // Redirect relocation to Thunk, we never go via the PLT to a Thunk + Rel.Sym = T->ThunkSym; + Rel.Expr = fromPlt(Rel.Expr); } - // Redirect relocation to Thunk, we never go via the PLT to a Thunk - Rel.Sym = T->ThunkSym; - Rel.Expr = fromPlt(Rel.Expr); - } - } - } + }); // Merge all created synthetic ThunkSections back into OutputSection - for (auto &KV : ThunkSections) - mergeThunks(KV.first, KV.second); + mergeThunks(); return !ThunkSections.empty(); } diff --git a/ELF/Relocations.h b/ELF/Relocations.h index 206f0d9423c9..dcbf545cde53 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -21,6 +21,7 @@ class SymbolBody; class InputSection; class InputSectionBase; class OutputSection; +struct OutputSectionCommand; // List of target-independent relocation types. Relocations read // from files are converted to these types so that the main code @@ -123,12 +124,18 @@ class Thunk; class ThunkCreator { public: // Return true if Thunks have been added to OutputSections - bool createThunks(ArrayRef OutputSections); + bool createThunks(ArrayRef OutputSections); private: - void mergeThunks(OutputSection *OS, std::vector &Thunks); - ThunkSection *getOSThunkSec(ThunkSection *&TS, OutputSection *OS); + void mergeThunks(); + ThunkSection *getOSThunkSec(OutputSection *OS, + std::vector *ISR); ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS); + void forEachExecInputSection( + ArrayRef OutputSections, + std::function *, + InputSection *)> + Fn); std::pair getThunk(SymbolBody &Body, uint32_t Type); // Track Symbols that already have a Thunk @@ -138,7 +145,11 @@ class ThunkCreator { llvm::DenseMap ThunkedSections; // Track the ThunksSections that need to be inserted into an OutputSection - std::map> ThunkSections; + std::map *, std::vector> + ThunkSections; + + // The ThunkSection for this vector of InputSections + ThunkSection *CurTS; }; // Return a int64_t to make sure we get the sign extension out of the way as diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index 02212fa8ba14..4a44944fe7ed 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -25,8 +25,8 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -76,6 +76,7 @@ class ScriptParser final : ScriptLexer { BytesDataCommand *readBytesDataCommand(StringRef Tok); uint32_t readFill(); uint32_t parseFill(StringRef Tok); + void readSectionAddressType(OutputSectionCommand *Cmd); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); @@ -127,16 +128,16 @@ static void moveAbsRight(ExprValue &A, ExprValue &B) { if (A.isAbsolute()) std::swap(A, B); if (!B.isAbsolute()) - error("At least one side of the expression must be absolute"); + error(A.Loc + ": at least one side of the expression must be absolute"); } static ExprValue add(ExprValue A, ExprValue B) { moveAbsRight(A, B); - return {A.Sec, A.ForceAbsolute, A.Val + B.getValue()}; + return {A.Sec, A.ForceAbsolute, A.Val + B.getValue(), A.Loc}; } static ExprValue sub(ExprValue A, ExprValue B) { - return {A.Sec, A.Val - B.getValue()}; + return {A.Sec, A.Val - B.getValue(), A.Loc}; } static ExprValue mul(ExprValue A, ExprValue B) { @@ -153,13 +154,13 @@ static ExprValue div(ExprValue A, ExprValue B) { static ExprValue bitAnd(ExprValue A, ExprValue B) { moveAbsRight(A, B); return {A.Sec, A.ForceAbsolute, - (A.getValue() & B.getValue()) - A.getSecAddr()}; + (A.getValue() & B.getValue()) - A.getSecAddr(), A.Loc}; } static ExprValue bitOr(ExprValue A, ExprValue B) { moveAbsRight(A, B); return {A.Sec, A.ForceAbsolute, - (A.getValue() | B.getValue()) - A.getSecAddr()}; + (A.getValue() | B.getValue()) - A.getSecAddr(), A.Loc}; } void ScriptParser::readDynamicList() { @@ -563,16 +564,42 @@ uint32_t ScriptParser::readFill() { return V; } +// Reads an expression and/or the special directive "(NOLOAD)" for an +// output section definition. +// +// An output section name can be followed by an address expression +// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be +// interpreted as either the beginning of some expression or "(NOLOAD)". +// +// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html +// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html +void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) { + if (consume("(")) { + if (consume("NOLOAD")) { + expect(")"); + Cmd->Noload = true; + return; + } + Cmd->AddrExpr = readExpr(); + expect(")"); + } else { + Cmd->AddrExpr = readExpr(); + } + + if (consume("(")) { + expect("NOLOAD"); + expect(")"); + Cmd->Noload = true; + } +} + OutputSectionCommand * ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSectionCommand *Cmd = Script->createOutputSectionCommand(OutSec, getCurrentLocation()); - // Read an address expression. - // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html if (peek() != ":") - Cmd->AddrExpr = readExpr(); - + readSectionAddressType(Cmd); expect(":"); if (consume("AT")) @@ -859,7 +886,9 @@ Expr ScriptParser::readPrimary() { if (Tok == "ADDR") { StringRef Name = readParenLiteral(); OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); - return [=]() -> ExprValue { return {checkSection(Cmd, Location), 0}; }; + return [=]() -> ExprValue { + return {checkSection(Cmd, Location), 0, Location}; + }; } if (Tok == "ALIGN") { expect("("); diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index ed8a790c9599..a223aec98624 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -156,7 +156,7 @@ template void SymbolTable::trace(StringRef Name) { // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. -template void SymbolTable::wrap(StringRef Name) { +template void SymbolTable::addSymbolWrap(StringRef Name) { SymbolBody *B = find(Name); if (!B) return; @@ -164,16 +164,16 @@ template void SymbolTable::wrap(StringRef Name) { Symbol *Real = addUndefined(Saver.save("__real_" + Name)); Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); - // We rename symbols by replacing the old symbol's SymbolBody with the new - // symbol's SymbolBody. This causes all SymbolBody pointers referring to the - // old symbol to instead refer to the new symbol. - memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body)); - memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body)); + // Tell LTO not to eliminate this symbol + Wrap->IsUsedInRegularObj = true; + + Config->RenamedSymbols[Real] = RenamedSymbol{Sym, Real->Binding}; + Config->RenamedSymbols[Sym] = RenamedSymbol{Wrap, Sym->Binding}; } // Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. -template -void SymbolTable::alias(StringRef Alias, StringRef Name) { +template void SymbolTable::addSymbolAlias(StringRef Alias, + StringRef Name) { SymbolBody *B = find(Name); if (!B) { error("-defsym: undefined symbol: " + Name); @@ -181,7 +181,27 @@ void SymbolTable::alias(StringRef Alias, StringRef Name) { } Symbol *Sym = B->symbol(); Symbol *AliasSym = addUndefined(Alias); - memcpy(AliasSym->Body.buffer, Sym->Body.buffer, sizeof(AliasSym->Body)); + + // Tell LTO not to eliminate this symbol + Sym->IsUsedInRegularObj = true; + Config->RenamedSymbols[AliasSym] = RenamedSymbol{Sym, AliasSym->Binding}; +} + +// Apply symbol renames created by -wrap and -defsym. The renames are created +// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform +// LTO (if LTO is running) not to include these symbols in IPO. Now that the +// symbols are finalized, we can perform the replacement. +template void SymbolTable::applySymbolRenames() { + for (auto &KV : Config->RenamedSymbols) { + Symbol *Sym = KV.first; + Symbol *Rename = KV.second.Target; + Sym->Binding = KV.second.OrigBinding; + + // We rename symbols by replacing the old symbol's SymbolBody with the new + // symbol's SymbolBody. This causes all SymbolBody pointers referring to the + // old symbol to instead refer to the new symbol. + memcpy(Sym->Body.buffer, Rename->Body.buffer, sizeof(Sym->Body)); + } } static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index 1a745f9deea5..f38d09760c7e 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -39,6 +39,9 @@ template class SymbolTable { public: void addFile(InputFile *File); void addCombinedLTOObject(); + void addSymbolAlias(StringRef Alias, StringRef Name); + void addSymbolWrap(StringRef Name); + void applySymbolRenames(); ArrayRef getSymbols() const { return SymVector; } ArrayRef *> getObjectFiles() const { return ObjectFiles; } @@ -85,8 +88,6 @@ template class SymbolTable { SymbolBody *findInCurrentDSO(StringRef Name); void trace(StringRef Name); - void wrap(StringRef Name); - void alias(StringRef Alias, StringRef Name); private: std::vector findByVersion(SymbolVersion Ver); diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 67e57d9c8f00..8f9b20477b29 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -264,15 +264,14 @@ Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, : SymbolBody(K, Name, IsLocal, StOther, Type) {} template bool DefinedRegular::isMipsPIC() const { + typedef typename ELFT::Ehdr Elf_Ehdr; if (!Section || !isFunc()) return false; + + auto *Sec = cast(Section); + const Elf_Ehdr *Hdr = Sec->template getFile()->getObj().getHeader(); return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || - (cast(Section) - ->template getFile() - ->getObj() - .getHeader() - ->e_flags & - EF_MIPS_PIC); + (Hdr->e_flags & EF_MIPS_PIC); } Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 223fc9a0fd07..5cd6c5f2b914 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -27,9 +27,9 @@ #include "Threads.h" #include "Writer.h" #include "lld/Config/Version.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/ELFObjectFile.h" -#include "llvm/Support/Dwarf.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MD5.h" #include "llvm/Support/RandomNumberGenerator.h" @@ -1691,49 +1691,44 @@ static uint32_t hash(StringRef Str) { return R; } -static std::vector> -readCuList(DWARFContext &Dwarf, InputSection *Sec) { - std::vector> Ret; +static std::vector readCuList(DWARFContext &Dwarf, + InputSection *Sec) { + std::vector Ret; for (std::unique_ptr &CU : Dwarf.compile_units()) Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); return Ret; } -static InputSection *findSection(ArrayRef Arr, - uint64_t Offset) { - for (InputSectionBase *S : Arr) - if (auto *IS = dyn_cast_or_null(S)) - if (IS != &InputSection::Discarded && IS->Live && - Offset >= IS->getOffsetInFile() && - Offset < IS->getOffsetInFile() + IS->getSize()) - return IS; - return nullptr; -} - -static std::vector -readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) { +static std::vector readAddressArea(DWARFContext &Dwarf, + InputSection *Sec) { std::vector Ret; + uint32_t CurrentCu = 0; for (std::unique_ptr &CU : Dwarf.compile_units()) { DWARFAddressRangesVector Ranges; CU->collectAddressRanges(Ranges); ArrayRef Sections = Sec->File->getSections(); - for (DWARFAddressRange &R : Ranges) - if (InputSection *S = findSection(Sections, R.LowPC)) - Ret.push_back({S, R.LowPC - S->getOffsetInFile(), - R.HighPC - S->getOffsetInFile(), CurrentCU}); - ++CurrentCU; + for (DWARFAddressRange &R : Ranges) { + InputSectionBase *S = Sections[R.SectionIndex]; + if (!S || S == &InputSection::Discarded || !S->Live) + continue; + // Range list with zero size has no effect. + if (R.LowPC == R.HighPC) + continue; + Ret.push_back({cast(S), R.LowPC, R.HighPC, CurrentCu}); + } + ++CurrentCu; } return Ret; } -static std::vector> -readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) { +static std::vector readPubNamesAndTypes(DWARFContext &Dwarf, + bool IsLE) { StringRef Data[] = {Dwarf.getGnuPubNamesSection(), Dwarf.getGnuPubTypesSection()}; - std::vector> Ret; + std::vector Ret; for (StringRef D : Data) { DWARFDebugPubTable PubTable(D, IsLE, true); for (const DWARFDebugPubTable::Set &Set : PubTable.getData()) @@ -1743,52 +1738,77 @@ readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) { return Ret; } -class ObjInfoTy : public llvm::LoadedObjectInfo { - uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { - auto &S = static_cast(Sec); - if (S.getFlags() & ELF::SHF_ALLOC) - return S.getOffset(); - return 0; +static std::vector getDebugInfoSections() { + std::vector Ret; + for (InputSectionBase *S : InputSections) + if (InputSection *IS = dyn_cast(S)) + if (IS->getParent() && IS->Name == ".debug_info") + Ret.push_back(IS); + return Ret; +} + +void GdbIndexSection::buildIndex() { + std::vector V = getDebugInfoSections(); + if (V.empty()) + return; + + for (InputSection *Sec : V) + Chunks.push_back(readDwarf(Sec)); + + uint32_t CuId = 0; + for (GdbIndexChunk &D : Chunks) { + for (AddressEntry &E : D.AddressArea) + E.CuIndex += CuId; + + // Populate constant pool area. + for (NameTypeEntry &NameType : D.NamesAndTypes) { + uint32_t Hash = hash(NameType.Name); + size_t Offset = StringPool.add(NameType.Name); + + bool IsNew; + GdbSymbol *Sym; + std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); + if (IsNew) { + Sym->CuVectorIndex = CuVectors.size(); + CuVectors.resize(CuVectors.size() + 1); + } + + CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24)); + } + + CuId += D.CompilationUnits.size(); } +} - std::unique_ptr clone() const override { return {}; } -}; - -void GdbIndexSection::readDwarf(InputSection *Sec) { +GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) { Expected> Obj = object::ObjectFile::createObjectFile(Sec->File->MB); if (!Obj) { error(toString(Sec->File) + ": error creating DWARF context"); - return; + return {}; } - ObjInfoTy ObjInfo; - DWARFContextInMemory Dwarf(*Obj.get(), &ObjInfo); + DWARFContextInMemory Dwarf(*Obj.get()); - size_t CuId = CompilationUnits.size(); - for (std::pair &P : readCuList(Dwarf, Sec)) - CompilationUnits.push_back(P); + GdbIndexChunk Ret; + Ret.CompilationUnits = readCuList(Dwarf, Sec); + Ret.AddressArea = readAddressArea(Dwarf, Sec); + Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE); + return Ret; +} - for (AddressEntry &Ent : readAddressArea(Dwarf, Sec, CuId)) - AddressArea.push_back(Ent); +static size_t getCuSize(std::vector &C) { + size_t Ret = 0; + for (GdbIndexChunk &D : C) + Ret += D.CompilationUnits.size(); + return Ret; +} - std::vector> NamesAndTypes = - readPubNamesAndTypes(Dwarf, Config->IsLE); - - for (std::pair &Pair : NamesAndTypes) { - uint32_t Hash = hash(Pair.first); - size_t Offset = StringPool.add(Pair.first); - - bool IsNew; - GdbSymbol *Sym; - std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); - if (IsNew) { - Sym->CuVectorIndex = CuVectors.size(); - CuVectors.resize(CuVectors.size() + 1); - } - - CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId); - } +static size_t getAddressAreaSize(std::vector &C) { + size_t Ret = 0; + for (GdbIndexChunk &D : C) + Ret += D.AddressArea.size(); + return Ret; } void GdbIndexSection::finalizeContents() { @@ -1796,17 +1816,14 @@ void GdbIndexSection::finalizeContents() { return; Finalized = true; - for (InputSectionBase *S : InputSections) - if (InputSection *IS = dyn_cast(S)) - if (IS->getParent() && IS->Name == ".debug_info") - readDwarf(IS); + buildIndex(); SymbolTable.finalizeContents(); // GdbIndex header consist from version fields // and 5 more fields with different kinds of offsets. - CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize; - SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize; + CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize; + SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize; ConstantPoolOffset = SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; @@ -1835,19 +1852,24 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { Buf += 24; // Write the CU list. - for (std::pair CU : CompilationUnits) { - write64le(Buf, CU.first); - write64le(Buf + 8, CU.second); - Buf += 16; + for (GdbIndexChunk &D : Chunks) { + for (CompilationUnitEntry &Cu : D.CompilationUnits) { + write64le(Buf, Cu.CuOffset); + write64le(Buf + 8, Cu.CuLength); + Buf += 16; + } } // Write the address area. - for (AddressEntry &E : AddressArea) { - uint64_t BaseAddr = E.Section->getParent()->Addr + E.Section->getOffset(0); - write64le(Buf, BaseAddr + E.LowAddress); - write64le(Buf + 8, BaseAddr + E.HighAddress); - write32le(Buf + 16, E.CuIndex); - Buf += 20; + for (GdbIndexChunk &D : Chunks) { + for (AddressEntry &E : D.AddressArea) { + uint64_t BaseAddr = + E.Section->getParent()->Addr + E.Section->getOffset(0); + write64le(Buf, BaseAddr + E.LowAddress); + write64le(Buf + 8, BaseAddr + E.HighAddress); + write32le(Buf + 16, E.CuIndex); + Buf += 20; + } } // Write the symbol table. diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index b47d2fab24ec..c807043c9dc2 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -509,20 +509,23 @@ class GdbIndexSection final : public SyntheticSection { size_t getSize() const override; bool empty() const override; - // Pairs of [CU Offset, CU length]. - std::vector> CompilationUnits; - - llvm::StringTableBuilder StringPool; - + // Symbol table is a hash table for types and names. + // It is the area of gdb index. GdbHashTab SymbolTable; - // The CU vector portion of the constant pool. + // CU vector is a part of constant pool area of section. std::vector> CuVectors; - std::vector AddressArea; + // String pool is also a part of constant pool, it follows CU vectors. + llvm::StringTableBuilder StringPool; + + // Each chunk contains information gathered from a debug sections of single + // object and used to build different areas of gdb index. + std::vector Chunks; private: - void readDwarf(InputSection *Sec); + GdbIndexChunk readDwarf(InputSection *Sec); + void buildIndex(); uint32_t CuTypesOffset; uint32_t SymTabOffset; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index b6c6e7089365..ee5a7690fc64 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -35,8 +35,8 @@ #include "Thunks.h" #include "Writer.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -537,7 +537,17 @@ void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, write16le(Loc, Val); break; case R_386_PC16: - checkInt<16>(Loc, Val, Type); + // R_386_PC16 is normally used with 16 bit code. In that situation + // the PC is 16 bits, just like the addend. This means that it can + // point from any 16 bit address to any other if the possibility + // of wrapping is included. + // The only restriction we have to check then is that the destination + // address fits in 16 bits. That is impossible to do here. The problem is + // that we are passed the final value, which already had the + // current location subtracted from it. + // We just check that Val fits in 17 bits. This misses some cases, but + // should have no false positives. + checkInt<17>(Loc, Val, Type); write16le(Loc, Val); break; default: @@ -2085,7 +2095,7 @@ RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, return R_MIPS_GOT_GP_PC; if (&S == ElfSym::MipsLocalGp) return R_MIPS_GOT_GP; - // fallthrough + LLVM_FALLTHROUGH; case R_MIPS_GOT_OFST: return R_ABS; case R_MIPS_PC32: @@ -2099,7 +2109,7 @@ RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, case R_MIPS_GOT16: if (S.isLocal()) return R_MIPS_GOT_LOCAL_PAGE; - // fallthrough + LLVM_FALLTHROUGH; case R_MIPS_CALL16: case R_MIPS_GOT_DISP: case R_MIPS_TLS_GOTTPREL: @@ -2353,7 +2363,7 @@ void MipsTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, case R_MIPS_TLS_GD: case R_MIPS_TLS_LDM: checkInt<16>(Loc, Val, Type); - // fallthrough + LLVM_FALLTHROUGH; case R_MIPS_CALL16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_LO16: diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index da2b13677513..752a881d7867 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -30,8 +30,8 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -143,7 +143,7 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); + Offset | 0x1, size(), &IS); addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } @@ -176,7 +176,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { 0x60, 0x47, // bx r12 }; uint64_t S = getARMThunkDestVA(Destination); - uint64_t P = ThunkSym->getVA(); + uint64_t P = ThunkSym->getVA() & ~0x1; memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12); Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8); @@ -185,7 +185,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); + Offset | 0x1, size(), &IS); addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index f68e07fc69d7..ad95a8acced4 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -93,21 +93,14 @@ template class Writer { } // anonymous namespace StringRef elf::getOutputSectionName(StringRef Name) { + // ".zdebug_" is a prefix for ZLIB-compressed sections. + // Because we decompressed input sections, we want to remove 'z'. + if (Name.startswith(".zdebug_")) + return Saver.save("." + Name.substr(2)); + if (Config->Relocatable) return Name; - // If -emit-relocs is given (which is rare), we need to copy - // relocation sections to the output. If input section .foo is - // output as .bar, we want to rename .rel.foo .rel.bar as well. - if (Config->EmitRelocs) { - for (StringRef V : {".rel.", ".rela."}) { - if (Name.startswith(V)) { - StringRef Inner = getOutputSectionName(Name.substr(V.size() - 1)); - return Saver.save(V.drop_back() + Inner); - } - } - } - for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", @@ -122,10 +115,6 @@ StringRef elf::getOutputSectionName(StringRef Name) { if (Name == "COMMON") return ".bss"; - // ".zdebug_" is a prefix for ZLIB-compressed sections. - // Because we decompressed input sections, we want to remove 'z'. - if (Name.startswith(".zdebug_")) - return Saver.save("." + Name.substr(2)); return Name; } @@ -257,18 +246,7 @@ template void Writer::run() { if (ErrorCount) return; - if (!Script->Opt.HasSections) - Script->fabricateDefaultCommands(); - else - Script->synchronize(); - - for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast(Base)) - OutputSectionCommands.push_back(Cmd); - - clearOutputSections(); - - if (!Script->Opt.HasSections &&!Config->Relocatable) + if (!Script->Opt.HasSections && !Config->Relocatable) fixSectionAlignments(); // If -compressed-debug-sections is specified, we need to compress @@ -278,22 +256,24 @@ template void Writer::run() { OutputSectionCommands.begin(), OutputSectionCommands.end(), [](OutputSectionCommand *Cmd) { Cmd->maybeCompress(); }); - if (Config->Relocatable) { + Script->assignAddresses(Phdrs, OutputSectionCommands); + + // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a + // 0 sized region. This has to be done late since only after assignAddresses + // we know the size of the sections. + removeEmptyPTLoad(); + + if (!Config->OFormatBinary) assignFileOffsets(); + else + assignFileOffsetsBinary(); + + setPhdrs(); + + if (Config->Relocatable) { + for (OutputSectionCommand *Cmd : OutputSectionCommands) + Cmd->Sec->Addr = 0; } else { - Script->assignAddresses(Phdrs, OutputSectionCommands); - - // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a - // 0 sized region. This has to be done late since only after assignAddresses - // we know the size of the sections. - removeEmptyPTLoad(); - - if (!Config->OFormatBinary) - assignFileOffsets(); - else - assignFileOffsetsBinary(); - - setPhdrs(); fixPredefinedSymbols(); } @@ -915,7 +895,14 @@ template void Writer::addReservedSymbols() { // this symbol unconditionally even when using a linker script, which // differs from the behavior implemented by GNU linker which only define // this symbol if ELF headers are in the memory mapped segment. - addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); + // __executable_start is not documented, but the expectation of at + // least the android libc is that it points to the elf header too. + // __dso_handle symbol is passed to cxa_finalize as a marker to identify + // each DSO. The address of the symbol doesn't matter as long as they are + // different in different DSOs, so we chose the start address of the DSO. + for (const char *Name : + {"__ehdr_start", "__executable_start", "__dso_handle"}) + addOptionalRegular(Name, Out::ElfHeader, 0, STV_HIDDEN); // If linker script do layout we do not need to create any standart symbols. if (Script->Opt.HasSections) @@ -1011,9 +998,6 @@ template void Writer::createSections() { sortInitFini(findSection(".fini_array")); sortCtorsDtors(findSection(".ctors")); sortCtorsDtors(findSection(".dtors")); - - for (OutputSection *Sec : OutputSections) - Sec->assignOffsets(); } // We want to find how similar two ranks are. @@ -1116,10 +1100,8 @@ template void Writer::sortSections() { static void applySynthetic(const std::vector &Sections, std::function Fn) { for (SyntheticSection *SS : Sections) - if (SS && SS->getParent() && !SS->empty()) { + if (SS && SS->getParent() && !SS->empty()) Fn(SS); - SS->getParent()->assignOffsets(); - } } // We need to add input synthetic sections early in createSyntheticSections() @@ -1225,6 +1207,12 @@ template void Writer::finalizeSections() { Sec->ShName = InX::ShStrTab->addString(Sec->Name); } + if (!Script->Opt.HasSections) + Script->fabricateDefaultCommands(); + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast(Base)) + OutputSectionCommands.push_back(Cmd); + // Binary and relocatable output does not have PHDRS. // The headers have to be created before finalize as that can influence the // image base and the dynamic section on mips includes the image base. @@ -1234,6 +1222,14 @@ template void Writer::finalizeSections() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); } + clearOutputSections(); + + // Compute the size of .rela.dyn and .rela.plt early since we need + // them to populate .dynamic. + for (SyntheticSection *SS : {In::RelaDyn, In::RelaPlt}) + if (SS->getParent() && !SS->empty()) + SS->getParent()->assignOffsets(); + // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo, @@ -1257,15 +1253,16 @@ template void Writer::finalizeSections() { // are out of range. This will need to turn into a loop that converges // when no more Thunks are added ThunkCreator TC; - if (TC.createThunks(OutputSections)) + if (TC.createThunks(OutputSectionCommands)) applySynthetic({InX::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); } + // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. - for (OutputSection *Sec : OutputSections) - Sec->finalize(); + for (OutputSectionCommand *Cmd : OutputSectionCommands) + Cmd->finalize(); // createThunks may have added local symbols to the static symbol table applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h index 5105eb1aa2be..32d04249f378 100644 --- a/include/lld/Core/Reader.h +++ b/include/lld/Core/Reader.h @@ -13,14 +13,13 @@ #include "lld/Core/LLVM.h" #include "lld/Core/Reference.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include #include -using llvm::sys::fs::file_magic; - namespace llvm { namespace yaml { class IO; @@ -45,7 +44,7 @@ class Reader { /// The method is called with: /// 1) the file_magic enumeration returned by identify_magic() /// 2) the whole file content buffer if the above is not enough. - virtual bool canParse(file_magic magic, MemoryBufferRef mb) const = 0; + virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0; /// \brief Parse a supplied buffer (already filled with the contents of a /// file) and create a File object. diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h index a9e80f50b23d..9eefa8c4d944 100644 --- a/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/include/lld/ReaderWriter/MachOLinkingContext.h @@ -16,8 +16,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MachO.h" #include using llvm::MachO::HeaderFileType; diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt index f2bf90509295..85046b93f34f 100644 --- a/lib/Core/CMakeLists.txt +++ b/lib/Core/CMakeLists.txt @@ -18,9 +18,10 @@ add_lld_library(lldCore ${LLD_INCLUDE_DIR}/lld/Core LINK_COMPONENTS + BinaryFormat MC Support - + LINK_LIBS ${LLVM_PTHREAD_LIB} diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp index 24652abec688..5d8bbbbfe4d7 100644 --- a/lib/Core/Reader.cpp +++ b/lib/Core/Reader.cpp @@ -11,12 +11,16 @@ #include "lld/Core/File.h" #include "lld/Core/Reference.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include #include +using llvm::file_magic; +using llvm::identify_magic; + namespace lld { YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() = default; @@ -33,7 +37,7 @@ ErrorOr> Registry::loadFile(std::unique_ptr mb) const { // Get file magic. StringRef content(mb->getBufferStart(), mb->getBufferSize()); - llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content); + file_magic fileType = identify_magic(content); // Ask each registered reader if it can handle this file type or extension. for (const std::unique_ptr &reader : _readers) { diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp index cacea5f30847..583c65acb5d3 100644 --- a/lib/Core/SymbolTable.cpp +++ b/lib/Core/SymbolTable.cpp @@ -161,7 +161,7 @@ bool SymbolTable::addByName(const Atom &newAtom) { llvm::errs() << "Size mismatch: " << existing->name() << " (" << existingSize << ") " << newAtom.name() << " (" << newSize << ")\n"; - // fallthrough + LLVM_FALLTHROUGH; } case MCR_Error: llvm::errs() << "Duplicate symbols: " diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp index 9b4aede19aa2..c859c9802349 100644 --- a/lib/Driver/DarwinLdDriver.cpp +++ b/lib/Driver/DarwinLdDriver.cpp @@ -18,30 +18,30 @@ #include "lld/Core/File.h" #include "lld/Core/Instrumentation.h" #include "lld/Core/LLVM.h" +#include "lld/Core/LinkingContext.h" #include "lld/Core/Node.h" #include "lld/Core/PassManager.h" #include "lld/Core/Resolver.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Core/Simple.h" -#include "lld/Core/LinkingContext.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" -#include "llvm/Option/Option.h" #include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp index 799f947a8c82..762d0871db06 100644 --- a/lib/ReaderWriter/FileArchive.cpp +++ b/lib/ReaderWriter/FileArchive.cpp @@ -11,15 +11,16 @@ #include "lld/Core/File.h" #include "lld/Core/LLVM.h" #include "lld/Core/Reader.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Object/Archive.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/MemoryBuffer.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Object/Archive.h" #include "llvm/Object/Error.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -30,6 +31,8 @@ #include using llvm::object::Archive; +using llvm::file_magic; +using llvm::identify_magic; namespace lld { @@ -201,7 +204,7 @@ class ArchiveReader : public Reader { ArchiveReader(bool logLoading) : _logLoading(logLoading) {} bool canParse(file_magic magic, MemoryBufferRef) const override { - return magic == llvm::sys::fs::file_magic::archive; + return magic == file_magic::archive; } ErrorOr> loadFile(std::unique_ptr mb, diff --git a/lib/ReaderWriter/MachO/ExecutableAtoms.h b/lib/ReaderWriter/MachO/ExecutableAtoms.h index acced33b7e74..ab14e6d8c3e7 100644 --- a/lib/ReaderWriter/MachO/ExecutableAtoms.h +++ b/lib/ReaderWriter/MachO/ExecutableAtoms.h @@ -13,7 +13,7 @@ #include "Atoms.h" #include "File.h" -#include "llvm/Support/MachO.h" +#include "llvm/BinaryFormat/MachO.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index db4a96823e74..7e7b559b150a 100644 --- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -22,11 +22,11 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/Path.h" #include diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h index 60d76d4b5c9b..31b24dfd1025 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFile.h +++ b/lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -48,10 +48,10 @@ #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorOr.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/YAMLTraits.h" using llvm::BumpPtrAllocator; diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index 23c7ea17f7e7..edbe576f0086 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -21,24 +21,25 @@ /// | normalized | /// +------------+ -#include "MachONormalizedFile.h" #include "ArchHandler.h" +#include "MachONormalizedFile.h" #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "lld/Core/SharedLibraryFile.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include @@ -46,6 +47,7 @@ using namespace llvm::MachO; using llvm::object::ExportEntry; +using llvm::file_magic; using llvm::object::MachOObjectFile; namespace lld { @@ -531,8 +533,7 @@ class MachOObjectReader : public Reader { MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {} bool canParse(file_magic magic, MemoryBufferRef mb) const override { - return (magic == llvm::sys::fs::file_magic::macho_object && - mb.getBufferSize() > 32); + return (magic == file_magic::macho_object && mb.getBufferSize() > 32); } ErrorOr> @@ -553,8 +554,8 @@ class MachODylibReader : public Reader { bool canParse(file_magic magic, MemoryBufferRef mb) const override { switch (magic) { - case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib: - case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: + case file_magic::macho_dynamically_linked_shared_lib: + case file_magic::macho_dynamically_linked_shared_lib_stub: return mb.getBufferSize() > 32; default: return false; diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h index d69c5389e9d6..b38f7059228f 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h @@ -14,12 +14,12 @@ #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/MachO.h" #include namespace lld { diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp index e853faf9112e..bac41d2a52bf 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -25,11 +25,12 @@ #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" -#include "llvm/ADT/ilist.h" -#include "llvm/ADT/ilist_node.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" @@ -37,7 +38,6 @@ #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index ddd3259842e2..e58e3d2e7a4b 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -20,19 +20,19 @@ /// | Atoms | /// +-------+ -#include "MachONormalizedFile.h" #include "ArchHandler.h" #include "DebugInfo.h" +#include "MachONormalizedFile.h" #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MachO.h" #include #include #include @@ -515,6 +515,7 @@ void Util::organizeSections() { // Main executables, need a zero-page segment segmentForName("__PAGEZERO"); // Fall into next case. + LLVM_FALLTHROUGH; case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: // All dynamic code needs TEXT segment to hold the load commands. diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 4b17f7b3a85f..18fb71f16bcf 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -20,20 +20,20 @@ /// | Atoms | /// +-------+ -#include "MachONormalizedFile.h" #include "ArchHandler.h" #include "Atoms.h" #include "File.h" +#include "MachONormalizedFile.h" #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Dwarf.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp index 218170965eca..fe67fc88c467 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp @@ -23,17 +23,16 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include - using llvm::StringRef; using namespace llvm::yaml; using namespace llvm::MachO; diff --git a/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp index f08487f21ac1..c457e7b55a43 100644 --- a/lib/ReaderWriter/MachO/WriterMachO.cpp +++ b/lib/ReaderWriter/MachO/WriterMachO.cpp @@ -12,10 +12,10 @@ #include "lld/Core/File.h" #include "lld/Core/Writer.h" #include "lld/ReaderWriter/MachOLinkingContext.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/raw_ostream.h" #include diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index 59ca43079a6d..4c88eb1d1476 100644 --- a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -43,6 +44,7 @@ #include #include +using llvm::file_magic; using llvm::yaml::MappingTraits; using llvm::yaml::ScalarEnumerationTraits; using llvm::yaml::ScalarTraits; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cef2e2c68ae1..1dbd1b7699ea 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -29,7 +29,7 @@ if (NOT LLD_BUILT_STANDALONE) list(APPEND LLD_TEST_DEPS FileCheck count not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm llc llvm-config llvm-objdump llvm-readobj yaml2obj obj2yaml - llvm-mc llvm-lib llvm-pdbdump opt + llvm-mc llvm-lib llvm-pdbutil opt ) endif() diff --git a/test/COFF/pdb-none.test b/test/COFF/pdb-none.test index 7e428693aec4..b4da5922ee7b 100644 --- a/test/COFF/pdb-none.test +++ b/test/COFF/pdb-none.test @@ -3,7 +3,7 @@ # RUN: lld-link /debug /debugtype:pdata /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ # RUN: %t1.obj %t2.obj -# RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.pdb | FileCheck %s +# RUN: llvm-pdbutil pdb2yaml -pdb-stream %t.pdb | FileCheck %s # CHECK: PdbStream: # CHECK-NEXT: Age: 0 diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test index f1fa4ec7c2b6..57286611ffcd 100644 --- a/test/COFF/pdb.test +++ b/test/COFF/pdb.test @@ -3,10 +3,10 @@ # RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ # RUN: %t1.obj %t2.obj -# RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream \ +# RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -pdb-stream \ # RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s -# RUN: llvm-pdbdump raw -modules -section-map -section-headers -section-contribs \ +# RUN: llvm-pdbutil raw -modules -section-map -section-headers -section-contribs \ # RUN: -tpi-records %t.pdb | FileCheck -check-prefix RAW %s # CHECK: MSF: diff --git a/test/ELF/Inputs/relocatable-comdat-multiple.s b/test/ELF/Inputs/relocatable-comdat-multiple.s new file mode 100644 index 000000000000..837a6bb06d09 --- /dev/null +++ b/test/ELF/Inputs/relocatable-comdat-multiple.s @@ -0,0 +1,2 @@ +.section .text.c,"axG",@progbits,bbb,comdat +.section .text.d,"axG",@progbits,bbb,comdat diff --git a/test/ELF/aarch64-undefined-weak.s b/test/ELF/aarch64-undefined-weak.s index 74fef669ed74..e611b6da6607 100644 --- a/test/ELF/aarch64-undefined-weak.s +++ b/test/ELF/aarch64-undefined-weak.s @@ -33,13 +33,13 @@ _start: // CHECK: Disassembly of section .text: // 131076 = 0x20004 -// CHECK: 20000: 01 80 00 14 b #131076 -// CHECK-NEXT: 20004: 02 80 00 94 bl #131080 -// CHECK-NEXT: 20008: 60 00 10 54 b.eq #131084 -// CHECK-NEXT: 2000c: 81 00 10 b4 cbz x1, #131088 -// CHECK-NEXT: 20010: 00 00 00 10 adr x0, #0 -// CHECK-NEXT: 20014: 00 00 00 90 adrp x0, #0 -// CHECK: 20018: 00 00 00 00 .word 0x00000000 -// CHECK-NEXT: 2001c: 00 00 00 00 .word 0x00000000 -// CHECK-NEXT: 20020: 00 00 00 00 .word 0x00000000 -// CHECK-NEXT: 20024: 00 00 .short 0x0000 +// CHECK: 20000: {{.*}} b #131076 +// CHECK-NEXT: 20004: {{.*}} bl #131080 +// CHECK-NEXT: 20008: {{.*}} b.eq #131084 +// CHECK-NEXT: 2000c: {{.*}} cbz x1, #131088 +// CHECK-NEXT: 20010: {{.*}} adr x0, #0 +// CHECK-NEXT: 20014: {{.*}} adrp x0, #0 +// CHECK: 20018: {{.*}} .word 0x00000000 +// CHECK-NEXT: 2001c: {{.*}} .word 0x00000000 +// CHECK-NEXT: 20020: {{.*}} .word 0x00000000 +// CHECK-NEXT: 20024: {{.*}} .short 0x0000 diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s index 17dfc82ef8f3..e32159b332e7 100644 --- a/test/ELF/amdgpu-globals.s +++ b/test/ELF/amdgpu-globals.s @@ -1,130 +1,56 @@ # RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o -# RUN: ld.lld %t.o -o %t +# RUN: ld.lld -shared %t.o -o %t # RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s # REQUIRES: amdgpu - .amdgpu_hsa_module_global module_global_program - .size module_global_program, 4 - .hsadata_global_program -module_global_program: - .long 0 ; 0x0 +.type glob0, @object +.data + .globl glob0 +glob0: + .long 1 + .size glob0, 4 - .amdgpu_hsa_program_global program_global_program - .size program_global_program, 4 - .hsadata_global_program -program_global_program: - .long 0 ; 0x0 - - .amdgpu_hsa_module_global module_global_agent - .size module_global_agent, 4 - .hsadata_global_agent -module_global_agent: - .long 0 ; 0x0 - - .amdgpu_hsa_program_global program_global_agent - .size program_global_agent, 4 - .hsadata_global_agent -program_global_agent: - .long 0 ; 0x0 - - .amdgpu_hsa_module_global module_global_readonly - .size module_global_readonly, 4 - .hsatext -module_global_readonly: - .long 0 ; 0x0 - - .amdgpu_hsa_program_global program_global_readonly - .size program_global_readonly, 4 - .hsatext -program_global_readonly: - .long 0 ; 0x0 +.type glob1, @object +.section .rodata, #alloc + .globl glob1 +glob1: + .long 2 + .size glob1, 4 # CHECK: Section { -# CHECK: Name: .hsatext -# CHECK: Type: SHT_PROGBITS -# CHECK: Flags [ (0xC00007) -# CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) -# CHECK: SHF_AMDGPU_HSA_CODE (0x400000) -# CHECK: SHF_EXECINSTR (0x4) -# CHECK: SHF_WRITE (0x1) -# CHECK: ] -# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]] +# CHECK: Name: .rodata +# CHECK: Type: SHT_PROGBITS +# CHECK: Flags [ (0x2) +# CHECK: SHF_ALLOC (0x2) +# CHECK: ] +# CHECK: Address: [[RODATA_ADDR:[0-9xa-f]+]] # CHECK: } # CHECK: Section { -# CHECK: Name: .hsadata_global_program -# CHECK: Type: SHT_PROGBITS (0x1) -# CHECK: Flags [ (0x100003) -# CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_GLOBAL (0x100000) -# CHECK: SHF_WRITE (0x1) -# CHECK: ] -# CHECK: Address: [[HSADATA_GLOBAL_PROGRAM_ADDR:[0-9xa-f]+]] -# CHECK: } - -# CHECK: Section { -# CHECK: Name: .hsadata_global_agent -# CHECK: Type: SHT_PROGBITS (0x1) -# CHECK: Flags [ (0x900003) -# CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) -# CHECK: SHF_AMDGPU_HSA_GLOBAL (0x100000) -# CHECK: SHF_WRITE (0x1) -# CHECK: ] +# CHECK: Name: .data +# CHECK: Type: SHT_PROGBITS +# CHECK: Flags [ (0x3) +# CHECK: SHF_ALLOC (0x2) +# CHECK: SHF_WRITE (0x1) +# CHECK: ] +# CHECK: Address: [[DATA_ADDR:[0-9xa-f]+]] # CHECK: } # CHECK: Symbol { -# CHECK: Name: module_global_agent -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Local -# CHECK: Section: .hsadata_global_agent +# CHECK: Name: glob0 +# CHECK: Value: [[DATA_ADDR]] +# CHECK: Size: 4 +# CHECK: Type: Object +# CHECK: Section: .data # CHECK: } # CHECK: Symbol { -# CHECK: Name: module_global_program -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Local -# CHECK: Section: .hsadata_global_program -# CHECK: } - -# CHECK: Symbol { -# CHECK: Name: module_global_readonly -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Local -# CHECK: Type: Object -# CHECK: Section: .hsatext -# CHECK: } - -# CHECK: Symbol { -# CHECK: Name: program_global_agent -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Global -# CHECK: Type: Object -# CHECK: Section: .hsadata_global_agent -# CHECK: } - -# CHECK: Symbol { -# CHECK: Name: program_global_program -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Global -# CHECK: Type: Object -# CHECK: Section: .hsadata_global_program -# CHECK: } - -# CHECK: Symbol { -# CHECK: Name: program_global_readonly -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Global -# CHECK: Type: Object -# CHECK: Section: .hsatext +# CHECK: Name: glob1 +# CHECK: Value: [[RODATA_ADDR]] +# CHECK: Size: 4 +# CHECK: Type: Object +# CHECK: Section: .rodata # CHECK: } # CHECK: ProgramHeader { diff --git a/test/ELF/amdgpu-kernels.s b/test/ELF/amdgpu-kernels.s index 62a8cb74a541..c76613f1a336 100644 --- a/test/ELF/amdgpu-kernels.s +++ b/test/ELF/amdgpu-kernels.s @@ -1,5 +1,5 @@ # RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o -# RUN: ld.lld %t.o -o %t +# RUN: ld.lld -shared %t.o -o %t # RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s # REQUIRES: amdgpu @@ -7,7 +7,7 @@ .hsa_code_object_version 1,0 .hsa_code_object_isa 7,0,0,"AMD","AMDGPU" -.hsatext +.text .globl kernel0 .align 256 .amdgpu_hsa_kernel kernel0 @@ -27,16 +27,12 @@ kernel1: # CHECK: Section { -# CHECK: Name: .hsatext +# CHECK: Name: .text # CHECK: Type: SHT_PROGBITS -# CHECK: Flags [ (0xC00007) +# CHECK: Flags [ (0x6) # CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) -# CHECK: SHF_AMDGPU_HSA_CODE (0x400000) # CHECK: SHF_EXECINSTR (0x4) -# CHECK: SHF_WRITE (0x1) # CHECK: ] -# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]] # CHECK: } # CHECK: Symbol { @@ -45,7 +41,7 @@ kernel1: # CHECK: Size: 4 # CHECK: Binding: Global # CHECK: Type: AMDGPU_HSA_KERNEL -# CHECK: Section: .hsatext +# CHECK: Section: .text # CHECK: } # CHECK: Symbol { @@ -54,7 +50,7 @@ kernel1: # CHECK: Size: 8 # CHECK: Binding: Global # CHECK: Type: AMDGPU_HSA_KERNEL -# CHECK: Section: .hsatext +# CHECK: Section: .text # CHECK: } # CHECK: ProgramHeader { diff --git a/test/ELF/arm-icf-exidx.s b/test/ELF/arm-icf-exidx.s index cb801b7f2420..6af30285db67 100644 --- a/test/ELF/arm-icf-exidx.s +++ b/test/ELF/arm-icf-exidx.s @@ -19,13 +19,15 @@ g: .section .text.h .global __aeabi_unwind_cpp_pr0 __aeabi_unwind_cpp_pr0: + nop bx lr // CHECK: Disassembly of section .text: // CHECK-NEXT: f: // CHECK-NEXT: 11000: 1e ff 2f e1 bx lr // CHECK: __aeabi_unwind_cpp_pr0: -// CHECK-NEXT: 11004: 1e ff 2f e1 bx lr +// CHECK-NEXT: 11004: 00 f0 20 e3 nop +// CHECK-NEXT: 11008: 1e ff 2f e1 bx lr // CHECK: Contents of section .ARM.exidx: // CHECK-NEXT: 100d4 2c0f0000 b0b0b080 280f0000 01000000 diff --git a/test/ELF/arm-thumb-no-undefined-thunk.s b/test/ELF/arm-thumb-no-undefined-thunk.s index f668c8c278de..af2d3eb52044 100644 --- a/test/ELF/arm-thumb-no-undefined-thunk.s +++ b/test/ELF/arm-thumb-no-undefined-thunk.s @@ -19,6 +19,6 @@ _start: // CHECK: Disassembly of section .text: // CHECK-NEXT: _start: // 69636 = 0x11004 = next instruction -// CHECK: 11000: 11 f0 02 f8 bl #69636 -// CHECK-NEXT: 11004: 11 f0 04 b8 b.w #69640 -// CHECK-NEXT: 11008: 11 f0 06 b8 b.w #69644 +// CHECK: 11000: {{.*}} bl #69636 +// CHECK-NEXT: 11004: {{.*}} b.w #69640 +// CHECK-NEXT: 11008: {{.*}} b.w #69644 diff --git a/test/ELF/arm-thumb-thunk-symbols.s b/test/ELF/arm-thumb-thunk-symbols.s new file mode 100644 index 000000000000..42046f802f96 --- /dev/null +++ b/test/ELF/arm-thumb-thunk-symbols.s @@ -0,0 +1,42 @@ +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o %t2 2>&1 +// RUN: llvm-readobj --symbols %t2 | FileCheck %s +// RUN: ld.lld --shared %t -o %t3 2>&1 +// RUN: llvm-readobj --symbols %t3 | FileCheck -check-prefix=CHECK-PI %s +// REQUIRES: arm + +// Check that the symbols generated for Thunks have the correct symbol type +// of STT_FUNC and the correct value of bit 0 (0 for ARM 1 for Thumb) + .syntax unified + .section .text.thumb, "ax", %progbits + .thumb + .balign 0x1000 + .globl thumb_fn + .type thumb_fn, %function +thumb_fn: + b.w arm_fn + + .section .text.arm, "ax", %progbits + .arm + .balign 0x1000 + .globl arm_fn + .type arm_fn, %function +arm_fn: + b thumb_fn + +// CHECK: Name: __Thumbv7ABSLongThunk_arm_fn +// CHECK-NEXT: Value: 0x11005 +// CHECK-NEXT: Size: 10 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: Function (0x2) +// CHECK: Name: __ARMv7ABSLongThunk_thumb_fn +// CHECK-NEXT: Value: 0x11010 +// CHECK-NEXT: Size: 12 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: Function (0x2) + +// CHECK-PI: Name: __ThumbV7PILongThunk_arm_fn +// CHECK-PI-NEXT: Value: 0x1005 +// CHECK-PI-NEXT: Size: 12 +// CHECK-PI-NEXT: Binding: Local (0x0) +// CHECK-PI-NEXT: Type: Function (0x2) diff --git a/test/ELF/arm-thumb-undefined-weak.s b/test/ELF/arm-thumb-undefined-weak.s index 087f8e71cb21..792b81e3603a 100644 --- a/test/ELF/arm-thumb-undefined-weak.s +++ b/test/ELF/arm-thumb-undefined-weak.s @@ -29,10 +29,10 @@ _start: // CHECK: Disassembly of section .text: // 69636 = 0x11004 -// CHECK: 11000: 11 f0 02 80 beq.w #69636 -// CHECK-NEXT: 11004: 11 f0 04 b8 b.w #69640 -// CHECK-NEXT: 11008: 11 f0 06 f8 bl #69644 +// CHECK: 11000: {{.*}} beq.w #69636 +// CHECK-NEXT: 11004: {{.*}} b.w #69640 +// CHECK-NEXT: 11008: {{.*}} bl #69644 // blx is transformed into bl so we don't change state -// CHECK-NEXT: 1100c: 11 f0 08 f8 bl #69648 -// CHECK-NEXT: 11010: c0 f2 00 00 movt r0, #0 -// CHECK-NEXT: 11014: 40 f2 00 00 movw r0, #0 +// CHECK-NEXT: 1100c: {{.*}} bl #69648 +// CHECK-NEXT: 11010: {{.*}} movt r0, #0 +// CHECK-NEXT: 11014: {{.*}} movw r0, #0 diff --git a/test/ELF/arm-undefined-weak.s b/test/ELF/arm-undefined-weak.s index df67b467e263..5d77b1b4e698 100644 --- a/test/ELF/arm-undefined-weak.s +++ b/test/ELF/arm-undefined-weak.s @@ -29,11 +29,11 @@ _start: // CHECK: Disassembly of section .text: // 69636 = 0x11004 -// CHECK: 11000: 01 44 00 ea b #69636 -// CHECK-NEXT: 11004: 02 44 00 eb bl #69640 +// CHECK: 11000: {{.*}} b #69636 +// CHECK-NEXT: 11004: {{.*}} bl #69640 // blx is transformed into bl so we don't change state -// CHECK-NEXT: 11008: 03 44 00 eb bl #69644 -// CHECK-NEXT: 1100c: 00 00 40 e3 movt r0, #0 -// CHECK-NEXT: 11010: 00 00 00 e3 movw r0, #0 -// CHECK: 11014: 00 00 00 00 .word 0x00000000 +// CHECK-NEXT: 11008: {{.*}} bl #69644 +// CHECK-NEXT: 1100c: {{.*}} movt r0, #0 +// CHECK-NEXT: 11010: {{.*}} movw r0, #0 +// CHECK: 11014: {{.*}} .word 0x00000000 diff --git a/test/ELF/dso_handle.s b/test/ELF/dso_handle.s new file mode 100644 index 000000000000..99e2594ef814 --- /dev/null +++ b/test/ELF/dso_handle.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t +# RUN: llvm-readobj -symbols %t | FileCheck %s +# CHECK: Name: __dso_handle +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other [ +# CHECK-NEXT: STV_HIDDEN +# CHECK-NEXT: ] +# CHECK-NEXT: Section: .dynsym + +.text +.global foo, __dso_handle +foo: + lea __dso_handle(%rip),%rax diff --git a/test/ELF/ehdr_start.s b/test/ELF/ehdr_start.s index 32bcf4b84751..94e0fedcfc52 100644 --- a/test/ELF/ehdr_start.s +++ b/test/ELF/ehdr_start.s @@ -13,10 +13,21 @@ # CHECK-NEXT: ] # CHECK-NEXT: Section: .text (0x1) +# CHECK: Name: __executable_start +# CHECK-NEXT: Value: 0x200000 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other [ +# CHECK-NEXT: STV_HIDDEN +# CHECK-NEXT: ] +# CHECK-NEXT: Section: .text + .text .global _start, __ehdr_start _start: .quad __ehdr_start + .quad __executable_start # RUN: ld.lld -r %t.o -o %t.r # RUN: llvm-readobj -symbols %t.r | FileCheck %s --check-prefix=RELOCATABLE diff --git a/test/ELF/emit-relocs-merge.s b/test/ELF/emit-relocs-merge.s index 3fecca23b735..c700c337e334 100644 --- a/test/ELF/emit-relocs-merge.s +++ b/test/ELF/emit-relocs-merge.s @@ -8,7 +8,7 @@ # CHECK-NEXT: 0x1000 R_X86_64_64 zed 0x0 # CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 # CHECK-NEXT: } -# CHECK-NEXT: Section ({{.*}}) .rela.data { +# CHECK-NEXT: Section ({{.*}}) .rela.data.foo { # CHECK-NEXT: 0x1000 R_X86_64_64 zed 0x0 # CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 # CHECK-NEXT: } diff --git a/test/ELF/gdb-index-empty.s b/test/ELF/gdb-index-empty.s index 933afed33e2f..24f20803a008 100644 --- a/test/ELF/gdb-index-empty.s +++ b/test/ELF/gdb-index-empty.s @@ -8,109 +8,73 @@ # echo "void _start() { __builtin_unreachable(); }" | \ # clang -Os -g -S -o gdb-index-empty.s -x c - -Xclang -fdebug-compilation-dir -Xclang . - .text - .file "-" - .globl _start - .type _start,@function -_start: # @_start +.text +.globl _start +.type _start,@function +_start: .Lfunc_begin0: - .cfi_startproc -# BB#0: # %entry .Lfunc_end0: - .size _start, .Lfunc_end0-_start - .cfi_endproc - .file 1 "" - .section .debug_str,"MS",@progbits,1 -.Linfo_string0: - .asciz "clang version 5.0.0 " # string offset=0 -.Linfo_string1: - .asciz "-" # string offset=21 -.Linfo_string2: - .asciz "." # string offset=23 -.Linfo_string3: - .asciz "_start" # string offset=25 - .section .debug_loc,"",@progbits - .section .debug_abbrev,"",@progbits - .byte 1 # Abbreviation Code - .byte 17 # DW_TAG_compile_unit - .byte 1 # DW_CHILDREN_yes - .byte 37 # DW_AT_producer - .byte 14 # DW_FORM_strp - .byte 19 # DW_AT_language - .byte 5 # DW_FORM_data2 - .byte 3 # DW_AT_name - .byte 14 # DW_FORM_strp - .byte 16 # DW_AT_stmt_list - .byte 23 # DW_FORM_sec_offset - .byte 27 # DW_AT_comp_dir - .byte 14 # DW_FORM_strp - .byte 17 # DW_AT_low_pc - .byte 1 # DW_FORM_addr - .byte 18 # DW_AT_high_pc - .byte 6 # DW_FORM_data4 - .byte 0 # EOM(1) - .byte 0 # EOM(2) - .byte 2 # Abbreviation Code - .byte 46 # DW_TAG_subprogram - .byte 0 # DW_CHILDREN_no - .byte 17 # DW_AT_low_pc - .byte 1 # DW_FORM_addr - .byte 18 # DW_AT_high_pc - .byte 6 # DW_FORM_data4 - .byte 64 # DW_AT_frame_base - .byte 24 # DW_FORM_exprloc - .byte 3 # DW_AT_name - .byte 14 # DW_FORM_strp - .byte 58 # DW_AT_decl_file - .byte 11 # DW_FORM_data1 - .byte 59 # DW_AT_decl_line - .byte 11 # DW_FORM_data1 - .byte 63 # DW_AT_external - .byte 25 # DW_FORM_flag_present - .byte 0 # EOM(1) - .byte 0 # EOM(2) - .byte 0 # EOM(3) - .section .debug_info,"",@progbits -.Lcu_begin0: - .long 60 # Length of Unit - .short 4 # DWARF version number - .long .debug_abbrev # Offset Into Abbrev. Section - .byte 8 # Address Size (in bytes) - .byte 1 # Abbrev [1] 0xb:0x35 DW_TAG_compile_unit - .long .Linfo_string0 # DW_AT_producer - .short 12 # DW_AT_language - .long .Linfo_string1 # DW_AT_name - .long .Lline_table_start0 # DW_AT_stmt_list - .long .Linfo_string2 # DW_AT_comp_dir - .quad .Lfunc_begin0 # DW_AT_low_pc - .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc - .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_subprogram - .quad .Lfunc_begin0 # DW_AT_low_pc - .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc - .byte 1 # DW_AT_frame_base - .byte 87 - .long .Linfo_string3 # DW_AT_name - .byte 1 # DW_AT_decl_file - .byte 1 # DW_AT_decl_line - # DW_AT_external - .byte 0 # End Of Children Mark - .section .debug_ranges,"",@progbits - .section .debug_macinfo,"",@progbits -.Lcu_macro_begin0: - .byte 0 # End Of Macro List Mark - .section .debug_pubnames,"",@progbits - .long .LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info -.LpubNames_begin0: - .short 2 # DWARF Version - .long .Lcu_begin0 # Offset of Compilation Unit Info - .long 64 # Compilation Unit Length - .long 42 # DIE offset - .asciz "_start" # External Name - .long 0 # End Mark -.LpubNames_end0: +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) - .ident "clang version 5.0.0 " - .section ".note.GNU-stack","",@progbits - .section .debug_line,"",@progbits -.Lline_table_start0: +.section .debug_info,"",@progbits + .long 60 # Length of Unit + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x35 DW_TAG_compile_unit + .long 0 # DW_AT_producer + .short 12 # DW_AT_language + .long 0 # DW_AT_name + .long 0 # DW_AT_stmt_list + .long 0 # DW_AT_comp_dir + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_subprogram + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + .long 0 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .byte 0 # End Of Children Mark diff --git a/test/ELF/i386-reloc-large-addend.s b/test/ELF/i386-reloc-large-addend.s new file mode 100644 index 000000000000..b644640404e2 --- /dev/null +++ b/test/ELF/i386-reloc-large-addend.s @@ -0,0 +1,15 @@ +// RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj + +// RUN: echo ".global foo; foo = 0x1" > %t1.s +// RUN: llvm-mc %t1.s -o %t1.o -triple i386-pc-linux -filetype=obj + +// RUN: ld.lld -Ttext 0x7000 %t.o %t1.o -o %t +// RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t | FileCheck %s + +// CHECK: Disassembly of section .text: +// CHECK-NEXT: _start: +// CHECK-NEXT: 7000: e9 fe 1f jmp 8190 +// 0x1 + 0x9000 - 0x7003 == 8190 + .global _start +_start: +jmp foo + 0x9000 diff --git a/test/ELF/i386-reloc-range.s b/test/ELF/i386-reloc-range.s new file mode 100644 index 000000000000..47447d0efa32 --- /dev/null +++ b/test/ELF/i386-reloc-range.s @@ -0,0 +1,22 @@ +// RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj + +// RUN: echo ".global foo; foo = 0x10202" > %t1.s +// RUN: llvm-mc %t1.s -o %t1.o -triple i386-pc-linux -filetype=obj +// RUN: echo ".global foo; foo = 0x10203" > %t2.s +// RUN: llvm-mc %t2.s -o %t2.o -triple i386-pc-linux -filetype=obj + +// RUN: ld.lld -Ttext 0x200 %t.o %t1.o -o %t1 +// RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t1 | FileCheck %s + +// CHECK: Disassembly of section .text: +// CHECK-NEXT: _start: +// CHECK-NEXT: 200: {{.*}} jmp -1 +// 0x10202 - 0x203 == 0xffff + +// RUN: not ld.lld -Ttext 0x200 %t.o %t2.o -o %t2 2>&1 | FileCheck --check-prefix=ERR %s + +// ERR: {{.*}}:(.text+0x1): relocation R_386_PC16 out of range + + .global _start +_start: + jmp foo diff --git a/test/ELF/icf-comdat.s b/test/ELF/icf-comdat.s new file mode 100644 index 000000000000..28c0a586bf03 --- /dev/null +++ b/test/ELF/icf-comdat.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s + +# CHECK: selected .text.f1 +# CHECK: removed .text.f2 + +.globl _start, f1, f2 +_start: + ret + +.section .text.f1,"ax" +f1: + mov $60, %rax + mov $42, %rdi + syscall + +.section .text.f2,"axG",@progbits,foo,comdat +f2: + mov $60, %rax + mov $42, %rdi + syscall diff --git a/test/ELF/linkerscript/early-assign-symbol.s b/test/ELF/linkerscript/early-assign-symbol.s index 21940c088393..0626e66e6fb6 100644 --- a/test/ELF/linkerscript/early-assign-symbol.s +++ b/test/ELF/linkerscript/early-assign-symbol.s @@ -7,7 +7,7 @@ # RUN: echo "SECTIONS { aaa = ABSOLUTE(foo - 1) + 1; .text : { *(.text*) } }" > %t2.script # RUN: not ld.lld -o %t --script %t2.script %t.o 2>&1 | FileCheck %s -# CHECK: error: unable to evaluate expression: input section .text has no output section assigned +# CHECK: error: {{.*}}.script:1: unable to evaluate expression: input section .text has no output section assigned .section .text .globl foo diff --git a/test/ELF/linkerscript/emit-relocs-multiple.s b/test/ELF/linkerscript/emit-relocs-multiple.s new file mode 100644 index 000000000000..b04ca1be7a15 --- /dev/null +++ b/test/ELF/linkerscript/emit-relocs-multiple.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { .zed : { *(.foo) *(.bar) } }" > %t.script +# RUN: ld.lld --emit-relocs --script %t.script %t.o -o %t1 +# RUN: llvm-readobj -r %t1 | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .rela.foo { +# CHECK-NEXT: 0x1 R_X86_64_32 .zed 0x0 +# CHECK-NEXT: 0x6 R_X86_64_32 .zed 0x5 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.section .foo,"ax",@progbits +aaa: + movl $aaa, %edx + +.section .bar,"ax",@progbits +bbb: + movl $bbb, %edx diff --git a/test/ELF/linkerscript/expr-invalid-sec.s b/test/ELF/linkerscript/expr-invalid-sec.s index 9476be3c3b14..5687751b6806 100644 --- a/test/ELF/linkerscript/expr-invalid-sec.s +++ b/test/ELF/linkerscript/expr-invalid-sec.s @@ -3,4 +3,4 @@ # RUN: echo "SECTIONS { foo = ADDR(.text) + ADDR(.text); };" > %t.script # RUN: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s -# CHECK: At least one side of the expression must be absolute +# CHECK: error: {{.*}}.script:1: at least one side of the expression must be absolute diff --git a/test/ELF/linkerscript/noload.s b/test/ELF/linkerscript/noload.s new file mode 100644 index 000000000000..9d0e085a0504 --- /dev/null +++ b/test/ELF/linkerscript/noload.s @@ -0,0 +1,46 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: .data_noload_a (NOLOAD) : { *(.data_noload_a) } \ +# RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } };" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj --symbols -sections %t + +# CHECK: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .data_noload_a +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Size: 4096 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .data_noload_b +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x10000 +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Size: 4096 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } + +.section .data_noload_a,"aw",@progbits +.zero 4096 + +.section .data_noload_b,"aw",@progbits +.zero 4096 diff --git a/test/ELF/lto/Inputs/defsym-bar.ll b/test/ELF/lto/Inputs/defsym-bar.ll new file mode 100644 index 000000000000..748c7b23f6a8 --- /dev/null +++ b/test/ELF/lto/Inputs/defsym-bar.ll @@ -0,0 +1,21 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @this_is_bar1() +declare void @this_is_bar2() +declare void @this_is_bar3() + +define hidden void @bar1() { + call void @this_is_bar1() + ret void +} + +define hidden void @bar2() { + call void @this_is_bar2() + ret void +} + +define hidden void @bar3() { + call void @this_is_bar3() + ret void +} diff --git a/test/ELF/lto/Inputs/wrap-bar.ll b/test/ELF/lto/Inputs/wrap-bar.ll new file mode 100644 index 000000000000..407ebfbf6ec3 --- /dev/null +++ b/test/ELF/lto/Inputs/wrap-bar.ll @@ -0,0 +1,14 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define hidden void @bar() { + ret void +} + +define hidden void @__real_bar() { + ret void +} + +define hidden void @__wrap_bar() { + ret void +} diff --git a/test/ELF/lto/defsym.ll b/test/ELF/lto/defsym.ll new file mode 100644 index 000000000000..4c2fe45b3c53 --- /dev/null +++ b/test/ELF/lto/defsym.ll @@ -0,0 +1,28 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: llvm-as %S/Inputs/defsym-bar.ll -o %t1.o +; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3 +; RUN: llvm-objdump -d %t.so | FileCheck %s + +; Call to bar2() should not be inlined and should be routed to bar3() +; Symbol bar3 should not be eliminated + +; CHECK: foo: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq +; CHECK-NEXT: callq{{.*}} +; CHECK-NEXT: callq + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar1() +declare void @bar2() +declare void @bar3() + +define void @foo() { + call void @bar1() + call void @bar2() + call void @bar3() + ret void +} diff --git a/test/ELF/lto/wrap-1.ll b/test/ELF/lto/wrap-1.ll new file mode 100644 index 000000000000..b61dfaeb5903 --- /dev/null +++ b/test/ELF/lto/wrap-1.ll @@ -0,0 +1,35 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps +; RUN: llvm-readobj -t %t.out | FileCheck %s +; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s + +; CHECK: Name: __wrap_bar +; CHECK-NEXT: Value: +; CHECK-NEXT: Size: +; CHECK-NEXT: Binding: Global +; CHECK-NEXT: Type: Function + +; Make sure that the 'r' (linker redefined) bit is set for bar and __wrap_bar +; in the resolutions file. +; RESOLS: ,bar,r +; RESOLS: ,__wrap_bar,px +; RESOLS: ,__real_bar,pxr + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar() + +define void @_start() { + call void @bar() + ret void +} + +define void @__wrap_bar() { + ret void +} + +define void @__real_bar() { + ret void +} diff --git a/test/ELF/lto/wrap-2.ll b/test/ELF/lto/wrap-2.ll new file mode 100644 index 000000000000..b2e33f83138e --- /dev/null +++ b/test/ELF/lto/wrap-2.ll @@ -0,0 +1,36 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o +; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar +; RUN: llvm-objdump -d %t.so | FileCheck %s +; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s + +; Make sure that calls in foo() are not eliminated and that bar is +; routed to __wrap_bar and __real_bar is routed to bar. + +; CHECK: foo: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq{{.*}}<__wrap_bar> +; CHECK-NEXT: callq{{.*}} + +; Check that bar and __wrap_bar retain their original binding. +; BIND: Name: bar +; BIND-NEXT: Value: +; BIND-NEXT: Size: +; BIND-NEXT: Binding: Local +; BIND: Name: __wrap_bar +; BIND-NEXT: Value: +; BIND-NEXT: Size: +; BIND-NEXT: Binding: Local + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar() +declare void @__real_bar() + +define void @foo() { + call void @bar() + call void @__real_bar() + ret void +} diff --git a/test/ELF/mips-npic-call-pic-script.s b/test/ELF/mips-npic-call-pic-script.s new file mode 100644 index 000000000000..6028989ee4cb --- /dev/null +++ b/test/ELF/mips-npic-call-pic-script.s @@ -0,0 +1,255 @@ +# REQUIRES: mips +# Check LA25 stubs creation. This stub code is necessary when +# non-PIC code calls PIC function. +# RUN: echo "SECTIONS { .out 0x20000 : { *(.text.*) . = . + 0x100 ; *(.text) } }" > %t1.script +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-fpic.s -o %t-fpic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-fnpic.s -o %t-fnpic.o +# RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-pic.s -o %t-pic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o +# RUN: ld.lld --script %t1.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe +# RUN: llvm-objdump -d %t.exe | FileCheck %s + +# CHECK: Disassembly of section .out: +# CHECK-NEXT: __LA25Thunk_foo1a: +# CHECK-NEXT: 20000: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20004: 08 00 80 08 j 131104 +# CHECK-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 +# CHECK-NEXT: 2000c: 00 00 00 00 nop +# CHECK: __LA25Thunk_foo1b: +# CHECK-NEXT: 20010: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20014: 08 00 80 09 j 131108 +# CHECK-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 +# CHECK-NEXT: 2001c: 00 00 00 00 nop +# CHECK: foo1a: +# CHECK-NEXT: 20020: 00 00 00 00 nop +# CHECK: foo1b: +# CHECK-NEXT: 20024: 00 00 00 00 nop +# CHECK: __LA25Thunk_foo2: +# CHECK-NEXT: 20028: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 2002c: 08 00 80 10 j 131136 +# CHECK-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 +# CHECK-NEXT: 20034: 00 00 00 00 nop +# CHECK-NEXT: 20038: 00 00 00 00 nop +# CHECK-NEXT: 2003c: 00 00 00 00 nop +# CHECK: foo2: +# CHECK-NEXT: 20040: 00 00 00 00 nop +# CHECK-NEXT: 20044: 00 00 00 00 nop +# CHECK-NEXT: 20048: 00 00 00 00 nop +# CHECK-NEXT: 2004c: 00 00 00 00 nop +# CHECK-NEXT: 20050: 00 00 00 00 nop +# CHECK-NEXT: 20054: 00 00 00 00 nop +# CHECK-NEXT: 20058: 00 00 00 00 nop +# CHECK-NEXT: 2005c: 00 00 00 00 nop +# CHECK-NEXT: 20060: 00 00 00 00 nop +# CHECK-NEXT: 20064: 00 00 00 00 nop +# CHECK-NEXT: 20068: 00 00 00 00 nop +# CHECK-NEXT: 2006c: 00 00 00 00 nop +# CHECK-NEXT: 20070: 00 00 00 00 nop +# CHECK-NEXT: 20074: 00 00 00 00 nop +# CHECK-NEXT: 20078: 00 00 00 00 nop +# CHECK-NEXT: 2007c: 00 00 00 00 nop +# CHECK-NEXT: 20080: 00 00 00 00 nop +# CHECK-NEXT: 20084: 00 00 00 00 nop +# CHECK-NEXT: 20088: 00 00 00 00 nop +# CHECK-NEXT: 2008c: 00 00 00 00 nop +# CHECK-NEXT: 20090: 00 00 00 00 nop +# CHECK-NEXT: 20094: 00 00 00 00 nop +# CHECK-NEXT: 20098: 00 00 00 00 nop +# CHECK-NEXT: 2009c: 00 00 00 00 nop +# CHECK-NEXT: 200a0: 00 00 00 00 nop +# CHECK-NEXT: 200a4: 00 00 00 00 nop +# CHECK-NEXT: 200a8: 00 00 00 00 nop +# CHECK-NEXT: 200ac: 00 00 00 00 nop +# CHECK-NEXT: 200b0: 00 00 00 00 nop +# CHECK-NEXT: 200b4: 00 00 00 00 nop +# CHECK-NEXT: 200b8: 00 00 00 00 nop +# CHECK-NEXT: 200bc: 00 00 00 00 nop +# CHECK-NEXT: 200c0: 00 00 00 00 nop +# CHECK-NEXT: 200c4: 00 00 00 00 nop +# CHECK-NEXT: 200c8: 00 00 00 00 nop +# CHECK-NEXT: 200cc: 00 00 00 00 nop +# CHECK-NEXT: 200d0: 00 00 00 00 nop +# CHECK-NEXT: 200d4: 00 00 00 00 nop +# CHECK-NEXT: 200d8: 00 00 00 00 nop +# CHECK-NEXT: 200dc: 00 00 00 00 nop +# CHECK-NEXT: 200e0: 00 00 00 00 nop +# CHECK-NEXT: 200e4: 00 00 00 00 nop +# CHECK-NEXT: 200e8: 00 00 00 00 nop +# CHECK-NEXT: 200ec: 00 00 00 00 nop +# CHECK-NEXT: 200f0: 00 00 00 00 nop +# CHECK-NEXT: 200f4: 00 00 00 00 nop +# CHECK-NEXT: 200f8: 00 00 00 00 nop +# CHECK-NEXT: 200fc: 00 00 00 00 nop +# CHECK-NEXT: 20100: 00 00 00 00 nop +# CHECK-NEXT: 20104: 00 00 00 00 nop +# CHECK-NEXT: 20108: 00 00 00 00 nop +# CHECK-NEXT: 2010c: 00 00 00 00 nop +# CHECK-NEXT: 20110: 00 00 00 00 nop +# CHECK-NEXT: 20114: 00 00 00 00 nop +# CHECK-NEXT: 20118: 00 00 00 00 nop +# CHECK-NEXT: 2011c: 00 00 00 00 nop +# CHECK-NEXT: 20120: 00 00 00 00 nop +# CHECK-NEXT: 20124: 00 00 00 00 nop +# CHECK-NEXT: 20128: 00 00 00 00 nop +# CHECK-NEXT: 2012c: 00 00 00 00 nop +# CHECK-NEXT: 20130: 00 00 00 00 nop +# CHECK-NEXT: 20134: 00 00 00 00 nop +# CHECK-NEXT: 20138: 00 00 00 00 nop +# CHECK-NEXT: 2013c: 00 00 00 00 nop +# CHECK-NEXT: 20140: 00 00 00 00 nop +# CHECK-NEXT: 20144: 00 00 00 00 nop +# CHECK-NEXT: 20148: 00 00 00 00 nop +# CHECK-NEXT: 2014c: 00 00 00 00 nop +# CHECK: __start: +# CHECK-NEXT: 20150: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> +# CHECK-NEXT: 20154: 00 00 00 00 nop +# CHECK-NEXT: 20158: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> +# CHECK-NEXT: 2015c: 00 00 00 00 nop +# CHECK-NEXT: 20160: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b> +# CHECK-NEXT: 20164: 00 00 00 00 nop +# CHECK-NEXT: 20168: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> +# CHECK-NEXT: 2016c: 00 00 00 00 nop +# CHECK-NEXT: 20170: 0c 00 80 60 jal 131456 <__LA25Thunk_fpic> +# CHECK-NEXT: 20174: 00 00 00 00 nop +# CHECK-NEXT: 20178: 0c 00 80 68 jal 131488 +# CHECK-NEXT: 2017c: 00 00 00 00 nop +# CHECK: __LA25Thunk_fpic: +# CHECK-NEXT: 20180: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20184: 08 00 80 64 j 131472 +# CHECK-NEXT: 20188: 27 39 01 90 addiu $25, $25, 400 +# CHECK-NEXT: 2018c: 00 00 00 00 nop +# CHECK: fpic: +# CHECK-NEXT: 20190: 00 00 00 00 nop +# CHECK-NEXT: 20194: 00 00 00 00 nop +# CHECK-NEXT: 20198: 00 00 00 00 nop +# CHECK-NEXT: 2019c: 00 00 00 00 nop +# CHECK: fnpic: +# CHECK-NEXT: 201a0: 00 00 00 00 nop + + .text + .globl __start +__start: + jal foo1a + jal foo2 + jal foo1b + jal foo2 + jal fpic + jal fnpic + +# Test script with orphans added to existing OutputSection, the .text.1 and +# .text.2 sections will be added to .text +# RUN: echo "SECTIONS { .text 0x20000 : { *(.text) } }" > %t2.script +# RUN: ld.lld --script %t2.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t2.exe +# RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=ORPH1 %s +# ORPH1: Disassembly of section .text: +# ORPH1-NEXT: __start: +# ORPH1-NEXT: 20000: 0c 00 80 15 jal 131156 <__LA25Thunk_foo1a> +# ORPH1-NEXT: 20004: 00 00 00 00 nop +# ORPH1-NEXT: 20008: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> +# ORPH1-NEXT: 2000c: 00 00 00 00 nop +# ORPH1-NEXT: 20010: 0c 00 80 19 jal 131172 <__LA25Thunk_foo1b> +# ORPH1-NEXT: 20014: 00 00 00 00 nop +# ORPH1-NEXT: 20018: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> +# ORPH1-NEXT: 2001c: 00 00 00 00 nop +# ORPH1-NEXT: 20020: 0c 00 80 0c jal 131120 <__LA25Thunk_fpic> +# ORPH1-NEXT: 20024: 00 00 00 00 nop +# ORPH1-NEXT: 20028: 0c 00 80 14 jal 131152 +# ORPH1-NEXT: 2002c: 00 00 00 00 nop +# ORPH1: __LA25Thunk_fpic: +# ORPH1-NEXT: 20030: 3c 19 00 02 lui $25, 2 +# ORPH1-NEXT: 20034: 08 00 80 10 j 131136 +# ORPH1-NEXT: 20038: 27 39 00 40 addiu $25, $25, 64 +# ORPH1-NEXT: 2003c: 00 00 00 00 nop +# ORPH1: fpic: +# ORPH1-NEXT: 20040: 00 00 00 00 nop +# ORPH1-NEXT: 20044: 00 00 00 00 nop +# ORPH1-NEXT: 20048: 00 00 00 00 nop +# ORPH1-NEXT: 2004c: 00 00 00 00 nop +# ORPH1: fnpic: +# ORPH1-NEXT: 20050: 00 00 00 00 nop +# ORPH1: __LA25Thunk_foo1a: +# ORPH1-NEXT: 20054: 3c 19 00 02 lui $25, 2 +# ORPH1-NEXT: 20058: 08 00 80 20 j 131200 +# ORPH1-NEXT: 2005c: 27 39 00 80 addiu $25, $25, 128 +# ORPH1-NEXT: 20060: 00 00 00 00 nop +# ORPH1: __LA25Thunk_foo1b: +# ORPH1-NEXT: 20064: 3c 19 00 02 lui $25, 2 +# ORPH1-NEXT: 20068: 08 00 80 21 j 131204 +# ORPH1-NEXT: 2006c: 27 39 00 84 addiu $25, $25, 132 +# ORPH1-NEXT: 20070: 00 00 00 00 nop +# ORPH1-NEXT: 20074: 00 00 00 00 nop +# ORPH1-NEXT: 20078: 00 00 00 00 nop +# ORPH1-NEXT: 2007c: 00 00 00 00 nop +# ORPH1: foo1a: +# ORPH1-NEXT: 20080: 00 00 00 00 nop +# ORPH1: foo1b: +# ORPH1-NEXT: 20084: 00 00 00 00 nop +# ORPH1: __LA25Thunk_foo2: +# ORPH1-NEXT: 20088: 3c 19 00 02 lui $25, 2 +# ORPH1-NEXT: 2008c: 08 00 80 28 j 131232 +# ORPH1-NEXT: 20090: 27 39 00 a0 addiu $25, $25, 160 +# ORPH1-NEXT: 20094: 00 00 00 00 nop +# ORPH1-NEXT: 20098: 00 00 00 00 nop +# ORPH1-NEXT: 2009c: 00 00 00 00 nop +# ORPH1: foo2: +# ORPH1-NEXT: 200a0: 00 00 00 00 nop + +# Test script with orphans added to new OutputSection, the .text.1 and +# .text.2 sections will form a new OutputSection .text +# RUN: echo "SECTIONS { .out 0x20000 : { *(.text) } }" > %t3.script +# RUN: ld.lld --script %t3.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t3.exe +# RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=ORPH2 %s +# ORPH2: Disassembly of section .out: +# ORPH2-NEXT: __start: +# ORPH2-NEXT: 20000: 0c 00 80 18 jal 131168 <__LA25Thunk_foo1a> +# ORPH2-NEXT: 20004: 00 00 00 00 nop +# ORPH2-NEXT: 20008: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> +# ORPH2-NEXT: 2000c: 00 00 00 00 nop +# ORPH2-NEXT: 20010: 0c 00 80 1c jal 131184 <__LA25Thunk_foo1b> +# ORPH2-NEXT: 20014: 00 00 00 00 nop +# ORPH2-NEXT: 20018: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> +# ORPH2-NEXT: 2001c: 00 00 00 00 nop +# ORPH2-NEXT: 20020: 0c 00 80 0c jal 131120 <__LA25Thunk_fpic> +# ORPH2-NEXT: 20024: 00 00 00 00 nop +# ORPH2-NEXT: 20028: 0c 00 80 14 jal 131152 +# ORPH2-NEXT: 2002c: 00 00 00 00 nop +# ORPH2: __LA25Thunk_fpic: +# ORPH2-NEXT: 20030: 3c 19 00 02 lui $25, 2 +# ORPH2-NEXT: 20034: 08 00 80 10 j 131136 +# ORPH2-NEXT: 20038: 27 39 00 40 addiu $25, $25, 64 +# ORPH2-NEXT: 2003c: 00 00 00 00 nop +# ORPH2: fpic: +# ORPH2-NEXT: 20040: 00 00 00 00 nop +# ORPH2-NEXT: 20044: 00 00 00 00 nop +# ORPH2-NEXT: 20048: 00 00 00 00 nop +# ORPH2-NEXT: 2004c: 00 00 00 00 nop +# ORPH2: fnpic: +# ORPH2-NEXT: 20050: 00 00 00 00 nop +# ORPH2-NEXT: Disassembly of section .text: +# ORPH2-NEXT: __LA25Thunk_foo1a: +# ORPH2-NEXT: 20060: 3c 19 00 02 lui $25, 2 +# ORPH2-NEXT: 20064: 08 00 80 20 j 131200 +# ORPH2-NEXT: 20068: 27 39 00 80 addiu $25, $25, 128 +# ORPH2-NEXT: 2006c: 00 00 00 00 nop +# ORPH2: __LA25Thunk_foo1b: +# ORPH2-NEXT: 20070: 3c 19 00 02 lui $25, 2 +# ORPH2-NEXT: 20074: 08 00 80 21 j 131204 +# ORPH2-NEXT: 20078: 27 39 00 84 addiu $25, $25, 132 +# ORPH2-NEXT: 2007c: 00 00 00 00 nop +# ORPH2: foo1a: +# ORPH2-NEXT: 20080: 00 00 00 00 nop +# ORPH2: foo1b: +# ORPH2-NEXT: 20084: 00 00 00 00 nop +# ORPH2: __LA25Thunk_foo2: +# ORPH2-NEXT: 20088: 3c 19 00 02 lui $25, 2 +# ORPH2-NEXT: 2008c: 08 00 80 28 j 131232 +# ORPH2-NEXT: 20090: 27 39 00 a0 addiu $25, $25, 160 +# ORPH2-NEXT: 20094: 00 00 00 00 nop +# ORPH2-NEXT: 20098: 00 00 00 00 nop +# ORPH2-NEXT: 2009c: 00 00 00 00 nop +# ORPH2: foo2: +# ORPH2-NEXT: 200a0: 00 00 00 00 nop diff --git a/test/ELF/relocatable-comdat-multiple.s b/test/ELF/relocatable-comdat-multiple.s new file mode 100644 index 000000000000..4c3e7ce7f6d4 --- /dev/null +++ b/test/ELF/relocatable-comdat-multiple.s @@ -0,0 +1,31 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/relocatable-comdat-multiple.s -o %t2.o +# RUN: ld.lld -r %t.o %t2.o -o %t +# RUN: llvm-readobj -elf-section-groups %t | FileCheck %s + +# CHECK: Groups { +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: aaa +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .text.a +# CHECK-NEXT: .text.b +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 5 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: bbb +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .text.c +# CHECK-NEXT: .text.d +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } + +.section .text.a,"axG",@progbits,aaa,comdat +.section .text.b,"axG",@progbits,aaa,comdat diff --git a/test/ELF/relocatable-compressed-input.s b/test/ELF/relocatable-compressed-input.s new file mode 100644 index 000000000000..bdfb2073a1e0 --- /dev/null +++ b/test/ELF/relocatable-compressed-input.s @@ -0,0 +1,45 @@ +# REQUIRES: zlib + +# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: llvm-readobj -sections %t1 | FileCheck -check-prefix=GNU %s +# GNU: Name: .zdebug_str + +# RUN: ld.lld %t1 -o %t2 -r +# RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s + +## Check we decompress section and remove ".z" prefix specific for zlib-gnu compression. +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .debug_str +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: SHF_STRINGS +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 1 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: {{.*}} |short unsigned i| +# CHECK-NEXT: 0010: {{.*}} |nt.unsigned int.| +# CHECK-NEXT: 0020: {{.*}} |long unsigned in| +# CHECK-NEXT: 0030: {{.*}} |t.char.unsigned | +# CHECK-NEXT: 0040: {{.*}} |char.| +# CHECK-NEXT: ) +# CHECK-NEXT: } + +.section .debug_str,"MS",@progbits,1 +.LASF2: + .string "short unsigned int" +.LASF3: + .string "unsigned int" +.LASF0: + .string "long unsigned int" +.LASF8: + .string "char" +.LASF1: + .string "unsigned char" diff --git a/test/ELF/relocatable-empty-archive.s b/test/ELF/relocatable-empty-archive.s new file mode 100644 index 000000000000..545ef7bfc24c --- /dev/null +++ b/test/ELF/relocatable-empty-archive.s @@ -0,0 +1,10 @@ +# REQUIRES: x86 +# RUN: rm -f %t.a +# RUN: llvm-ar rc %t.a +# RUN: ld.lld -m elf_x86_64 %t.a -o %t -r +# RUN: llvm-readobj -file-headers %t | FileCheck %s + +# CHECK: Format: ELF64-x86-64 +# CHECK: Arch: x86_64 +# CHECK: AddressSize: 64bit +# CHECK: Type: Relocatable diff --git a/unittests/DriverTests/DarwinLdDriverTest.cpp b/unittests/DriverTests/DarwinLdDriverTest.cpp index ea7fcc7eafcb..d81f1543f453 100644 --- a/unittests/DriverTests/DarwinLdDriverTest.cpp +++ b/unittests/DriverTests/DarwinLdDriverTest.cpp @@ -14,7 +14,7 @@ #include "lld/Driver/Driver.h" #include "lld/ReaderWriter/MachOLinkingContext.h" -#include "llvm/Support/MachO.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" diff --git a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp index a3c445a93619..3e8793a0ef48 100644 --- a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp @@ -7,14 +7,14 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Error.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLTraits.h" +#include "gtest/gtest.h" #include #include diff --git a/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp index 51196e6eeba6..210fecbf0866 100644 --- a/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/MachO.h" +#include "gtest/gtest.h" #include #include #include diff --git a/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp b/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp index 8205ea97520a..a0176bb671b7 100644 --- a/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h" #include "lld/Core/Atom.h" #include "lld/Core/DefinedAtom.h" @@ -15,9 +14,10 @@ #include "lld/Core/UndefinedAtom.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Error.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/YAMLTraits.h" +#include "gtest/gtest.h" #include #include diff --git a/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp b/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp index e41b7ecd801c..6bbde72d3dd1 100644 --- a/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp @@ -7,18 +7,18 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Error.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" #include #include -#include #include +#include using llvm::StringRef; using llvm::MemoryBuffer; From 7c7aba6e5fef47a01a136be655b0a92cfd7090f6 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Fri, 16 Jun 2017 21:03:24 +0000 Subject: [PATCH 09/11] Vendor import of llvm trunk r305575: https://llvm.org/svn/llvm-project/llvm/trunk@305575 --- cmake/modules/TableGen.cmake | 50 +- docs/BranchWeightMetadata.rst | 14 + docs/LangRef.rst | 241 +- docs/Lexicon.rst | 7 + docs/Phabricator.rst | 3 +- include/llvm/ADT/AllocatorList.h | 61 +- include/llvm/ADT/ArrayRef.h | 44 +- include/llvm/ADT/BreadthFirstIterator.h | 11 +- include/llvm/ADT/DAGDeltaAlgorithm.h | 10 +- include/llvm/ADT/DeltaAlgorithm.h | 10 +- include/llvm/ADT/DenseMap.h | 72 +- include/llvm/ADT/DenseMapInfo.h | 40 +- include/llvm/ADT/DenseSet.h | 46 +- include/llvm/ADT/DepthFirstIterator.h | 23 +- include/llvm/ADT/EquivalenceClasses.h | 22 +- include/llvm/ADT/FoldingSet.h | 233 +- include/llvm/ADT/GraphTraits.h | 15 +- include/llvm/ADT/ImmutableList.h | 8 +- include/llvm/ADT/ImmutableMap.h | 62 +- include/llvm/ADT/ImmutableSet.h | 121 +- include/llvm/ADT/IndexedMap.h | 18 +- include/llvm/ADT/IntervalMap.h | 49 +- include/llvm/ADT/IntrusiveRefCntPtr.h | 18 +- include/llvm/ADT/MapVector.h | 24 +- include/llvm/ADT/Optional.h | 35 +- include/llvm/ADT/PackedVector.h | 6 +- include/llvm/ADT/PointerEmbeddedInt.h | 30 +- include/llvm/ADT/PointerUnion.h | 2 +- include/llvm/ADT/ScopedHashTable.h | 12 +- include/llvm/ADT/SmallBitVector.h | 58 +- include/llvm/ADT/SmallSet.h | 7 +- include/llvm/ADT/StringExtras.h | 12 +- include/llvm/ADT/Triple.h | 4 +- include/llvm/ADT/ilist_base.h | 6 +- include/llvm/ADT/ilist_iterator.h | 59 +- include/llvm/ADT/ilist_node.h | 52 +- include/llvm/ADT/iterator.h | 8 +- include/llvm/ADT/simple_ilist.h | 33 +- include/llvm/Analysis/MemorySSA.h | 6 - include/llvm/Analysis/ScalarEvolution.h | 32 +- include/llvm/Analysis/TargetTransformInfo.h | 14 +- .../llvm/Analysis/TargetTransformInfoImpl.h | 4 +- include/llvm/Analysis/TypeMetadataUtils.h | 7 + include/llvm/Analysis/ValueTracking.h | 4 +- include/llvm/BinaryFormat/ELF.h | 38 +- include/llvm/Bitcode/BitcodeReader.h | 20 +- include/llvm/Bitcode/BitcodeWriter.h | 4 + include/llvm/Bitcode/LLVMBitCodes.h | 8 + include/llvm/CodeGen/BasicTTIImpl.h | 4 +- include/llvm/CodeGen/FunctionLoweringInfo.h | 12 + .../llvm/CodeGen/GlobalISel/LegalizerHelper.h | 8 + .../CodeGen/GlobalISel/MachineIRBuilder.h | 24 +- include/llvm/CodeGen/RuntimeLibcalls.h | 19 +- include/llvm/CodeGen/SelectionDAG.h | 6 + .../CodeGen/TargetLoweringObjectFileImpl.h | 15 +- include/llvm/DebugInfo/CodeView/CodeView.h | 5 + .../CodeView/DebugFrameDataSubsection.h | 1 + .../CodeView/DebugInlineeLinesSubsection.h | 2 +- .../CodeView/DebugSubsectionRecord.h | 7 +- .../CodeView/DebugSubsectionVisitor.h | 80 +- include/llvm/DebugInfo/CodeView/Formatters.h | 17 + .../DebugInfo/CodeView/StringsAndChecksums.h | 106 + .../llvm/DebugInfo/CodeView/SymbolRecord.h | 10 +- include/llvm/DebugInfo/CodeView/TypeIndex.h | 2 + .../DebugInfo/DWARF/DWARFAcceleratorTable.h | 4 + include/llvm/DebugInfo/DWARF/DWARFVerifier.h | 28 +- .../PDB/Native/DbiModuleDescriptorBuilder.h | 4 +- .../llvm/DebugInfo/PDB/Native/DbiModuleList.h | 2 + .../DebugInfo/PDB/Native/DbiStreamBuilder.h | 9 +- .../llvm/DebugInfo/PDB/Native/InfoStream.h | 1 + .../DebugInfo/PDB/Native/ModuleDebugStream.h | 9 +- include/llvm/DebugInfo/PDB/Native/PDBFile.h | 2 + .../DebugInfo/PDB/Native/PDBStringTable.h | 2 +- .../PDB/Native/PDBStringTableBuilder.h | 5 +- .../llvm/DebugInfo/PDB/Native/PublicsStream.h | 1 + .../llvm/DebugInfo/PDB/Native/RawConstants.h | 6 +- .../llvm/DebugInfo/PDB/Native/SymbolStream.h | 4 + .../DebugInfo/PDB/Native/TpiStreamBuilder.h | 2 + include/llvm/IR/Constants.h | 9 - include/llvm/IR/DebugInfoMetadata.h | 3 - include/llvm/IR/GlobalVariable.h | 2 - include/llvm/IR/IRBuilder.h | 24 +- include/llvm/IR/InstrTypes.h | 8 - include/llvm/IR/Instructions.h | 29 - include/llvm/IR/IntrinsicInst.h | 90 +- include/llvm/IR/Intrinsics.td | 15 +- include/llvm/IR/ModuleSummaryIndex.h | 26 +- include/llvm/IR/ModuleSummaryIndexYAML.h | 18 + include/llvm/IR/Operator.h | 1 - include/llvm/IR/PatternMatch.h | 36 +- include/llvm/LTO/LTO.h | 33 +- include/llvm/LTO/legacy/LTOModule.h | 2 +- include/llvm/MC/MCSymbolWasm.h | 6 +- include/llvm/MC/MCWasmObjectWriter.h | 15 +- include/llvm/Object/ArchiveWriter.h | 1 + include/llvm/Object/WindowsResource.h | 12 +- include/llvm/ObjectYAML/COFFYAML.h | 4 + .../ObjectYAML/CodeViewYAMLDebugSections.h | 23 +- include/llvm/ObjectYAML/CodeViewYAMLTypes.h | 3 + include/llvm/Option/Arg.h | 15 +- include/llvm/Option/ArgList.h | 52 +- include/llvm/Option/OptSpecifier.h | 40 +- include/llvm/Option/OptTable.h | 19 +- include/llvm/Option/Option.h | 15 +- include/llvm/Support/BinaryStreamArray.h | 6 + include/llvm/Support/DebugCounter.h | 6 +- include/llvm/Support/FormatAdapters.h | 13 +- include/llvm/Support/FormatCommon.h | 20 +- include/llvm/Support/MathExtras.h | 107 +- include/llvm/Support/ThreadPool.h | 28 +- include/llvm/TableGen/Main.h | 10 +- include/llvm/TableGen/Record.h | 150 +- include/llvm/TableGen/SetTheory.h | 6 +- include/llvm/TableGen/StringMatcher.h | 9 +- .../llvm/Target/TargetLoweringObjectFile.h | 7 +- include/llvm/Target/TargetRegisterInfo.h | 10 + include/llvm/Testing/Support/Error.h | 69 + include/llvm/Testing/Support/SupportHelpers.h | 47 + .../llvm/Transforms/Scalar/GVNExpression.h | 5 +- include/llvm/Transforms/Utils/CodeExtractor.h | 21 +- include/llvm/Transforms/Utils/Mem2Reg.h | 2 +- lib/Analysis/BasicAliasAnalysis.cpp | 22 +- lib/Analysis/CallGraphSCCPass.cpp | 8 +- lib/Analysis/DivergenceAnalysis.cpp | 2 +- lib/Analysis/MemorySSA.cpp | 2 +- lib/Analysis/ScalarEvolution.cpp | 129 +- lib/Analysis/TargetTransformInfo.cpp | 4 + lib/Analysis/ValueTracking.cpp | 5 +- lib/Bitcode/Reader/BitcodeReader.cpp | 87 +- lib/Bitcode/Reader/MetadataLoader.cpp | 123 +- lib/Bitcode/Writer/BitcodeWriter.cpp | 52 +- lib/CMakeLists.txt | 1 + lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 6 +- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 6 +- lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 2 +- lib/CodeGen/AsmPrinter/DwarfDebug.h | 7 + lib/CodeGen/AsmPrinter/DwarfExpression.cpp | 33 +- lib/CodeGen/AsmPrinter/DwarfExpression.h | 3 + lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 6 +- lib/CodeGen/CodeGenPrepare.cpp | 2 +- lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 81 +- lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 18 + lib/CodeGen/MachineBlockPlacement.cpp | 10 +- lib/CodeGen/MachineLICM.cpp | 7 +- lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 62 +- .../SelectionDAG/FunctionLoweringInfo.cpp | 26 + lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 15 +- .../SelectionDAG/LegalizeIntegerTypes.cpp | 21 +- lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 18 + .../SelectionDAG/SelectionDAGBuilder.cpp | 61 +- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 79 + lib/CodeGen/SplitKit.cpp | 3 +- lib/CodeGen/StackColoring.cpp | 237 +- lib/CodeGen/TargetLoweringBase.cpp | 28 +- lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 49 +- lib/DebugInfo/CodeView/CMakeLists.txt | 3 +- .../CodeView/DebugStringTableSubsection.cpp | 5 + .../CodeView/DebugSubsectionRecord.cpp | 2 +- .../CodeView/DebugSubsectionVisitor.cpp | 37 +- .../CodeView/StringsAndChecksums.cpp | 55 + lib/DebugInfo/CodeView/SymbolDumper.cpp | 8 +- .../CodeView/SymbolRecordMapping.cpp | 4 +- lib/DebugInfo/CodeView/TypeDatabase.cpp | 71 +- lib/DebugInfo/CodeView/TypeIndex.cpp | 81 +- lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp | 2 +- lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 7 + lib/DebugInfo/DWARF/DWARFContext.cpp | 249 +- lib/DebugInfo/DWARF/DWARFDebugFrame.cpp | 23 +- lib/DebugInfo/DWARF/DWARFVerifier.cpp | 34 + .../PDB/Native/DbiModuleDescriptorBuilder.cpp | 2 +- lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp | 34 +- lib/DebugInfo/PDB/Native/InfoStream.cpp | 4 + lib/DebugInfo/PDB/Native/PDBFile.cpp | 10 + lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp | 10 + lib/DebugInfo/PDB/Native/PDBStringTable.cpp | 3 +- .../PDB/Native/PDBStringTableBuilder.cpp | 5 + lib/DebugInfo/PDB/Native/PublicsStream.cpp | 9 + lib/DebugInfo/PDB/Native/TpiHashing.cpp | 1 + lib/DebugInfo/PDB/UDTLayout.cpp | 5 +- lib/Fuzzer/FuzzerDriver.cpp | 4 +- lib/Fuzzer/FuzzerLoop.cpp | 4 +- lib/Fuzzer/FuzzerTracePC.cpp | 23 + lib/Fuzzer/FuzzerTracePC.h | 35 +- lib/Fuzzer/test/AbsNegAndConstant64Test.cpp | 2 +- lib/Fuzzer/test/CMakeLists.txt | 3 + .../test/FourIndependentBranchesTest.cpp | 1 + lib/Fuzzer/test/FuzzerUnittest.cpp | 12 + lib/Fuzzer/test/ShrinkControlFlowTest.cpp | 1 + lib/Fuzzer/test/SimpleHashTest.cpp | 2 +- lib/Fuzzer/test/SingleStrncmpTest.cpp | 1 + lib/Fuzzer/test/TableLookupTest.cpp | 3 +- lib/Fuzzer/test/fuzzer-dirs.test | 8 +- lib/Fuzzer/test/inline-8bit-counters.test | 4 + .../test/inline-8bit-counters/CMakeLists.txt | 12 + lib/Fuzzer/test/trace-pc/CMakeLists.txt | 3 +- lib/IR/ConstantFold.cpp | 9 +- lib/IR/ConstantsContext.h | 18 - lib/IR/DebugInfoMetadata.cpp | 28 +- lib/IR/IRBuilder.cpp | 15 +- lib/IR/Metadata.cpp | 2 +- lib/IR/ModuleSummaryIndex.cpp | 13 + lib/IR/Verifier.cpp | 39 +- lib/LLVMBuild.txt | 1 + lib/LTO/LTO.cpp | 196 +- lib/LTO/LTOModule.cpp | 12 +- lib/MC/MCParser/ELFAsmParser.cpp | 2 + lib/MC/MCSectionELF.cpp | 2 + lib/MC/WasmObjectWriter.cpp | 43 +- lib/Object/ArchiveWriter.cpp | 14 +- lib/Object/ELF.cpp | 1 + lib/Object/IRSymtab.cpp | 6 +- lib/Object/WindowsResource.cpp | 156 +- lib/ObjectYAML/COFFYAML.cpp | 11 +- lib/ObjectYAML/CodeViewYAMLDebugSections.cpp | 338 +- lib/ObjectYAML/CodeViewYAMLSymbols.cpp | 64 +- lib/ObjectYAML/CodeViewYAMLTypes.cpp | 40 + lib/ObjectYAML/ELFYAML.cpp | 1 + lib/Option/Arg.cpp | 10 +- lib/Option/ArgList.cpp | 21 +- lib/Option/OptTable.cpp | 40 +- lib/Option/Option.cpp | 10 +- lib/Passes/PassBuilder.cpp | 6 +- lib/Support/BinaryStreamWriter.cpp | 4 +- lib/Support/DebugCounter.cpp | 6 +- lib/Support/FoldingSet.cpp | 42 +- lib/Support/ThreadPool.cpp | 19 +- lib/Support/Unix/Program.inc | 10 - lib/TableGen/Record.cpp | 43 +- lib/TableGen/SetTheory.cpp | 20 +- lib/Target/AArch64/AArch64.td | 1 + lib/Target/AArch64/AArch64FastISel.cpp | 8 + lib/Target/AArch64/AArch64ISelLowering.cpp | 2 +- .../AArch64/AArch64SchedFalkorDetails.td | 61 +- lib/Target/AArch64/AArch64Subtarget.cpp | 4 + .../AArch64/AArch64TargetTransformInfo.h | 2 +- lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp | 2 +- .../AMDGPU/AMDGPUAnnotateUniformValues.cpp | 2 +- lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp | 34 +- .../AMDGPU/AMDGPUInstructionSelector.cpp | 10 +- lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp | 2 + .../AMDGPU/AMDGPUTargetTransformInfo.cpp | 15 +- lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h | 3 +- .../AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 21 + lib/Target/AMDGPU/FLATInstructions.td | 77 +- lib/Target/AMDGPU/SIISelLowering.cpp | 14 +- lib/Target/AMDGPU/SIInstrInfo.cpp | 19 +- lib/Target/AMDGPU/SIInstrInfo.td | 12 + lib/Target/ARM/ARMCallLowering.cpp | 55 +- lib/Target/ARM/ARMInstrVFP.td | 18 +- lib/Target/ARM/ARMLegalizerInfo.cpp | 45 + lib/Target/ARM/ARMTargetTransformInfo.h | 2 +- lib/Target/BPF/BPFAsmPrinter.cpp | 5 +- lib/Target/BPF/BPFISelDAGToDAG.cpp | 240 +- lib/Target/BPF/BPFInstrInfo.td | 14 +- lib/Target/Hexagon/HexagonGenMux.cpp | 52 +- lib/Target/Hexagon/HexagonISelDAGToDAG.cpp | 15 + .../Hexagon/HexagonLoopIdiomRecognition.cpp | 3 +- lib/Target/Hexagon/HexagonPatterns.td | 19 +- lib/Target/Hexagon/HexagonTargetMachine.cpp | 8 +- lib/Target/Mips/MipsISelLowering.cpp | 135 +- lib/Target/Mips/MipsInstrInfo.cpp | 9 +- lib/Target/Mips/MipsLongBranch.cpp | 12 +- lib/Target/Mips/MipsSEISelDAGToDAG.cpp | 99 +- lib/Target/Mips/MipsSEISelDAGToDAG.h | 3 +- lib/Target/Mips/MipsSEISelLowering.cpp | 176 - lib/Target/Mips/MipsSubtarget.h | 2 +- lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 26 - lib/Target/PowerPC/PPCISelLowering.cpp | 118 +- lib/Target/PowerPC/PPCISelLowering.h | 22 + lib/Target/PowerPC/PPCInstr64Bit.td | 10 + lib/Target/PowerPC/PPCInstrInfo.cpp | 2 +- lib/Target/PowerPC/PPCInstrInfo.td | 13 + lib/Target/PowerPC/PPCInstrVSX.td | 10 + lib/Target/PowerPC/PPCRegisterInfo.cpp | 14 + lib/Target/PowerPC/PPCRegisterInfo.h | 1 + lib/Target/PowerPC/PPCTargetTransformInfo.cpp | 2 +- lib/Target/PowerPC/PPCTargetTransformInfo.h | 2 +- .../SystemZ/SystemZTargetTransformInfo.cpp | 2 +- .../SystemZ/SystemZTargetTransformInfo.h | 2 +- .../MCTargetDesc/WebAssemblyTargetStreamer.h | 4 +- .../WebAssemblyWasmObjectWriter.cpp | 25 +- .../WebAssembly/WebAssemblyAsmPrinter.cpp | 10 +- .../WebAssemblyTargetTransformInfo.cpp | 2 +- .../WebAssemblyTargetTransformInfo.h | 2 +- lib/Target/X86/X86ISelLowering.cpp | 218 +- lib/Target/X86/X86InstrAVX512.td | 2 + lib/Target/X86/X86InstrFragmentsSIMD.td | 12 +- lib/Target/X86/X86InstrInfo.cpp | 134 +- lib/Testing/CMakeLists.txt | 1 + lib/Testing/LLVMBuild.txt | 19 + lib/Testing/Support/CMakeLists.txt | 12 + lib/Testing/Support/Error.cpp | 22 + lib/Testing/Support/LLVMBuild.txt | 22 + lib/Transforms/IPO/CrossDSOCFI.cpp | 11 + lib/Transforms/IPO/Inliner.cpp | 53 +- lib/Transforms/IPO/LowerTypeTests.cpp | 166 +- lib/Transforms/IPO/PartialInlining.cpp | 492 +- lib/Transforms/IPO/PassManagerBuilder.cpp | 6 +- lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp | 50 +- .../InstCombine/InstCombineAndOrXor.cpp | 113 +- .../InstCombine/InstCombineCalls.cpp | 113 +- .../InstCombine/InstCombineInternal.h | 9 +- .../InstCombine/InstCombineShifts.cpp | 14 +- lib/Transforms/Instrumentation/CMakeLists.txt | 1 + .../Instrumentation/IndirectCallPromotion.cpp | 353 -- .../Instrumentation/InstrProfiling.cpp | 12 +- .../Instrumentation/PGOMemOPSizeOpt.cpp | 419 ++ .../Instrumentation/SanitizerCoverage.cpp | 2 +- .../Scalar/CorrelatedValuePropagation.cpp | 2 +- lib/Transforms/Scalar/EarlyCSE.cpp | 5 +- lib/Transforms/Scalar/GVNSink.cpp | 11 + lib/Transforms/Scalar/LoopIdiomRecognize.cpp | 24 +- lib/Transforms/Scalar/NewGVN.cpp | 4 +- .../Scalar/RewriteStatepointsForGC.cpp | 69 +- lib/Transforms/Scalar/SCCP.cpp | 11 - lib/Transforms/Utils/CodeExtractor.cpp | 219 +- lib/Transforms/Utils/PredicateInfo.cpp | 3 + lib/Transforms/Utils/SimplifyIndVar.cpp | 14 +- test/Analysis/ScalarEvolution/limit-depth.ll | 44 + test/Assembler/diexpression.ll | 14 +- test/Bitcode/DIExpression-deref.ll | 6 +- test/Bitcode/DIExpression-minus-upgrade.ll | 16 + test/Bitcode/DIExpression-minus-upgrade.ll.bc | Bin 0 -> 988 bytes test/Bitcode/DIGlobalVariableExpression.ll | 2 +- test/Bitcode/upgrade-linker-options.ll | 15 + .../GlobalISel/legalize-load-store.mir | 8 +- test/CodeGen/AArch64/arm64-sincos.ll | 54 +- test/CodeGen/AArch64/fast-isel-sp-adjust.ll | 288 ++ test/CodeGen/AArch64/misched-fusion-aes.ll | 77 +- test/CodeGen/AArch64/sincos-expansion.ll | 42 +- test/CodeGen/AArch64/swifterror.ll | 27 + .../GlobalISel/inst-select-load-flat.mir | 2 +- .../GlobalISel/inst-select-store-flat.mir | 2 +- .../AMDGPU/GlobalISel/legalize-add.mir | 22 + test/CodeGen/AMDGPU/always-uniform.ll | 21 + .../AMDGPU/cgp-addressing-modes-flat.ll | 123 +- ...code-object-metadata-kernel-debug-props.ll | 4 +- .../AMDGPU/constant-fold-imm-immreg.mir | 70 +- test/CodeGen/AMDGPU/flat-address-space.ll | 56 +- test/CodeGen/AMDGPU/flat_atomics.ll | 168 +- test/CodeGen/AMDGPU/global_smrd_cfg.ll | 33 + test/CodeGen/AMDGPU/inserted-wait-states.mir | 10 +- test/CodeGen/AMDGPU/limit-coalesce.mir | 6 +- ...dependent-subregs-invalid-mac-operands.mir | 4 +- test/CodeGen/AMDGPU/sdwa-scalar-ops.mir | 16 +- test/CodeGen/AMDGPU/waitcnt.mir | 22 +- .../ARM/GlobalISel/arm-irtranslator.ll | 195 +- .../CodeGen/ARM/GlobalISel/arm-isel-divmod.ll | 21 + .../ARM/GlobalISel/arm-legalize-divmod.mir | 75 + .../CodeGen/ARM/GlobalISel/arm-unsupported.ll | 8 + test/CodeGen/ARM/cortex-a57-misched-vfma.ll | 38 + test/CodeGen/ARM/debug-info-blocks.ll | 6 +- test/CodeGen/ARM/sincos.ll | 67 +- test/CodeGen/ARM/swifterror.ll | 28 + test/CodeGen/BPF/rodata_1.ll | 52 + test/CodeGen/BPF/rodata_2.ll | 51 + test/CodeGen/BPF/rodata_3.ll | 41 + test/CodeGen/BPF/rodata_4.ll | 43 + .../Hexagon/loop-idiom/pmpy-shiftconv-fail.ll | 48 + test/CodeGen/Hexagon/mulh.ll | 27 + test/CodeGen/Hexagon/mux-kill.mir | 15 + test/CodeGen/Hexagon/mux-kill2.mir | 17 + .../CodeGen/Hexagon/store-imm-stack-object.ll | 86 + test/CodeGen/Mips/2008-06-05-Carry.ll | 13 +- test/CodeGen/Mips/brundef.ll | 26 + test/CodeGen/Mips/dsp-patterns.ll | 4 +- test/CodeGen/Mips/llcarry.ll | 11 +- test/CodeGen/Mips/llvm-ir/add.ll | 380 +- test/CodeGen/Mips/llvm-ir/sub.ll | 170 +- test/CodeGen/Mips/longbranch.ll | 40 +- test/CodeGen/Mips/madd-msub.ll | 81 +- test/CodeGen/PowerPC/atomic-2.ll | 2 +- test/CodeGen/PowerPC/atomics-constant.ll | 2 +- test/CodeGen/PowerPC/atomics-regression.ll | 20 +- test/CodeGen/PowerPC/licm-tocReg.ll | 110 + test/CodeGen/PowerPC/logic-ops-on-compares.ll | 73 +- test/CodeGen/PowerPC/ppc64-P9-mod.ll | 263 ++ test/CodeGen/PowerPC/testComparesinesll.ll | 125 - test/CodeGen/PowerPC/testComparesineull.ll | 125 - test/CodeGen/PowerPC/testComparesllnesll.ll | 125 - test/CodeGen/PowerPC/testComparesllneull.ll | 125 - test/CodeGen/PowerPC/vec_revb.ll | 54 + test/CodeGen/SystemZ/fp-sincos-01.ll | 55 +- test/CodeGen/X86/2012-01-11-split-cv.ll | 3 +- test/CodeGen/X86/StackColoring.ll | 64 + test/CodeGen/X86/add-sub-nsw-nuw.ll | 3 +- test/CodeGen/X86/addcarry.ll | 24 + test/CodeGen/X86/avx-vperm2x128.ll | 20 +- test/CodeGen/X86/bt.ll | 209 +- test/CodeGen/X86/cmov-into-branch.ll | 24 +- test/CodeGen/X86/combine-64bit-vec-binop.ll | 23 +- .../element-wise-atomic-memory-intrinsics.ll | 45 +- test/CodeGen/X86/fast-isel-select-sse.ll | 26 +- test/CodeGen/X86/fp-logic-replace.ll | 2 +- test/CodeGen/X86/fp-logic.ll | 23 +- test/CodeGen/X86/fp-select-cmp-and.ll | 20 +- test/CodeGen/X86/immediate_merging64.ll | 4 +- test/CodeGen/X86/lea-opt-with-debug.mir | 2 +- test/CodeGen/X86/loop-search.ll | 3 +- test/CodeGen/X86/mask-negated-bool.ll | 8 +- test/CodeGen/X86/memset-2.ll | 6 +- test/CodeGen/X86/memset-nonzero.ll | 12 +- test/CodeGen/X86/memset64-on-x86-32.ll | 3 +- test/CodeGen/X86/negate-i1.ll | 10 +- test/CodeGen/X86/negate-shift.ll | 6 +- test/CodeGen/X86/negate.ll | 8 +- test/CodeGen/X86/negative-sin.ll | 14 +- test/CodeGen/X86/no-sse2-avg.ll | 3 +- test/CodeGen/X86/not-and-simplify.ll | 1 - test/CodeGen/X86/pr13577.ll | 8 +- test/CodeGen/X86/pr18014.ll | 3 +- test/CodeGen/X86/pr32368.ll | 153 + test/CodeGen/X86/rem.ll | 8 +- test/CodeGen/X86/sar_fold64.ll | 8 +- test/CodeGen/X86/select-with-and-or.ll | 16 +- test/CodeGen/X86/sext-setcc-self.ll | 8 +- test/CodeGen/X86/shift-pcmp.ll | 4 +- test/CodeGen/X86/sincos-opt.ll | 139 +- .../CodeGen/X86/sse-intrinsics-x86-upgrade.ll | 2 +- .../X86/sse41-intrinsics-x86-upgrade.ll | 10 +- test/CodeGen/X86/stack-folding-int-avx512.ll | 93 +- .../CodeGen/X86/stack-folding-int-avx512vl.ll | 74 +- test/CodeGen/X86/statepoint-live-in.ll | 8 +- test/CodeGen/X86/swifterror.ll | 108 + test/CodeGen/X86/urem-i8-constant.ll | 3 +- test/CodeGen/X86/urem-power-of-two.ll | 7 +- test/CodeGen/X86/vec3.ll | 4 +- test/CodeGen/X86/vector-compare-combines.ll | 4 +- test/CodeGen/X86/vector-shuffle-256-v16.ll | 18 + test/CodeGen/X86/vzero-excess.ll | 2 +- test/CodeGen/X86/x86-interleaved-access.ll | 44 +- test/DebugInfo/COFF/array-odr-violation.ll | 6 +- test/DebugInfo/COFF/inlining-same-name.ll | 3 +- test/DebugInfo/Generic/block-asan.ll | 4 +- .../Inputs/dwarfdump-str-offsets-dwp.x86_64.o | Bin 0 -> 3328 bytes test/DebugInfo/Inputs/dwarfdump-str-offsets.s | 250 -- test/DebugInfo/Inputs/dwarfdump-test-zlib.cc | 3 +- .../Inputs/dwarfdump-test-zlib.o.elf-x86-64 | Bin 0 -> 4688 bytes .../MIR/ARM/split-superreg-complex.mir | 2 +- test/DebugInfo/PDB/Inputs/unknown-symbol.yaml | 10 + test/DebugInfo/PDB/pdb-unknown-symbol.test | 6 + test/DebugInfo/PDB/pdb-yaml-types.test | 74 - .../PDB/pdbdump-debug-subsections.test | 146 +- test/DebugInfo/PDB/pdbdump-headers.test | 3971 +++++------------ .../PDB/pdbdump-merge-ids-and-types.test | 106 +- test/DebugInfo/PDB/pdbdump-mergeids.test | 43 +- test/DebugInfo/PDB/pdbdump-mergetypes.test | 60 +- test/DebugInfo/PDB/pdbdump-raw-blocks.test | 64 +- test/DebugInfo/PDB/pdbdump-raw-stream.test | 51 +- test/DebugInfo/PDB/pdbdump-readwrite.test | 73 +- test/DebugInfo/X86/block-capture.ll | 2 +- .../X86/debug-info-block-captured-self.ll | 4 +- test/DebugInfo/X86/debug-info-blocks.ll | 2 +- test/DebugInfo/X86/double-declare.ll | 44 + test/DebugInfo/X86/dw_op_minus.ll | 4 +- test/DebugInfo/X86/dw_op_minus_direct.ll | 2 +- test/DebugInfo/X86/safestack-byval.ll | 4 +- test/DebugInfo/X86/stack-value-dwarf2.ll | 2 +- test/DebugInfo/X86/unattached-global.ll | 2 +- test/DebugInfo/dwarfdump-str-offsets-dwp.test | 56 + test/DebugInfo/dwarfdump-zlib.test | 5 + .../InstrProfiling/always_inline.ll | 28 + .../SanitizerCoverage/inline-8bit-counters.ll | 2 +- .../X86/Inputs/dead-strip-fulllto.ll | 16 + test/LTO/Resolution/X86/dead-strip-fulllto.ll | 37 + test/LTO/Resolution/X86/symtab-elf.ll | 4 +- test/LTO/Resolution/X86/symtab.ll | 4 +- test/LibDriver/use-paths.test | 24 + test/MC/AMDGPU/flat-gfx9.s | 40 + test/MC/AMDGPU/flat.s | 3 +- test/MC/COFF/cv-compiler-info.ll | 6 +- test/MC/COFF/linker-options.ll | 8 +- .../Disassembler/PowerPC/ppc64-encoding.txt | 12 + .../Disassembler/PowerPC/ppc64le-encoding.txt | 12 + test/MC/ELF/section.s | 12 + test/MC/MachO/linker-options.ll | 7 +- test/MC/PowerPC/ppc64-encoding.s | 13 + test/MC/WebAssembly/external-data.ll | 4 +- test/MC/WebAssembly/external-func-address.ll | 25 + test/MC/WebAssembly/func-address.ll | 48 + test/ThinLTO/X86/cfi-icall.ll | 29 + test/Transforms/CodeExtractor/live_shrink.ll | 67 + .../CodeExtractor/live_shrink_gep.ll | 66 + .../CodeExtractor/live_shrink_hoist.ll | 66 + .../CodeExtractor/live_shrink_multiple.ll | 66 + .../CodeExtractor/live_shrink_unsafe.ll | 94 + test/Transforms/CrossDSOCFI/cfi_functions.ll | 23 + test/Transforms/EarlyCSE/pr33406.ll | 26 + test/Transforms/GVN/pr32314.ll | 53 + test/Transforms/GlobalMerge/debug-info.ll | 2 +- test/Transforms/Inline/always-inline.ll | 11 + test/Transforms/InstCombine/debuginfo-dce.ll | 12 +- .../element-atomic-memcpy-to-loads.ll | 30 +- test/Transforms/InstCombine/ffs-1.ll | 156 +- test/Transforms/InstCombine/lshr.ll | 19 +- test/Transforms/InstCombine/onehot_merge.ll | 76 + test/Transforms/InstCombine/or-xor.ll | 44 + .../InstCombine/select-with-bitwise-ops.ll | 268 ++ test/Transforms/InstCombine/shift.ll | 10 + test/Transforms/InstCombine/xor2.ll | 33 + .../LoopIdiom/X86/unordered-atomic-memcpy.ll | 36 +- .../unordered-atomic-memcpy-noarch.ll | 2 +- .../LowerTypeTests/Inputs/import-icall.yaml | 19 + .../Transforms/LowerTypeTests/export-icall.ll | 70 + .../Transforms/LowerTypeTests/import-icall.ll | 40 + test/Transforms/PGOProfile/memop_size_opt.ll | 9 +- .../drop-invalid-metadata.ll | 92 + .../Transforms/SLPVectorizer/X86/arith-add.ll | 58 + test/Transforms/SLPVectorizer/X86/arith-fp.ll | 180 +- .../Transforms/SLPVectorizer/X86/arith-mul.ll | 74 + .../Transforms/SLPVectorizer/X86/arith-sub.ll | 58 + test/Transforms/SafeStack/X86/debug-loc.ll | 4 +- test/Transforms/SafeStack/X86/debug-loc2.ll | 6 +- test/Transforms/Util/PredicateInfo/pr33456.ll | 68 + test/Transforms/Util/PredicateInfo/pr33457.ll | 93 + .../element-wise-atomic-memory-intrinsics.ll | 20 +- test/lit.cfg | 2 +- .../llvm-cvtres/Inputs/combined.obj.coff | Bin 0 -> 4040 bytes test/tools/llvm-cvtres/Inputs/languages.rc | 36 + test/tools/llvm-cvtres/Inputs/languages.res | Bin 0 -> 452 bytes .../Inputs/test_resource.obj.coff.arm | Bin 0 -> 3472 bytes .../Inputs/test_resource.obj.coff.x64 | Bin 0 -> 3472 bytes test/tools/llvm-cvtres/basic.test | 4 - test/tools/llvm-cvtres/combined.test | 313 ++ test/tools/llvm-cvtres/help.test | 13 + test/tools/llvm-cvtres/machine.test | 59 + test/tools/llvm-cvtres/object.test | 227 +- test/tools/llvm-cvtres/parse.test | 2 +- .../X86/apple_names_verify_buckets.s | 192 + test/tools/llvm-pdbdump/raw-stream-data.test | 47 - test/tools/llvm-readobj/resources.test | 230 +- tools/llvm-ar/llvm-ar.cpp | 12 +- tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp | 2 + tools/llvm-cvtres/llvm-cvtres.cpp | 16 +- tools/llvm-dwarfdump/llvm-dwarfdump.cpp | 1 + tools/llvm-pdbutil/CMakeLists.txt | 5 +- tools/llvm-pdbutil/FormatUtil.cpp | 49 + tools/llvm-pdbutil/FormatUtil.h | 120 + tools/llvm-pdbutil/LLVMOutputStyle.cpp | 1188 ----- tools/llvm-pdbutil/LinePrinter.cpp | 33 +- tools/llvm-pdbutil/LinePrinter.h | 31 +- tools/llvm-pdbutil/MinimalSymbolDumper.cpp | 749 ++++ tools/llvm-pdbutil/MinimalSymbolDumper.h | 47 + tools/llvm-pdbutil/MinimalTypeDumper.cpp | 543 +++ tools/llvm-pdbutil/MinimalTypeDumper.h | 61 + .../PrettyClassLayoutGraphicalDumper.cpp | 24 +- tools/llvm-pdbutil/RawOutputStyle.cpp | 1064 +++++ .../{LLVMOutputStyle.h => RawOutputStyle.h} | 40 +- tools/llvm-pdbutil/YAMLOutputStyle.cpp | 34 +- tools/llvm-pdbutil/llvm-pdbutil.cpp | 217 +- tools/llvm-pdbutil/llvm-pdbutil.h | 49 +- tools/llvm-readobj/COFFDumper.cpp | 45 +- tools/llvm-readobj/ELFDumper.cpp | 2 + tools/llvm-stress/llvm-stress.cpp | 20 +- tools/obj2yaml/CMakeLists.txt | 1 + tools/obj2yaml/coff2yaml.cpp | 57 + tools/yaml2obj/CMakeLists.txt | 1 + tools/yaml2obj/yaml2coff.cpp | 56 + tools/yaml2obj/yaml2obj.cpp | 1 + unittests/ADT/SCCIteratorTest.cpp | 6 +- unittests/ADT/SmallVectorTest.cpp | 20 +- unittests/ADT/StringRefTest.cpp | 3 +- unittests/CodeGen/LowLevelTypeTest.cpp | 3 +- unittests/DebugInfo/CodeView/CMakeLists.txt | 2 + unittests/DebugInfo/CodeView/ErrorChecking.h | 70 - .../CodeView/RandomAccessVisitorTest.cpp | 18 +- .../CodeView/TypeIndexDiscoveryTest.cpp | 1 - .../DebugInfo/DWARF/DWARFDebugInfoTest.cpp | 12 +- unittests/DebugInfo/PDB/CMakeLists.txt | 2 + unittests/DebugInfo/PDB/ErrorChecking.h | 61 - unittests/DebugInfo/PDB/HashTableTest.cpp | 10 +- unittests/DebugInfo/PDB/MSFBuilderTest.cpp | 101 +- .../DebugInfo/PDB/MappedBlockStreamTest.cpp | 119 +- .../DebugInfo/PDB/StringTableBuilderTest.cpp | 19 +- .../DebugInfo/PDB/TypeServerHandlerTest.cpp | 32 +- unittests/IR/MetadataTest.cpp | 14 +- unittests/IR/PatternMatch.cpp | 77 +- unittests/MI/LiveIntervalTest.cpp | 3 +- unittests/Support/BinaryStreamTest.cpp | 163 +- unittests/Support/CMakeLists.txt | 2 +- unittests/Support/CommandLineTest.cpp | 9 +- .../Support/DynamicLibrary/CMakeLists.txt | 4 +- .../DynamicLibrary/DynamicLibraryTest.cpp | 2 - .../Support/DynamicLibrary/ExportedFuncs.cxx | 16 + .../Support/DynamicLibrary/PipSqueak.cxx | 3 +- unittests/Support/DynamicLibrary/PipSqueak.h | 2 + unittests/Support/FormatVariadicTest.cpp | 2 + unittests/Target/AArch64/InstSizes.cpp | 15 +- .../Transforms/Scalar/LoopPassManagerTest.cpp | 11 + utils/TableGen/CodeGenDAGPatterns.cpp | 4 +- utils/opt-viewer/opt-diff.py | 2 +- utils/opt-viewer/opt-stats.py | 2 +- utils/opt-viewer/opt-viewer.py | 2 +- utils/release/test-release.sh | 5 +- utils/update_test_checks.py | 96 +- 595 files changed, 17871 insertions(+), 11385 deletions(-) create mode 100644 include/llvm/DebugInfo/CodeView/StringsAndChecksums.h create mode 100644 include/llvm/Testing/Support/Error.h create mode 100644 include/llvm/Testing/Support/SupportHelpers.h create mode 100644 lib/DebugInfo/CodeView/StringsAndChecksums.cpp create mode 100644 lib/Fuzzer/test/inline-8bit-counters.test create mode 100644 lib/Fuzzer/test/inline-8bit-counters/CMakeLists.txt create mode 100644 lib/Testing/CMakeLists.txt create mode 100644 lib/Testing/LLVMBuild.txt create mode 100644 lib/Testing/Support/CMakeLists.txt create mode 100644 lib/Testing/Support/Error.cpp create mode 100644 lib/Testing/Support/LLVMBuild.txt create mode 100644 lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp create mode 100644 test/Analysis/ScalarEvolution/limit-depth.ll create mode 100644 test/Bitcode/DIExpression-minus-upgrade.ll create mode 100644 test/Bitcode/DIExpression-minus-upgrade.ll.bc create mode 100644 test/Bitcode/upgrade-linker-options.ll create mode 100644 test/CodeGen/AArch64/fast-isel-sp-adjust.ll create mode 100644 test/CodeGen/AMDGPU/GlobalISel/legalize-add.mir create mode 100644 test/CodeGen/AMDGPU/always-uniform.ll create mode 100644 test/CodeGen/BPF/rodata_1.ll create mode 100644 test/CodeGen/BPF/rodata_2.ll create mode 100644 test/CodeGen/BPF/rodata_3.ll create mode 100644 test/CodeGen/BPF/rodata_4.ll create mode 100644 test/CodeGen/Hexagon/loop-idiom/pmpy-shiftconv-fail.ll create mode 100644 test/CodeGen/Hexagon/mulh.ll create mode 100644 test/CodeGen/Hexagon/mux-kill.mir create mode 100644 test/CodeGen/Hexagon/mux-kill2.mir create mode 100644 test/CodeGen/Hexagon/store-imm-stack-object.ll create mode 100644 test/CodeGen/Mips/brundef.ll create mode 100644 test/CodeGen/PowerPC/licm-tocReg.ll create mode 100644 test/CodeGen/PowerPC/ppc64-P9-mod.ll delete mode 100644 test/CodeGen/PowerPC/testComparesinesll.ll delete mode 100644 test/CodeGen/PowerPC/testComparesineull.ll delete mode 100644 test/CodeGen/PowerPC/testComparesllnesll.ll delete mode 100644 test/CodeGen/PowerPC/testComparesllneull.ll create mode 100644 test/CodeGen/PowerPC/vec_revb.ll create mode 100644 test/CodeGen/X86/pr32368.ll create mode 100644 test/DebugInfo/Inputs/dwarfdump-str-offsets-dwp.x86_64.o create mode 100644 test/DebugInfo/Inputs/dwarfdump-test-zlib.o.elf-x86-64 create mode 100644 test/DebugInfo/PDB/Inputs/unknown-symbol.yaml create mode 100644 test/DebugInfo/PDB/pdb-unknown-symbol.test delete mode 100644 test/DebugInfo/PDB/pdb-yaml-types.test create mode 100644 test/DebugInfo/X86/double-declare.ll create mode 100644 test/DebugInfo/dwarfdump-str-offsets-dwp.test create mode 100644 test/Instrumentation/InstrProfiling/always_inline.ll create mode 100644 test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll create mode 100644 test/LTO/Resolution/X86/dead-strip-fulllto.ll create mode 100644 test/LibDriver/use-paths.test create mode 100644 test/MC/AMDGPU/flat-gfx9.s create mode 100644 test/MC/WebAssembly/external-func-address.ll create mode 100644 test/MC/WebAssembly/func-address.ll create mode 100644 test/ThinLTO/X86/cfi-icall.ll create mode 100644 test/Transforms/CodeExtractor/live_shrink.ll create mode 100644 test/Transforms/CodeExtractor/live_shrink_gep.ll create mode 100644 test/Transforms/CodeExtractor/live_shrink_hoist.ll create mode 100644 test/Transforms/CodeExtractor/live_shrink_multiple.ll create mode 100644 test/Transforms/CodeExtractor/live_shrink_unsafe.ll create mode 100644 test/Transforms/CrossDSOCFI/cfi_functions.ll create mode 100644 test/Transforms/EarlyCSE/pr33406.ll create mode 100644 test/Transforms/GVN/pr32314.ll create mode 100644 test/Transforms/LowerTypeTests/Inputs/import-icall.yaml create mode 100644 test/Transforms/LowerTypeTests/export-icall.ll create mode 100644 test/Transforms/LowerTypeTests/import-icall.ll create mode 100644 test/Transforms/RewriteStatepointsForGC/drop-invalid-metadata.ll create mode 100644 test/Transforms/Util/PredicateInfo/pr33456.ll create mode 100644 test/Transforms/Util/PredicateInfo/pr33457.ll create mode 100644 test/tools/llvm-cvtres/Inputs/combined.obj.coff create mode 100644 test/tools/llvm-cvtres/Inputs/languages.rc create mode 100644 test/tools/llvm-cvtres/Inputs/languages.res create mode 100644 test/tools/llvm-cvtres/Inputs/test_resource.obj.coff.arm create mode 100644 test/tools/llvm-cvtres/Inputs/test_resource.obj.coff.x64 delete mode 100644 test/tools/llvm-cvtres/basic.test create mode 100644 test/tools/llvm-cvtres/combined.test create mode 100644 test/tools/llvm-cvtres/help.test create mode 100644 test/tools/llvm-cvtres/machine.test create mode 100644 test/tools/llvm-dwarfdump/X86/apple_names_verify_buckets.s delete mode 100644 test/tools/llvm-pdbdump/raw-stream-data.test create mode 100644 tools/llvm-pdbutil/FormatUtil.cpp create mode 100644 tools/llvm-pdbutil/FormatUtil.h delete mode 100644 tools/llvm-pdbutil/LLVMOutputStyle.cpp create mode 100644 tools/llvm-pdbutil/MinimalSymbolDumper.cpp create mode 100644 tools/llvm-pdbutil/MinimalSymbolDumper.h create mode 100644 tools/llvm-pdbutil/MinimalTypeDumper.cpp create mode 100644 tools/llvm-pdbutil/MinimalTypeDumper.h create mode 100644 tools/llvm-pdbutil/RawOutputStyle.cpp rename tools/llvm-pdbutil/{LLVMOutputStyle.h => RawOutputStyle.h} (62%) delete mode 100644 unittests/DebugInfo/CodeView/ErrorChecking.h delete mode 100644 unittests/DebugInfo/PDB/ErrorChecking.h create mode 100644 unittests/Support/DynamicLibrary/ExportedFuncs.cxx diff --git a/cmake/modules/TableGen.cmake b/cmake/modules/TableGen.cmake index 17ae1c9e7717..21421e4fdbd2 100644 --- a/cmake/modules/TableGen.cmake +++ b/cmake/modules/TableGen.cmake @@ -35,38 +35,24 @@ function(tablegen project ofn) # a tablegen change, as cmake does not propagate file-level dependencies # of custom targets. See the following ticket for more information: # https://cmake.org/Bug/view.php?id=15858 - # We could always have just one dependency on both the target and - # the file, but these 2 cases would produce cleaner cmake files. - if (${${project}_TABLEGEN_TARGET} STREQUAL ${${project}_TABLEGEN_EXE}) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp - # Generate tablegen output in a temporary file. - COMMAND ${${project}_TABLEGEN_EXE} ${ARGN} -I ${CMAKE_CURRENT_SOURCE_DIR} - ${LLVM_TABLEGEN_FLAGS} - ${LLVM_TARGET_DEFINITIONS_ABSOLUTE} - -o ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp - # The file in LLVM_TARGET_DEFINITIONS may be not in the current - # directory and local_tds may not contain it, so we must - # explicitly list it here: - DEPENDS ${${project}_TABLEGEN_TARGET} ${local_tds} ${global_tds} - ${LLVM_TARGET_DEFINITIONS_ABSOLUTE} - COMMENT "Building ${ofn}..." - ) - else() - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp - # Generate tablegen output in a temporary file. - COMMAND ${${project}_TABLEGEN_EXE} ${ARGN} -I ${CMAKE_CURRENT_SOURCE_DIR} - ${LLVM_TABLEGEN_FLAGS} - ${LLVM_TARGET_DEFINITIONS_ABSOLUTE} - -o ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp - # The file in LLVM_TARGET_DEFINITIONS may be not in the current - # directory and local_tds may not contain it, so we must - # explicitly list it here: - DEPENDS ${${project}_TABLEGEN_TARGET} ${${project}_TABLEGEN_EXE} - ${local_tds} ${global_tds} - ${LLVM_TARGET_DEFINITIONS_ABSOLUTE} - COMMENT "Building ${ofn}..." - ) - endif() + # The dependency on both, the target and the file, produces the same + # dependency twice in the result file when + # ("${${project}_TABLEGEN_TARGET}" STREQUAL "${${project}_TABLEGEN_EXE}") + # but lets us having smaller and cleaner code here. + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp + # Generate tablegen output in a temporary file. + COMMAND ${${project}_TABLEGEN_EXE} ${ARGN} -I ${CMAKE_CURRENT_SOURCE_DIR} + ${LLVM_TABLEGEN_FLAGS} + ${LLVM_TARGET_DEFINITIONS_ABSOLUTE} + -o ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp + # The file in LLVM_TARGET_DEFINITIONS may be not in the current + # directory and local_tds may not contain it, so we must + # explicitly list it here: + DEPENDS ${${project}_TABLEGEN_TARGET} ${${project}_TABLEGEN_EXE} + ${local_tds} ${global_tds} + ${LLVM_TARGET_DEFINITIONS_ABSOLUTE} + COMMENT "Building ${ofn}..." + ) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn} # Only update the real output file if there are any differences. # This prevents recompilation of all the files depending on it if there diff --git a/docs/BranchWeightMetadata.rst b/docs/BranchWeightMetadata.rst index b941d0d15050..9bd8bd4ae744 100644 --- a/docs/BranchWeightMetadata.rst +++ b/docs/BranchWeightMetadata.rst @@ -64,6 +64,20 @@ Branch weights are assigned to every destination. [ , i32 ... ] } +``CallInst`` +^^^^^^^^^^^^^^^^^^ + +Calls may have branch weight metadata, containing the execution count of +the call. It is currently used in SamplePGO mode only, to augment the +block and entry counts which may not be accurate with sampling. + +.. code-block:: none + + !0 = metadata !{ + metadata !"branch_weights", + i32 + } + Other ^^^^^ diff --git a/docs/LangRef.rst b/docs/LangRef.rst index e063f6bd35fe..68aa500150ae 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -4033,26 +4033,26 @@ DICompileUnit """"""""""""" ``DICompileUnit`` nodes represent a compile unit. The ``enums:``, -``retainedTypes:``, ``subprograms:``, ``globals:``, ``imports:`` and ``macros:`` -fields are tuples containing the debug info to be emitted along with the compile -unit, regardless of code optimizations (some nodes are only emitted if there are -references to them from instructions). The ``debugInfoForProfiling:`` field is a -boolean indicating whether or not line-table discriminators are updated to -provide more-accurate debug info for profiling results. +``retainedTypes:``, ``globals:``, ``imports:`` and ``macros:`` fields are tuples +containing the debug info to be emitted along with the compile unit, regardless +of code optimizations (some nodes are only emitted if there are references to +them from instructions). The ``debugInfoForProfiling:`` field is a boolean +indicating whether or not line-table discriminators are updated to provide +more-accurate debug info for profiling results. .. code-block:: text !0 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, flags: "-O2", runtimeVersion: 2, splitDebugFilename: "abc.debug", emissionKind: FullDebug, - enums: !2, retainedTypes: !3, subprograms: !4, - globals: !5, imports: !6, macros: !7, dwoId: 0x0abcd) + enums: !2, retainedTypes: !3, globals: !4, imports: !5, + macros: !6, dwoId: 0x0abcd) Compile unit descriptors provide the root scope for objects declared in a -specific compilation unit. File descriptors are defined using this scope. -These descriptors are collected by a named metadata ``!llvm.dbg.cu``. They -keep track of subprograms, global variables, type information, and imported -entities (declarations and namespaces). +specific compilation unit. File descriptors are defined using this scope. These +descriptors are collected by a named metadata node ``!llvm.dbg.cu``. They keep +track of global variables, type information, and imported entities (declarations +and namespaces). .. _DIFile: @@ -4326,8 +4326,8 @@ and ``scope:``. containingType: !4, virtuality: DW_VIRTUALITY_pure_virtual, virtualIndex: 10, flags: DIFlagPrototyped, - isOptimized: true, templateParams: !5, - declaration: !6, variables: !7) + isOptimized: true, unit: !5, templateParams: !6, + declaration: !7, variables: !8, thrownTypes: !9) .. _DILexicalBlock: @@ -4404,7 +4404,12 @@ referenced LLVM variable relates to the source language variable. The current supported vocabulary is limited: - ``DW_OP_deref`` dereferences the top of the expression stack. -- ``DW_OP_plus, 93`` adds ``93`` to the working expression. +- ``DW_OP_plus`` pops the last two entries from the expression stack, adds + them together and appends the result to the expression stack. +- ``DW_OP_minus`` pops the last two entries from the expression stack, subtracts + the last entry from the second last entry and appends the result to the + expression stack. +- ``DW_OP_plus_uconst, 93`` adds ``93`` to the working expression. - ``DW_OP_LLVM_fragment, 16, 8`` specifies the offset and size (``16`` and ``8`` here, respectively) of the variable fragment from the working expression. Note that contrary to DW_OP_bit_piece, the offset is describing the the location @@ -4426,9 +4431,10 @@ combined with a concrete location. .. code-block:: llvm !0 = !DIExpression(DW_OP_deref) - !1 = !DIExpression(DW_OP_plus, 3) + !1 = !DIExpression(DW_OP_plus_uconst, 3) + !1 = !DIExpression(DW_OP_constu, 3, DW_OP_plus) !2 = !DIExpression(DW_OP_bit_piece, 3, 7) - !3 = !DIExpression(DW_OP_deref, DW_OP_plus, 3, DW_OP_LLVM_fragment, 3, 7) + !3 = !DIExpression(DW_OP_deref, DW_OP_constu, 3, DW_OP_plus, DW_OP_LLVM_fragment, 3, 7) !4 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef) !5 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value) @@ -5186,6 +5192,72 @@ Example: !0 = !{i32* @a} +'``prof``' Metadata +^^^^^^^^^^^^^^^^^^^ + +The ``prof`` metadata is used to record profile data in the IR. +The first operand of the metadata node indicates the profile metadata +type. There are currently 3 types: +:ref:`branch_weights`, +:ref:`function_entry_count`, and +:ref:`VP`. + +.. _prof_node_branch_weights: + +branch_weights +"""""""""""""" + +Branch weight metadata attached to a branch, select, switch or call instruction +represents the likeliness of the associated branch being taken. +For more information, see :doc:`BranchWeightMetadata`. + +.. _prof_node_function_entry_count: + +function_entry_count +"""""""""""""""""""" + +Function entry count metadata can be attached to function definitions +to record the number of times the function is called. Used with BFI +information, it is also used to derive the basic block profile count. +For more information, see :doc:`BranchWeightMetadata`. + +.. _prof_node_VP: + +VP +"" + +VP (value profile) metadata can be attached to instructions that have +value profile information. Currently this is indirect calls (where it +records the hottest callees) and calls to memory intrinsics such as memcpy, +memmove, and memset (where it records the hottest byte lengths). + +Each VP metadata node contains "VP" string, then a uint32_t value for the value +profiling kind, a uint64_t value for the total number of times the instruction +is executed, followed by uint64_t value and execution count pairs. +The value profiling kind is 0 for indirect call targets and 1 for memory +operations. For indirect call targets, each profile value is a hash +of the callee function name, and for memory operations each value is the +byte length. + +Note that the value counts do not need to add up to the total count +listed in the third operand (in practice only the top hottest values +are tracked and reported). + +Indirect call example: + +.. code-block:: llvm + + call void %f(), !prof !1 + !1 = !{!"VP", i32 0, i64 1600, i64 7651369219802541373, i64 1030, i64 -4377547752858689819, i64 410} + +Note that the VP type is 0 (the second operand), which indicates this is +an indirect call value profile data. The third operand indicates that the +indirect call executed 1600 times. The 4th and 6th operands give the +hashes of the 2 hottest target functions' names (this is the same hash used +to represent function names in the profile database), and the 5th and 7th +operands give the execution count that each of the respective prior target +functions was called. + Module Flags Metadata ===================== @@ -5352,40 +5424,6 @@ Some important flag interactions: - A module with ``Objective-C Garbage Collection`` set to 0 cannot be merged with a module with ``Objective-C GC Only`` set to 6. -Automatic Linker Flags Module Flags Metadata --------------------------------------------- - -Some targets support embedding flags to the linker inside individual object -files. Typically this is used in conjunction with language extensions which -allow source files to explicitly declare the libraries they depend on, and have -these automatically be transmitted to the linker via object files. - -These flags are encoded in the IR using metadata in the module flags section, -using the ``Linker Options`` key. The merge behavior for this flag is required -to be ``AppendUnique``, and the value for the key is expected to be a metadata -node which should be a list of other metadata nodes, each of which should be a -list of metadata strings defining linker options. - -For example, the following metadata section specifies two separate sets of -linker options, presumably to link against ``libz`` and the ``Cocoa`` -framework:: - - !0 = !{ i32 6, !"Linker Options", - !{ - !{ !"-lz" }, - !{ !"-framework", !"Cocoa" } } } - !llvm.module.flags = !{ !0 } - -The metadata encoding as lists of lists of options, as opposed to a collapsed -list of options, is chosen so that the IR encoding can use multiple option -strings to specify e.g., a single library, while still having that specifier be -preserved as an atomic element that can be recognized by a target specific -assembly writer or object file emitter. - -Each individual option is required to be either a valid option for the target's -linker, or an option that is reserved by the target specific assembly writer or -object file emitter. No other aspect of these options is defined by the IR. - C type width Module Flags Metadata ---------------------------------- @@ -5422,6 +5460,37 @@ enum is the smallest type which can represent all of its values:: !0 = !{i32 1, !"short_wchar", i32 1} !1 = !{i32 1, !"short_enum", i32 0} +Automatic Linker Flags Named Metadata +===================================== + +Some targets support embedding flags to the linker inside individual object +files. Typically this is used in conjunction with language extensions which +allow source files to explicitly declare the libraries they depend on, and have +these automatically be transmitted to the linker via object files. + +These flags are encoded in the IR using named metadata with the name +``!llvm.linker.options``. Each operand is expected to be a metadata node +which should be a list of other metadata nodes, each of which should be a +list of metadata strings defining linker options. + +For example, the following metadata section specifies two separate sets of +linker options, presumably to link against ``libz`` and the ``Cocoa`` +framework:: + + !0 = !{ !"-lz" }, + !1 = !{ !"-framework", !"Cocoa" } } } + !llvm.linker.options = !{ !0, !1 } + +The metadata encoding as lists of lists of options, as opposed to a collapsed +list of options, is chosen so that the IR encoding can use multiple option +strings to specify e.g., a single library, while still having that specifier be +preserved as an atomic element that can be recognized by a target specific +assembly writer or object file emitter. + +Each individual option is required to be either a valid option for the target's +linker, or an option that is reserved by the target specific assembly writer or +object file emitter. No other aspect of these options is defined by the IR. + .. _intrinsicglobalvariables: Intrinsic Global Variables @@ -13999,62 +14068,66 @@ Element Wise Atomic Memory Intrinsics These intrinsics are similar to the standard library memory intrinsics except that they perform memory transfer as a sequence of atomic memory accesses. -.. _int_memcpy_element_atomic: +.. _int_memcpy_element_unordered_atomic: -'``llvm.memcpy.element.atomic``' Intrinsic -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +'``llvm.memcpy.element.unordered.atomic``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Syntax: """"""" -This is an overloaded intrinsic. You can use ``llvm.memcpy.element.atomic`` on +This is an overloaded intrinsic. You can use ``llvm.memcpy.element.unordered.atomic`` on any integer bit width and for different address spaces. Not all targets support all bit widths however. :: - declare void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* , i8* , - i64 , i32 ) + declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* , + i8* , + i32 , + i32 ) + declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* , + i8* , + i64 , + i32 ) Overview: """"""""" -The '``llvm.memcpy.element.atomic.*``' intrinsic performs copy of a block of -memory from the source location to the destination location as a sequence of -unordered atomic memory accesses where each access is a multiple of -``element_size`` bytes wide and aligned at an element size boundary. For example -each element is accessed atomically in source and destination buffers. +The '``llvm.memcpy.element.unordered.atomic.*``' intrinsic is a specialization of the +'``llvm.memcpy.*``' intrinsic. It differs in that the ``dest`` and ``src`` are treated +as arrays with elements that are exactly ``element_size`` bytes, and the copy between +buffers uses a sequence of :ref:`unordered atomic ` load/store operations +that are a positive integer multiple of the ``element_size`` in size. Arguments: """""""""" -The first argument is a pointer to the destination, the second is a -pointer to the source. The third argument is an integer argument -specifying the number of elements to copy, the fourth argument is size of -the single element in bytes. +The first three arguments are the same as they are in the :ref:`@llvm.memcpy ` +intrinsic, with the added constraint that ``len`` is required to be a positive integer +multiple of the ``element_size``. If ``len`` is not a positive integer multiple of +``element_size``, then the behaviour of the intrinsic is undefined. -``element_size`` should be a power of two, greater than zero and less than -a target-specific atomic access size limit. +``element_size`` must be a compile-time constant positive power of two no greater than +target-specific atomic access size limit. -For each of the input pointers ``align`` parameter attribute must be specified. -It must be a power of two and greater than or equal to the ``element_size``. -Caller guarantees that both the source and destination pointers are aligned to -that boundary. +For each of the input pointers ``align`` parameter attribute must be specified. It +must be a power of two no less than the ``element_size``. Caller guarantees that +both the source and destination pointers are aligned to that boundary. Semantics: """""""""" -The '``llvm.memcpy.element.atomic.*``' intrinsic copies -'``num_elements`` * ``element_size``' bytes of memory from the source location to -the destination location. These locations are not allowed to overlap. Memory copy -is performed as a sequence of unordered atomic memory accesses where each access -is guaranteed to be a multiple of ``element_size`` bytes wide and aligned at an -element size boundary. +The '``llvm.memcpy.element.unordered.atomic.*``' intrinsic copies ``len`` bytes of +memory from the source location to the destination location. These locations are not +allowed to overlap. The memory copy is performed as a sequence of load/store operations +where each access is guaranteed to be a multiple of ``element_size`` bytes wide and +aligned at an ``element_size`` boundary. The order of the copy is unspecified. The same value may be read from the source buffer many times, but only one write is issued to the destination buffer per -element. It is well defined to have concurrent reads and writes to both source -and destination provided those reads and writes are at least unordered atomic. +element. It is well defined to have concurrent reads and writes to both source and +destination provided those reads and writes are unordered atomic when specified. This intrinsic does not provide any additional ordering guarantees over those provided by a set of unordered loads from the source location and stores to the @@ -14063,8 +14136,8 @@ destination. Lowering: """"""""" -In the most general case call to the '``llvm.memcpy.element.atomic.*``' is lowered -to a call to the symbol ``__llvm_memcpy_element_atomic_*``. Where '*' is replaced -with an actual element size. +In the most general case call to the '``llvm.memcpy.element.unordered.atomic.*``' is +lowered to a call to the symbol ``__llvm_memcpy_element_unordered_atomic_*``. Where '*' +is replaced with an actual element size. -Optimizer is allowed to inline memory copy when it's profitable to do so. +The optimizer is allowed to inline the memory copy when it's profitable to do so. diff --git a/docs/Lexicon.rst b/docs/Lexicon.rst index ebc3fb772e81..ce7ed318fe4b 100644 --- a/docs/Lexicon.rst +++ b/docs/Lexicon.rst @@ -109,6 +109,13 @@ G Garbage Collection. The practice of using reachability analysis instead of explicit memory management to reclaim unused memory. +**GVN** + Global Value Numbering. GVN is a pass that partitions values computed by a + function into congruence classes. Values ending up in the same congruence + class are guaranteed to be the same for every execution of the program. + In that respect, congruency is a compile-time approximation of equivalence + of values at runtime. + H - diff --git a/docs/Phabricator.rst b/docs/Phabricator.rst index 8d1984b65cd9..cc8484cc1e3e 100644 --- a/docs/Phabricator.rst +++ b/docs/Phabricator.rst @@ -54,7 +54,8 @@ reviewer understand your code. To get a full diff, use one of the following commands (or just use Arcanist to upload your patch): -* ``git diff -U999999 other-branch`` +* ``git show HEAD -U999999 > mypatch.patch`` +* ``git format-patch -U999999 @{u}`` * ``svn diff --diff-cmd=diff -x -U999999`` To upload a new patch: diff --git a/include/llvm/ADT/AllocatorList.h b/include/llvm/ADT/AllocatorList.h index 05a549f96ec7..178c6742a87b 100644 --- a/include/llvm/ADT/AllocatorList.h +++ b/include/llvm/ADT/AllocatorList.h @@ -10,10 +10,16 @@ #ifndef LLVM_ADT_ALLOCATORLIST_H #define LLVM_ADT_ALLOCATORLIST_H +#include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/simple_ilist.h" #include "llvm/Support/Allocator.h" +#include +#include +#include +#include #include +#include namespace llvm { @@ -39,7 +45,8 @@ template class AllocatorList : AllocatorT { T V; }; - typedef simple_ilist list_type; + using list_type = simple_ilist; + list_type List; AllocatorT &getAlloc() { return *this; } @@ -51,13 +58,17 @@ template class AllocatorList : AllocatorT { struct Cloner { AllocatorList &AL; + Cloner(AllocatorList &AL) : AL(AL) {} + Node *operator()(const Node &N) const { return AL.create(N.V); } }; struct Disposer { AllocatorList &AL; + Disposer(AllocatorList &AL) : AL(AL) {} + void operator()(Node *N) const { N->~Node(); AL.getAlloc().Deallocate(N); @@ -65,13 +76,13 @@ template class AllocatorList : AllocatorT { }; public: - typedef T value_type; - typedef T *pointer; - typedef T &reference; - typedef const T *const_pointer; - typedef const T &const_reference; - typedef typename list_type::size_type size_type; - typedef typename list_type::difference_type difference_type; + using value_type = T; + using pointer = T *; + using reference = T &; + using const_pointer = const T *; + using const_reference = const T &; + using size_type = typename list_type::size_type; + using difference_type = typename list_type::difference_type; private: template @@ -83,20 +94,18 @@ template class AllocatorList : AllocatorT { friend class IteratorImpl; friend AllocatorList; - typedef iterator_adaptor_base, - IteratorBase, std::bidirectional_iterator_tag, - ValueT> - base_type; + using base_type = + iterator_adaptor_base, IteratorBase, + std::bidirectional_iterator_tag, ValueT>; public: - typedef ValueT value_type; - typedef ValueT *pointer; - typedef ValueT &reference; + using value_type = ValueT; + using pointer = ValueT *; + using reference = ValueT &; IteratorImpl() = default; IteratorImpl(const IteratorImpl &) = default; IteratorImpl &operator=(const IteratorImpl &) = default; - ~IteratorImpl() = default; explicit IteratorImpl(const IteratorBase &I) : base_type(I) {} @@ -106,6 +115,8 @@ template class AllocatorList : AllocatorT { OtherIteratorBase, IteratorBase>::value>::type * = nullptr) : base_type(X.wrapped()) {} + ~IteratorImpl() = default; + reference operator*() const { return base_type::wrapped()->V; } pointer operator->() const { return &operator*(); } @@ -118,30 +129,34 @@ template class AllocatorList : AllocatorT { }; public: - typedef IteratorImpl iterator; - typedef IteratorImpl - reverse_iterator; - typedef IteratorImpl - const_iterator; - typedef IteratorImpl - const_reverse_iterator; + using iterator = IteratorImpl; + using reverse_iterator = + IteratorImpl; + using const_iterator = + IteratorImpl; + using const_reverse_iterator = + IteratorImpl; AllocatorList() = default; AllocatorList(AllocatorList &&X) : AllocatorT(std::move(X.getAlloc())), List(std::move(X.List)) {} + AllocatorList(const AllocatorList &X) { List.cloneFrom(X.List, Cloner(*this), Disposer(*this)); } + AllocatorList &operator=(AllocatorList &&X) { clear(); // Dispose of current nodes explicitly. List = std::move(X.List); getAlloc() = std::move(X.getAlloc()); return *this; } + AllocatorList &operator=(const AllocatorList &X) { List.cloneFrom(X.List, Cloner(*this), Disposer(*this)); return *this; } + ~AllocatorList() { clear(); } void swap(AllocatorList &RHS) { diff --git a/include/llvm/ADT/ArrayRef.h b/include/llvm/ADT/ArrayRef.h index 6b35d0aec8b2..925ebafc3fed 100644 --- a/include/llvm/ADT/ArrayRef.h +++ b/include/llvm/ADT/ArrayRef.h @@ -1,4 +1,4 @@ -//===--- ArrayRef.h - Array Reference Wrapper -------------------*- C++ -*-===// +//===- ArrayRef.h - Array Reference Wrapper ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,12 +12,21 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/None.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" +#include #include +#include +#include +#include +#include +#include +#include #include namespace llvm { + /// ArrayRef - Represent a constant reference to an array (0 or more elements /// consecutively in memory), i.e. a start pointer and a length. It allows /// various APIs to take consecutive elements easily and conveniently. @@ -32,28 +41,27 @@ namespace llvm { template class LLVM_NODISCARD ArrayRef { public: - typedef const T *iterator; - typedef const T *const_iterator; - typedef size_t size_type; - - typedef std::reverse_iterator reverse_iterator; + using iterator = const T *; + using const_iterator = const T *; + using size_type = size_t; + using reverse_iterator = std::reverse_iterator; private: /// The start of the array, in an external buffer. - const T *Data; + const T *Data = nullptr; /// The number of elements. - size_type Length; + size_type Length = 0; public: /// @name Constructors /// @{ /// Construct an empty ArrayRef. - /*implicit*/ ArrayRef() : Data(nullptr), Length(0) {} + /*implicit*/ ArrayRef() = default; /// Construct an empty ArrayRef from None. - /*implicit*/ ArrayRef(NoneType) : Data(nullptr), Length(0) {} + /*implicit*/ ArrayRef(NoneType) {} /// Construct an ArrayRef from a single element. /*implicit*/ ArrayRef(const T &OneElt) @@ -282,9 +290,8 @@ namespace llvm { template class LLVM_NODISCARD MutableArrayRef : public ArrayRef { public: - typedef T *iterator; - - typedef std::reverse_iterator reverse_iterator; + using iterator = T *; + using reverse_iterator = std::reverse_iterator; /// Construct an empty MutableArrayRef. /*implicit*/ MutableArrayRef() : ArrayRef() {} @@ -416,19 +423,23 @@ namespace llvm { /// This is a MutableArrayRef that owns its array. template class OwningArrayRef : public MutableArrayRef { public: - OwningArrayRef() {} + OwningArrayRef() = default; OwningArrayRef(size_t Size) : MutableArrayRef(new T[Size], Size) {} + OwningArrayRef(ArrayRef Data) : MutableArrayRef(new T[Data.size()], Data.size()) { std::copy(Data.begin(), Data.end(), this->begin()); } + OwningArrayRef(OwningArrayRef &&Other) { *this = Other; } + OwningArrayRef &operator=(OwningArrayRef &&Other) { delete[] this->data(); this->MutableArrayRef::operator=(Other); Other.MutableArrayRef::operator=(MutableArrayRef()); return *this; } + ~OwningArrayRef() { delete[] this->data(); } }; @@ -517,13 +528,14 @@ namespace llvm { // ArrayRefs can be treated like a POD type. template struct isPodLike; - template struct isPodLike > { + template struct isPodLike> { static const bool value = true; }; template hash_code hash_value(ArrayRef S) { return hash_combine_range(S.begin(), S.end()); } + } // end namespace llvm #endif // LLVM_ADT_ARRAYREF_H diff --git a/include/llvm/ADT/BreadthFirstIterator.h b/include/llvm/ADT/BreadthFirstIterator.h index eaeecb6e057f..6bc63c283b09 100644 --- a/include/llvm/ADT/BreadthFirstIterator.h +++ b/include/llvm/ADT/BreadthFirstIterator.h @@ -25,7 +25,6 @@ #include "llvm/ADT/iterator_range.h" #include #include -#include #include namespace llvm { @@ -49,13 +48,13 @@ template , public bf_iterator_storage { - typedef std::iterator super; + using super = std::iterator; - typedef typename GT::NodeRef NodeRef; - typedef typename GT::ChildIteratorType ChildItTy; + using NodeRef = typename GT::NodeRef; + using ChildItTy = typename GT::ChildIteratorType; // First element is the node reference, second is the next child to visit. - typedef std::pair> QueueElement; + using QueueElement = std::pair>; // Visit queue - used to maintain BFS ordering. // Optional<> because we need markers for levels. @@ -109,7 +108,7 @@ class bf_iterator } public: - typedef typename super::pointer pointer; + using pointer = typename super::pointer; // Provide static begin and end methods as our public "constructors" static bf_iterator begin(const GraphT &G) { diff --git a/include/llvm/ADT/DAGDeltaAlgorithm.h b/include/llvm/ADT/DAGDeltaAlgorithm.h index 5ea0fe872868..41fdd43efb8a 100644 --- a/include/llvm/ADT/DAGDeltaAlgorithm.h +++ b/include/llvm/ADT/DAGDeltaAlgorithm.h @@ -1,4 +1,4 @@ -//===--- DAGDeltaAlgorithm.h - A DAG Minimization Algorithm ----*- C++ -*--===// +//===- DAGDeltaAlgorithm.h - A DAG Minimization Algorithm ------*- C++ -*--===// // // The LLVM Compiler Infrastructure // @@ -40,12 +40,12 @@ class DAGDeltaAlgorithm { virtual void anchor(); public: - typedef unsigned change_ty; - typedef std::pair edge_ty; + using change_ty = unsigned; + using edge_ty = std::pair; // FIXME: Use a decent data structure. - typedef std::set changeset_ty; - typedef std::vector changesetlist_ty; + using changeset_ty = std::set; + using changesetlist_ty = std::vector; public: virtual ~DAGDeltaAlgorithm() = default; diff --git a/include/llvm/ADT/DeltaAlgorithm.h b/include/llvm/ADT/DeltaAlgorithm.h index a26f37dfdc7d..6becb2a60104 100644 --- a/include/llvm/ADT/DeltaAlgorithm.h +++ b/include/llvm/ADT/DeltaAlgorithm.h @@ -1,4 +1,4 @@ -//===--- DeltaAlgorithm.h - A Set Minimization Algorithm -------*- C++ -*--===// +//===- DeltaAlgorithm.h - A Set Minimization Algorithm ---------*- C++ -*--===// // // The LLVM Compiler Infrastructure // @@ -35,10 +35,10 @@ namespace llvm { /// predicate. class DeltaAlgorithm { public: - typedef unsigned change_ty; + using change_ty = unsigned; // FIXME: Use a decent data structure. - typedef std::set changeset_ty; - typedef std::vector changesetlist_ty; + using changeset_ty = std::set; + using changesetlist_ty = std::vector; private: /// Cache of failed test results. Successful test results are never cached @@ -90,4 +90,4 @@ class DeltaAlgorithm { } // end namespace llvm -#endif +#endif // LLVM_ADT_DELTAALGORITHM_H diff --git a/include/llvm/ADT/DenseMap.h b/include/llvm/ADT/DenseMap.h index fd8d3bf368a8..b311e69ec9d3 100644 --- a/include/llvm/ADT/DenseMap.h +++ b/include/llvm/ADT/DenseMap.h @@ -25,8 +25,8 @@ #include #include #include -#include #include +#include #include namespace llvm { @@ -57,14 +57,15 @@ class DenseMapBase : public DebugEpochBase { using const_arg_type_t = typename const_pointer_or_const_ref::type; public: - typedef unsigned size_type; - typedef KeyT key_type; - typedef ValueT mapped_type; - typedef BucketT value_type; + using size_type = unsigned; + using key_type = KeyT; + using mapped_type = ValueT; + using value_type = BucketT; + + using iterator = DenseMapIterator; + using const_iterator = + DenseMapIterator; - typedef DenseMapIterator iterator; - typedef DenseMapIterator - const_iterator; inline iterator begin() { // When the map is empty, avoid the overhead of AdvancePastEmptyBuckets(). return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this); @@ -387,15 +388,18 @@ class DenseMapBase : public DebugEpochBase { static unsigned getHashValue(const KeyT &Val) { return KeyInfoT::getHashValue(Val); } + template static unsigned getHashValue(const LookupKeyT &Val) { return KeyInfoT::getHashValue(Val); } + static const KeyT getEmptyKey() { static_assert(std::is_base_of::value, "Must pass the derived type to this template!"); return KeyInfoT::getEmptyKey(); } + static const KeyT getTombstoneKey() { return KeyInfoT::getTombstoneKey(); } @@ -404,39 +408,51 @@ class DenseMapBase : public DebugEpochBase { unsigned getNumEntries() const { return static_cast(this)->getNumEntries(); } + void setNumEntries(unsigned Num) { static_cast(this)->setNumEntries(Num); } + void incrementNumEntries() { setNumEntries(getNumEntries() + 1); } + void decrementNumEntries() { setNumEntries(getNumEntries() - 1); } + unsigned getNumTombstones() const { return static_cast(this)->getNumTombstones(); } + void setNumTombstones(unsigned Num) { static_cast(this)->setNumTombstones(Num); } + void incrementNumTombstones() { setNumTombstones(getNumTombstones() + 1); } + void decrementNumTombstones() { setNumTombstones(getNumTombstones() - 1); } + const BucketT *getBuckets() const { return static_cast(this)->getBuckets(); } + BucketT *getBuckets() { return static_cast(this)->getBuckets(); } + unsigned getNumBuckets() const { return static_cast(this)->getNumBuckets(); } + BucketT *getBucketsEnd() { return getBuckets() + getNumBuckets(); } + const BucketT *getBucketsEnd() const { return getBuckets() + getNumBuckets(); } @@ -587,10 +603,11 @@ template > class DenseMap : public DenseMapBase, KeyT, ValueT, KeyInfoT, BucketT> { + friend class DenseMapBase; + // Lift some types from the dependent base class into this class for // simplicity of referring to them. - typedef DenseMapBase BaseT; - friend class DenseMapBase; + using BaseT = DenseMapBase; BucketT *Buckets; unsigned NumEntries; @@ -705,6 +722,7 @@ class DenseMap : public DenseMapBase, unsigned getNumEntries() const { return NumEntries; } + void setNumEntries(unsigned Num) { NumEntries = Num; } @@ -712,6 +730,7 @@ class DenseMap : public DenseMapBase, unsigned getNumTombstones() const { return NumTombstones; } + void setNumTombstones(unsigned Num) { NumTombstones = Num; } @@ -743,10 +762,12 @@ class SmallDenseMap : public DenseMapBase< SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT> { + friend class DenseMapBase; + // Lift some types from the dependent base class into this class for // simplicity of referring to them. - typedef DenseMapBase BaseT; - friend class DenseMapBase; + using BaseT = DenseMapBase; + static_assert(isPowerOf2_64(InlineBuckets), "InlineBuckets must be a power of 2."); @@ -972,6 +993,7 @@ class SmallDenseMap unsigned getNumEntries() const { return NumEntries; } + void setNumEntries(unsigned Num) { // NumEntries is hardcoded to be 31 bits wide. assert(Num < (1U << 31) && "Cannot support more than 1<<31 entries"); @@ -981,6 +1003,7 @@ class SmallDenseMap unsigned getNumTombstones() const { return NumTombstones; } + void setNumTombstones(unsigned Num) { NumTombstones = Num; } @@ -992,15 +1015,18 @@ class SmallDenseMap // 'storage.buffer' static type is 'char *'. return reinterpret_cast(storage.buffer); } + BucketT *getInlineBuckets() { return const_cast( const_cast(this)->getInlineBuckets()); } + const LargeRep *getLargeRep() const { assert(!Small); // Note, same rule about aliasing as with getInlineBuckets. return reinterpret_cast(storage.buffer); } + LargeRep *getLargeRep() { return const_cast( const_cast(this)->getLargeRep()); @@ -1009,10 +1035,12 @@ class SmallDenseMap const BucketT *getBuckets() const { return Small ? getInlineBuckets() : getLargeRep()->Buckets; } + BucketT *getBuckets() { return const_cast( const_cast(this)->getBuckets()); } + unsigned getNumBuckets() const { return Small ? InlineBuckets : getLargeRep()->NumBuckets; } @@ -1037,23 +1065,25 @@ class SmallDenseMap template class DenseMapIterator : DebugEpochBase::HandleBase { - typedef DenseMapIterator ConstIterator; friend class DenseMapIterator; friend class DenseMapIterator; + using ConstIterator = DenseMapIterator; + public: - typedef ptrdiff_t difference_type; - typedef typename std::conditional::type - value_type; - typedef value_type *pointer; - typedef value_type &reference; - typedef std::forward_iterator_tag iterator_category; + using difference_type = ptrdiff_t; + using value_type = + typename std::conditional::type; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::forward_iterator_tag; private: - pointer Ptr, End; + pointer Ptr = nullptr; + pointer End = nullptr; public: - DenseMapIterator() : Ptr(nullptr), End(nullptr) {} + DenseMapIterator() = default; DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch, bool NoAdvance = false) diff --git a/include/llvm/ADT/DenseMapInfo.h b/include/llvm/ADT/DenseMapInfo.h index bb973ac65063..a96904c7dbbf 100644 --- a/include/llvm/ADT/DenseMapInfo.h +++ b/include/llvm/ADT/DenseMapInfo.h @@ -18,7 +18,10 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/PointerLikeTypeTraits.h" -#include "llvm/Support/type_traits.h" +#include +#include +#include +#include namespace llvm { @@ -38,15 +41,18 @@ struct DenseMapInfo { Val <<= PointerLikeTypeTraits::NumLowBitsAvailable; return reinterpret_cast(Val); } + static inline T* getTombstoneKey() { uintptr_t Val = static_cast(-2); Val <<= PointerLikeTypeTraits::NumLowBitsAvailable; return reinterpret_cast(Val); } + static unsigned getHashValue(const T *PtrVal) { return (unsigned((uintptr_t)PtrVal) >> 4) ^ (unsigned((uintptr_t)PtrVal) >> 9); } + static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; } }; @@ -55,6 +61,7 @@ template<> struct DenseMapInfo { static inline char getEmptyKey() { return ~0; } static inline char getTombstoneKey() { return ~0 - 1; } static unsigned getHashValue(const char& Val) { return Val * 37U; } + static bool isEqual(const char &LHS, const char &RHS) { return LHS == RHS; } @@ -65,6 +72,7 @@ template <> struct DenseMapInfo { static inline unsigned short getEmptyKey() { return 0xFFFF; } static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; } static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; } + static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) { return LHS == RHS; } @@ -75,6 +83,7 @@ template<> struct DenseMapInfo { static inline unsigned getEmptyKey() { return ~0U; } static inline unsigned getTombstoneKey() { return ~0U - 1; } static unsigned getHashValue(const unsigned& Val) { return Val * 37U; } + static bool isEqual(const unsigned& LHS, const unsigned& RHS) { return LHS == RHS; } @@ -84,9 +93,11 @@ template<> struct DenseMapInfo { template<> struct DenseMapInfo { static inline unsigned long getEmptyKey() { return ~0UL; } static inline unsigned long getTombstoneKey() { return ~0UL - 1L; } + static unsigned getHashValue(const unsigned long& Val) { return (unsigned)(Val * 37UL); } + static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) { return LHS == RHS; } @@ -96,9 +107,11 @@ template<> struct DenseMapInfo { template<> struct DenseMapInfo { static inline unsigned long long getEmptyKey() { return ~0ULL; } static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; } + static unsigned getHashValue(const unsigned long long& Val) { return (unsigned)(Val * 37ULL); } + static bool isEqual(const unsigned long long& LHS, const unsigned long long& RHS) { return LHS == RHS; @@ -118,6 +131,7 @@ template<> struct DenseMapInfo { static inline int getEmptyKey() { return 0x7fffffff; } static inline int getTombstoneKey() { return -0x7fffffff - 1; } static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); } + static bool isEqual(const int& LHS, const int& RHS) { return LHS == RHS; } @@ -128,10 +142,13 @@ template<> struct DenseMapInfo { static inline long getEmptyKey() { return (1UL << (sizeof(long) * 8 - 1)) - 1UL; } + static inline long getTombstoneKey() { return getEmptyKey() - 1L; } + static unsigned getHashValue(const long& Val) { return (unsigned)(Val * 37UL); } + static bool isEqual(const long& LHS, const long& RHS) { return LHS == RHS; } @@ -141,9 +158,11 @@ template<> struct DenseMapInfo { template<> struct DenseMapInfo { static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; } static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; } + static unsigned getHashValue(const long long& Val) { return (unsigned)(Val * 37ULL); } + static bool isEqual(const long long& LHS, const long long& RHS) { return LHS == RHS; @@ -152,19 +171,21 @@ template<> struct DenseMapInfo { // Provide DenseMapInfo for all pairs whose members have info. template -struct DenseMapInfo > { - typedef std::pair Pair; - typedef DenseMapInfo FirstInfo; - typedef DenseMapInfo SecondInfo; +struct DenseMapInfo> { + using Pair = std::pair; + using FirstInfo = DenseMapInfo; + using SecondInfo = DenseMapInfo; static inline Pair getEmptyKey() { return std::make_pair(FirstInfo::getEmptyKey(), SecondInfo::getEmptyKey()); } + static inline Pair getTombstoneKey() { return std::make_pair(FirstInfo::getTombstoneKey(), SecondInfo::getTombstoneKey()); } + static unsigned getHashValue(const Pair& PairVal) { uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32 | (uint64_t)SecondInfo::getHashValue(PairVal.second); @@ -178,6 +199,7 @@ struct DenseMapInfo > { key ^= (key >> 31); return (unsigned)key; } + static bool isEqual(const Pair &LHS, const Pair &RHS) { return FirstInfo::isEqual(LHS.first, RHS.first) && SecondInfo::isEqual(LHS.second, RHS.second); @@ -190,16 +212,19 @@ template <> struct DenseMapInfo { return StringRef(reinterpret_cast(~static_cast(0)), 0); } + static inline StringRef getTombstoneKey() { return StringRef(reinterpret_cast(~static_cast(1)), 0); } + static unsigned getHashValue(StringRef Val) { assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!"); assert(Val.data() != getTombstoneKey().data() && "Cannot hash the tombstone key!"); return (unsigned)(hash_value(Val)); } + static bool isEqual(StringRef LHS, StringRef RHS) { if (RHS.data() == getEmptyKey().data()) return LHS.data() == getEmptyKey().data(); @@ -215,16 +240,19 @@ template struct DenseMapInfo> { return ArrayRef(reinterpret_cast(~static_cast(0)), size_t(0)); } + static inline ArrayRef getTombstoneKey() { return ArrayRef(reinterpret_cast(~static_cast(1)), size_t(0)); } + static unsigned getHashValue(ArrayRef Val) { assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!"); assert(Val.data() != getTombstoneKey().data() && "Cannot hash the tombstone key!"); return (unsigned)(hash_value(Val)); } + static bool isEqual(ArrayRef LHS, ArrayRef RHS) { if (RHS.data() == getEmptyKey().data()) return LHS.data() == getEmptyKey().data(); @@ -236,4 +264,4 @@ template struct DenseMapInfo> { } // end namespace llvm -#endif +#endif // LLVM_ADT_DENSEMAPINFO_H diff --git a/include/llvm/ADT/DenseSet.h b/include/llvm/ADT/DenseSet.h index fcf304c3ecc4..7e5171c3f3a4 100644 --- a/include/llvm/ADT/DenseSet.h +++ b/include/llvm/ADT/DenseSet.h @@ -15,11 +15,18 @@ #define LLVM_ADT_DENSESET_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/type_traits.h" +#include +#include #include +#include +#include namespace llvm { namespace detail { + struct DenseSetEmpty {}; // Use the empty base class trick so we can create a DenseMap where the buckets @@ -48,13 +55,14 @@ class DenseSetImpl { static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT), "DenseMap buckets unexpectedly large!"); MapTy TheMap; + template using const_arg_type_t = typename const_pointer_or_const_ref::type; public: - typedef ValueT key_type; - typedef ValueT value_type; - typedef unsigned size_type; + using key_type = ValueT; + using value_type = ValueT; + using size_type = unsigned; explicit DenseSetImpl(unsigned InitialReserve = 0) : TheMap(InitialReserve) {} @@ -100,11 +108,11 @@ class DenseSetImpl { friend class ConstIterator; public: - typedef typename MapTy::iterator::difference_type difference_type; - typedef ValueT value_type; - typedef value_type *pointer; - typedef value_type &reference; - typedef std::forward_iterator_tag iterator_category; + using difference_type = typename MapTy::iterator::difference_type; + using value_type = ValueT; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::forward_iterator_tag; Iterator() = default; Iterator(const typename MapTy::iterator &i) : I(i) {} @@ -126,16 +134,14 @@ class DenseSetImpl { friend class Iterator; public: - typedef typename MapTy::const_iterator::difference_type difference_type; - typedef ValueT value_type; - typedef value_type *pointer; - typedef value_type &reference; - typedef std::forward_iterator_tag iterator_category; - - ConstIterator(const Iterator &B) : I(B.I) {} + using difference_type = typename MapTy::const_iterator::difference_type; + using value_type = ValueT; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::forward_iterator_tag; ConstIterator() = default; - + ConstIterator(const Iterator &B) : I(B.I) {} ConstIterator(const typename MapTy::const_iterator &i) : I(i) {} const ValueT &operator*() const { return I->getFirst(); } @@ -147,8 +153,8 @@ class DenseSetImpl { bool operator!=(const ConstIterator& X) const { return I != X.I; } }; - typedef Iterator iterator; - typedef ConstIterator const_iterator; + using iterator = Iterator; + using const_iterator = ConstIterator; iterator begin() { return Iterator(TheMap.begin()); } iterator end() { return Iterator(TheMap.end()); } @@ -208,7 +214,7 @@ class DenseSetImpl { } }; -} // namespace detail +} // end namespace detail /// Implements a dense probed hash-table based set. template > @@ -246,4 +252,4 @@ class SmallDenseSet } // end namespace llvm -#endif +#endif // LLVM_ADT_DENSESET_H diff --git a/include/llvm/ADT/DepthFirstIterator.h b/include/llvm/ADT/DepthFirstIterator.h index b020d48cb3f0..e964d7fa2391 100644 --- a/include/llvm/ADT/DepthFirstIterator.h +++ b/include/llvm/ADT/DepthFirstIterator.h @@ -68,13 +68,14 @@ class df_iterator_storage { // cross edges in the spanning tree but is not used in the common case. template struct df_iterator_default_set : public SmallPtrSet { - typedef SmallPtrSet BaseSet; - typedef typename BaseSet::iterator iterator; - std::pair insert(NodeRef N) { return BaseSet::insert(N) ; } + using BaseSet = SmallPtrSet; + using iterator = typename BaseSet::iterator; + + std::pair insert(NodeRef N) { return BaseSet::insert(N); } template void insert(IterT Begin, IterT End) { BaseSet::insert(Begin,End); } - void completed(NodeRef) { } + void completed(NodeRef) {} }; // Generic Depth First Iterator @@ -85,15 +86,14 @@ template , public df_iterator_storage { - typedef std::iterator super; - - typedef typename GT::NodeRef NodeRef; - typedef typename GT::ChildIteratorType ChildItTy; + using super = std::iterator; + using NodeRef = typename GT::NodeRef; + using ChildItTy = typename GT::ChildIteratorType; // First element is node reference, second is the 'next child' to visit. // The second child is initialized lazily to pick up graph changes during the // DFS. - typedef std::pair> StackElement; + using StackElement = std::pair>; // VisitStack - Used to maintain the ordering. Top = current block std::vector VisitStack; @@ -103,12 +103,15 @@ class df_iterator this->Visited.insert(Node); VisitStack.push_back(StackElement(Node, None)); } + inline df_iterator() = default; // End is when stack is empty + inline df_iterator(NodeRef Node, SetType &S) : df_iterator_storage(S) { if (this->Visited.insert(Node).second) VisitStack.push_back(StackElement(Node, None)); } + inline df_iterator(SetType &S) : df_iterator_storage(S) { // End is when stack is empty @@ -142,7 +145,7 @@ class df_iterator } public: - typedef typename super::pointer pointer; + using pointer = typename super::pointer; // Provide static begin and end methods as our public "constructors" static df_iterator begin(const GraphT &G) { diff --git a/include/llvm/ADT/EquivalenceClasses.h b/include/llvm/ADT/EquivalenceClasses.h index 8fcac178ffc9..af293d4c1422 100644 --- a/include/llvm/ADT/EquivalenceClasses.h +++ b/include/llvm/ADT/EquivalenceClasses.h @@ -1,4 +1,4 @@ -//===-- llvm/ADT/EquivalenceClasses.h - Generic Equiv. Classes --*- C++ -*-===// +//===- llvm/ADT/EquivalenceClasses.h - Generic Equiv. Classes ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -69,6 +69,7 @@ class EquivalenceClasses { /// leader is determined by a bit stolen from one of the pointers. class ECValue { friend class EquivalenceClasses; + mutable const ECValue *Leader, *Next; ElemTy Data; @@ -141,14 +142,14 @@ class EquivalenceClasses { // /// iterator* - Provides a way to iterate over all values in the set. - typedef typename std::set::const_iterator iterator; + using iterator = typename std::set::const_iterator; + iterator begin() const { return TheMapping.begin(); } iterator end() const { return TheMapping.end(); } bool empty() const { return TheMapping.empty(); } /// member_* Iterate over the members of an equivalence class. - /// class member_iterator; member_iterator member_begin(iterator I) const { // Only leaders provide anything to iterate over. @@ -204,7 +205,6 @@ class EquivalenceClasses { /// equivalence class it is in. This does the path-compression part that /// makes union-find "union findy". This returns an end iterator if the value /// is not in the equivalence class. - /// member_iterator findLeader(iterator I) const { if (I == TheMapping.end()) return member_end(); return member_iterator(I->getLeader()); @@ -241,15 +241,17 @@ class EquivalenceClasses { class member_iterator : public std::iterator { - typedef std::iterator super; - const ECValue *Node; friend class EquivalenceClasses; + using super = std::iterator; + + const ECValue *Node; + public: - typedef size_t size_type; - typedef typename super::pointer pointer; - typedef typename super::reference reference; + using size_type = size_t; + using pointer = typename super::pointer; + using reference = typename super::reference; explicit member_iterator() = default; explicit member_iterator(const ECValue *N) : Node(N) {} diff --git a/include/llvm/ADT/FoldingSet.h b/include/llvm/ADT/FoldingSet.h index dab18297dd3b..c5987a947e18 100644 --- a/include/llvm/ADT/FoldingSet.h +++ b/include/llvm/ADT/FoldingSet.h @@ -40,7 +40,7 @@ namespace llvm { /// FoldingSetNode. The node class must also define a Profile method used to /// establish the unique bits of data for the node. The Profile method is /// passed a FoldingSetNodeID object which is used to gather the bits. Just -/// call one of the Add* functions defined in the FoldingSetImpl::NodeID class. +/// call one of the Add* functions defined in the FoldingSetBase::NodeID class. /// NOTE: That the folding set does not own the nodes and it is the /// responsibility of the user to dispose of the nodes. /// @@ -104,13 +104,13 @@ class FoldingSetNodeID; class StringRef; //===----------------------------------------------------------------------===// -/// FoldingSetImpl - Implements the folding set functionality. The main +/// FoldingSetBase - Implements the folding set functionality. The main /// structure is an array of buckets. Each bucket is indexed by the hash of /// the nodes it contains. The bucket itself points to the nodes contained /// in the bucket via a singly linked list. The last node in the list points /// back to the bucket to facilitate node removal. /// -class FoldingSetImpl { +class FoldingSetBase { virtual void anchor(); // Out of line virtual method. protected: @@ -126,10 +126,10 @@ class FoldingSetImpl { /// is greater than twice the number of buckets. unsigned NumNodes; - explicit FoldingSetImpl(unsigned Log2InitSize = 6); - FoldingSetImpl(FoldingSetImpl &&Arg); - FoldingSetImpl &operator=(FoldingSetImpl &&RHS); - ~FoldingSetImpl(); + explicit FoldingSetBase(unsigned Log2InitSize = 6); + FoldingSetBase(FoldingSetBase &&Arg); + FoldingSetBase &operator=(FoldingSetBase &&RHS); + ~FoldingSetBase(); public: //===--------------------------------------------------------------------===// @@ -152,33 +152,6 @@ class FoldingSetImpl { /// clear - Remove all nodes from the folding set. void clear(); - /// RemoveNode - Remove a node from the folding set, returning true if one - /// was removed or false if the node was not in the folding set. - bool RemoveNode(Node *N); - - /// GetOrInsertNode - If there is an existing simple Node exactly - /// equal to the specified node, return it. Otherwise, insert 'N' and return - /// it instead. - Node *GetOrInsertNode(Node *N); - - /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, - /// return it. If not, return the insertion token that will make insertion - /// faster. - Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos); - - /// InsertNode - Insert the specified node into the folding set, knowing that - /// it is not already in the folding set. InsertPos must be obtained from - /// FindNodeOrInsertPos. - void InsertNode(Node *N, void *InsertPos); - - /// InsertNode - Insert the specified node into the folding set, knowing that - /// it is not already in the folding set. - void InsertNode(Node *N) { - Node *Inserted = GetOrInsertNode(N); - (void)Inserted; - assert(Inserted == N && "Node already inserted!"); - } - /// size - Returns the number of nodes in the folding set. unsigned size() const { return NumNodes; } @@ -220,6 +193,28 @@ class FoldingSetImpl { /// ComputeNodeHash - Instantiations of the FoldingSet template implement /// this function to compute a hash value for the given node. virtual unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const = 0; + + // The below methods are protected to encourage subclasses to provide a more + // type-safe API. + + /// RemoveNode - Remove a node from the folding set, returning true if one + /// was removed or false if the node was not in the folding set. + bool RemoveNode(Node *N); + + /// GetOrInsertNode - If there is an existing simple Node exactly + /// equal to the specified node, return it. Otherwise, insert 'N' and return + /// it instead. + Node *GetOrInsertNode(Node *N); + + /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, + /// return it. If not, return the insertion token that will make insertion + /// faster. + Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos); + + /// InsertNode - Insert the specified node into the folding set, knowing that + /// it is not already in the folding set. InsertPos must be obtained from + /// FindNodeOrInsertPos. + void InsertNode(Node *N, void *InsertPos); }; //===----------------------------------------------------------------------===// @@ -293,7 +288,7 @@ class FoldingSetNodeIDRef { FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {} /// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef, - /// used to lookup the node in the FoldingSetImpl. + /// used to lookup the node in the FoldingSetBase. unsigned ComputeHash() const; bool operator==(FoldingSetNodeIDRef) const; @@ -345,7 +340,7 @@ class FoldingSetNodeID { inline void clear() { Bits.clear(); } /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used - /// to lookup the node in the FoldingSetImpl. + /// to lookup the node in the FoldingSetBase. unsigned ComputeHash() const; /// operator== - Used to compare two nodes to each other. @@ -368,7 +363,7 @@ class FoldingSetNodeID { }; // Convenience type to hide the implementation of the folding set. -typedef FoldingSetImpl::Node FoldingSetNode; +typedef FoldingSetBase::Node FoldingSetNode; template class FoldingSetIterator; template class FoldingSetBucketIterator; @@ -407,6 +402,71 @@ DefaultContextualFoldingSetTrait::ComputeHash(T &X, return TempID.ComputeHash(); } +//===----------------------------------------------------------------------===// +/// FoldingSetImpl - An implementation detail that lets us share code between +/// FoldingSet and ContextualFoldingSet. +template class FoldingSetImpl : public FoldingSetBase { +protected: + explicit FoldingSetImpl(unsigned Log2InitSize) + : FoldingSetBase(Log2InitSize) {} + + FoldingSetImpl(FoldingSetImpl &&Arg) = default; + FoldingSetImpl &operator=(FoldingSetImpl &&RHS) = default; + ~FoldingSetImpl() = default; + +public: + typedef FoldingSetIterator iterator; + iterator begin() { return iterator(Buckets); } + iterator end() { return iterator(Buckets+NumBuckets); } + + typedef FoldingSetIterator const_iterator; + const_iterator begin() const { return const_iterator(Buckets); } + const_iterator end() const { return const_iterator(Buckets+NumBuckets); } + + typedef FoldingSetBucketIterator bucket_iterator; + + bucket_iterator bucket_begin(unsigned hash) { + return bucket_iterator(Buckets + (hash & (NumBuckets-1))); + } + + bucket_iterator bucket_end(unsigned hash) { + return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true); + } + + /// RemoveNode - Remove a node from the folding set, returning true if one + /// was removed or false if the node was not in the folding set. + bool RemoveNode(T *N) { return FoldingSetBase::RemoveNode(N); } + + /// GetOrInsertNode - If there is an existing simple Node exactly + /// equal to the specified node, return it. Otherwise, insert 'N' and + /// return it instead. + T *GetOrInsertNode(T *N) { + return static_cast(FoldingSetBase::GetOrInsertNode(N)); + } + + /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, + /// return it. If not, return the insertion token that will make insertion + /// faster. + T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { + return static_cast(FoldingSetBase::FindNodeOrInsertPos(ID, InsertPos)); + } + + /// InsertNode - Insert the specified node into the folding set, knowing that + /// it is not already in the folding set. InsertPos must be obtained from + /// FindNodeOrInsertPos. + void InsertNode(T *N, void *InsertPos) { + FoldingSetBase::InsertNode(N, InsertPos); + } + + /// InsertNode - Insert the specified node into the folding set, knowing that + /// it is not already in the folding set. + void InsertNode(T *N) { + T *Inserted = GetOrInsertNode(N); + (void)Inserted; + assert(Inserted == N && "Node already inserted!"); + } +}; + //===----------------------------------------------------------------------===// /// FoldingSet - This template class is used to instantiate a specialized /// implementation of the folding set to the node class T. T must be a @@ -416,8 +476,10 @@ DefaultContextualFoldingSetTrait::ComputeHash(T &X, /// moved-from state is not a valid state for anything other than /// move-assigning and destroying. This is primarily to enable movable APIs /// that incorporate these objects. -template class FoldingSet final : public FoldingSetImpl { -private: +template class FoldingSet final : public FoldingSetImpl { + using Super = FoldingSetImpl; + using Node = typename Super::Node; + /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a /// way to convert nodes into a unique specifier. void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override { @@ -442,45 +504,10 @@ template class FoldingSet final : public FoldingSetImpl { public: explicit FoldingSet(unsigned Log2InitSize = 6) - : FoldingSetImpl(Log2InitSize) {} + : Super(Log2InitSize) {} - FoldingSet(FoldingSet &&Arg) : FoldingSetImpl(std::move(Arg)) {} - FoldingSet &operator=(FoldingSet &&RHS) { - (void)FoldingSetImpl::operator=(std::move(RHS)); - return *this; - } - - typedef FoldingSetIterator iterator; - iterator begin() { return iterator(Buckets); } - iterator end() { return iterator(Buckets+NumBuckets); } - - typedef FoldingSetIterator const_iterator; - const_iterator begin() const { return const_iterator(Buckets); } - const_iterator end() const { return const_iterator(Buckets+NumBuckets); } - - typedef FoldingSetBucketIterator bucket_iterator; - - bucket_iterator bucket_begin(unsigned hash) { - return bucket_iterator(Buckets + (hash & (NumBuckets-1))); - } - - bucket_iterator bucket_end(unsigned hash) { - return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true); - } - - /// GetOrInsertNode - If there is an existing simple Node exactly - /// equal to the specified node, return it. Otherwise, insert 'N' and - /// return it instead. - T *GetOrInsertNode(Node *N) { - return static_cast(FoldingSetImpl::GetOrInsertNode(N)); - } - - /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, - /// return it. If not, return the insertion token that will make insertion - /// faster. - T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { - return static_cast(FoldingSetImpl::FindNodeOrInsertPos(ID, InsertPos)); - } + FoldingSet(FoldingSet &&Arg) = default; + FoldingSet &operator=(FoldingSet &&RHS) = default; }; //===----------------------------------------------------------------------===// @@ -493,74 +520,42 @@ template class FoldingSet final : public FoldingSetImpl { /// function with signature /// void Profile(FoldingSetNodeID &, Ctx); template -class ContextualFoldingSet final : public FoldingSetImpl { +class ContextualFoldingSet final : public FoldingSetImpl { // Unfortunately, this can't derive from FoldingSet because the - // construction vtable for FoldingSet requires + // construction of the vtable for FoldingSet requires // FoldingSet::GetNodeProfile to be instantiated, which in turn // requires a single-argument T::Profile(). -private: + using Super = FoldingSetImpl; + using Node = typename Super::Node; + Ctx Context; /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a /// way to convert nodes into a unique specifier. - void GetNodeProfile(FoldingSetImpl::Node *N, - FoldingSetNodeID &ID) const override { + void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override { T *TN = static_cast(N); ContextualFoldingSetTrait::Profile(*TN, ID, Context); } - bool NodeEquals(FoldingSetImpl::Node *N, const FoldingSetNodeID &ID, - unsigned IDHash, FoldingSetNodeID &TempID) const override { + bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID) const override { T *TN = static_cast(N); return ContextualFoldingSetTrait::Equals(*TN, ID, IDHash, TempID, Context); } - unsigned ComputeNodeHash(FoldingSetImpl::Node *N, - FoldingSetNodeID &TempID) const override { + unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override { T *TN = static_cast(N); return ContextualFoldingSetTrait::ComputeHash(*TN, TempID, Context); } public: explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6) - : FoldingSetImpl(Log2InitSize), Context(Context) + : Super(Log2InitSize), Context(Context) {} Ctx getContext() const { return Context; } - - typedef FoldingSetIterator iterator; - iterator begin() { return iterator(Buckets); } - iterator end() { return iterator(Buckets+NumBuckets); } - - typedef FoldingSetIterator const_iterator; - const_iterator begin() const { return const_iterator(Buckets); } - const_iterator end() const { return const_iterator(Buckets+NumBuckets); } - - typedef FoldingSetBucketIterator bucket_iterator; - - bucket_iterator bucket_begin(unsigned hash) { - return bucket_iterator(Buckets + (hash & (NumBuckets-1))); - } - - bucket_iterator bucket_end(unsigned hash) { - return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true); - } - - /// GetOrInsertNode - If there is an existing simple Node exactly - /// equal to the specified node, return it. Otherwise, insert 'N' - /// and return it instead. - T *GetOrInsertNode(Node *N) { - return static_cast(FoldingSetImpl::GetOrInsertNode(N)); - } - - /// FindNodeOrInsertPos - Look up the node specified by ID. If it - /// exists, return it. If not, return the insertion token that will - /// make insertion faster. - T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { - return static_cast(FoldingSetImpl::FindNodeOrInsertPos(ID, InsertPos)); - } }; //===----------------------------------------------------------------------===// diff --git a/include/llvm/ADT/GraphTraits.h b/include/llvm/ADT/GraphTraits.h index 68149d9e3bf5..225d9eb847f0 100644 --- a/include/llvm/ADT/GraphTraits.h +++ b/include/llvm/ADT/GraphTraits.h @@ -1,4 +1,4 @@ -//===-- llvm/ADT/GraphTraits.h - Graph traits template ----------*- C++ -*-===// +//===- llvm/ADT/GraphTraits.h - Graph traits template -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -41,7 +41,6 @@ struct GraphTraits { // static ChildIteratorType child_end (NodeRef) // Return iterators that point to the beginning and ending of the child // node list for the specified node. - // // typedef ...iterator nodes_iterator; - dereference to a NodeRef // static nodes_iterator nodes_begin(GraphType *G) @@ -50,7 +49,6 @@ struct GraphTraits { // static unsigned size (GraphType *G) // Return total number of nodes in the graph - // // If anyone tries to use this class without having an appropriate // specialization, make an error. If you get this error, it's because you @@ -58,11 +56,9 @@ struct GraphTraits { // graph, or you need to define it for a new graph type. Either that or // your argument to XXX_begin(...) is unknown or needs to have the proper .h // file #include'd. - // - typedef typename GraphType::UnknownGraphTypeError NodeRef; + using NodeRef = typename GraphType::UnknownGraphTypeError; }; - // Inverse - This class is used as a little marker class to tell the graph // iterator to iterate over the graph in a graph defined "Inverse" ordering. // Not all graphs define an inverse ordering, and if they do, it depends on @@ -73,7 +69,7 @@ struct GraphTraits { // for (; I != E; ++I) { ... } // // Which is equivalent to: -// df_iterator > I = idf_begin(M), E = idf_end(M); +// df_iterator> I = idf_begin(M), E = idf_end(M); // for (; I != E; ++I) { ... } // template @@ -114,6 +110,7 @@ inverse_children(const typename GraphTraits::NodeRef &G) { return make_range(GraphTraits>::child_begin(G), GraphTraits>::child_end(G)); } -} // End llvm namespace -#endif +} // end namespace llvm + +#endif // LLVM_ADT_GRAPHTRAITS_H diff --git a/include/llvm/ADT/ImmutableList.h b/include/llvm/ADT/ImmutableList.h index e5f51bafe995..60d63e09d426 100644 --- a/include/llvm/ADT/ImmutableList.h +++ b/include/llvm/ADT/ImmutableList.h @@ -63,8 +63,8 @@ class ImmutableListImpl : public FoldingSetNode { template class ImmutableList { public: - typedef T value_type; - typedef ImmutableListFactory Factory; + using value_type = T; + using Factory = ImmutableListFactory; private: const ImmutableListImpl* X; @@ -141,8 +141,8 @@ class ImmutableList { template class ImmutableListFactory { - typedef ImmutableListImpl ListTy; - typedef FoldingSet CacheTy; + using ListTy = ImmutableListImpl; + using CacheTy = FoldingSet; CacheTy Cache; uintptr_t Allocator; diff --git a/include/llvm/ADT/ImmutableMap.h b/include/llvm/ADT/ImmutableMap.h index f197d407ba3b..10d1e1f0139b 100644 --- a/include/llvm/ADT/ImmutableMap.h +++ b/include/llvm/ADT/ImmutableMap.h @@ -26,12 +26,12 @@ namespace llvm { /// only the first element (the key) is used by isEqual and isLess. template struct ImutKeyValueInfo { - typedef const std::pair value_type; - typedef const value_type& value_type_ref; - typedef const T key_type; - typedef const T& key_type_ref; - typedef const S data_type; - typedef const S& data_type_ref; + using value_type = const std::pair; + using value_type_ref = const value_type&; + using key_type = const T; + using key_type_ref = const T&; + using data_type = const S; + using data_type_ref = const S&; static inline key_type_ref KeyOfValue(value_type_ref V) { return V.first; @@ -62,13 +62,13 @@ template > class ImmutableMap { public: - typedef typename ValInfo::value_type value_type; - typedef typename ValInfo::value_type_ref value_type_ref; - typedef typename ValInfo::key_type key_type; - typedef typename ValInfo::key_type_ref key_type_ref; - typedef typename ValInfo::data_type data_type; - typedef typename ValInfo::data_type_ref data_type_ref; - typedef ImutAVLTree TreeTy; + using value_type = typename ValInfo::value_type; + using value_type_ref = typename ValInfo::value_type_ref; + using key_type = typename ValInfo::key_type; + using key_type_ref = typename ValInfo::key_type_ref; + using data_type = typename ValInfo::data_type; + using data_type_ref = typename ValInfo::data_type_ref; + using TreeTy = ImutAVLTree; protected: TreeTy* Root; @@ -86,6 +86,10 @@ class ImmutableMap { if (Root) { Root->retain(); } } + ~ImmutableMap() { + if (Root) { Root->release(); } + } + ImmutableMap &operator=(const ImmutableMap &X) { if (Root != X.Root) { if (X.Root) { X.Root->retain(); } @@ -95,10 +99,6 @@ class ImmutableMap { return *this; } - ~ImmutableMap() { - if (Root) { Root->release(); } - } - class Factory { typename TreeTy::Factory F; const bool Canonicalize; @@ -166,12 +166,14 @@ class ImmutableMap { template struct CBWrapper { Callback C; + void operator()(value_type_ref V) { C(V.first,V.second); } }; template struct CBWrapperRef { Callback &C; + CBWrapperRef(Callback& c) : C(c) {} void operator()(value_type_ref V) { C(V.first,V.second); } @@ -254,14 +256,14 @@ template > class ImmutableMapRef { public: - typedef typename ValInfo::value_type value_type; - typedef typename ValInfo::value_type_ref value_type_ref; - typedef typename ValInfo::key_type key_type; - typedef typename ValInfo::key_type_ref key_type_ref; - typedef typename ValInfo::data_type data_type; - typedef typename ValInfo::data_type_ref data_type_ref; - typedef ImutAVLTree TreeTy; - typedef typename TreeTy::Factory FactoryTy; + using value_type = typename ValInfo::value_type; + using value_type_ref = typename ValInfo::value_type_ref; + using key_type = typename ValInfo::key_type; + using key_type_ref = typename ValInfo::key_type_ref; + using data_type = typename ValInfo::data_type; + using data_type_ref = typename ValInfo::data_type_ref; + using TreeTy = ImutAVLTree; + using FactoryTy = typename TreeTy::Factory; protected: TreeTy *Root; @@ -292,6 +294,11 @@ class ImmutableMapRef { } } + ~ImmutableMapRef() { + if (Root) + Root->release(); + } + ImmutableMapRef &operator=(const ImmutableMapRef &X) { if (Root != X.Root) { if (X.Root) @@ -306,11 +313,6 @@ class ImmutableMapRef { return *this; } - ~ImmutableMapRef() { - if (Root) - Root->release(); - } - static inline ImmutableMapRef getEmptyMap(FactoryTy *F) { return ImmutableMapRef(0, F); } diff --git a/include/llvm/ADT/ImmutableSet.h b/include/llvm/ADT/ImmutableSet.h index 9c9bcb81f76b..9d580c5a3d41 100644 --- a/include/llvm/ADT/ImmutableSet.h +++ b/include/llvm/ADT/ImmutableSet.h @@ -41,18 +41,16 @@ template class ImutAVLTreeGenericIterator; template class ImutAVLTree { public: - typedef typename ImutInfo::key_type_ref key_type_ref; - typedef typename ImutInfo::value_type value_type; - typedef typename ImutInfo::value_type_ref value_type_ref; + using key_type_ref = typename ImutInfo::key_type_ref; + using value_type = typename ImutInfo::value_type; + using value_type_ref = typename ImutInfo::value_type_ref; + using Factory = ImutAVLFactory; + using iterator = ImutAVLTreeInOrderIterator; - typedef ImutAVLFactory Factory; friend class ImutAVLFactory; friend class ImutIntervalAVLFactory; - friend class ImutAVLTreeGenericIterator; - typedef ImutAVLTreeInOrderIterator iterator; - //===----------------------------------------------------===// // Public Interface. //===----------------------------------------------------===// @@ -225,17 +223,17 @@ class ImutAVLTree { Factory *factory; ImutAVLTree *left; ImutAVLTree *right; - ImutAVLTree *prev; - ImutAVLTree *next; + ImutAVLTree *prev = nullptr; + ImutAVLTree *next = nullptr; - unsigned height : 28; - unsigned IsMutable : 1; - unsigned IsDigestCached : 1; - unsigned IsCanonicalized : 1; + unsigned height : 28; + bool IsMutable : 1; + bool IsDigestCached : 1; + bool IsCanonicalized : 1; value_type value; - uint32_t digest; - uint32_t refCount; + uint32_t digest = 0; + uint32_t refCount = 0; //===----------------------------------------------------===// // Internal methods (node manipulation; used by Factory). @@ -246,9 +244,8 @@ class ImutAVLTree { /// ImutAVLFactory. ImutAVLTree(Factory *f, ImutAVLTree* l, ImutAVLTree* r, value_type_ref v, unsigned height) - : factory(f), left(l), right(r), prev(nullptr), next(nullptr), - height(height), IsMutable(true), IsDigestCached(false), - IsCanonicalized(0), value(v), digest(0), refCount(0) + : factory(f), left(l), right(r), height(height), IsMutable(true), + IsDigestCached(false), IsCanonicalized(false), value(v) { if (left) left->retain(); if (right) right->retain(); @@ -369,11 +366,11 @@ class ImutAVLTree { template class ImutAVLFactory { friend class ImutAVLTree; - typedef ImutAVLTree TreeTy; - typedef typename TreeTy::value_type_ref value_type_ref; - typedef typename TreeTy::key_type_ref key_type_ref; - typedef DenseMap CacheTy; + using TreeTy = ImutAVLTree; + using value_type_ref = typename TreeTy::value_type_ref; + using key_type_ref = typename TreeTy::key_type_ref; + using CacheTy = DenseMap; CacheTy Cache; uintptr_t Allocator; @@ -659,7 +656,7 @@ class ImutAVLTreeGenericIterator enum VisitFlag { VisitedNone=0x0, VisitedLeft=0x1, VisitedRight=0x3, Flags=0x3 }; - typedef ImutAVLTree TreeTy; + using TreeTy = ImutAVLTree; ImutAVLTreeGenericIterator() = default; ImutAVLTreeGenericIterator(const TreeTy *Root) { @@ -764,11 +761,12 @@ template class ImutAVLTreeInOrderIterator : public std::iterator> { - typedef ImutAVLTreeGenericIterator InternalIteratorTy; + using InternalIteratorTy = ImutAVLTreeGenericIterator; + InternalIteratorTy InternalItr; public: - typedef ImutAVLTree TreeTy; + using TreeTy = ImutAVLTree; ImutAVLTreeInOrderIterator(const TreeTy* Root) : InternalItr(Root) { if (Root) @@ -840,8 +838,8 @@ struct ImutAVLValueIterator /// and generic handling of pointers is done below. template struct ImutProfileInfo { - typedef const T value_type; - typedef const T& value_type_ref; + using value_type = const T; + using value_type_ref = const T&; static void Profile(FoldingSetNodeID &ID, value_type_ref X) { FoldingSetTrait::Profile(X,ID); @@ -851,8 +849,8 @@ struct ImutProfileInfo { /// Profile traits for integers. template struct ImutProfileInteger { - typedef const T value_type; - typedef const T& value_type_ref; + using value_type = const T; + using value_type_ref = const T&; static void Profile(FoldingSetNodeID &ID, value_type_ref X) { ID.AddInteger(X); @@ -878,8 +876,8 @@ PROFILE_INTEGER_INFO(unsigned long long) /// Profile traits for booleans. template <> struct ImutProfileInfo { - typedef const bool value_type; - typedef const bool& value_type_ref; + using value_type = const bool; + using value_type_ref = const bool&; static void Profile(FoldingSetNodeID &ID, value_type_ref X) { ID.AddBoolean(X); @@ -890,8 +888,8 @@ struct ImutProfileInfo { /// references to unique objects. template struct ImutProfileInfo { - typedef const T* value_type; - typedef value_type value_type_ref; + using value_type = const T*; + using value_type_ref = value_type; static void Profile(FoldingSetNodeID &ID, value_type_ref X) { ID.AddPointer(X); @@ -910,12 +908,12 @@ struct ImutProfileInfo { /// std::equal_to<> and std::less<> to perform comparison of elements. template struct ImutContainerInfo : public ImutProfileInfo { - typedef typename ImutProfileInfo::value_type value_type; - typedef typename ImutProfileInfo::value_type_ref value_type_ref; - typedef value_type key_type; - typedef value_type_ref key_type_ref; - typedef bool data_type; - typedef bool data_type_ref; + using value_type = typename ImutProfileInfo::value_type; + using value_type_ref = typename ImutProfileInfo::value_type_ref; + using key_type = value_type; + using key_type_ref = value_type_ref; + using data_type = bool; + using data_type_ref = bool; static key_type_ref KeyOfValue(value_type_ref D) { return D; } static data_type_ref DataOfValue(value_type_ref) { return true; } @@ -936,12 +934,12 @@ struct ImutContainerInfo : public ImutProfileInfo { /// their addresses. template struct ImutContainerInfo : public ImutProfileInfo { - typedef typename ImutProfileInfo::value_type value_type; - typedef typename ImutProfileInfo::value_type_ref value_type_ref; - typedef value_type key_type; - typedef value_type_ref key_type_ref; - typedef bool data_type; - typedef bool data_type_ref; + using value_type = typename ImutProfileInfo::value_type; + using value_type_ref = typename ImutProfileInfo::value_type_ref; + using key_type = value_type; + using key_type_ref = value_type_ref; + using data_type = bool; + using data_type_ref = bool; static key_type_ref KeyOfValue(value_type_ref D) { return D; } static data_type_ref DataOfValue(value_type_ref) { return true; } @@ -960,9 +958,9 @@ struct ImutContainerInfo : public ImutProfileInfo { template > class ImmutableSet { public: - typedef typename ValInfo::value_type value_type; - typedef typename ValInfo::value_type_ref value_type_ref; - typedef ImutAVLTree TreeTy; + using value_type = typename ValInfo::value_type; + using value_type_ref = typename ValInfo::value_type_ref; + using TreeTy = ImutAVLTree; private: TreeTy *Root; @@ -980,6 +978,10 @@ class ImmutableSet { if (Root) { Root->retain(); } } + ~ImmutableSet() { + if (Root) { Root->release(); } + } + ImmutableSet &operator=(const ImmutableSet &X) { if (Root != X.Root) { if (X.Root) { X.Root->retain(); } @@ -989,10 +991,6 @@ class ImmutableSet { return *this; } - ~ImmutableSet() { - if (Root) { Root->release(); } - } - class Factory { typename TreeTy::Factory F; const bool Canonicalize; @@ -1084,7 +1082,7 @@ class ImmutableSet { // Iterators. //===--------------------------------------------------===// - typedef ImutAVLValueIterator iterator; + using iterator = ImutAVLValueIterator; iterator begin() const { return iterator(Root); } iterator end() const { return iterator(); } @@ -1112,10 +1110,10 @@ class ImmutableSet { template > class ImmutableSetRef { public: - typedef typename ValInfo::value_type value_type; - typedef typename ValInfo::value_type_ref value_type_ref; - typedef ImutAVLTree TreeTy; - typedef typename TreeTy::Factory FactoryTy; + using value_type = typename ValInfo::value_type; + using value_type_ref = typename ValInfo::value_type_ref; + using TreeTy = ImutAVLTree; + using FactoryTy = typename TreeTy::Factory; private: TreeTy *Root; @@ -1138,6 +1136,10 @@ class ImmutableSetRef { if (Root) { Root->retain(); } } + ~ImmutableSetRef() { + if (Root) { Root->release(); } + } + ImmutableSetRef &operator=(const ImmutableSetRef &X) { if (Root != X.Root) { if (X.Root) { X.Root->retain(); } @@ -1147,9 +1149,6 @@ class ImmutableSetRef { } return *this; } - ~ImmutableSetRef() { - if (Root) { Root->release(); } - } static ImmutableSetRef getEmptySet(FactoryTy *F) { return ImmutableSetRef(0, F); @@ -1196,7 +1195,7 @@ class ImmutableSetRef { // Iterators. //===--------------------------------------------------===// - typedef ImutAVLValueIterator iterator; + using iterator = ImutAVLValueIterator; iterator begin() const { return iterator(Root); } iterator end() const { return iterator(); } diff --git a/include/llvm/ADT/IndexedMap.h b/include/llvm/ADT/IndexedMap.h index 5ba85c027920..2ee80d2cde63 100644 --- a/include/llvm/ADT/IndexedMap.h +++ b/include/llvm/ADT/IndexedMap.h @@ -20,28 +20,28 @@ #ifndef LLVM_ADT_INDEXEDMAP_H #define LLVM_ADT_INDEXEDMAP_H -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include -#include namespace llvm { -template > +template > class IndexedMap { - typedef typename ToIndexT::argument_type IndexT; + using IndexT = typename ToIndexT::argument_type; // Prefer SmallVector with zero inline storage over std::vector. IndexedMaps // can grow very large and SmallVector grows more efficiently as long as T // is trivially copyable. - typedef SmallVector StorageT; + using StorageT = SmallVector; + StorageT storage_; T nullVal_; ToIndexT toIndex_; public: - IndexedMap() : nullVal_(T()) { } + IndexedMap() : nullVal_(T()) {} - explicit IndexedMap(const T& val) : nullVal_(val) { } + explicit IndexedMap(const T& val) : nullVal_(val) {} typename StorageT::reference operator[](IndexT n) { assert(toIndex_(n) < storage_.size() && "index out of bounds!"); @@ -80,6 +80,6 @@ template > } }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_ADT_INDEXEDMAP_H diff --git a/include/llvm/ADT/IntervalMap.h b/include/llvm/ADT/IntervalMap.h index 430b9671bd1d..f71366811218 100644 --- a/include/llvm/ADT/IntervalMap.h +++ b/include/llvm/ADT/IntervalMap.h @@ -106,6 +106,7 @@ #include "llvm/Support/RecyclingAllocator.h" #include #include +#include #include #include #include @@ -186,7 +187,7 @@ struct IntervalMapHalfOpenInfo { /// It should be considered private to the implementation. namespace IntervalMapImpl { -typedef std::pair IdxPair; +using IdxPair = std::pair; //===----------------------------------------------------------------------===// //--- IntervalMapImpl::NodeBase ---// @@ -445,7 +446,7 @@ struct NodeSizer { LeafSize = DesiredLeafSize > MinLeafSize ? DesiredLeafSize : MinLeafSize }; - typedef NodeBase, ValT, LeafSize> LeafBase; + using LeafBase = NodeBase, ValT, LeafSize>; enum { // Now that we have the leaf branching factor, compute the actual allocation @@ -461,8 +462,8 @@ struct NodeSizer { /// This typedef is very likely to be identical for all IntervalMaps with /// reasonably sized entries, so the same allocator can be shared among /// different kinds of maps. - typedef RecyclingAllocator Allocator; + using Allocator = + RecyclingAllocator; }; //===----------------------------------------------------------------------===// @@ -930,12 +931,12 @@ template ::LeafSize, typename Traits = IntervalMapInfo> class IntervalMap { - typedef IntervalMapImpl::NodeSizer Sizer; - typedef IntervalMapImpl::LeafNode Leaf; - typedef IntervalMapImpl::BranchNode - Branch; - typedef IntervalMapImpl::LeafNode RootLeaf; - typedef IntervalMapImpl::IdxPair IdxPair; + using Sizer = IntervalMapImpl::NodeSizer; + using Leaf = IntervalMapImpl::LeafNode; + using Branch = + IntervalMapImpl::BranchNode; + using RootLeaf = IntervalMapImpl::LeafNode; + using IdxPair = IntervalMapImpl::IdxPair; // The RootLeaf capacity is given as a template parameter. We must compute the // corresponding RootBranch capacity. @@ -945,8 +946,8 @@ class IntervalMap { RootBranchCap = DesiredRootBranchCap ? DesiredRootBranchCap : 1 }; - typedef IntervalMapImpl::BranchNode - RootBranch; + using RootBranch = + IntervalMapImpl::BranchNode; // When branched, we store a global start key as well as the branch node. struct RootBranchData { @@ -955,10 +956,10 @@ class IntervalMap { }; public: - typedef typename Sizer::Allocator Allocator; - typedef KeyT KeyType; - typedef ValT ValueType; - typedef Traits KeyTraits; + using Allocator = typename Sizer::Allocator; + using KeyType = KeyT; + using ValueType = ValT; + using KeyTraits = Traits; private: // The root data is either a RootLeaf or a RootBranchData instance. @@ -1290,7 +1291,7 @@ class IntervalMap::const_iterator : friend class IntervalMap; // The map referred to. - IntervalMap *map; + IntervalMap *map = nullptr; // We store a full path from the root to the current position. // The path may be partially filled, but never between iterator calls. @@ -1338,7 +1339,7 @@ class IntervalMap::const_iterator : public: /// const_iterator - Create an iterator that isn't pointing anywhere. - const_iterator() : map(nullptr) {} + const_iterator() = default; /// setMap - Change the map iterated over. This call must be followed by a /// call to goToBegin(), goToEnd(), or find() @@ -1509,7 +1510,8 @@ const_iterator::treeAdvanceTo(KeyT x) { template class IntervalMap::iterator : public const_iterator { friend class IntervalMap; - typedef IntervalMapImpl::IdxPair IdxPair; + + using IdxPair = IntervalMapImpl::IdxPair; explicit iterator(IntervalMap &map) : const_iterator(map) {} @@ -2003,7 +2005,7 @@ iterator::overflow(unsigned Level) { // Elements have been rearranged, now update node sizes and stops. bool SplitRoot = false; unsigned Pos = 0; - for (;;) { + while (true) { KeyT Stop = Node[Pos]->stop(NewSize[Pos]-1); if (NewNode && Pos == NewNode) { SplitRoot = insertNode(Level, NodeRef(Node[Pos], NewSize[Pos]), Stop); @@ -2045,8 +2047,9 @@ iterator::overflow(unsigned Level) { /// template class IntervalMapOverlaps { - typedef typename MapA::KeyType KeyType; - typedef typename MapA::KeyTraits Traits; + using KeyType = typename MapA::KeyType; + using Traits = typename MapA::KeyTraits; + typename MapA::const_iterator posA; typename MapB::const_iterator posB; @@ -2071,7 +2074,7 @@ class IntervalMapOverlaps { // Already overlapping. return; - for (;;) { + while (true) { // Make a.end > b.start. posA.advanceTo(posB.start()); if (!posA.valid() || !Traits::stopLess(posB.stop(), posA.start())) diff --git a/include/llvm/ADT/IntrusiveRefCntPtr.h b/include/llvm/ADT/IntrusiveRefCntPtr.h index a77cf04ea4d1..430ef86afbd9 100644 --- a/include/llvm/ADT/IntrusiveRefCntPtr.h +++ b/include/llvm/ADT/IntrusiveRefCntPtr.h @@ -1,4 +1,4 @@ -//== llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer ---*- C++ -*-==// +//==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -73,9 +73,10 @@ template class RefCountedBase { public: RefCountedBase() = default; - RefCountedBase(const RefCountedBase &) : RefCount(0) {} + RefCountedBase(const RefCountedBase &) {} void Retain() const { ++RefCount; } + void Release() const { assert(RefCount > 0 && "Reference count is already zero."); if (--RefCount == 0) @@ -136,7 +137,7 @@ template class IntrusiveRefCntPtr { T *Obj = nullptr; public: - typedef T element_type; + using element_type = T; explicit IntrusiveRefCntPtr() = default; IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } @@ -153,13 +154,13 @@ template class IntrusiveRefCntPtr { retain(); } + ~IntrusiveRefCntPtr() { release(); } + IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { swap(S); return *this; } - ~IntrusiveRefCntPtr() { release(); } - T &operator*() const { return *Obj; } T *operator->() const { return Obj; } T *get() const { return Obj; } @@ -183,6 +184,7 @@ template class IntrusiveRefCntPtr { if (Obj) IntrusiveRefCntPtrInfo::retain(Obj); } + void release() { if (Obj) IntrusiveRefCntPtrInfo::release(Obj); @@ -248,14 +250,16 @@ bool operator!=(const IntrusiveRefCntPtr &A, std::nullptr_t B) { template struct simplify_type; template struct simplify_type> { - typedef T *SimpleType; + using SimpleType = T *; + static SimpleType getSimplifiedValue(IntrusiveRefCntPtr &Val) { return Val.get(); } }; template struct simplify_type> { - typedef /*const*/ T *SimpleType; + using SimpleType = /*const*/ T *; + static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr &Val) { return Val.get(); } diff --git a/include/llvm/ADT/MapVector.h b/include/llvm/ADT/MapVector.h index ac1885758cb9..26a555ee1d3b 100644 --- a/include/llvm/ADT/MapVector.h +++ b/include/llvm/ADT/MapVector.h @@ -19,6 +19,12 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include +#include +#include +#include +#include +#include #include namespace llvm { @@ -27,20 +33,20 @@ namespace llvm { /// in a deterministic order. The values are kept in a std::vector and the /// mapping is done with DenseMap from Keys to indexes in that vector. template, - typename VectorType = std::vector > > + typename MapType = DenseMap, + typename VectorType = std::vector>> class MapVector { - typedef typename VectorType::value_type value_type; - typedef typename VectorType::size_type size_type; + using value_type = typename VectorType::value_type; + using size_type = typename VectorType::size_type; MapType Map; VectorType Vector; public: - typedef typename VectorType::iterator iterator; - typedef typename VectorType::const_iterator const_iterator; - typedef typename VectorType::reverse_iterator reverse_iterator; - typedef typename VectorType::const_reverse_iterator const_reverse_iterator; + using iterator = typename VectorType::iterator; + using const_iterator = typename VectorType::const_iterator; + using reverse_iterator = typename VectorType::reverse_iterator; + using const_reverse_iterator = typename VectorType::const_reverse_iterator; /// Clear the MapVector and return the underlying vector. VectorType takeVector() { @@ -220,4 +226,4 @@ struct SmallMapVector } // end namespace llvm -#endif +#endif // LLVM_ADT_MAPVECTOR_H diff --git a/include/llvm/ADT/Optional.h b/include/llvm/ADT/Optional.h index 701872c9f63f..b782d9da17ac 100644 --- a/include/llvm/ADT/Optional.h +++ b/include/llvm/ADT/Optional.h @@ -1,4 +1,4 @@ -//===-- Optional.h - Simple variant for passing optional values ---*- C++ -*-=// +//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,6 +19,8 @@ #include "llvm/ADT/None.h" #include "llvm/Support/AlignOf.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/type_traits.h" +#include #include #include #include @@ -28,15 +30,18 @@ namespace llvm { template class Optional { AlignedCharArrayUnion storage; - bool hasVal; -public: - typedef T value_type; + bool hasVal = false; + +public: + using value_type = T; + + Optional(NoneType) {} + explicit Optional() {} - Optional(NoneType) : hasVal(false) {} - explicit Optional() : hasVal(false) {} Optional(const T &y) : hasVal(true) { new (storage.buffer) T(y); } + Optional(const Optional &O) : hasVal(O.hasVal) { if (hasVal) new (storage.buffer) T(*O); @@ -45,12 +50,18 @@ class Optional { Optional(T &&y) : hasVal(true) { new (storage.buffer) T(std::forward(y)); } + Optional(Optional &&O) : hasVal(O) { if (O) { new (storage.buffer) T(std::move(*O)); O.reset(); } } + + ~Optional() { + reset(); + } + Optional &operator=(T &&y) { if (hasVal) **this = std::move(y); @@ -60,6 +71,7 @@ class Optional { } return *this; } + Optional &operator=(Optional &&O) { if (!O) reset(); @@ -112,10 +124,6 @@ class Optional { } } - ~Optional() { - reset(); - } - const T* getPointer() const { assert(hasVal); return reinterpret_cast(storage.buffer); } T* getPointer() { assert(hasVal); return reinterpret_cast(storage.buffer); } const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } @@ -144,8 +152,7 @@ class Optional { #endif }; -template struct isPodLike; -template struct isPodLike > { +template struct isPodLike> { // An Optional is pod-like if T is. static const bool value = isPodLike::value; }; @@ -284,6 +291,6 @@ template bool operator>=(const T &X, const Optional &Y) { return !(X < Y); } -} // end llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_ADT_OPTIONAL_H diff --git a/include/llvm/ADT/PackedVector.h b/include/llvm/ADT/PackedVector.h index 8f925f1ff5cb..95adc2926813 100644 --- a/include/llvm/ADT/PackedVector.h +++ b/include/llvm/ADT/PackedVector.h @@ -76,8 +76,8 @@ template class PackedVector : public PackedVectorBase::is_signed> { BitVectorTy Bits; - typedef PackedVectorBase::is_signed> base; + using base = PackedVectorBase::is_signed>; public: class reference { @@ -99,7 +99,7 @@ class PackedVector : public PackedVectorBase #include +#include +#include namespace llvm { @@ -29,7 +32,7 @@ namespace llvm { /// Also, the default constructed value zero initializes the integer. template class PointerEmbeddedInt { - uintptr_t Value; + uintptr_t Value = 0; // Note: This '<' is correct; using '<=' would result in some shifts // overflowing their storage types. @@ -54,15 +57,12 @@ class PointerEmbeddedInt { explicit PointerEmbeddedInt(uintptr_t Value, RawValueTag) : Value(Value) {} public: - PointerEmbeddedInt() : Value(0) {} + PointerEmbeddedInt() = default; - PointerEmbeddedInt(IntT I) { - *this = I; - } + PointerEmbeddedInt(IntT I) { *this = I; } PointerEmbeddedInt &operator=(IntT I) { - assert((std::is_signed::value ? llvm::isInt(I) - : llvm::isUInt(I)) && + assert((std::is_signed::value ? isInt(I) : isUInt(I)) && "Integer has bits outside those preserved!"); Value = static_cast(I) << Shift; return *this; @@ -81,15 +81,17 @@ class PointerEmbeddedInt { // types. template class PointerLikeTypeTraits> { - typedef PointerEmbeddedInt T; + using T = PointerEmbeddedInt; public: static inline void *getAsVoidPointer(const T &P) { return reinterpret_cast(P.Value); } + static inline T getFromVoidPointer(void *P) { return T(reinterpret_cast(P), typename T::RawValueTag()); } + static inline T getFromVoidPointer(const void *P) { return T(reinterpret_cast(P), typename T::RawValueTag()); } @@ -101,17 +103,19 @@ class PointerLikeTypeTraits> { // itself can be a key. template struct DenseMapInfo> { - typedef PointerEmbeddedInt T; - - typedef DenseMapInfo IntInfo; + using T = PointerEmbeddedInt; + using IntInfo = DenseMapInfo; static inline T getEmptyKey() { return IntInfo::getEmptyKey(); } static inline T getTombstoneKey() { return IntInfo::getTombstoneKey(); } + static unsigned getHashValue(const T &Arg) { return IntInfo::getHashValue(Arg); } + static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_ADT_POINTEREMBEDDEDINT_H diff --git a/include/llvm/ADT/PointerUnion.h b/include/llvm/ADT/PointerUnion.h index 7ce70ebc8ce0..aeab641f5715 100644 --- a/include/llvm/ADT/PointerUnion.h +++ b/include/llvm/ADT/PointerUnion.h @@ -158,7 +158,7 @@ template class PointerUnion { assert( get() == Val.getPointer() && "Can't get the address because PointerLikeTypeTraits changes the ptr"); - return (PT1 *)Val.getAddrOfPointer(); + return const_cast(reinterpret_cast(Val.getAddrOfPointer())); } /// Assignment from nullptr which just clears the union. diff --git a/include/llvm/ADT/ScopedHashTable.h b/include/llvm/ADT/ScopedHashTable.h index d52128e294a3..22b0c1bdaf4d 100644 --- a/include/llvm/ADT/ScopedHashTable.h +++ b/include/llvm/ADT/ScopedHashTable.h @@ -109,6 +109,7 @@ class ScopedHashTableScope { ScopedHashTableVal *getLastValInScope() { return LastValInScope; } + void setLastValInScope(ScopedHashTableVal *Val) { LastValInScope = Val; } @@ -151,13 +152,14 @@ class ScopedHashTable { public: /// ScopeTy - This is a helpful typedef that allows clients to get easy access /// to the name of the scope for this hash table. - typedef ScopedHashTableScope ScopeTy; - typedef unsigned size_type; + using ScopeTy = ScopedHashTableScope; + using size_type = unsigned; private: friend class ScopedHashTableScope; - typedef ScopedHashTableVal ValTy; + using ValTy = ScopedHashTableVal; + DenseMap TopLevelMap; ScopeTy *CurScope = nullptr; @@ -165,7 +167,7 @@ class ScopedHashTable { public: ScopedHashTable() = default; - ScopedHashTable(AllocatorTy A) : CurScope(0), Allocator(A) {} + ScopedHashTable(AllocatorTy A) : Allocator(A) {} ScopedHashTable(const ScopedHashTable &) = delete; ScopedHashTable &operator=(const ScopedHashTable &) = delete; @@ -194,7 +196,7 @@ class ScopedHashTable { insertIntoScope(CurScope, Key, Val); } - typedef ScopedHashTableIterator iterator; + using iterator = ScopedHashTableIterator; iterator end() { return iterator(0); } diff --git a/include/llvm/ADT/SmallBitVector.h b/include/llvm/ADT/SmallBitVector.h index 0ff427066959..b6391746639b 100644 --- a/include/llvm/ADT/SmallBitVector.h +++ b/include/llvm/ADT/SmallBitVector.h @@ -15,8 +15,15 @@ #define LLVM_ADT_SMALLBITVECTOR_H #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/MathExtras.h" +#include #include +#include +#include +#include +#include +#include namespace llvm { @@ -29,7 +36,7 @@ class SmallBitVector { // TODO: In "large" mode, a pointer to a BitVector is used, leading to an // unnecessary level of indirection. It would be more efficient to use a // pointer to memory containing size, allocation size, and the array of bits. - uintptr_t X; + uintptr_t X = 1; enum { // The number of bits in this class. @@ -54,7 +61,8 @@ class SmallBitVector { "Unsupported word size"); public: - typedef unsigned size_type; + using size_type = unsigned; + // Encapsulation of a single bit. class reference { SmallBitVector &TheVector; @@ -134,21 +142,8 @@ class SmallBitVector { } public: - typedef const_set_bits_iterator_impl const_set_bits_iterator; - typedef const_set_bits_iterator set_iterator; - - const_set_bits_iterator set_bits_begin() const { - return const_set_bits_iterator(*this); - } - const_set_bits_iterator set_bits_end() const { - return const_set_bits_iterator(*this, -1); - } - iterator_range set_bits() const { - return make_range(set_bits_begin(), set_bits_end()); - } - /// Creates an empty bitvector. - SmallBitVector() : X(1) {} + SmallBitVector() = default; /// Creates a bitvector of specified number of bits. All bits are initialized /// to the specified value. @@ -176,6 +171,21 @@ class SmallBitVector { delete getPointer(); } + using const_set_bits_iterator = const_set_bits_iterator_impl; + using set_iterator = const_set_bits_iterator; + + const_set_bits_iterator set_bits_begin() const { + return const_set_bits_iterator(*this); + } + + const_set_bits_iterator set_bits_end() const { + return const_set_bits_iterator(*this, -1); + } + + iterator_range set_bits() const { + return make_range(set_bits_begin(), set_bits_end()); + } + /// Tests whether there are no bits in this bitvector. bool empty() const { return isSmall() ? getSmallSize() == 0 : getPointer()->empty(); @@ -677,14 +687,16 @@ operator^(const SmallBitVector &LHS, const SmallBitVector &RHS) { return Result; } -} // End llvm namespace +} // end namespace llvm namespace std { - /// Implement std::swap in terms of BitVector swap. - inline void - swap(llvm::SmallBitVector &LHS, llvm::SmallBitVector &RHS) { - LHS.swap(RHS); - } + +/// Implement std::swap in terms of BitVector swap. +inline void +swap(llvm::SmallBitVector &LHS, llvm::SmallBitVector &RHS) { + LHS.swap(RHS); } -#endif +} // end namespace std + +#endif // LLVM_ADT_SMALLBITVECTOR_H diff --git a/include/llvm/ADT/SmallSet.h b/include/llvm/ADT/SmallSet.h index 6dac1677b7a2..d52d0f07f9a6 100644 --- a/include/llvm/ADT/SmallSet.h +++ b/include/llvm/ADT/SmallSet.h @@ -39,8 +39,9 @@ class SmallSet { /// we will never use. SmallVector Vector; std::set Set; - typedef typename SmallVector::const_iterator VIterator; - typedef typename SmallVector::iterator mutable_iterator; + + using VIterator = typename SmallVector::const_iterator; + using mutable_iterator = typename SmallVector::iterator; // In small mode SmallPtrSet uses linear search for the elements, so it is // not a good idea to choose this value too high. You may consider using a @@ -48,7 +49,7 @@ class SmallSet { static_assert(N <= 32, "N should be small"); public: - typedef size_t size_type; + using size_type = size_t; SmallSet() = default; diff --git a/include/llvm/ADT/StringExtras.h b/include/llvm/ADT/StringExtras.h index bbea8619a673..ffcf998a3d32 100644 --- a/include/llvm/ADT/StringExtras.h +++ b/include/llvm/ADT/StringExtras.h @@ -14,6 +14,7 @@ #ifndef LLVM_ADT_STRINGEXTRAS_H #define LLVM_ADT_STRINGEXTRAS_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include #include @@ -40,6 +41,11 @@ static inline StringRef toStringRef(bool B) { return StringRef(B ? "true" : "false"); } +/// Construct a string ref from an array ref of unsigned chars. +static inline StringRef toStringRef(ArrayRef Input) { + return StringRef(reinterpret_cast(Input.begin()), Input.size()); +} + /// Interpret the given character \p C as a hexadecimal digit and return its /// value. /// @@ -68,7 +74,7 @@ static inline std::string utohexstr(uint64_t X, bool LowerCase = false) { /// Convert buffer \p Input to its hexadecimal representation. /// The returned string is double the size of \p Input. -static inline std::string toHex(StringRef Input) { +inline std::string toHex(StringRef Input) { static const char *const LUT = "0123456789ABCDEF"; size_t Length = Input.size(); @@ -82,6 +88,10 @@ static inline std::string toHex(StringRef Input) { return Output; } +inline std::string toHex(ArrayRef Input) { + return toHex(toStringRef(Input)); +} + static inline uint8_t hexFromNibbles(char MSB, char LSB) { unsigned U1 = hexDigitValue(MSB); unsigned U2 = hexDigitValue(LSB); diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index 07626982d289..26a991812a3a 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -239,7 +239,9 @@ class Triple { /// Default constructor is the same as an empty string and leaves all /// triple fields unknown. - Triple() : Data(), Arch(), Vendor(), OS(), Environment(), ObjectFormat() {} + Triple() + : Data(), Arch(), SubArch(), Vendor(), OS(), Environment(), + ObjectFormat() {} explicit Triple(const Twine &Str); Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr); diff --git a/include/llvm/ADT/ilist_base.h b/include/llvm/ADT/ilist_base.h index 1ffc864bea2f..3d818a48d41d 100644 --- a/include/llvm/ADT/ilist_base.h +++ b/include/llvm/ADT/ilist_base.h @@ -1,4 +1,4 @@ -//===- llvm/ADT/ilist_base.h - Intrusive List Base ---------------*- C++ -*-==// +//===- llvm/ADT/ilist_base.h - Intrusive List Base --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,15 +12,13 @@ #include "llvm/ADT/ilist_node_base.h" #include -#include -#include namespace llvm { /// Implementations of list algorithms using ilist_node_base. template class ilist_base { public: - typedef ilist_node_base node_base_type; + using node_base_type = ilist_node_base; static void insertBeforeImpl(node_base_type &Next, node_base_type &N) { node_base_type &Prev = *Next.getPrev(); diff --git a/include/llvm/ADT/ilist_iterator.h b/include/llvm/ADT/ilist_iterator.h index c848d1a134f1..671e644e0154 100644 --- a/include/llvm/ADT/ilist_iterator.h +++ b/include/llvm/ADT/ilist_iterator.h @@ -1,4 +1,4 @@ -//===- llvm/ADT/ilist_iterator.h - Intrusive List Iterator -------*- C++ -*-==// +//===- llvm/ADT/ilist_iterator.h - Intrusive List Iterator ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,28 +23,30 @@ namespace ilist_detail { /// Find const-correct node types. template struct IteratorTraits; template struct IteratorTraits { - typedef typename OptionsT::value_type value_type; - typedef typename OptionsT::pointer pointer; - typedef typename OptionsT::reference reference; - typedef ilist_node_impl *node_pointer; - typedef ilist_node_impl &node_reference; + using value_type = typename OptionsT::value_type; + using pointer = typename OptionsT::pointer; + using reference = typename OptionsT::reference; + using node_pointer = ilist_node_impl *; + using node_reference = ilist_node_impl &; }; template struct IteratorTraits { - typedef const typename OptionsT::value_type value_type; - typedef typename OptionsT::const_pointer pointer; - typedef typename OptionsT::const_reference reference; - typedef const ilist_node_impl *node_pointer; - typedef const ilist_node_impl &node_reference; + using value_type = const typename OptionsT::value_type; + using pointer = typename OptionsT::const_pointer; + using reference = typename OptionsT::const_reference; + using node_pointer = const ilist_node_impl *; + using node_reference = const ilist_node_impl &; }; template struct IteratorHelper; template <> struct IteratorHelper : ilist_detail::NodeAccess { - typedef ilist_detail::NodeAccess Access; + using Access = ilist_detail::NodeAccess; + template static void increment(T *&I) { I = Access::getNext(*I); } template static void decrement(T *&I) { I = Access::getPrev(*I); } }; template <> struct IteratorHelper : ilist_detail::NodeAccess { - typedef ilist_detail::NodeAccess Access; + using Access = ilist_detail::NodeAccess; + template static void increment(T *&I) { I = Access::getPrev(*I); } template static void decrement(T *&I) { I = Access::getNext(*I); } }; @@ -58,24 +60,23 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess { friend ilist_iterator; friend ilist_iterator; - typedef ilist_detail::IteratorTraits Traits; - typedef ilist_detail::SpecificNodeAccess Access; + using Traits = ilist_detail::IteratorTraits; + using Access = ilist_detail::SpecificNodeAccess; public: - typedef typename Traits::value_type value_type; - typedef typename Traits::pointer pointer; - typedef typename Traits::reference reference; - typedef ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - typedef typename OptionsT::const_pointer const_pointer; - typedef typename OptionsT::const_reference const_reference; + using value_type = typename Traits::value_type; + using pointer = typename Traits::pointer; + using reference = typename Traits::reference; + using difference_type = ptrdiff_t; + using iterator_category = std::bidirectional_iterator_tag; + using const_pointer = typename OptionsT::const_pointer; + using const_reference = typename OptionsT::const_reference; private: - typedef typename Traits::node_pointer node_pointer; - typedef typename Traits::node_reference node_reference; + using node_pointer = typename Traits::node_pointer; + using node_reference = typename Traits::node_reference; - node_pointer NodePtr; + node_pointer NodePtr = nullptr; public: /// Create from an ilist_node. @@ -83,7 +84,7 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess { explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {} explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {} - ilist_iterator() : NodePtr(nullptr) {} + ilist_iterator() = default; // This is templated so that we can allow constructing a const iterator from // a nonconst iterator... @@ -184,8 +185,8 @@ template struct simplify_type; /// FIXME: remove this, since there is no implicit conversion to NodeTy. template struct simplify_type> { - typedef ilist_iterator iterator; - typedef typename iterator::pointer SimpleType; + using iterator = ilist_iterator; + using SimpleType = typename iterator::pointer; static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; } }; diff --git a/include/llvm/ADT/ilist_node.h b/include/llvm/ADT/ilist_node.h index 7244d0f40586..3362611697cb 100644 --- a/include/llvm/ADT/ilist_node.h +++ b/include/llvm/ADT/ilist_node.h @@ -1,4 +1,4 @@ -//==-- llvm/ADT/ilist_node.h - Intrusive Linked List Helper ------*- C++ -*-==// +//===- llvm/ADT/ilist_node.h - Intrusive Linked List Helper -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -21,11 +21,10 @@ namespace llvm { namespace ilist_detail { -struct NodeAccess; -} // end namespace ilist_detail -template -struct ilist_traits; +struct NodeAccess; + +} // end namespace ilist_detail template class ilist_iterator; template class ilist_sentinel; @@ -39,9 +38,9 @@ template class ilist_sentinel; /// provide type safety: you can't insert nodes of \a ilist_node_impl into the /// wrong \a simple_ilist or \a iplist. template class ilist_node_impl : OptionsT::node_base_type { - typedef typename OptionsT::value_type value_type; - typedef typename OptionsT::node_base_type node_base_type; - typedef typename OptionsT::list_base_type list_base_type; + using value_type = typename OptionsT::value_type; + using node_base_type = typename OptionsT::node_base_type; + using list_base_type = typename OptionsT::list_base_type; friend typename OptionsT::list_base_type; friend struct ilist_detail::NodeAccess; @@ -52,17 +51,18 @@ template class ilist_node_impl : OptionsT::node_base_type { friend class ilist_iterator; protected: - ilist_node_impl() = default; + using self_iterator = ilist_iterator; + using const_self_iterator = ilist_iterator; + using reverse_self_iterator = ilist_iterator; + using const_reverse_self_iterator = ilist_iterator; - typedef ilist_iterator self_iterator; - typedef ilist_iterator const_self_iterator; - typedef ilist_iterator reverse_self_iterator; - typedef ilist_iterator const_reverse_self_iterator; + ilist_node_impl() = default; private: ilist_node_impl *getPrev() { return static_cast(node_base_type::getPrev()); } + ilist_node_impl *getNext() { return static_cast(node_base_type::getNext()); } @@ -70,6 +70,7 @@ template class ilist_node_impl : OptionsT::node_base_type { const ilist_node_impl *getPrev() const { return static_cast(node_base_type::getPrev()); } + const ilist_node_impl *getNext() const { return static_cast(node_base_type::getNext()); } @@ -80,9 +81,11 @@ template class ilist_node_impl : OptionsT::node_base_type { public: self_iterator getIterator() { return self_iterator(*this); } const_self_iterator getIterator() const { return const_self_iterator(*this); } + reverse_self_iterator getReverseIterator() { return reverse_self_iterator(*this); } + const_reverse_self_iterator getReverseIterator() const { return const_reverse_self_iterator(*this); } @@ -151,6 +154,7 @@ class ilist_node }; namespace ilist_detail { + /// An access class for ilist_node private API. /// /// This gives access to the private parts of ilist nodes. Nodes for an ilist @@ -163,15 +167,18 @@ struct NodeAccess { static ilist_node_impl *getNodePtr(typename OptionsT::pointer N) { return N; } + template static const ilist_node_impl * getNodePtr(typename OptionsT::const_pointer N) { return N; } + template static typename OptionsT::pointer getValuePtr(ilist_node_impl *N) { return static_cast(N); } + template static typename OptionsT::const_pointer getValuePtr(const ilist_node_impl *N) { @@ -182,15 +189,18 @@ struct NodeAccess { static ilist_node_impl *getPrev(ilist_node_impl &N) { return N.getPrev(); } + template static ilist_node_impl *getNext(ilist_node_impl &N) { return N.getNext(); } + template static const ilist_node_impl * getPrev(const ilist_node_impl &N) { return N.getPrev(); } + template static const ilist_node_impl * getNext(const ilist_node_impl &N) { @@ -200,23 +210,27 @@ struct NodeAccess { template struct SpecificNodeAccess : NodeAccess { protected: - typedef typename OptionsT::pointer pointer; - typedef typename OptionsT::const_pointer const_pointer; - typedef ilist_node_impl node_type; + using pointer = typename OptionsT::pointer; + using const_pointer = typename OptionsT::const_pointer; + using node_type = ilist_node_impl; static node_type *getNodePtr(pointer N) { return NodeAccess::getNodePtr(N); } + static const node_type *getNodePtr(const_pointer N) { return NodeAccess::getNodePtr(N); } + static pointer getValuePtr(node_type *N) { return NodeAccess::getValuePtr(N); } + static const_pointer getValuePtr(const node_type *N) { return NodeAccess::getValuePtr(N); } }; + } // end namespace ilist_detail template @@ -265,6 +279,7 @@ class ilist_node_with_parent : public ilist_node { getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr)); return List.getPrevNode(*static_cast(this)); } + /// \brief Get the previous node, or \c nullptr for the list head. const NodeTy *getPrevNode() const { return const_cast(this)->getPrevNode(); @@ -278,6 +293,7 @@ class ilist_node_with_parent : public ilist_node { getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr)); return List.getNextNode(*static_cast(this)); } + /// \brief Get the next node, or \c nullptr for the list tail. const NodeTy *getNextNode() const { return const_cast(this)->getNextNode(); @@ -285,6 +301,6 @@ class ilist_node_with_parent : public ilist_node { /// @} }; -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_ADT_ILIST_NODE_H diff --git a/include/llvm/ADT/iterator.h b/include/llvm/ADT/iterator.h index 28dcdf9613ef..15720a67c047 100644 --- a/include/llvm/ADT/iterator.h +++ b/include/llvm/ADT/iterator.h @@ -11,9 +11,11 @@ #define LLVM_ADT_ITERATOR_H #include "llvm/ADT/iterator_range.h" +#include #include #include #include +#include namespace llvm { @@ -206,7 +208,7 @@ template < class iterator_adaptor_base : public iterator_facade_base { - typedef typename iterator_adaptor_base::iterator_facade_base BaseT; + using BaseT = typename iterator_adaptor_base::iterator_facade_base; protected: WrappedIteratorT I; @@ -221,7 +223,7 @@ class iterator_adaptor_base const WrappedIteratorT &wrapped() const { return I; } public: - typedef DifferenceTypeT difference_type; + using difference_type = DifferenceTypeT; DerivedT &operator+=(difference_type n) { static_assert( @@ -279,7 +281,7 @@ class iterator_adaptor_base /// which is implemented with some iterator over T*s: /// /// \code -/// typedef pointee_iterator::iterator> iterator; +/// using iterator = pointee_iterator::iterator>; /// \endcode template #include #include +#include +#include +#include namespace llvm { @@ -77,23 +82,23 @@ class simple_ilist typename ilist_detail::compute_node_options::type> { static_assert(ilist_detail::check_options::value, "Unrecognized node option!"); - typedef - typename ilist_detail::compute_node_options::type OptionsT; - typedef typename OptionsT::list_base_type list_base_type; + using OptionsT = + typename ilist_detail::compute_node_options::type; + using list_base_type = typename OptionsT::list_base_type; ilist_sentinel Sentinel; public: - typedef typename OptionsT::value_type value_type; - typedef typename OptionsT::pointer pointer; - typedef typename OptionsT::reference reference; - typedef typename OptionsT::const_pointer const_pointer; - typedef typename OptionsT::const_reference const_reference; - typedef ilist_iterator iterator; - typedef ilist_iterator const_iterator; - typedef ilist_iterator reverse_iterator; - typedef ilist_iterator const_reverse_iterator; - typedef size_t size_type; - typedef ptrdiff_t difference_type; + using value_type = typename OptionsT::value_type; + using pointer = typename OptionsT::pointer; + using reference = typename OptionsT::reference; + using const_pointer = typename OptionsT::const_pointer; + using const_reference = typename OptionsT::const_reference; + using iterator = ilist_iterator; + using const_iterator = ilist_iterator; + using reverse_iterator = ilist_iterator; + using const_reverse_iterator = ilist_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; simple_ilist() = default; ~simple_ilist() = default; diff --git a/include/llvm/Analysis/MemorySSA.h b/include/llvm/Analysis/MemorySSA.h index f0bba8c4c020..462e4594266e 100644 --- a/include/llvm/Analysis/MemorySSA.h +++ b/include/llvm/Analysis/MemorySSA.h @@ -147,7 +147,6 @@ class MemoryAccess MemoryAccess(const MemoryAccess &) = delete; MemoryAccess &operator=(const MemoryAccess &) = delete; - void *operator new(size_t, unsigned) = delete; void *operator new(size_t) = delete; BasicBlock *getBlock() const { return Block; } @@ -232,7 +231,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const MemoryAccess &MA) { /// MemoryDef instead. class MemoryUseOrDef : public MemoryAccess { public: - void *operator new(size_t, unsigned) = delete; void *operator new(size_t) = delete; DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess); @@ -298,7 +296,6 @@ class MemoryUse final : public MemoryUseOrDef { // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 1); } - void *operator new(size_t, unsigned) = delete; static inline bool classof(const Value *MA) { return MA->getValueID() == MemoryUseVal; @@ -355,7 +352,6 @@ class MemoryDef final : public MemoryUseOrDef { // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 1); } - void *operator new(size_t, unsigned) = delete; static inline bool classof(const Value *MA) { return MA->getValueID() == MemoryDefVal; @@ -438,8 +434,6 @@ class MemoryPhi final : public MemoryAccess { allocHungoffUses(ReservedSpace); } - void *operator new(size_t, unsigned) = delete; - // Block iterator interface. This provides access to the list of incoming // basic blocks, which parallels the list of incoming values. typedef BasicBlock **block_iterator; diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index 8ee9712b93d8..2a4b768256d1 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/include/llvm/Analysis/ScalarEvolution.h @@ -1214,26 +1214,31 @@ class ScalarEvolution { SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap, unsigned Depth = 0); const SCEV *getAddExpr(const SCEV *LHS, const SCEV *RHS, - SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap) { + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap, + unsigned Depth = 0) { SmallVector Ops = {LHS, RHS}; - return getAddExpr(Ops, Flags); + return getAddExpr(Ops, Flags, Depth); } const SCEV *getAddExpr(const SCEV *Op0, const SCEV *Op1, const SCEV *Op2, - SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap) { + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap, + unsigned Depth = 0) { SmallVector Ops = {Op0, Op1, Op2}; - return getAddExpr(Ops, Flags); + return getAddExpr(Ops, Flags, Depth); } const SCEV *getMulExpr(SmallVectorImpl &Ops, - SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap); + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap, + unsigned Depth = 0); const SCEV *getMulExpr(const SCEV *LHS, const SCEV *RHS, - SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap) { + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap, + unsigned Depth = 0) { SmallVector Ops = {LHS, RHS}; - return getMulExpr(Ops, Flags); + return getMulExpr(Ops, Flags, Depth); } const SCEV *getMulExpr(const SCEV *Op0, const SCEV *Op1, const SCEV *Op2, - SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap) { + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap, + unsigned Depth = 0) { SmallVector Ops = {Op0, Op1, Op2}; - return getMulExpr(Ops, Flags); + return getMulExpr(Ops, Flags, Depth); } const SCEV *getUDivExpr(const SCEV *LHS, const SCEV *RHS); const SCEV *getUDivExactExpr(const SCEV *LHS, const SCEV *RHS); @@ -1287,7 +1292,8 @@ class ScalarEvolution { /// Return LHS-RHS. Minus is represented in SCEV as A+B*-1. const SCEV *getMinusSCEV(const SCEV *LHS, const SCEV *RHS, - SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap); + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap, + unsigned Depth = 0); /// Return a SCEV corresponding to a conversion of the input value to the /// specified type. If the type must be extended, it is zero extended. @@ -1693,10 +1699,14 @@ class ScalarEvolution { bool doesIVOverflowOnGT(const SCEV *RHS, const SCEV *Stride, bool IsSigned, bool NoWrap); - /// Get add expr already created or create a new one + /// Get add expr already created or create a new one. const SCEV *getOrCreateAddExpr(SmallVectorImpl &Ops, SCEV::NoWrapFlags Flags); + /// Get mul expr already created or create a new one. + const SCEV *getOrCreateMulExpr(SmallVectorImpl &Ops, + SCEV::NoWrapFlags Flags); + private: FoldingSet UniqueSCEVs; FoldingSet UniquePreds; diff --git a/include/llvm/Analysis/TargetTransformInfo.h b/include/llvm/Analysis/TargetTransformInfo.h index cd8c2cd24244..af2ebb7b6b44 100644 --- a/include/llvm/Analysis/TargetTransformInfo.h +++ b/include/llvm/Analysis/TargetTransformInfo.h @@ -235,6 +235,11 @@ class TargetTransformInfo { /// starting with the sources of divergence. bool isSourceOfDivergence(const Value *V) const; + // \brief Returns true for the target specific + // set of operations which produce uniform result + // even taking non-unform arguments + bool isAlwaysUniform(const Value *V) const; + /// Returns the address space ID for a target's 'flat' address space. Note /// this is not necessarily the same as addrspace(0), which LLVM sometimes /// refers to as the generic address space. The flat address space is a @@ -821,6 +826,7 @@ class TargetTransformInfo::Concept { virtual int getUserCost(const User *U) = 0; virtual bool hasBranchDivergence() = 0; virtual bool isSourceOfDivergence(const Value *V) = 0; + virtual bool isAlwaysUniform(const Value *V) = 0; virtual unsigned getFlatAddressSpace() = 0; virtual bool isLoweredToCall(const Function *F) = 0; virtual void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) = 0; @@ -873,7 +879,7 @@ class TargetTransformInfo::Concept { virtual int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, Type *Ty) = 0; virtual unsigned getNumberOfRegisters(bool Vector) = 0; - virtual unsigned getRegisterBitWidth(bool Vector) = 0; + virtual unsigned getRegisterBitWidth(bool Vector) const = 0; virtual unsigned getMinVectorRegisterBitWidth() = 0; virtual bool shouldConsiderAddressTypePromotion( const Instruction &I, bool &AllowPromotionWithoutCommonHeader) = 0; @@ -998,6 +1004,10 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept { return Impl.isSourceOfDivergence(V); } + bool isAlwaysUniform(const Value *V) override { + return Impl.isAlwaysUniform(V); + } + unsigned getFlatAddressSpace() override { return Impl.getFlatAddressSpace(); } @@ -1119,7 +1129,7 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept { unsigned getNumberOfRegisters(bool Vector) override { return Impl.getNumberOfRegisters(Vector); } - unsigned getRegisterBitWidth(bool Vector) override { + unsigned getRegisterBitWidth(bool Vector) const override { return Impl.getRegisterBitWidth(Vector); } unsigned getMinVectorRegisterBitWidth() override { diff --git a/include/llvm/Analysis/TargetTransformInfoImpl.h b/include/llvm/Analysis/TargetTransformInfoImpl.h index 72de7c12eb3e..24ac3b1213e1 100644 --- a/include/llvm/Analysis/TargetTransformInfoImpl.h +++ b/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -177,6 +177,8 @@ class TargetTransformInfoImplBase { bool isSourceOfDivergence(const Value *V) { return false; } + bool isAlwaysUniform(const Value *V) { return false; } + unsigned getFlatAddressSpace () { return -1; } @@ -320,7 +322,7 @@ class TargetTransformInfoImplBase { unsigned getNumberOfRegisters(bool Vector) { return 8; } - unsigned getRegisterBitWidth(bool Vector) { return 32; } + unsigned getRegisterBitWidth(bool Vector) const { return 32; } unsigned getMinVectorRegisterBitWidth() { return 128; } diff --git a/include/llvm/Analysis/TypeMetadataUtils.h b/include/llvm/Analysis/TypeMetadataUtils.h index 17906ba4e392..422e153a5a78 100644 --- a/include/llvm/Analysis/TypeMetadataUtils.h +++ b/include/llvm/Analysis/TypeMetadataUtils.h @@ -20,6 +20,13 @@ namespace llvm { +/// The type of CFI jumptable needed for a function. +enum CfiFunctionLinkage { + CFL_Definition = 0, + CFL_Declaration = 1, + CFL_WeakDeclaration = 2 +}; + /// A call site that could be devirtualized. struct DevirtCallSite { /// The offset from the address point to the virtual function. diff --git a/include/llvm/Analysis/ValueTracking.h b/include/llvm/Analysis/ValueTracking.h index 612779b1ce86..e953ec8ab6ab 100644 --- a/include/llvm/Analysis/ValueTracking.h +++ b/include/llvm/Analysis/ValueTracking.h @@ -249,8 +249,8 @@ template class ArrayRef; }; /// Returns true if the value \p V is a pointer into a ContantDataArray. - /// If successfull \p Index will point to a ConstantDataArray info object - /// with an apropriate offset. + /// If successful \p Index will point to a ConstantDataArray info object + /// with an appropriate offset. bool getConstantDataArrayInfo(const Value *V, ConstantDataArraySlice &Slice, unsigned ElementSize, uint64_t Offset = 0); diff --git a/include/llvm/BinaryFormat/ELF.h b/include/llvm/BinaryFormat/ELF.h index 3724f555c283..a4450ee13b40 100644 --- a/include/llvm/BinaryFormat/ELF.h +++ b/include/llvm/BinaryFormat/ELF.h @@ -1,4 +1,4 @@ -//===-- llvm/BinaryFormat/ELF.h - ELF constants and structures --*- C++ -*-===// +//===- llvm/BinaryFormat/ELF.h - ELF constants and structures ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -20,27 +20,25 @@ #ifndef LLVM_BINARYFORMAT_ELF_H #define LLVM_BINARYFORMAT_ELF_H -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DataTypes.h" +#include #include namespace llvm { - namespace ELF { -typedef uint32_t Elf32_Addr; // Program address -typedef uint32_t Elf32_Off; // File offset -typedef uint16_t Elf32_Half; -typedef uint32_t Elf32_Word; -typedef int32_t Elf32_Sword; +using Elf32_Addr = uint32_t; // Program address +using Elf32_Off = uint32_t; // File offset +using Elf32_Half = uint16_t; +using Elf32_Word = uint32_t; +using Elf32_Sword = int32_t; -typedef uint64_t Elf64_Addr; -typedef uint64_t Elf64_Off; -typedef uint16_t Elf64_Half; -typedef uint32_t Elf64_Word; -typedef int32_t Elf64_Sword; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; +using Elf64_Addr = uint64_t; +using Elf64_Off = uint64_t; +using Elf64_Half = uint16_t; +using Elf64_Word = uint32_t; +using Elf64_Sword = int32_t; +using Elf64_Xword = uint64_t; +using Elf64_Sxword = int64_t; // Object file magic string. static const char ElfMagic[] = {0x7f, 'E', 'L', 'F', '\0'}; @@ -75,9 +73,11 @@ struct Elf32_Ehdr { Elf32_Half e_shentsize; // Size of an entry in the section header table Elf32_Half e_shnum; // Number of entries in the section header table Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table + bool checkMagic() const { return (memcmp(e_ident, ElfMagic, strlen(ElfMagic))) == 0; } + unsigned char getFileClass() const { return e_ident[EI_CLASS]; } unsigned char getDataEncoding() const { return e_ident[EI_DATA]; } }; @@ -99,9 +99,11 @@ struct Elf64_Ehdr { Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; + bool checkMagic() const { return (memcmp(e_ident, ElfMagic, strlen(ElfMagic))) == 0; } + unsigned char getFileClass() const { return e_ident[EI_CLASS]; } unsigned char getDataEncoding() const { return e_ident[EI_DATA]; } }; @@ -683,6 +685,7 @@ enum : unsigned { SHT_GROUP = 17, // Section group. SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries. SHT_LOOS = 0x60000000, // Lowest operating system-specific type. + SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table. SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes. SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table. SHT_GNU_verdef = 0x6ffffffd, // GNU version definitions. @@ -1356,7 +1359,6 @@ enum { }; } // end namespace ELF - } // end namespace llvm -#endif +#endif // LLVM_BINARYFORMAT_ELF_H diff --git a/include/llvm/Bitcode/BitcodeReader.h b/include/llvm/Bitcode/BitcodeReader.h index 61e4f6351b19..0e17e9a0a278 100644 --- a/include/llvm/Bitcode/BitcodeReader.h +++ b/include/llvm/Bitcode/BitcodeReader.h @@ -42,6 +42,12 @@ namespace llvm { struct BitcodeFileContents; + /// Basic information extracted from a bitcode module to be used for LTO. + struct BitcodeLTOInfo { + bool IsThinLTO; + bool HasSummary; + }; + /// Represents a module in a bitcode file. class BitcodeModule { // This covers the identification (if present) and module blocks. @@ -90,15 +96,17 @@ namespace llvm { /// Read the entire bitcode module and return it. Expected> parseModule(LLVMContext &Context); - /// Check if the given bitcode buffer contains a summary block. - Expected hasSummary(); + /// Returns information about the module to be used for LTO: whether to + /// compile with ThinLTO, and whether it has a summary. + Expected getLTOInfo(); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getSummary(); /// Parse the specified bitcode buffer and merge its module summary index /// into CombinedIndex. - Error readSummary(ModuleSummaryIndex &CombinedIndex, unsigned ModuleId); + Error readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, + uint64_t ModuleId); }; struct BitcodeFileContents { @@ -147,8 +155,8 @@ namespace llvm { Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); - /// Check if the given bitcode buffer contains a summary block. - Expected hasGlobalValueSummary(MemoryBufferRef Buffer); + /// Returns LTO information for the specified bitcode file. + Expected getBitcodeLTOInfo(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer, returning the module summary index. Expected> @@ -157,7 +165,7 @@ namespace llvm { /// Parse the specified bitcode buffer and merge the index into CombinedIndex. Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, - unsigned ModuleId); + uint64_t ModuleId); /// Parse the module summary index out of an IR file and return the module /// summary index object if found, or an empty summary if not. If Path refers diff --git a/include/llvm/Bitcode/BitcodeWriter.h b/include/llvm/Bitcode/BitcodeWriter.h index 23b5ae87b278..7c3c4b2e0cbd 100644 --- a/include/llvm/Bitcode/BitcodeWriter.h +++ b/include/llvm/Bitcode/BitcodeWriter.h @@ -67,6 +67,10 @@ namespace llvm { void writeModule(const Module *M, bool ShouldPreserveUseListOrder = false, const ModuleSummaryIndex *Index = nullptr, bool GenerateHash = false, ModuleHash *ModHash = nullptr); + + void writeIndex( + const ModuleSummaryIndex *Index, + const std::map *ModuleToSummariesForIndex); }; /// \brief Write the specified module to the specified raw output stream. diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index a643bfd1dcea..4e3e177cac8f 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -240,6 +240,14 @@ enum GlobalValueSummarySymtabCodes { // summaries, but it can also appear in per-module summaries for PGO data. // [valueid, guid] FS_VALUE_GUID = 16, + // The list of local functions with CFI jump tables. Function names are + // strings in strtab. + // [n * name] + FS_CFI_FUNCTION_DEFS = 17, + // The list of external functions with CFI jump tables. Function names are + // strings in strtab. + // [n * name] + FS_CFI_FUNCTION_DECLS = 18, }; enum MetadataCodes { diff --git a/include/llvm/CodeGen/BasicTTIImpl.h b/include/llvm/CodeGen/BasicTTIImpl.h index 9e33df6b55ec..5eb7a0f61eec 100644 --- a/include/llvm/CodeGen/BasicTTIImpl.h +++ b/include/llvm/CodeGen/BasicTTIImpl.h @@ -93,6 +93,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase { bool isSourceOfDivergence(const Value *V) { return false; } + bool isAlwaysUniform(const Value *V) { return false; } + unsigned getFlatAddressSpace() { // Return an invalid address space. return -1; @@ -346,7 +348,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase { unsigned getNumberOfRegisters(bool Vector) { return Vector ? 0 : 1; } - unsigned getRegisterBitWidth(bool Vector) { return 32; } + unsigned getRegisterBitWidth(bool Vector) const { return 32; } /// Estimate the overhead of scalarizing an instruction. Insert and Extract /// are set if the result needs to be inserted and/or extracted from vectors. diff --git a/include/llvm/CodeGen/FunctionLoweringInfo.h b/include/llvm/CodeGen/FunctionLoweringInfo.h index 7d7c3e8cfd22..f32a58915118 100644 --- a/include/llvm/CodeGen/FunctionLoweringInfo.h +++ b/include/llvm/CodeGen/FunctionLoweringInfo.h @@ -82,6 +82,11 @@ class FunctionLoweringInfo { DenseMap, unsigned> SwiftErrorVRegUpwardsUse; + /// A map from instructions that define/use a swifterror value to the virtual + /// register that represents that def/use. + llvm::DenseMap, unsigned> + SwiftErrorVRegDefUses; + /// The swifterror argument of the current function. const Value *SwiftErrorArg; @@ -101,6 +106,13 @@ class FunctionLoweringInfo { void setCurrentSwiftErrorVReg(const MachineBasicBlock *MBB, const Value *, unsigned); + /// Get or create the swifterror value virtual register for a def of a + /// swifterror by an instruction. + std::pair getOrCreateSwiftErrorVRegDefAt(const Instruction *); + std::pair + getOrCreateSwiftErrorVRegUseAt(const Instruction *, const MachineBasicBlock *, + const Value *); + /// ValueMap - Since we emit code for the function a basic block at a time, /// we must remember which virtual registers hold the values for /// cross-basic-block values. diff --git a/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h index 3148e70b56f8..5197ba869c0a 100644 --- a/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ b/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -21,9 +21,11 @@ #ifndef LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZEHELPER_H #define LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZEHELPER_H +#include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/LowLevelType.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/RuntimeLibcalls.h" namespace llvm { // Forward declarations. @@ -99,6 +101,12 @@ class LegalizerHelper { const LegalizerInfo &LI; }; +/// Helper function that replaces \p MI with a libcall. +LegalizerHelper::LegalizeResult +replaceWithLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, + RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result, + ArrayRef Args); + } // End namespace llvm. #endif diff --git a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index db72f78c8321..4e7b8350038b 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -40,8 +40,8 @@ class MachineIRBuilder { MachineFunction *MF; /// Information used to access the description of the opcodes. const TargetInstrInfo *TII; - /// Information used to verify types are consistent. - const MachineRegisterInfo *MRI; + /// Information used to verify types are consistent and to create virtual registers. + MachineRegisterInfo *MRI; /// Debug location to be set to any instruction we create. DebugLoc DL; @@ -229,6 +229,26 @@ class MachineIRBuilder { MachineInstrBuilder buildGEP(unsigned Res, unsigned Op0, unsigned Op1); + /// Materialize and insert \p Res = G_GEP \p Op0, (G_CONSTANT \p Value) + /// + /// G_GEP adds \p Value bytes to the pointer specified by \p Op0, + /// storing the resulting pointer in \p Res. If \p Value is zero then no + /// G_GEP or G_CONSTANT will be created and \pre Op0 will be assigned to + /// \p Res. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre \p Op0 must be a generic virtual register with pointer type. + /// \pre \p ValueTy must be a scalar type. + /// \pre \p Res must be 0. This is to detect confusion between + /// materializeGEP() and buildGEP(). + /// \post \p Res will either be a new generic virtual register of the same + /// type as \p Op0 or \p Op0 itself. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + Optional materializeGEP(unsigned &Res, unsigned Op0, + const LLT &ValueTy, + uint64_t Value); + /// Build and insert \p Res = G_PTR_MASK \p Op0, \p NumBits /// /// G_PTR_MASK clears the low bits of a pointer operand without destroying its diff --git a/include/llvm/CodeGen/RuntimeLibcalls.h b/include/llvm/CodeGen/RuntimeLibcalls.h index ddfabb0c44d6..8c3aacaa8efc 100644 --- a/include/llvm/CodeGen/RuntimeLibcalls.h +++ b/include/llvm/CodeGen/RuntimeLibcalls.h @@ -333,12 +333,12 @@ namespace RTLIB { MEMSET, MEMMOVE, - // ELEMENT-WISE ATOMIC MEMORY - MEMCPY_ELEMENT_ATOMIC_1, - MEMCPY_ELEMENT_ATOMIC_2, - MEMCPY_ELEMENT_ATOMIC_4, - MEMCPY_ELEMENT_ATOMIC_8, - MEMCPY_ELEMENT_ATOMIC_16, + // ELEMENT-WISE UNORDERED-ATOMIC MEMORY of different element sizes + MEMCPY_ELEMENT_UNORDERED_ATOMIC_1, + MEMCPY_ELEMENT_UNORDERED_ATOMIC_2, + MEMCPY_ELEMENT_UNORDERED_ATOMIC_4, + MEMCPY_ELEMENT_UNORDERED_ATOMIC_8, + MEMCPY_ELEMENT_UNORDERED_ATOMIC_16, // EXCEPTION HANDLING UNWIND_RESUME, @@ -511,9 +511,10 @@ namespace RTLIB { /// UNKNOWN_LIBCALL if there is none. Libcall getSYNC(unsigned Opc, MVT VT); - /// getMEMCPY_ELEMENT_ATOMIC - Return MEMCPY_ELEMENT_ATOMIC_* value for the - /// given element size or UNKNOW_LIBCALL if there is none. - Libcall getMEMCPY_ELEMENT_ATOMIC(uint64_t ElementSize); + /// getMEMCPY_ELEMENT_UNORDERED_ATOMIC - Return + /// MEMCPY_ELEMENT_UNORDERED_ATOMIC_* value for the given element size or + /// UNKNOW_LIBCALL if there is none. + Libcall getMEMCPY_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize); } } diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index 2ef7796a4a07..f3f3003b7e20 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -1217,6 +1217,12 @@ class SelectionDAG { void ReplaceAllUsesOfValuesWith(const SDValue *From, const SDValue *To, unsigned Num); + /// If an existing load has uses of its chain, create a token factor node with + /// that chain and the new memory node's chain and update users of the old + /// chain to the token factor. This ensures that the new memory node will have + /// the same relative memory dependency position as the old load. + void makeEquivalentMemoryOrdering(LoadSDNode *Old, SDValue New); + /// Topological-sort the AllNodes list and a /// assign a unique node id for each node in the DAG based on their /// topological order. Returns the number of nodes. diff --git a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 106a084a95c0..e4d3cc9cecfc 100644 --- a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -42,9 +42,8 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { ~TargetLoweringObjectFileELF() override = default; /// Emit Obj-C garbage collection and linker options. - void emitModuleFlags(MCStreamer &Streamer, - ArrayRef ModuleFlags, - const TargetMachine &TM) const override; + void emitModuleMetadata(MCStreamer &Streamer, Module &M, + const TargetMachine &TM) const override; void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &TM, const MCSymbol *Sym) const override; @@ -99,9 +98,8 @@ class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile { void Initialize(MCContext &Ctx, const TargetMachine &TM) override; /// Emit the module flags that specify the garbage collection information. - void emitModuleFlags(MCStreamer &Streamer, - ArrayRef ModuleFlags, - const TargetMachine &TM) const override; + void emitModuleMetadata(MCStreamer &Streamer, Module &M, + const TargetMachine &TM) const override; MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const override; @@ -155,9 +153,8 @@ class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { const TargetMachine &TM) const override; /// Emit Obj-C garbage collection and linker options. - void emitModuleFlags(MCStreamer &Streamer, - ArrayRef ModuleFlags, - const TargetMachine &TM) const override; + void emitModuleMetadata(MCStreamer &Streamer, Module &M, + const TargetMachine &TM) const override; MCSection *getStaticCtorSection(unsigned Priority, const MCSymbol *KeySym) const override; diff --git a/include/llvm/DebugInfo/CodeView/CodeView.h b/include/llvm/DebugInfo/CodeView/CodeView.h index 251c9d1ae62c..6820e26b754c 100644 --- a/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/include/llvm/DebugInfo/CodeView/CodeView.h @@ -418,6 +418,8 @@ CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ProcSymFlags) /// Corresponds to COMPILESYM2::Flags bitfield. enum class CompileSym2Flags : uint32_t { + None = 0, + SourceLanguageMask = 0xFF, EC = 1 << 8, NoDbgInfo = 1 << 9, LTCG = 1 << 10, @@ -432,6 +434,8 @@ CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym2Flags) /// Corresponds to COMPILESYM3::Flags bitfield. enum class CompileSym3Flags : uint32_t { + None = 0, + SourceLanguageMask = 0xFF, EC = 1 << 8, NoDbgInfo = 1 << 9, LTCG = 1 << 10, @@ -448,6 +452,7 @@ enum class CompileSym3Flags : uint32_t { CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym3Flags) enum class ExportFlags : uint16_t { + None = 0, IsConstant = 1 << 0, IsData = 1 << 1, IsPrivate = 1 << 2, diff --git a/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h b/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h index 686b5c4f242e..1e329c7c3f14 100644 --- a/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h +++ b/include/llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h @@ -49,6 +49,7 @@ class DebugFrameDataSubsection final : public DebugSubsection { Error commit(BinaryStreamWriter &Writer) const override; void addFrameData(const FrameData &Frame); + void setFrames(ArrayRef Frames); private: std::vector Frames; diff --git a/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h b/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h index c9b062717baa..7484af663105 100644 --- a/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h +++ b/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h @@ -19,7 +19,7 @@ namespace llvm { namespace codeview { -class DebugInlineeLinesSubsectionsRef; +class DebugInlineeLinesSubsectionRef; class DebugChecksumsSubsection; enum class InlineeLinesSignature : uint32_t { diff --git a/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h b/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h index 49a269d92e35..694731742064 100644 --- a/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h +++ b/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h @@ -49,13 +49,13 @@ class DebugSubsectionRecord { class DebugSubsectionRecordBuilder { public: - DebugSubsectionRecordBuilder(std::unique_ptr Subsection, + DebugSubsectionRecordBuilder(std::shared_ptr Subsection, CodeViewContainer Container); uint32_t calculateSerializedLength(); Error commit(BinaryStreamWriter &Writer) const; private: - std::unique_ptr Subsection; + std::shared_ptr Subsection; CodeViewContainer Container; }; @@ -64,6 +64,9 @@ class DebugSubsectionRecordBuilder { template <> struct VarStreamArrayExtractor { Error operator()(BinaryStreamRef Stream, uint32_t &Length, codeview::DebugSubsectionRecord &Info) { + // FIXME: We need to pass the container type through to this function. In + // practice this isn't super important since the subsection header describes + // its length and we can just skip it. It's more important when writing. if (auto EC = codeview::DebugSubsectionRecord::initialize( Stream, Info, codeview::CodeViewContainer::Pdb)) return EC; diff --git a/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h b/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h index d4a3d9195a36..75f749dfa933 100644 --- a/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h +++ b/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h @@ -12,6 +12,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" #include "llvm/Support/Error.h" #include @@ -30,56 +31,7 @@ class DebugStringTableSubsectionRef; class DebugSymbolRVASubsectionRef; class DebugSymbolsSubsectionRef; class DebugUnknownSubsectionRef; - -struct DebugSubsectionState { -public: - // If no subsections are known about initially, we find as much as we can. - DebugSubsectionState(); - - // If only a string table subsection is given, we find a checksums subsection. - explicit DebugSubsectionState(const DebugStringTableSubsectionRef &Strings); - - // If both subsections are given, we don't need to find anything. - DebugSubsectionState(const DebugStringTableSubsectionRef &Strings, - const DebugChecksumsSubsectionRef &Checksums); - - template void initialize(T &&FragmentRange) { - for (const DebugSubsectionRecord &R : FragmentRange) { - if (Strings && Checksums) - return; - if (R.kind() == DebugSubsectionKind::FileChecksums) { - initializeChecksums(R); - continue; - } - if (R.kind() == DebugSubsectionKind::StringTable && !Strings) { - // While in practice we should never encounter a string table even - // though the string table is already initialized, in theory it's - // possible. PDBs are supposed to have one global string table and - // then this subsection should not appear. Whereas object files are - // supposed to have this subsection appear exactly once. However, - // for testing purposes it's nice to be able to test this subsection - // independently of one format or the other, so for some tests we - // manually construct a PDB that contains this subsection in addition - // to a global string table. - initializeStrings(R); - continue; - } - } - } - - const DebugStringTableSubsectionRef &strings() const { return *Strings; } - const DebugChecksumsSubsectionRef &checksums() const { return *Checksums; } - -private: - void initializeStrings(const DebugSubsectionRecord &SR); - void initializeChecksums(const DebugSubsectionRecord &FCR); - - std::unique_ptr OwnedStrings; - std::unique_ptr OwnedChecksums; - - const DebugStringTableSubsectionRef *Strings = nullptr; - const DebugChecksumsSubsectionRef *Checksums = nullptr; -}; +class StringsAndChecksumsRef; class DebugSubsectionVisitor { public: @@ -89,38 +41,38 @@ class DebugSubsectionVisitor { return Error::success(); } virtual Error visitLines(DebugLinesSubsectionRef &Lines, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; virtual Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; virtual Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; virtual Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; virtual Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSE, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; virtual Error visitStringTable(DebugStringTableSubsectionRef &ST, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; virtual Error visitSymbols(DebugSymbolsSubsectionRef &CSE, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; virtual Error visitFrameData(DebugFrameDataSubsectionRef &FD, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; virtual Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &RVAs, - const DebugSubsectionState &State) = 0; + const StringsAndChecksumsRef &State) = 0; }; Error visitDebugSubsection(const DebugSubsectionRecord &R, DebugSubsectionVisitor &V, - const DebugSubsectionState &State); + const StringsAndChecksumsRef &State); namespace detail { template Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V, - DebugSubsectionState &State) { + StringsAndChecksumsRef &State) { State.initialize(std::forward(FragmentRange)); for (const DebugSubsectionRecord &L : FragmentRange) { @@ -133,7 +85,7 @@ Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V, template Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V) { - DebugSubsectionState State; + StringsAndChecksumsRef State; return detail::visitDebugSubsections(std::forward(FragmentRange), V, State); } @@ -141,7 +93,7 @@ Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V) { template Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V, const DebugStringTableSubsectionRef &Strings) { - DebugSubsectionState State(Strings); + StringsAndChecksumsRef State(Strings); return detail::visitDebugSubsections(std::forward(FragmentRange), V, State); } @@ -150,7 +102,7 @@ template Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V, const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums) { - DebugSubsectionState State(Strings, Checksums); + StringsAndChecksumsRef State(Strings, Checksums); return detail::visitDebugSubsections(std::forward(FragmentRange), V, State); } diff --git a/include/llvm/DebugInfo/CodeView/Formatters.h b/include/llvm/DebugInfo/CodeView/Formatters.h index 37a91098a8b6..1fbb0dd6f9b0 100644 --- a/include/llvm/DebugInfo/CodeView/Formatters.h +++ b/include/llvm/DebugInfo/CodeView/Formatters.h @@ -12,7 +12,10 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatProviders.h" +#include "llvm/Support/FormatVariadic.h" namespace llvm { namespace codeview { @@ -35,6 +38,20 @@ inline detail::GuidAdapter fmt_guid(ArrayRef Item) { return detail::GuidAdapter(Item); } } + +template <> struct format_provider { +public: + static void format(const codeview::TypeIndex &V, llvm::raw_ostream &Stream, + StringRef Style) { + if (V.isNoneType()) + Stream << ""; + else { + Stream << formatv("{0:X+4}", V.getIndex()); + if (V.isSimple()) + Stream << " (" << codeview::TypeIndex::simpleTypeName(V) << ")"; + } + } +}; } #endif diff --git a/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h b/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h new file mode 100644 index 000000000000..708b317164fc --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h @@ -0,0 +1,106 @@ +//===- StringsAndChecksums.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STRINGS_AND_CHECKSUMS_H +#define LLVM_DEBUGINFO_CODEVIEW_STRINGS_AND_CHECKSUMS_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" + +#include + +namespace llvm { +namespace codeview { + +class DebugSubsectionRecord; +class DebugChecksumsSubsectionRef; +class DebugStringTableSubsectionRef; +class DebugChecksumsSubsection; +class DebugStringTableSubsection; + +class StringsAndChecksumsRef { +public: + // If no subsections are known about initially, we find as much as we can. + StringsAndChecksumsRef(); + + // If only a string table subsection is given, we find a checksums subsection. + explicit StringsAndChecksumsRef(const DebugStringTableSubsectionRef &Strings); + + // If both subsections are given, we don't need to find anything. + StringsAndChecksumsRef(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums); + + void setChecksums(const DebugChecksumsSubsectionRef &CS); + + template void initialize(T &&FragmentRange) { + for (const DebugSubsectionRecord &R : FragmentRange) { + if (Strings && Checksums) + return; + if (R.kind() == DebugSubsectionKind::FileChecksums) { + initializeChecksums(R); + continue; + } + if (R.kind() == DebugSubsectionKind::StringTable && !Strings) { + // While in practice we should never encounter a string table even + // though the string table is already initialized, in theory it's + // possible. PDBs are supposed to have one global string table and + // then this subsection should not appear. Whereas object files are + // supposed to have this subsection appear exactly once. However, + // for testing purposes it's nice to be able to test this subsection + // independently of one format or the other, so for some tests we + // manually construct a PDB that contains this subsection in addition + // to a global string table. + initializeStrings(R); + continue; + } + } + } + + const DebugStringTableSubsectionRef &strings() const { return *Strings; } + const DebugChecksumsSubsectionRef &checksums() const { return *Checksums; } + + bool hasStrings() const { return Strings != nullptr; } + bool hasChecksums() const { return Checksums != nullptr; } + +private: + void initializeStrings(const DebugSubsectionRecord &SR); + void initializeChecksums(const DebugSubsectionRecord &FCR); + + std::unique_ptr OwnedStrings; + std::unique_ptr OwnedChecksums; + + const DebugStringTableSubsectionRef *Strings = nullptr; + const DebugChecksumsSubsectionRef *Checksums = nullptr; +}; + +class StringsAndChecksums { +public: + using StringsPtr = std::shared_ptr; + using ChecksumsPtr = std::shared_ptr; + // If no subsections are known about initially, we find as much as we can. + StringsAndChecksums() {} + + void setStrings(const StringsPtr &SP) { Strings = SP; } + void setChecksums(const ChecksumsPtr &CP) { Checksums = CP; } + + const StringsPtr &strings() const { return Strings; } + const ChecksumsPtr &checksums() const { return Checksums; } + + bool hasStrings() const { return Strings != nullptr; } + bool hasChecksums() const { return Checksums != nullptr; } + +private: + StringsPtr Strings; + ChecksumsPtr Checksums; +}; + +} // namespace codeview +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/include/llvm/DebugInfo/CodeView/SymbolRecord.h index a3e4dff647bd..5f85ed28cb3a 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ b/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -363,7 +363,7 @@ class PublicSym32 : public SymbolRecord { : SymbolRecord(SymbolRecordKind::PublicSym32), RecordOffset(RecordOffset) {} - uint32_t Index; + TypeIndex Index; uint32_t Offset; uint16_t Segment; StringRef Name; @@ -379,7 +379,7 @@ class RegisterSym : public SymbolRecord { : SymbolRecord(SymbolRecordKind::RegisterSym), RecordOffset(RecordOffset) {} - uint32_t Index; + TypeIndex Index; RegisterId Register; StringRef Name; @@ -679,7 +679,7 @@ class FileStaticSym : public SymbolRecord { : SymbolRecord(SymbolRecordKind::FileStaticSym), RecordOffset(RecordOffset) {} - uint32_t Index; + TypeIndex Index; uint32_t ModFilenameOffset; LocalSymFlags Flags; StringRef Name; @@ -814,7 +814,7 @@ class FrameCookieSym : public SymbolRecord { uint32_t CodeOffset; uint16_t Register; - uint8_t CookieKind; + FrameCookieKind CookieKind; uint8_t Flags; uint32_t RecordOffset; @@ -871,7 +871,7 @@ class RegRelativeSym : public SymbolRecord { uint32_t Offset; TypeIndex Type; - uint16_t Register; + RegisterId Register; StringRef Name; uint32_t RecordOffset; diff --git a/include/llvm/DebugInfo/CodeView/TypeIndex.h b/include/llvm/DebugInfo/CodeView/TypeIndex.h index 31eed7d3e877..10d51c2d6244 100644 --- a/include/llvm/DebugInfo/CodeView/TypeIndex.h +++ b/include/llvm/DebugInfo/CodeView/TypeIndex.h @@ -248,6 +248,8 @@ class TypeIndex { return A.toArrayIndex() - B.toArrayIndex(); } + static StringRef simpleTypeName(TypeIndex TI); + private: support::ulittle32_t Index; }; diff --git a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index 72793e97b60d..3012b39dcc52 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -50,6 +50,10 @@ class DWARFAcceleratorTable { : AccelSection(AccelSection), StringSection(StringSection), Relocs(Relocs) {} bool extract(); + uint32_t getNumBuckets(); + uint32_t getNumHashes(); + uint32_t getSizeHdr(); + uint32_t getHeaderDataLength(); void dump(raw_ostream &OS) const; }; diff --git a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h index b9f14be85926..9eb5c45faba8 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -20,6 +20,7 @@ struct DWARFAttribute; class DWARFContext; class DWARFDie; class DWARFUnit; +class DWARFAcceleratorTable; /// A class that verifies DWARF debug information given a DWARF Context. class DWARFVerifier { @@ -29,8 +30,9 @@ class DWARFVerifier { /// can verify each reference points to a valid DIE and not an offset that /// lies between to valid DIEs. std::map> ReferenceToDIEOffsets; - uint32_t NumDebugInfoErrors; - uint32_t NumDebugLineErrors; + uint32_t NumDebugInfoErrors = 0; + uint32_t NumDebugLineErrors = 0; + uint32_t NumAppleNamesErrors = 0; /// Verifies the attribute's DWARF attribute and its value. /// @@ -38,8 +40,8 @@ class DWARFVerifier { /// - DW_AT_ranges values is a valid .debug_ranges offset /// - DW_AT_stmt_list is a valid .debug_line offset /// - /// @param Die The DWARF DIE that owns the attribute value - /// @param AttrValue The DWARF attribute value to check + /// \param Die The DWARF DIE that owns the attribute value + /// \param AttrValue The DWARF attribute value to check void verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue); /// Verifies the attribute's DWARF form. @@ -49,8 +51,8 @@ class DWARFVerifier { /// - All DW_FORM_ref_addr values have valid .debug_info offsets /// - All DW_FORM_strp values have valid .debug_str offsets /// - /// @param Die The DWARF DIE that owns the attribute value - /// @param AttrValue The DWARF attribute value to check + /// \param Die The DWARF DIE that owns the attribute value + /// \param AttrValue The DWARF attribute value to check void verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue); /// Verifies the all valid references that were found when iterating through @@ -75,13 +77,13 @@ class DWARFVerifier { public: DWARFVerifier(raw_ostream &S, DWARFContext &D) - : OS(S), DCtx(D), NumDebugInfoErrors(0), NumDebugLineErrors(0) {} + : OS(S), DCtx(D) {} /// Verify the information in the .debug_info section. /// /// Any errors are reported to the stream that was this object was /// constructed with. /// - /// @return True if the .debug_info verifies successfully, false otherwise. + /// \returns true if the .debug_info verifies successfully, false otherwise. bool handleDebugInfo(); /// Verify the information in the .debug_line section. @@ -89,8 +91,16 @@ class DWARFVerifier { /// Any errors are reported to the stream that was this object was /// constructed with. /// - /// @return True if the .debug_line verifies successfully, false otherwise. + /// \returns true if the .debug_line verifies successfully, false otherwise. bool handleDebugLine(); + + /// Verify the information in the .apple_names accelerator table. + /// + /// Any errors are reported to the stream that was this object was + /// constructed with. + /// + /// \returns true if the .apple_names verifies successfully, false otherwise. + bool handleAppleNames(); }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h index 2ff166b24e68..a89e26ae943c 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h @@ -50,12 +50,14 @@ class DbiModuleDescriptorBuilder { void addSymbol(codeview::CVSymbol Symbol); void - addDebugSubsection(std::unique_ptr Subsection); + addDebugSubsection(std::shared_ptr Subsection); uint16_t getStreamIndex() const; StringRef getModuleName() const { return ModuleName; } StringRef getObjFileName() const { return ObjFileName; } + unsigned getModuleIndex() const { return Layout.Mod; } + ArrayRef source_files() const { return makeArrayRef(SourceFiles); } diff --git a/include/llvm/DebugInfo/PDB/Native/DbiModuleList.h b/include/llvm/DebugInfo/PDB/Native/DbiModuleList.h index bcf1cff8f6e5..2885081628f6 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiModuleList.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiModuleList.h @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/BinaryStreamRef.h" @@ -21,6 +22,7 @@ #include namespace llvm { +namespace codeview {} namespace pdb { class DbiModuleList; diff --git a/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h index e116f314ac0e..aeb2e2ab026a 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -49,7 +49,6 @@ class DbiStreamBuilder { void setPdbDllRbld(uint16_t R); void setFlags(uint16_t F); void setMachineType(PDB_Machine M); - void setSectionContribs(ArrayRef SecMap); void setSectionMap(ArrayRef SecMap); // Add given bytes as a new stream. @@ -65,10 +64,8 @@ class DbiStreamBuilder { Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef MsfBuffer); - // A helper function to create Section Contributions from COFF input - // section headers. - static std::vector - createSectionContribs(ArrayRef SecHdrs); + void addSectionContrib(DbiModuleDescriptorBuilder *ModuleDbi, + const llvm::object::coff_section *SecHdr); // A helper function to create a Section Map from a COFF section header. static std::vector @@ -112,7 +109,7 @@ class DbiStreamBuilder { WritableBinaryStreamRef NamesBuffer; MutableBinaryByteStream FileInfoBuffer; - ArrayRef SectionContribs; + std::vector SectionContribs; ArrayRef SectionMap; llvm::SmallVector DbgStreams; }; diff --git a/include/llvm/DebugInfo/PDB/Native/InfoStream.h b/include/llvm/DebugInfo/PDB/Native/InfoStream.h index 1c38c2b6194f..fc91fc7097bd 100644 --- a/include/llvm/DebugInfo/PDB/Native/InfoStream.h +++ b/include/llvm/DebugInfo/PDB/Native/InfoStream.h @@ -35,6 +35,7 @@ class InfoStream { uint32_t getStreamSize() const; + bool containsIdStream() const; PdbRaw_ImplVer getVersion() const; uint32_t getSignature() const; uint32_t getAge() const; diff --git a/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h b/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h index a8121978d882..c744696ae250 100644 --- a/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h +++ b/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h @@ -31,6 +31,7 @@ class ModuleDebugStreamRef { public: ModuleDebugStreamRef(const DbiModuleDescriptor &Module, std::unique_ptr Stream); + ModuleDebugStreamRef(ModuleDebugStreamRef &&Other) = default; ~ModuleDebugStreamRef(); Error reload(); @@ -40,6 +41,12 @@ class ModuleDebugStreamRef { iterator_range symbols(bool *HadError) const; + const codeview::CVSymbolArray &getSymbolArray() const { + return SymbolsSubstream; + } + + ModuleDebugStreamRef &operator=(ModuleDebugStreamRef &&Other) = default; + llvm::iterator_range subsections() const; bool hasDebugSubsections() const; @@ -54,7 +61,7 @@ class ModuleDebugStreamRef { uint32_t Signature; - std::unique_ptr Stream; + std::shared_ptr Stream; codeview::CVSymbolArray SymbolsSubstream; BinaryStreamRef C11LinesSubstream; diff --git a/include/llvm/DebugInfo/PDB/Native/PDBFile.h b/include/llvm/DebugInfo/PDB/Native/PDBFile.h index 3bed67141c56..4d3c569c3cdf 100644 --- a/include/llvm/DebugInfo/PDB/Native/PDBFile.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBFile.h @@ -108,6 +108,8 @@ class PDBFile : public msf::IMSFFile { bool hasPDBTpiStream() const; bool hasPDBStringTable(); + uint32_t getPointerSize(); + private: Expected> safelyCreateIndexedStream(const msf::MSFLayout &Layout, diff --git a/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h b/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h index 28a14d7356d2..86ef1136b41d 100644 --- a/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h @@ -45,7 +45,7 @@ class PDBStringTable { FixedStreamArray name_ids() const; - codeview::DebugStringTableSubsectionRef getStringTable() const; + const codeview::DebugStringTableSubsectionRef &getStringTable() const; private: Error readHeader(BinaryStreamReader &Reader); diff --git a/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h b/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h index 0faa02dc4525..b57707ee7923 100644 --- a/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h @@ -41,10 +41,7 @@ class PDBStringTableBuilder { uint32_t calculateSerializedSize() const; Error commit(BinaryStreamWriter &Writer) const; - codeview::DebugStringTableSubsection &getStrings() { return Strings; } - const codeview::DebugStringTableSubsection &getStrings() const { - return Strings; - } + void setStrings(const codeview::DebugStringTableSubsection &Strings); private: uint32_t calculateHashTableSize() const; diff --git a/include/llvm/DebugInfo/PDB/Native/PublicsStream.h b/include/llvm/DebugInfo/PDB/Native/PublicsStream.h index 4a541edd6a7b..4570c80c76d7 100644 --- a/include/llvm/DebugInfo/PDB/Native/PublicsStream.h +++ b/include/llvm/DebugInfo/PDB/Native/PublicsStream.h @@ -35,6 +35,7 @@ class PublicsStream { uint32_t getSymHash() const; uint32_t getAddrMap() const; uint32_t getNumBuckets() const { return NumBuckets; } + Expected getSymbolArray() const; iterator_range getSymbols(bool *HadError) const; FixedStreamArray getHashBuckets() const { diff --git a/include/llvm/DebugInfo/PDB/Native/RawConstants.h b/include/llvm/DebugInfo/PDB/Native/RawConstants.h index e1bd86b2870b..bb1d097b5123 100644 --- a/include/llvm/DebugInfo/PDB/Native/RawConstants.h +++ b/include/llvm/DebugInfo/PDB/Native/RawConstants.h @@ -98,15 +98,19 @@ enum class DbgHeaderType : uint16_t { }; enum class OMFSegDescFlags : uint16_t { + None = 0, Read = 1 << 0, // Segment is readable. Write = 1 << 1, // Segment is writable. Execute = 1 << 2, // Segment is executable. AddressIs32Bit = 1 << 3, // Descriptor describes a 32-bit linear address. IsSelector = 1 << 8, // Frame represents a selector. IsAbsoluteAddress = 1 << 9, // Frame represents an absolute address. - IsGroup = 1 << 10 // If set, descriptor represents a group. + IsGroup = 1 << 10, // If set, descriptor represents a group. + LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IsGroup) }; +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + } // end namespace pdb } // end namespace llvm diff --git a/include/llvm/DebugInfo/PDB/Native/SymbolStream.h b/include/llvm/DebugInfo/PDB/Native/SymbolStream.h index 41d5e6ad64a0..17695f587849 100644 --- a/include/llvm/DebugInfo/PDB/Native/SymbolStream.h +++ b/include/llvm/DebugInfo/PDB/Native/SymbolStream.h @@ -27,6 +27,10 @@ class SymbolStream { ~SymbolStream(); Error reload(); + const codeview::CVSymbolArray &getSymbolArray() const { + return SymbolRecords; + } + iterator_range getSymbols(bool *HadError) const; diff --git a/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h index 21cfa83e6af4..411720d6f56b 100644 --- a/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h @@ -58,6 +58,8 @@ class TpiStreamBuilder { Error finalizeMsfLayout(); + uint32_t getRecordCount() const { return TypeRecords.size(); } + Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer); uint32_t calculateSerializedLength(); diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h index bb5e1931393b..003a6d5d075d 100644 --- a/include/llvm/IR/Constants.h +++ b/include/llvm/IR/Constants.h @@ -68,11 +68,8 @@ class ConstantData : public Constant { void *operator new(size_t s) { return User::operator new(s, 0); } public: - ConstantData() = delete; ConstantData(const ConstantData &) = delete; - void *operator new(size_t, unsigned) = delete; - /// Methods to support type inquiry through isa, cast, and dyn_cast. static bool classof(const Value *V) { return V->getValueID() >= ConstantDataFirstVal && @@ -691,8 +688,6 @@ class ConstantDataArray final : public ConstantDataSequential { public: ConstantDataArray(const ConstantDataArray &) = delete; - void *operator new(size_t, unsigned) = delete; - /// get() constructors - Return a constant with array type with an element /// count and element type matching the ArrayRef passed in. Note that this /// can return a ConstantAggregateZero object. @@ -752,8 +747,6 @@ class ConstantDataVector final : public ConstantDataSequential { public: ConstantDataVector(const ConstantDataVector &) = delete; - void *operator new(size_t, unsigned) = delete; - /// get() constructors - Return a constant with vector type with an element /// count and element type matching the ArrayRef passed in. Note that this /// can return a ConstantAggregateZero object. @@ -830,8 +823,6 @@ class BlockAddress final : public Constant { Value *handleOperandChangeImpl(Value *From, Value *To); public: - void *operator new(size_t, unsigned) = delete; - /// Return a BlockAddress for the specified function and basic block. static BlockAddress *get(Function *F, BasicBlock *BB); diff --git a/include/llvm/IR/DebugInfoMetadata.h b/include/llvm/IR/DebugInfoMetadata.h index 2174e1f301ee..9374fe4fae76 100644 --- a/include/llvm/IR/DebugInfoMetadata.h +++ b/include/llvm/IR/DebugInfoMetadata.h @@ -2117,9 +2117,6 @@ class DIVariable : public DINode { /// variable, or the location of a single piece of a variable, or (when using /// DW_OP_stack_value) is the constant variable value. /// -/// FIXME: Instead of DW_OP_plus taking an argument, this should use DW_OP_const -/// and have DW_OP_plus consume the topmost elements on the stack. -/// /// TODO: Co-allocate the expression elements. /// TODO: Separate from MDNode, or otherwise drop Distinct and Temporary /// storage types. diff --git a/include/llvm/IR/GlobalVariable.h b/include/llvm/IR/GlobalVariable.h index 454492769c8b..8255a4f298c0 100644 --- a/include/llvm/IR/GlobalVariable.h +++ b/include/llvm/IR/GlobalVariable.h @@ -78,8 +78,6 @@ class GlobalVariable : public GlobalObject, public ilist_node { return User::operator new(s, 1); } - void *operator new(size_t, unsigned) = delete; - /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h index 5ddaf2b1733b..ec33f82f7022 100644 --- a/include/llvm/IR/IRBuilder.h +++ b/include/llvm/IR/IRBuilder.h @@ -435,27 +435,25 @@ class IRBuilderBase { MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr); - /// \brief Create and insert an atomic memcpy between the specified - /// pointers. + /// \brief Create and insert an element unordered-atomic memcpy between the + /// specified pointers. /// /// If the pointers aren't i8*, they will be converted. If a TBAA tag is /// specified, it will be added to the instruction. Likewise with alias.scope /// and noalias tags. - CallInst *CreateElementAtomicMemCpy( - Value *Dst, Value *Src, uint64_t NumElements, uint32_t ElementSize, + CallInst *CreateElementUnorderedAtomicMemCpy( + Value *Dst, Value *Src, uint64_t Size, uint32_t ElementSize, MDNode *TBAATag = nullptr, MDNode *TBAAStructTag = nullptr, MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr) { - return CreateElementAtomicMemCpy(Dst, Src, getInt64(NumElements), - ElementSize, TBAATag, TBAAStructTag, - ScopeTag, NoAliasTag); + return CreateElementUnorderedAtomicMemCpy( + Dst, Src, getInt64(Size), ElementSize, TBAATag, TBAAStructTag, ScopeTag, + NoAliasTag); } - CallInst *CreateElementAtomicMemCpy(Value *Dst, Value *Src, - Value *NumElements, uint32_t ElementSize, - MDNode *TBAATag = nullptr, - MDNode *TBAAStructTag = nullptr, - MDNode *ScopeTag = nullptr, - MDNode *NoAliasTag = nullptr); + CallInst *CreateElementUnorderedAtomicMemCpy( + Value *Dst, Value *Src, Value *Size, uint32_t ElementSize, + MDNode *TBAATag = nullptr, MDNode *TBAAStructTag = nullptr, + MDNode *ScopeTag = nullptr, MDNode *NoAliasTag = nullptr); /// \brief Create and insert a memmove between the specified /// pointers. diff --git a/include/llvm/IR/InstrTypes.h b/include/llvm/IR/InstrTypes.h index ff63da50afee..b3c6644c7e81 100644 --- a/include/llvm/IR/InstrTypes.h +++ b/include/llvm/IR/InstrTypes.h @@ -294,8 +294,6 @@ class UnaryInstruction : public Instruction { return User::operator new(s, 1); } - void *operator new(size_t, unsigned) = delete; - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); @@ -343,8 +341,6 @@ class BinaryOperator : public Instruction { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); @@ -907,15 +903,11 @@ class CmpInst : public Instruction { BasicBlock *InsertAtEnd); public: - CmpInst() = delete; - // allocate space for exactly two operands void *operator new(size_t s) { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - /// Construct a compare instruction, given the opcode, the predicate and /// the two operands. Optionally (if InstBefore is specified) insert the /// instruction into a BasicBlock right before the specified instruction. diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index 6029b0a7c571..b3032f54aa42 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -337,8 +337,6 @@ class StoreInst : public Instruction { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - /// Return true if this is a store to a volatile memory location. bool isVolatile() const { return getSubclassDataFromInstruction() & 1; } @@ -460,8 +458,6 @@ class FenceInst : public Instruction { return User::operator new(s, 0); } - void *operator new(size_t, unsigned) = delete; - /// Returns the ordering effect of this fence. AtomicOrdering getOrdering() const { return AtomicOrdering(getSubclassDataFromInstruction() >> 1); @@ -538,8 +534,6 @@ class AtomicCmpXchgInst : public Instruction { return User::operator new(s, 3); } - void *operator new(size_t, unsigned) = delete; - /// Return true if this is a cmpxchg from a volatile memory /// location. /// @@ -728,8 +722,6 @@ class AtomicRMWInst : public Instruction { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - BinOp getOperation() const { return static_cast(getSubclassDataFromInstruction() >> 5); } @@ -2234,8 +2226,6 @@ class ShuffleVectorInst : public Instruction { return User::operator new(s, 3); } - void *operator new(size_t, unsigned) = delete; - /// Return true if a shufflevector instruction can be /// formed with the specified operands. static bool isValidOperands(const Value *V1, const Value *V2, @@ -2467,8 +2457,6 @@ class InsertValueInst : public Instruction { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - static InsertValueInst *Create(Value *Agg, Value *Val, ArrayRef Idxs, const Twine &NameStr = "", @@ -2596,11 +2584,6 @@ class PHINode : public Instruction { allocHungoffUses(ReservedSpace); } - // allocate space for exactly zero operands - void *operator new(size_t s) { - return User::operator new(s); - } - protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; @@ -2615,8 +2598,6 @@ class PHINode : public Instruction { } public: - void *operator new(size_t, unsigned) = delete; - /// Constructors - NumReservedValues is a hint for the number of incoming /// edges that this phi node will have (use 0 if you really have no idea). static PHINode *Create(Type *Ty, unsigned NumReservedValues, @@ -2834,8 +2815,6 @@ class LandingPadInst : public Instruction { LandingPadInst *cloneImpl() const; public: - void *operator new(size_t, unsigned) = delete; - /// Constructors - NumReservedClauses is a hint for the number of incoming /// clauses that this landingpad will have (use 0 if you really have no idea). static LandingPadInst *Create(Type *RetTy, unsigned NumReservedClauses, @@ -3134,8 +3113,6 @@ class SwitchInst : public TerminatorInst { SwitchInst *cloneImpl() const; public: - void *operator new(size_t, unsigned) = delete; - // -2 static const unsigned DefaultPseudoIndex = static_cast(~0L-1); @@ -3489,8 +3466,6 @@ class IndirectBrInst : public TerminatorInst { IndirectBrInst *cloneImpl() const; public: - void *operator new(size_t, unsigned) = delete; - static IndirectBrInst *Create(Value *Address, unsigned NumDests, Instruction *InsertBefore = nullptr) { return new IndirectBrInst(Address, NumDests, InsertBefore); @@ -4173,8 +4148,6 @@ class CatchSwitchInst : public TerminatorInst { CatchSwitchInst *cloneImpl() const; public: - void *operator new(size_t, unsigned) = delete; - static CatchSwitchInst *Create(Value *ParentPad, BasicBlock *UnwindDest, unsigned NumHandlers, const Twine &NameStr = "", @@ -4609,8 +4582,6 @@ class UnreachableInst : public TerminatorInst { return User::operator new(s, 0); } - void *operator new(size_t, unsigned) = delete; - unsigned getNumSuccessors() const { return 0; } // Methods for support type inquiry through isa, cast, and dyn_cast: diff --git a/include/llvm/IR/IntrinsicInst.h b/include/llvm/IR/IntrinsicInst.h index 2ae98d9e35b0..e0dd3ca7d01e 100644 --- a/include/llvm/IR/IntrinsicInst.h +++ b/include/llvm/IR/IntrinsicInst.h @@ -205,25 +205,91 @@ namespace llvm { }; /// This class represents atomic memcpy intrinsic - /// TODO: Integrate this class into MemIntrinsic hierarchy. - class ElementAtomicMemCpyInst : public IntrinsicInst { + /// TODO: Integrate this class into MemIntrinsic hierarchy; for now this is + /// C&P of all methods from that hierarchy + class ElementUnorderedAtomicMemCpyInst : public IntrinsicInst { + private: + enum { ARG_DEST = 0, ARG_SOURCE = 1, ARG_LENGTH = 2, ARG_ELEMENTSIZE = 3 }; + public: - Value *getRawDest() const { return getArgOperand(0); } - Value *getRawSource() const { return getArgOperand(1); } + Value *getRawDest() const { + return const_cast(getArgOperand(ARG_DEST)); + } + const Use &getRawDestUse() const { return getArgOperandUse(ARG_DEST); } + Use &getRawDestUse() { return getArgOperandUse(ARG_DEST); } - Value *getNumElements() const { return getArgOperand(2); } - void setNumElements(Value *V) { setArgOperand(2, V); } + /// Return the arguments to the instruction. + Value *getRawSource() const { + return const_cast(getArgOperand(ARG_SOURCE)); + } + const Use &getRawSourceUse() const { return getArgOperandUse(ARG_SOURCE); } + Use &getRawSourceUse() { return getArgOperandUse(ARG_SOURCE); } - uint64_t getSrcAlignment() const { return getParamAlignment(0); } - uint64_t getDstAlignment() const { return getParamAlignment(1); } + Value *getLength() const { + return const_cast(getArgOperand(ARG_LENGTH)); + } + const Use &getLengthUse() const { return getArgOperandUse(ARG_LENGTH); } + Use &getLengthUse() { return getArgOperandUse(ARG_LENGTH); } - uint64_t getElementSizeInBytes() const { - Value *Arg = getArgOperand(3); - return cast(Arg)->getZExtValue(); + bool isVolatile() const { return false; } + + Value *getRawElementSizeInBytes() const { + return const_cast(getArgOperand(ARG_ELEMENTSIZE)); + } + + ConstantInt *getElementSizeInBytesCst() const { + return cast(getRawElementSizeInBytes()); + } + + uint32_t getElementSizeInBytes() const { + return getElementSizeInBytesCst()->getZExtValue(); + } + + /// This is just like getRawDest, but it strips off any cast + /// instructions that feed it, giving the original input. The returned + /// value is guaranteed to be a pointer. + Value *getDest() const { return getRawDest()->stripPointerCasts(); } + + /// This is just like getRawSource, but it strips off any cast + /// instructions that feed it, giving the original input. The returned + /// value is guaranteed to be a pointer. + Value *getSource() const { return getRawSource()->stripPointerCasts(); } + + unsigned getDestAddressSpace() const { + return cast(getRawDest()->getType())->getAddressSpace(); + } + + unsigned getSourceAddressSpace() const { + return cast(getRawSource()->getType())->getAddressSpace(); + } + + /// Set the specified arguments of the instruction. + void setDest(Value *Ptr) { + assert(getRawDest()->getType() == Ptr->getType() && + "setDest called with pointer of wrong type!"); + setArgOperand(ARG_DEST, Ptr); + } + + void setSource(Value *Ptr) { + assert(getRawSource()->getType() == Ptr->getType() && + "setSource called with pointer of wrong type!"); + setArgOperand(ARG_SOURCE, Ptr); + } + + void setLength(Value *L) { + assert(getLength()->getType() == L->getType() && + "setLength called with value of wrong type!"); + setArgOperand(ARG_LENGTH, L); + } + + void setElementSizeInBytes(Constant *V) { + assert(V->getType() == Type::getInt8Ty(getContext()) && + "setElementSizeInBytes called with value of wrong type!"); + setArgOperand(ARG_ELEMENTSIZE, V); } static inline bool classof(const IntrinsicInst *I) { - return I->getIntrinsicID() == Intrinsic::memcpy_element_atomic; + return I->getIntrinsicID() == Intrinsic::memcpy_element_unordered_atomic; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 291d16fb0d9b..45936a6e9b66 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -862,11 +862,16 @@ def int_xray_customevent : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty], //===------ Memory intrinsics with element-wise atomicity guarantees ------===// // -def int_memcpy_element_atomic : Intrinsic<[], - [llvm_anyptr_ty, llvm_anyptr_ty, - llvm_i64_ty, llvm_i32_ty], - [IntrArgMemOnly, NoCapture<0>, NoCapture<1>, - WriteOnly<0>, ReadOnly<1>]>; +// @llvm.memcpy.element.unordered.atomic.*(dest, src, length, elementsize) +def int_memcpy_element_unordered_atomic + : Intrinsic<[], + [ + llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty, llvm_i32_ty + ], + [ + IntrArgMemOnly, NoCapture<0>, NoCapture<1>, WriteOnly<0>, + ReadOnly<1> + ]>; //===------------------------ Reduction Intrinsics ------------------------===// // diff --git a/include/llvm/IR/ModuleSummaryIndex.h b/include/llvm/IR/ModuleSummaryIndex.h index 144e45f18d2c..b43d58865862 100644 --- a/include/llvm/IR/ModuleSummaryIndex.h +++ b/include/llvm/IR/ModuleSummaryIndex.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -542,6 +543,9 @@ class ModuleSummaryIndex { /// considered live. bool WithGlobalValueDeadStripping = false; + std::set CfiFunctionDefs; + std::set CfiFunctionDecls; + // YAML I/O support. friend yaml::MappingTraits; @@ -567,6 +571,7 @@ class ModuleSummaryIndex { bool isGlobalValueLive(const GlobalValueSummary *GVS) const { return !WithGlobalValueDeadStripping || GVS->isLive(); } + bool isGUIDLive(GlobalValue::GUID GUID) const; /// Return a ValueInfo for GUID if it exists, otherwise return ValueInfo(). ValueInfo getValueInfo(GlobalValue::GUID GUID) const { @@ -592,6 +597,12 @@ class ModuleSummaryIndex { return I == OidGuidMap.end() ? 0 : I->second; } + std::set &cfiFunctionDefs() { return CfiFunctionDefs; } + const std::set &cfiFunctionDefs() const { return CfiFunctionDefs; } + + std::set &cfiFunctionDecls() { return CfiFunctionDecls; } + const std::set &cfiFunctionDecls() const { return CfiFunctionDecls; } + /// Add a global value summary for a value of the given name. void addGlobalValueSummary(StringRef ValueName, std::unique_ptr Summary) { @@ -691,14 +702,13 @@ class ModuleSummaryIndex { return Pair.first; } - /// Add a new module path with the given \p Hash, mapped to the given \p - /// ModID, and return an iterator to the entry in the index. - ModulePathStringTableTy::iterator - addModulePath(StringRef ModPath, uint64_t ModId, - ModuleHash Hash = ModuleHash{{0}}) { - return ModulePathStringTable.insert(std::make_pair( - ModPath, - std::make_pair(ModId, Hash))).first; + typedef ModulePathStringTableTy::value_type ModuleInfo; + + /// Add a new module with the given \p Hash, mapped to the given \p + /// ModID, and return a reference to the module. + ModuleInfo *addModule(StringRef ModPath, uint64_t ModId, + ModuleHash Hash = ModuleHash{{0}}) { + return &*ModulePathStringTable.insert({ModPath, {ModId, Hash}}).first; } /// Check if the given Module has any functions available for exporting diff --git a/include/llvm/IR/ModuleSummaryIndexYAML.h b/include/llvm/IR/ModuleSummaryIndexYAML.h index 891d84c2dbca..8950c527cc18 100644 --- a/include/llvm/IR/ModuleSummaryIndexYAML.h +++ b/include/llvm/IR/ModuleSummaryIndexYAML.h @@ -188,6 +188,7 @@ template <> struct MappingTraits { LLVM_YAML_IS_STRING_MAP(TypeIdSummary) LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummaryYaml) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::string) namespace llvm { namespace yaml { @@ -240,6 +241,23 @@ template <> struct MappingTraits { io.mapOptional("TypeIdMap", index.TypeIdMap); io.mapOptional("WithGlobalValueDeadStripping", index.WithGlobalValueDeadStripping); + + if (io.outputting()) { + std::vector CfiFunctionDefs(index.CfiFunctionDefs.begin(), + index.CfiFunctionDefs.end()); + io.mapOptional("CfiFunctionDefs", CfiFunctionDefs); + std::vector CfiFunctionDecls(index.CfiFunctionDecls.begin(), + index.CfiFunctionDecls.end()); + io.mapOptional("CfiFunctionDecls", CfiFunctionDecls); + } else { + std::vector CfiFunctionDefs; + io.mapOptional("CfiFunctionDefs", CfiFunctionDefs); + index.CfiFunctionDefs = {CfiFunctionDefs.begin(), CfiFunctionDefs.end()}; + std::vector CfiFunctionDecls; + io.mapOptional("CfiFunctionDecls", CfiFunctionDecls); + index.CfiFunctionDecls = {CfiFunctionDecls.begin(), + CfiFunctionDecls.end()}; + } } }; diff --git a/include/llvm/IR/Operator.h b/include/llvm/IR/Operator.h index 49fa6a6a877a..6eb5998478c6 100644 --- a/include/llvm/IR/Operator.h +++ b/include/llvm/IR/Operator.h @@ -35,7 +35,6 @@ class Operator : public User { Operator() = delete; ~Operator() = delete; - void *operator new(size_t, unsigned) = delete; void *operator new(size_t s) = delete; /// Return the opcode for this Instruction or ConstantExpr. diff --git a/include/llvm/IR/PatternMatch.h b/include/llvm/IR/PatternMatch.h index 542570aaaa24..015a17e8e7ca 100644 --- a/include/llvm/IR/PatternMatch.h +++ b/include/llvm/IR/PatternMatch.h @@ -1027,7 +1027,7 @@ struct MaxMin_match { (TrueVal != RHS || FalseVal != LHS)) return false; typename CmpInst_t::Predicate Pred = - LHS == TrueVal ? Cmp->getPredicate() : Cmp->getSwappedPredicate(); + LHS == TrueVal ? Cmp->getPredicate() : Cmp->getInversePredicate(); // Does "(x pred y) ? x : y" represent the desired max/min operation? if (!Pred_t::match(Pred)) return false; @@ -1138,7 +1138,7 @@ inline MaxMin_match m_OrdFMax(const LHS &L, /// semantics. In the presence of 'NaN' we have to preserve the original /// select(fcmp(olt/le, L, R), L, R) semantics matched by this predicate. /// -/// max(L, R) iff L and R are not NaN +/// min(L, R) iff L and R are not NaN /// m_OrdFMin(L, R) = R iff L or R are NaN template inline MaxMin_match m_OrdFMin(const LHS &L, @@ -1154,13 +1154,28 @@ inline MaxMin_match m_OrdFMin(const LHS &L, /// select(fcmp(ugt/ge, L, R), L, R) semantics matched by this predicate. /// /// max(L, R) iff L and R are not NaN -/// m_UnordFMin(L, R) = L iff L or R are NaN +/// m_UnordFMax(L, R) = L iff L or R are NaN template inline MaxMin_match m_UnordFMax(const LHS &L, const RHS &R) { return MaxMin_match(L, R); } +/// \brief Match an 'unordered' floating point minimum function. +/// Floating point has one special value 'NaN'. Therefore, there is no total +/// order. However, if we can ignore the 'NaN' value (for example, because of a +/// 'no-nans-float-math' flag) a combination of a fcmp and select has 'minimum' +/// semantics. In the presence of 'NaN' we have to preserve the original +/// select(fcmp(ult/le, L, R), L, R) semantics matched by this predicate. +/// +/// min(L, R) iff L and R are not NaN +/// m_UnordFMin(L, R) = L iff L or R are NaN +template +inline MaxMin_match +m_UnordFMin(const LHS &L, const RHS &R) { + return MaxMin_match(L, R); +} + //===----------------------------------------------------------------------===// // Matchers for overflow check patterns: e.g. (a + b) u< a // @@ -1207,21 +1222,6 @@ m_UAddWithOverflow(const LHS_t &L, const RHS_t &R, const Sum_t &S) { return UAddWithOverflow_match(L, R, S); } -/// \brief Match an 'unordered' floating point minimum function. -/// Floating point has one special value 'NaN'. Therefore, there is no total -/// order. However, if we can ignore the 'NaN' value (for example, because of a -/// 'no-nans-float-math' flag) a combination of a fcmp and select has 'minimum' -/// semantics. In the presence of 'NaN' we have to preserve the original -/// select(fcmp(ult/le, L, R), L, R) semantics matched by this predicate. -/// -/// max(L, R) iff L and R are not NaN -/// m_UnordFMin(L, R) = L iff L or R are NaN -template -inline MaxMin_match -m_UnordFMin(const LHS &L, const RHS &R) { - return MaxMin_match(L, R); -} - template struct Argument_match { unsigned OpI; Opnd_t Val; diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h index 774e144b3ef0..d678a68ed860 100644 --- a/include/llvm/LTO/LTO.h +++ b/include/llvm/LTO/LTO.h @@ -281,6 +281,16 @@ class LTO { bool HasModule = false; std::unique_ptr CombinedModule; std::unique_ptr Mover; + + // This stores the information about a regular LTO module that we have added + // to the link. It will either be linked immediately (for modules without + // summaries) or after summary-based dead stripping (for modules with + // summaries). + struct AddedModule { + std::unique_ptr M; + std::vector Keep; + }; + std::vector ModsWithSummaries; } RegularLTO; struct ThinLTOState { @@ -303,9 +313,10 @@ class LTO { /// The unmangled name of the global. std::string IRName; - /// Keep track if the symbol is visible outside of ThinLTO (i.e. in - /// either a regular object or the regular LTO partition). - bool VisibleOutsideThinLTO = false; + /// Keep track if the symbol is visible outside of a module with a summary + /// (i.e. in either a regular object or a regular LTO module without a + /// summary). + bool VisibleOutsideSummary = false; bool UnnamedAddr = true; @@ -339,8 +350,9 @@ class LTO { // Global mapping from mangled symbol names to resolutions. StringMap GlobalResolutions; - void addSymbolToGlobalRes(const InputFile::Symbol &Sym, SymbolResolution Res, - unsigned Partition); + void addModuleToGlobalRes(ArrayRef Syms, + ArrayRef Res, unsigned Partition, + bool InSummary); // These functions take a range of symbol resolutions [ResI, ResE) and consume // the resolutions used by a single input module by incrementing ResI. After @@ -348,10 +360,13 @@ class LTO { // the remaining modules in the InputFile. Error addModule(InputFile &Input, unsigned ModI, const SymbolResolution *&ResI, const SymbolResolution *ResE); - Error addRegularLTO(BitcodeModule BM, - ArrayRef Syms, - const SymbolResolution *&ResI, - const SymbolResolution *ResE); + + Expected + addRegularLTO(BitcodeModule BM, ArrayRef Syms, + const SymbolResolution *&ResI, const SymbolResolution *ResE); + Error linkRegularLTO(RegularLTOState::AddedModule Mod, + bool LivenessFromIndex); + Error addThinLTO(BitcodeModule BM, ArrayRef Syms, const SymbolResolution *&ResI, const SymbolResolution *ResE); diff --git a/include/llvm/LTO/legacy/LTOModule.h b/include/llvm/LTO/legacy/LTOModule.h index 2a8758587a11..017e223ed8a6 100644 --- a/include/llvm/LTO/legacy/LTOModule.h +++ b/include/llvm/LTO/legacy/LTOModule.h @@ -158,7 +158,7 @@ struct LTOModule { private: /// Parse metadata from the module - // FIXME: it only parses "Linker Options" metadata at the moment + // FIXME: it only parses "llvm.linker.options" metadata at the moment void parseMetadata(); /// Parse the symbols from the module and model-level ASM and add them to diff --git a/include/llvm/MC/MCSymbolWasm.h b/include/llvm/MC/MCSymbolWasm.h index 7d661ccc5de7..1b87095552d6 100644 --- a/include/llvm/MC/MCSymbolWasm.h +++ b/include/llvm/MC/MCSymbolWasm.h @@ -13,6 +13,7 @@ #include "llvm/MC/MCSymbol.h" namespace llvm { + class MCSymbolWasm : public MCSymbol { private: bool IsFunction = false; @@ -52,6 +53,7 @@ class MCSymbolWasm : public MCSymbol { Params = std::move(Pars); } }; -} -#endif +} // end namespace llvm + +#endif // LLVM_MC_MCSYMBOLWASM_H diff --git a/include/llvm/MC/MCWasmObjectWriter.h b/include/llvm/MC/MCWasmObjectWriter.h index c250d3bf03fb..bebc0a825810 100644 --- a/include/llvm/MC/MCWasmObjectWriter.h +++ b/include/llvm/MC/MCWasmObjectWriter.h @@ -12,20 +12,12 @@ #include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/Wasm.h" -#include "llvm/MC/MCValue.h" #include "llvm/Support/DataTypes.h" -#include "llvm/Support/raw_ostream.h" -#include namespace llvm { -class MCAssembler; -class MCContext; + class MCFixup; -class MCFragment; class MCObjectWriter; -class MCSectionWasm; -class MCSymbol; -class MCSymbolWasm; class MCValue; class raw_pwrite_stream; @@ -38,8 +30,8 @@ class MCWasmObjectTargetWriter { public: virtual ~MCWasmObjectTargetWriter(); - virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target, - const MCFixup &Fixup, bool IsPCRel) const = 0; + virtual unsigned getRelocType(const MCValue &Target, + const MCFixup &Fixup) const = 0; /// \name Accessors /// @{ @@ -54,6 +46,7 @@ class MCWasmObjectTargetWriter { /// \returns The constructed object writer. MCObjectWriter *createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS); + } // End llvm namespace #endif diff --git a/include/llvm/Object/ArchiveWriter.h b/include/llvm/Object/ArchiveWriter.h index 3e84a5814d79..1ed758d40df2 100644 --- a/include/llvm/Object/ArchiveWriter.h +++ b/include/llvm/Object/ArchiveWriter.h @@ -22,6 +22,7 @@ namespace llvm { struct NewArchiveMember { std::unique_ptr Buf; + StringRef MemberName; sys::TimePoint ModTime; unsigned UID = 0, GID = 0, Perms = 0644; diff --git a/include/llvm/Object/WindowsResource.h b/include/llvm/Object/WindowsResource.h index c5189329d3ec..4839013c8228 100644 --- a/include/llvm/Object/WindowsResource.h +++ b/include/llvm/Object/WindowsResource.h @@ -118,7 +118,7 @@ class WindowsResourceParser { class TreeNode; WindowsResourceParser(); Error parse(WindowsResource *WR); - void printTree() const; + void printTree(raw_ostream &OS) const; const TreeNode &getTree() const { return Root; } const ArrayRef> getData() const { return Data; } const ArrayRef> getStringTable() const { @@ -159,14 +159,16 @@ class WindowsResourceParser { TreeNode(uint16_t MajorVersion, uint16_t MinorVersion, uint32_t Characteristics); - void addEntry(const ResourceEntryRef &Entry); - TreeNode &addTypeNode(const ResourceEntryRef &Entry); - TreeNode &addNameNode(const ResourceEntryRef &Entry); + void addEntry(const ResourceEntryRef &Entry, bool &IsNewTypeString, + bool &IsNewNameString); + TreeNode &addTypeNode(const ResourceEntryRef &Entry, bool &IsNewTypeString); + TreeNode &addNameNode(const ResourceEntryRef &Entry, bool &IsNewNameString); TreeNode &addLanguageNode(const ResourceEntryRef &Entry); TreeNode &addChild(uint32_t ID, bool IsDataNode = false, uint16_t MajorVersion = 0, uint16_t MinorVersion = 0, uint32_t Characteristics = 0); - TreeNode &addChild(ArrayRef NameRef); + TreeNode &addChild(ArrayRef NameRef, bool &IsNewString); + bool IsDataNode = false; uint32_t StringIndex; uint32_t DataIndex; diff --git a/include/llvm/ObjectYAML/COFFYAML.h b/include/llvm/ObjectYAML/COFFYAML.h index 1b5f7b00239a..719cb1acf6ef 100644 --- a/include/llvm/ObjectYAML/COFFYAML.h +++ b/include/llvm/ObjectYAML/COFFYAML.h @@ -16,6 +16,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" +#include "llvm/ObjectYAML/CodeViewYAMLTypes.h" #include "llvm/ObjectYAML/YAML.h" namespace llvm { @@ -56,6 +58,8 @@ namespace COFFYAML { COFF::section Header; unsigned Alignment = 0; yaml::BinaryRef SectionData; + std::vector DebugS; + std::vector DebugT; std::vector Relocations; StringRef Name; Section(); diff --git a/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h b/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h index faa3ed8a6c52..8180e0fc83f4 100644 --- a/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h +++ b/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h @@ -28,6 +28,8 @@ class DebugStringTableSubsectionRef; class DebugChecksumsSubsectionRef; class DebugStringTableSubsection; class DebugChecksumsSubsection; +class StringsAndChecksums; +class StringsAndChecksumsRef; } namespace CodeViewYAML { @@ -103,25 +105,24 @@ struct InlineeInfo { struct YAMLDebugSubsection { static Expected - fromCodeViewSubection(const codeview::DebugStringTableSubsectionRef &Strings, - const codeview::DebugChecksumsSubsectionRef &Checksums, + fromCodeViewSubection(const codeview::StringsAndChecksumsRef &SC, const codeview::DebugSubsectionRecord &SS); std::shared_ptr Subsection; }; -Expected>> +struct DebugSubsectionState {}; + +Expected>> toCodeViewSubsectionList(BumpPtrAllocator &Allocator, ArrayRef Subsections, - codeview::DebugStringTableSubsection &Strings); -Expected>> -toCodeViewSubsectionList( - BumpPtrAllocator &Allocator, ArrayRef Subsections, - std::unique_ptr &TakeStrings, - codeview::DebugStringTableSubsection *StringsRef); + const codeview::StringsAndChecksums &SC); -std::unique_ptr -findStringTable(ArrayRef Sections); +std::vector +fromDebugS(ArrayRef Data, const codeview::StringsAndChecksumsRef &SC); + +void initializeStringsAndChecksums(ArrayRef Sections, + codeview::StringsAndChecksums &SC); } // namespace CodeViewYAML } // namespace llvm diff --git a/include/llvm/ObjectYAML/CodeViewYAMLTypes.h b/include/llvm/ObjectYAML/CodeViewYAMLTypes.h index 91b75aabe7a5..e97d5f92bf7f 100644 --- a/include/llvm/ObjectYAML/CodeViewYAMLTypes.h +++ b/include/llvm/ObjectYAML/CodeViewYAMLTypes.h @@ -41,6 +41,9 @@ struct LeafRecord { codeview::CVType toCodeViewRecord(codeview::TypeTableBuilder &TS) const; static Expected fromCodeViewRecord(codeview::CVType Type); }; + +std::vector fromDebugT(ArrayRef DebugT); +ArrayRef toDebugT(ArrayRef, BumpPtrAllocator &Alloc); } // namespace CodeViewYAML } // namespace llvm diff --git a/include/llvm/Option/Arg.h b/include/llvm/Option/Arg.h index 99d329693de2..c519a4a824c5 100644 --- a/include/llvm/Option/Arg.h +++ b/include/llvm/Option/Arg.h @@ -1,4 +1,4 @@ -//===--- Arg.h - Parsed Argument Classes ------------------------*- C++ -*-===// +//===- Arg.h - Parsed Argument Classes --------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -21,7 +21,11 @@ #include namespace llvm { + +class raw_ostream; + namespace opt { + class ArgList; /// \brief A concrete instance of a particular driver option. @@ -29,9 +33,6 @@ class ArgList; /// The Arg class encodes just enough information to be able to /// derive the argument values efficiently. class Arg { - Arg(const Arg &) = delete; - void operator=(const Arg &) = delete; - private: /// \brief The option this argument is an instance of. const Option Opt; @@ -65,6 +66,8 @@ class Arg { const char *Value0, const Arg *BaseArg = nullptr); Arg(const Option Opt, StringRef Spelling, unsigned Index, const char *Value0, const char *Value1, const Arg *BaseArg = nullptr); + Arg(const Arg &) = delete; + Arg &operator=(const Arg &) = delete; ~Arg(); const Option &getOption() const { return Opt; } @@ -89,6 +92,7 @@ class Arg { void claim() const { getBaseArg().Claimed = true; } unsigned getNumValues() const { return Values.size(); } + const char *getValue(unsigned N = 0) const { return Values[N]; } @@ -122,6 +126,7 @@ class Arg { }; } // end namespace opt + } // end namespace llvm -#endif +#endif // LLVM_OPTION_ARG_H diff --git a/include/llvm/Option/ArgList.h b/include/llvm/Option/ArgList.h index 6a92dd01e911..aaea68bf8e27 100644 --- a/include/llvm/Option/ArgList.h +++ b/include/llvm/Option/ArgList.h @@ -1,4 +1,4 @@ -//===--- ArgList.h - Argument List Management -------------------*- C++ -*-===// +//===- ArgList.h - Argument List Management ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,7 +10,9 @@ #ifndef LLVM_OPTION_ARGLIST_H #define LLVM_OPTION_ARGLIST_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -18,15 +20,21 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/OptSpecifier.h" #include "llvm/Option/Option.h" +#include +#include +#include +#include #include #include #include +#include #include namespace llvm { + +class raw_ostream; + namespace opt { -class ArgList; -class Option; /// arg_iterator - Iterates through arguments stored inside an ArgList. template @@ -59,14 +67,14 @@ class arg_iterator { } } - typedef std::iterator_traits Traits; + using Traits = std::iterator_traits; public: - typedef typename Traits::value_type value_type; - typedef typename Traits::reference reference; - typedef typename Traits::pointer pointer; - typedef std::forward_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; + using value_type = typename Traits::value_type; + using reference = typename Traits::reference; + using pointer = typename Traits::pointer; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; arg_iterator( BaseIter Current, BaseIter End, @@ -111,12 +119,12 @@ class arg_iterator { /// and to iterate over groups of arguments. class ArgList { public: - typedef SmallVector arglist_type; - typedef arg_iterator iterator; - typedef arg_iterator const_iterator; - typedef arg_iterator reverse_iterator; - typedef arg_iterator - const_reverse_iterator; + using arglist_type = SmallVector; + using iterator = arg_iterator; + using const_iterator = arg_iterator; + using reverse_iterator = arg_iterator; + using const_reverse_iterator = + arg_iterator; template using filtered_iterator = arg_iterator; @@ -127,7 +135,7 @@ class ArgList { /// The internal list of arguments. arglist_type Args; - typedef std::pair OptRange; + using OptRange = std::pair; static OptRange emptyRange() { return {-1u, 0u}; } /// The first and last index of each different OptSpecifier ID. @@ -142,6 +150,7 @@ class ArgList { // derived objects, but can still be used by derived objects to implement // their own special members. ArgList() = default; + // Explicit move operations to ensure the container is cleared post-move // otherwise it could lead to a double-delete in the case of moving of an // InputArgList which deletes the contents of the container. If we could fix @@ -152,6 +161,7 @@ class ArgList { RHS.Args.clear(); RHS.OptRanges.clear(); } + ArgList &operator=(ArgList &&RHS) { Args = std::move(RHS.Args); RHS.Args.clear(); @@ -159,6 +169,7 @@ class ArgList { RHS.OptRanges.clear(); return *this; } + // Protect the dtor to ensure this type is never destroyed polymorphically. ~ArgList() = default; @@ -380,10 +391,12 @@ class InputArgList final : public ArgList { public: InputArgList(const char* const *ArgBegin, const char* const *ArgEnd); + InputArgList(InputArgList &&RHS) : ArgList(std::move(RHS)), ArgStrings(std::move(RHS.ArgStrings)), SynthesizedStrings(std::move(RHS.SynthesizedStrings)), NumInputArgStrings(RHS.NumInputArgStrings) {} + InputArgList &operator=(InputArgList &&RHS) { releaseMemory(); ArgList::operator=(std::move(RHS)); @@ -392,6 +405,7 @@ class InputArgList final : public ArgList { NumInputArgStrings = RHS.NumInputArgStrings; return *this; } + ~InputArgList() { releaseMemory(); } const char *getArgString(unsigned Index) const override { @@ -464,7 +478,6 @@ class DerivedArgList final : public ArgList { append(MakePositionalArg(BaseArg, Opt, Value)); } - /// AddSeparateArg - Construct a new Positional arg for the given option /// \p Id, with the provided \p Value and append it to the argument /// list. @@ -473,7 +486,6 @@ class DerivedArgList final : public ArgList { append(MakeSeparateArg(BaseArg, Opt, Value)); } - /// AddJoinedArg - Construct a new Positional arg for the given option /// \p Id, with the provided \p Value and append it to the argument list. void AddJoinedArg(const Arg *BaseArg, const Option Opt, @@ -481,7 +493,6 @@ class DerivedArgList final : public ArgList { append(MakeJoinedArg(BaseArg, Opt, Value)); } - /// MakeFlagArg - Construct a new FlagArg for the given option \p Id. Arg *MakeFlagArg(const Arg *BaseArg, const Option Opt) const; @@ -504,6 +515,7 @@ class DerivedArgList final : public ArgList { }; } // end namespace opt + } // end namespace llvm -#endif +#endif // LLVM_OPTION_ARGLIST_H diff --git a/include/llvm/Option/OptSpecifier.h b/include/llvm/Option/OptSpecifier.h index 0b2aaaec3afc..84c3cf8ad534 100644 --- a/include/llvm/Option/OptSpecifier.h +++ b/include/llvm/Option/OptSpecifier.h @@ -1,4 +1,4 @@ -//===--- OptSpecifier.h - Option Specifiers ---------------------*- C++ -*-===// +//===- OptSpecifier.h - Option Specifiers -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,32 +10,30 @@ #ifndef LLVM_OPTION_OPTSPECIFIER_H #define LLVM_OPTION_OPTSPECIFIER_H -#include "llvm/Support/Compiler.h" - namespace llvm { namespace opt { - class Option; - /// OptSpecifier - Wrapper class for abstracting references to option IDs. - class OptSpecifier { - unsigned ID; +class Option; - private: - explicit OptSpecifier(bool) = delete; +/// OptSpecifier - Wrapper class for abstracting references to option IDs. +class OptSpecifier { + unsigned ID = 0; - public: - OptSpecifier() : ID(0) {} - /*implicit*/ OptSpecifier(unsigned ID) : ID(ID) {} - /*implicit*/ OptSpecifier(const Option *Opt); +public: + OptSpecifier() = default; + explicit OptSpecifier(bool) = delete; + /*implicit*/ OptSpecifier(unsigned ID) : ID(ID) {} + /*implicit*/ OptSpecifier(const Option *Opt); - bool isValid() const { return ID != 0; } + bool isValid() const { return ID != 0; } - unsigned getID() const { return ID; } + unsigned getID() const { return ID; } - bool operator==(OptSpecifier Opt) const { return ID == Opt.getID(); } - bool operator!=(OptSpecifier Opt) const { return !(*this == Opt); } - }; -} -} + bool operator==(OptSpecifier Opt) const { return ID == Opt.getID(); } + bool operator!=(OptSpecifier Opt) const { return !(*this == Opt); } +}; -#endif +} // end namespace opt +} // end namespace llvm + +#endif // LLVM_OPTION_OPTSPECIFIER_H diff --git a/include/llvm/Option/OptTable.h b/include/llvm/Option/OptTable.h index 8a323a255ca1..e0169b927319 100644 --- a/include/llvm/Option/OptTable.h +++ b/include/llvm/Option/OptTable.h @@ -1,4 +1,4 @@ -//===--- OptTable.h - Option Table ------------------------------*- C++ -*-===// +//===- OptTable.h - Option Table --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,12 +11,19 @@ #define LLVM_OPTION_OPTTABLE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Option/OptSpecifier.h" +#include +#include +#include namespace llvm { + class raw_ostream; + namespace opt { + class Arg; class ArgList; class InputArgList; @@ -53,12 +60,12 @@ class OptTable { ArrayRef OptionInfos; bool IgnoreCase; - unsigned TheInputOptionID; - unsigned TheUnknownOptionID; + unsigned TheInputOptionID = 0; + unsigned TheUnknownOptionID = 0; /// The index of the first option which can be parsed (i.e., is not a /// special option like 'input' or 'unknown', and is not an option group). - unsigned FirstSearchableIndex; + unsigned FirstSearchableIndex = 0; /// The union of all option prefixes. If an argument does not begin with /// one of these, it is an input. @@ -176,7 +183,9 @@ class OptTable { void PrintHelp(raw_ostream &OS, const char *Name, const char *Title, bool ShowHidden = false) const; }; + } // end namespace opt + } // end namespace llvm -#endif +#endif // LLVM_OPTION_OPTTABLE_H diff --git a/include/llvm/Option/Option.h b/include/llvm/Option/Option.h index 139f281b3c4c..c08834f90598 100644 --- a/include/llvm/Option/Option.h +++ b/include/llvm/Option/Option.h @@ -1,4 +1,4 @@ -//===--- Option.h - Abstract Driver Options ---------------------*- C++ -*-===// +//===- Option.h - Abstract Driver Options -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,15 +12,23 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Option/OptSpecifier.h" #include "llvm/Option/OptTable.h" #include "llvm/Support/ErrorHandling.h" +#include +#include namespace llvm { + +class raw_ostream; + namespace opt { + class Arg; class ArgList; + /// ArgStringList - Type used for constructing argv lists for subprocesses. -typedef SmallVector ArgStringList; +using ArgStringList = SmallVector; /// Base flags for all options. Custom flags may be added after. enum DriverFlag { @@ -202,6 +210,7 @@ class Option { }; } // end namespace opt + } // end namespace llvm -#endif +#endif // LLVM_OPTION_OPTION_H diff --git a/include/llvm/Support/BinaryStreamArray.h b/include/llvm/Support/BinaryStreamArray.h index 65ec15f6d9e0..3f5562ba7519 100644 --- a/include/llvm/Support/BinaryStreamArray.h +++ b/include/llvm/Support/BinaryStreamArray.h @@ -290,6 +290,12 @@ template class FixedStreamArray { return FixedStreamArrayIterator(*this, size()); } + const T &front() const { return *begin(); } + const T &back() const { + FixedStreamArrayIterator I = end(); + return *(--I); + } + BinaryStreamRef getUnderlyingStream() const { return Stream; } private: diff --git a/include/llvm/Support/DebugCounter.h b/include/llvm/Support/DebugCounter.h index 9687cb7b9d95..a533feae7fa3 100644 --- a/include/llvm/Support/DebugCounter.h +++ b/include/llvm/Support/DebugCounter.h @@ -121,10 +121,10 @@ class DebugCounter { Us.Counters[ID] = Val; } - // Dump or print the current counter set. - LLVM_DUMP_METHOD void dump() { print(dbgs()); } + // Dump or print the current counter set into llvm::dbgs(). + LLVM_DUMP_METHOD void dump() const; - void print(raw_ostream &OS); + void print(raw_ostream &OS) const; // Get the counter ID for a given named counter, or return 0 if none is found. unsigned getCounterId(const std::string &Name) const { diff --git a/include/llvm/Support/FormatAdapters.h b/include/llvm/Support/FormatAdapters.h index 698e134b328d..197beb7363df 100644 --- a/include/llvm/Support/FormatAdapters.h +++ b/include/llvm/Support/FormatAdapters.h @@ -28,14 +28,16 @@ namespace detail { template class AlignAdapter final : public FormatAdapter { AlignStyle Where; size_t Amount; + char Fill; public: - AlignAdapter(T &&Item, AlignStyle Where, size_t Amount) - : FormatAdapter(std::forward(Item)), Where(Where), Amount(Amount) {} + AlignAdapter(T &&Item, AlignStyle Where, size_t Amount, char Fill) + : FormatAdapter(std::forward(Item)), Where(Where), Amount(Amount), + Fill(Fill) {} void format(llvm::raw_ostream &Stream, StringRef Style) { auto Adapter = detail::build_format_adapter(std::forward(this->Item)); - FmtAlign(Adapter, Where, Amount).format(Stream, Style); + FmtAlign(Adapter, Where, Amount, Fill).format(Stream, Style); } }; @@ -72,8 +74,9 @@ template class RepeatAdapter final : public FormatAdapter { } template -detail::AlignAdapter fmt_align(T &&Item, AlignStyle Where, size_t Amount) { - return detail::AlignAdapter(std::forward(Item), Where, Amount); +detail::AlignAdapter fmt_align(T &&Item, AlignStyle Where, size_t Amount, + char Fill = ' ') { + return detail::AlignAdapter(std::forward(Item), Where, Amount, Fill); } template diff --git a/include/llvm/Support/FormatCommon.h b/include/llvm/Support/FormatCommon.h index a8c5fdeb6bff..36fbad296c3f 100644 --- a/include/llvm/Support/FormatCommon.h +++ b/include/llvm/Support/FormatCommon.h @@ -21,9 +21,11 @@ struct FmtAlign { detail::format_adapter &Adapter; AlignStyle Where; size_t Amount; + char Fill; - FmtAlign(detail::format_adapter &Adapter, AlignStyle Where, size_t Amount) - : Adapter(Adapter), Where(Where), Amount(Amount) {} + FmtAlign(detail::format_adapter &Adapter, AlignStyle Where, size_t Amount, + char Fill = ' ') + : Adapter(Adapter), Where(Where), Amount(Amount), Fill(Fill) {} void format(raw_ostream &S, StringRef Options) { // If we don't need to align, we can format straight into the underlying @@ -48,21 +50,27 @@ struct FmtAlign { switch (Where) { case AlignStyle::Left: S << Item; - S.indent(PadAmount); + fill(S, PadAmount); break; case AlignStyle::Center: { size_t X = PadAmount / 2; - S.indent(X); + fill(S, X); S << Item; - S.indent(PadAmount - X); + fill(S, PadAmount - X); break; } default: - S.indent(PadAmount); + fill(S, PadAmount); S << Item; break; } } + +private: + void fill(llvm::raw_ostream &S, uint32_t Count) { + for (uint32_t I = 0; I < Count; ++I) + S << Fill; + } }; } diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h index bb840380d4d3..fd29865c8475 100644 --- a/include/llvm/Support/MathExtras.h +++ b/include/llvm/Support/MathExtras.h @@ -272,23 +272,22 @@ T reverseBits(T Val) { // type overloading so that signed and unsigned integers can be used without // ambiguity. -/// Hi_32 - This function returns the high 32 bits of a 64 bit value. +/// Return the high 32 bits of a 64 bit value. constexpr inline uint32_t Hi_32(uint64_t Value) { return static_cast(Value >> 32); } -/// Lo_32 - This function returns the low 32 bits of a 64 bit value. +/// Return the low 32 bits of a 64 bit value. constexpr inline uint32_t Lo_32(uint64_t Value) { return static_cast(Value); } -/// Make_64 - This functions makes a 64-bit integer from a high / low pair of -/// 32-bit integers. +/// Make a 64-bit integer from a high / low pair of 32-bit integers. constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) { return ((uint64_t)High << 32) | (uint64_t)Low; } -/// isInt - Checks if an integer fits into the given bit width. +/// Checks if an integer fits into the given bit width. template constexpr inline bool isInt(int64_t x) { return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1))); } @@ -303,8 +302,7 @@ template <> constexpr inline bool isInt<32>(int64_t x) { return static_cast(x) == x; } -/// isShiftedInt - Checks if a signed integer is an N bit number shifted -/// left by S. +/// Checks if a signed integer is an N bit number shifted left by S. template constexpr inline bool isShiftedInt(int64_t x) { static_assert( @@ -313,7 +311,7 @@ constexpr inline bool isShiftedInt(int64_t x) { return isInt(x) && (x % (UINT64_C(1) << S) == 0); } -/// isUInt - Checks if an unsigned integer fits into the given bit width. +/// Checks if an unsigned integer fits into the given bit width. /// /// This is written as two functions rather than as simply /// @@ -383,71 +381,63 @@ inline int64_t maxIntN(int64_t N) { return (UINT64_C(1) << (N - 1)) - 1; } -/// isUIntN - Checks if an unsigned integer fits into the given (dynamic) -/// bit width. +/// Checks if an unsigned integer fits into the given (dynamic) bit width. inline bool isUIntN(unsigned N, uint64_t x) { return N >= 64 || x <= maxUIntN(N); } -/// isIntN - Checks if an signed integer fits into the given (dynamic) -/// bit width. +/// Checks if an signed integer fits into the given (dynamic) bit width. inline bool isIntN(unsigned N, int64_t x) { return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N)); } -/// isMask_32 - This function returns true if the argument is a non-empty -/// sequence of ones starting at the least significant bit with the remainder -/// zero (32 bit version). Ex. isMask_32(0x0000FFFFU) == true. +/// Return true if the argument is a non-empty sequence of ones starting at the +/// least significant bit with the remainder zero (32 bit version). +/// Ex. isMask_32(0x0000FFFFU) == true. constexpr inline bool isMask_32(uint32_t Value) { return Value && ((Value + 1) & Value) == 0; } -/// isMask_64 - This function returns true if the argument is a non-empty -/// sequence of ones starting at the least significant bit with the remainder -/// zero (64 bit version). +/// Return true if the argument is a non-empty sequence of ones starting at the +/// least significant bit with the remainder zero (64 bit version). constexpr inline bool isMask_64(uint64_t Value) { return Value && ((Value + 1) & Value) == 0; } -/// isShiftedMask_32 - This function returns true if the argument contains a -/// non-empty sequence of ones with the remainder zero (32 bit version.) -/// Ex. isShiftedMask_32(0x0000FF00U) == true. +/// Return true if the argument contains a non-empty sequence of ones with the +/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true. constexpr inline bool isShiftedMask_32(uint32_t Value) { return Value && isMask_32((Value - 1) | Value); } -/// isShiftedMask_64 - This function returns true if the argument contains a -/// non-empty sequence of ones with the remainder zero (64 bit version.) +/// Return true if the argument contains a non-empty sequence of ones with the +/// remainder zero (64 bit version.) constexpr inline bool isShiftedMask_64(uint64_t Value) { return Value && isMask_64((Value - 1) | Value); } -/// isPowerOf2_32 - This function returns true if the argument is a power of -/// two > 0. Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.) +/// Return true if the argument is a power of two > 0. +/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.) constexpr inline bool isPowerOf2_32(uint32_t Value) { return Value && !(Value & (Value - 1)); } -/// isPowerOf2_64 - This function returns true if the argument is a power of two -/// > 0 (64 bit edition.) +/// Return true if the argument is a power of two > 0 (64 bit edition.) constexpr inline bool isPowerOf2_64(uint64_t Value) { return Value && !(Value & (Value - int64_t(1L))); } -/// ByteSwap_16 - This function returns a byte-swapped representation of the -/// 16-bit argument, Value. +/// Return a byte-swapped representation of the 16-bit argument. inline uint16_t ByteSwap_16(uint16_t Value) { return sys::SwapByteOrder_16(Value); } -/// ByteSwap_32 - This function returns a byte-swapped representation of the -/// 32-bit argument, Value. +/// Return a byte-swapped representation of the 32-bit argument. inline uint32_t ByteSwap_32(uint32_t Value) { return sys::SwapByteOrder_32(Value); } -/// ByteSwap_64 - This function returns a byte-swapped representation of the -/// 64-bit argument, Value. +/// Return a byte-swapped representation of the 64-bit argument. inline uint64_t ByteSwap_64(uint64_t Value) { return sys::SwapByteOrder_64(Value); } @@ -455,7 +445,7 @@ inline uint64_t ByteSwap_64(uint64_t Value) { /// \brief Count the number of ones from the most significant bit to the first /// zero bit. /// -/// Ex. CountLeadingOnes(0xFF0FFF00) == 8. +/// Ex. countLeadingOnes(0xFF0FFF00) == 8. /// Only unsigned integral types are allowed. /// /// \param ZB the behavior on an input of all ones. Only ZB_Width and @@ -526,7 +516,7 @@ inline unsigned countPopulation(T Value) { return detail::PopulationCounter::count(Value); } -/// Log2 - This function returns the log base 2 of the specified value +/// Return the log base 2 of the specified value. inline double Log2(double Value) { #if defined(__ANDROID_API__) && __ANDROID_API__ < 18 return __builtin_log(Value) / __builtin_log(2.0); @@ -535,34 +525,33 @@ inline double Log2(double Value) { #endif } -/// Log2_32 - This function returns the floor log base 2 of the specified value, -/// -1 if the value is zero. (32 bit edition.) +/// Return the floor log base 2 of the specified value, -1 if the value is zero. +/// (32 bit edition.) /// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2 inline unsigned Log2_32(uint32_t Value) { return 31 - countLeadingZeros(Value); } -/// Log2_64 - This function returns the floor log base 2 of the specified value, -/// -1 if the value is zero. (64 bit edition.) +/// Return the floor log base 2 of the specified value, -1 if the value is zero. +/// (64 bit edition.) inline unsigned Log2_64(uint64_t Value) { return 63 - countLeadingZeros(Value); } -/// Log2_32_Ceil - This function returns the ceil log base 2 of the specified -/// value, 32 if the value is zero. (32 bit edition). +/// Return the ceil log base 2 of the specified value, 32 if the value is zero. +/// (32 bit edition). /// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3 inline unsigned Log2_32_Ceil(uint32_t Value) { return 32 - countLeadingZeros(Value - 1); } -/// Log2_64_Ceil - This function returns the ceil log base 2 of the specified -/// value, 64 if the value is zero. (64 bit edition.) +/// Return the ceil log base 2 of the specified value, 64 if the value is zero. +/// (64 bit edition.) inline unsigned Log2_64_Ceil(uint64_t Value) { return 64 - countLeadingZeros(Value - 1); } -/// GreatestCommonDivisor64 - Return the greatest common divisor of the two -/// values using Euclid's algorithm. +/// Return the greatest common divisor of the values using Euclid's algorithm. inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) { while (B) { uint64_t T = B; @@ -572,8 +561,7 @@ inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) { return A; } -/// BitsToDouble - This function takes a 64-bit integer and returns the bit -/// equivalent double. +/// This function takes a 64-bit integer and returns the bit equivalent double. inline double BitsToDouble(uint64_t Bits) { double D; static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes"); @@ -581,8 +569,7 @@ inline double BitsToDouble(uint64_t Bits) { return D; } -/// BitsToFloat - This function takes a 32-bit integer and returns the bit -/// equivalent float. +/// This function takes a 32-bit integer and returns the bit equivalent float. inline float BitsToFloat(uint32_t Bits) { float F; static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes"); @@ -590,10 +577,9 @@ inline float BitsToFloat(uint32_t Bits) { return F; } -/// DoubleToBits - This function takes a double and returns the bit -/// equivalent 64-bit integer. Note that copying doubles around -/// changes the bits of NaNs on some hosts, notably x86, so this -/// routine cannot be used if these bits are needed. +/// This function takes a double and returns the bit equivalent 64-bit integer. +/// Note that copying doubles around changes the bits of NaNs on some hosts, +/// notably x86, so this routine cannot be used if these bits are needed. inline uint64_t DoubleToBits(double Double) { uint64_t Bits; static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes"); @@ -601,10 +587,9 @@ inline uint64_t DoubleToBits(double Double) { return Bits; } -/// FloatToBits - This function takes a float and returns the bit -/// equivalent 32-bit integer. Note that copying floats around -/// changes the bits of NaNs on some hosts, notably x86, so this -/// routine cannot be used if these bits are needed. +/// This function takes a float and returns the bit equivalent 32-bit integer. +/// Note that copying floats around changes the bits of NaNs on some hosts, +/// notably x86, so this routine cannot be used if these bits are needed. inline uint32_t FloatToBits(float Float) { uint32_t Bits; static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes"); @@ -612,8 +597,8 @@ inline uint32_t FloatToBits(float Float) { return Bits; } -/// MinAlign - A and B are either alignments or offsets. Return the minimum -/// alignment that may be assumed after adding the two together. +/// A and B are either alignments or offsets. Return the minimum alignment that +/// may be assumed after adding the two together. constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) { // The largest power of 2 that divides both A and B. // @@ -642,8 +627,8 @@ inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) { return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr; } -/// NextPowerOf2 - Returns the next power of two (in 64-bits) -/// that is strictly greater than A. Returns zero on overflow. +/// Returns the next power of two (in 64-bits) that is strictly greater than A. +/// Returns zero on overflow. inline uint64_t NextPowerOf2(uint64_t A) { A |= (A >> 1); A |= (A >> 2); diff --git a/include/llvm/Support/ThreadPool.h b/include/llvm/Support/ThreadPool.h index f0e3ffa0999c..9ada946c6dae 100644 --- a/include/llvm/Support/ThreadPool.h +++ b/include/llvm/Support/ThreadPool.h @@ -35,17 +35,8 @@ namespace llvm { /// for some work to become available. class ThreadPool { public: -#ifndef _MSC_VER - using VoidTy = void; using TaskTy = std::function; using PackagedTaskTy = std::packaged_task; -#else - // MSVC 2013 has a bug and can't use std::packaged_task; - // We force it to use bool(bool) instead. - using VoidTy = bool; - using TaskTy = std::function; - using PackagedTaskTy = std::packaged_task; -#endif /// Construct a pool with the number of core available on the system (or /// whatever the value returned by std::thread::hardware_concurrency() is). @@ -60,30 +51,17 @@ class ThreadPool { /// Asynchronous submission of a task to the pool. The returned future can be /// used to wait for the task to finish and is *non-blocking* on destruction. template - inline std::shared_future async(Function &&F, Args &&... ArgList) { + inline std::shared_future async(Function &&F, Args &&... ArgList) { auto Task = std::bind(std::forward(F), std::forward(ArgList)...); -#ifndef _MSC_VER return asyncImpl(std::move(Task)); -#else - // This lambda has to be marked mutable because MSVC 2013's std::bind call - // operator isn't const qualified. - return asyncImpl([Task](VoidTy) mutable -> VoidTy { - Task(); - return VoidTy(); - }); -#endif } /// Asynchronous submission of a task to the pool. The returned future can be /// used to wait for the task to finish and is *non-blocking* on destruction. template - inline std::shared_future async(Function &&F) { -#ifndef _MSC_VER + inline std::shared_future async(Function &&F) { return asyncImpl(std::forward(F)); -#else - return asyncImpl([F] (VoidTy) -> VoidTy { F(); return VoidTy(); }); -#endif } /// Blocking wait for all the threads to complete and the queue to be empty. @@ -93,7 +71,7 @@ class ThreadPool { private: /// Asynchronous submission of a task to the pool. The returned future can be /// used to wait for the task to finish and is *non-blocking* on destruction. - std::shared_future asyncImpl(TaskTy F); + std::shared_future asyncImpl(TaskTy F); /// Threads in flight std::vector Threads; diff --git a/include/llvm/TableGen/Main.h b/include/llvm/TableGen/Main.h index 866b9868deb5..ca8c95cb6da2 100644 --- a/include/llvm/TableGen/Main.h +++ b/include/llvm/TableGen/Main.h @@ -16,13 +16,15 @@ namespace llvm { -class RecordKeeper; class raw_ostream; +class RecordKeeper; + /// \brief Perform the action using Records, and write output to OS. /// \returns true on error, false otherwise -typedef bool TableGenMainFn(raw_ostream &OS, RecordKeeper &Records); +using TableGenMainFn = bool (raw_ostream &OS, RecordKeeper &Records); int TableGenMain(char *argv0, TableGenMainFn *MainFn); -} -#endif +} // end namespace llvm + +#endif // LLVM_TABLEGEN_MAIN_H diff --git a/include/llvm/TableGen/Record.h b/include/llvm/TableGen/Record.h index 5c3bf88fbbfa..fa9ca285bcde 100644 --- a/include/llvm/TableGen/Record.h +++ b/include/llvm/TableGen/Record.h @@ -38,11 +38,11 @@ namespace llvm { class ListRecTy; +struct MultiClass; class Record; class RecordKeeper; class RecordVal; class StringInit; -struct MultiClass; //===----------------------------------------------------------------------===// // Type Classes @@ -90,7 +90,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const RecTy &Ty) { } /// 'bit' - Represent a single bit -/// class BitRecTy : public RecTy { static BitRecTy Shared; @@ -109,7 +108,6 @@ class BitRecTy : public RecTy { }; /// 'bits' - Represent a fixed number of bits -/// class BitsRecTy : public RecTy { unsigned Size; @@ -130,7 +128,6 @@ class BitsRecTy : public RecTy { }; /// 'code' - Represent a code fragment -/// class CodeRecTy : public RecTy { static CodeRecTy Shared; @@ -147,7 +144,6 @@ class CodeRecTy : public RecTy { }; /// 'int' - Represent an integer value of no particular size -/// class IntRecTy : public RecTy { static IntRecTy Shared; @@ -166,7 +162,6 @@ class IntRecTy : public RecTy { }; /// 'string' - Represent an string value -/// class StringRecTy : public RecTy { static StringRecTy Shared; @@ -185,14 +180,13 @@ class StringRecTy : public RecTy { /// 'list' - Represent a list of values, all of which must be of /// the specified type. -/// class ListRecTy : public RecTy { + friend ListRecTy *RecTy::getListTy(); + RecTy *Ty; explicit ListRecTy(RecTy *T) : RecTy(ListRecTyKind), Ty(T) {} - friend ListRecTy *RecTy::getListTy(); - public: static bool classof(const RecTy *RT) { return RT->getRecTyKind() == ListRecTyKind; @@ -207,7 +201,6 @@ class ListRecTy : public RecTy { }; /// 'dag' - Represent a dag fragment -/// class DagRecTy : public RecTy { static DagRecTy Shared; @@ -225,14 +218,13 @@ class DagRecTy : public RecTy { /// '[classname]' - Represent an instance of a class, such as: /// (R32 X = EAX). -/// class RecordRecTy : public RecTy { + friend class Record; + Record *Rec; explicit RecordRecTy(Record *R) : RecTy(RecordRecTyKind), Rec(R) {} - friend class Record; - public: static bool classof(const RecTy *RT) { return RT->getRecTyKind() == RecordRecTyKind; @@ -249,7 +241,6 @@ class RecordRecTy : public RecTy { /// Find a common type that T1 and T2 convert to. /// Return 0 if no such type exists. -/// RecTy *resolveTypes(RecTy *T1, RecTy *T2); //===----------------------------------------------------------------------===// @@ -341,7 +332,6 @@ class Init { /// selection operator. Given an initializer, it selects the specified bits /// out, returning them as a new init of bits type. If it is not legal to use /// the bit subscript operator on this initializer, return null. - /// virtual Init *convertInitializerBitRange(ArrayRef Bits) const { return nullptr; } @@ -350,7 +340,6 @@ class Init { /// selection operator. Given an initializer, it selects the specified list /// elements, returning them as a new init of list type. If it is not legal /// to take a slice of this, return null. - /// virtual Init *convertInitListSlice(ArrayRef Elements) const { return nullptr; } @@ -358,7 +347,6 @@ class Init { /// This method is used to implement the FieldInit class. /// Implementors of this method should return the type of the named field if /// they are of record type. - /// virtual RecTy *getFieldType(StringInit *FieldName) const { return nullptr; } @@ -366,7 +354,6 @@ class Init { /// This method complements getFieldType to return the /// initializer for the specified field. If getFieldType returns non-null /// this method should return non-null, otherwise it returns null. - /// virtual Init *getFieldInit(Record &R, const RecordVal *RV, StringInit *FieldName) const { return nullptr; @@ -376,7 +363,6 @@ class Init { /// variables which may not be defined at the time the expression is formed. /// If a value is set for the variable later, this method will be called on /// users of the value to allow the value to propagate out. - /// virtual Init *resolveReferences(Record &R, const RecordVal *RV) const { return const_cast(this); } @@ -400,7 +386,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const Init &I) { /// This is the common super-class of types that have a specific, /// explicit, type. -/// class TypedInit : public Init { RecTy *Ty; @@ -409,8 +394,8 @@ class TypedInit : public Init { : Init(K, Opc), Ty(T) {} public: - TypedInit(const TypedInit &Other) = delete; - TypedInit &operator=(const TypedInit &Other) = delete; + TypedInit(const TypedInit &) = delete; + TypedInit &operator=(const TypedInit &) = delete; static bool classof(const Init *I) { return I->getKind() >= IK_FirstTypedInit && @@ -438,13 +423,12 @@ class TypedInit : public Init { }; /// '?' - Represents an uninitialized value -/// class UnsetInit : public Init { UnsetInit() : Init(IK_UnsetInit) {} public: UnsetInit(const UnsetInit &) = delete; - UnsetInit &operator=(const UnsetInit &Other) = delete; + UnsetInit &operator=(const UnsetInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_UnsetInit; @@ -463,15 +447,14 @@ class UnsetInit : public Init { }; /// 'true'/'false' - Represent a concrete initializer for a bit. -/// class BitInit : public Init { bool Value; explicit BitInit(bool V) : Init(IK_BitInit), Value(V) {} public: - BitInit(const BitInit &Other) = delete; - BitInit &operator=(BitInit &Other) = delete; + BitInit(const BitInit &) = delete; + BitInit &operator=(BitInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_BitInit; @@ -493,7 +476,6 @@ class BitInit : public Init { /// '{ a, b, c }' - Represents an initializer for a BitsRecTy value. /// It contains a vector of bits, whose size is determined by the type. -/// class BitsInit final : public TypedInit, public FoldingSetNode, public TrailingObjects { unsigned NumBits; @@ -502,8 +484,8 @@ class BitsInit final : public TypedInit, public FoldingSetNode, : TypedInit(IK_BitsInit, BitsRecTy::get(N)), NumBits(N) {} public: - BitsInit(const BitsInit &Other) = delete; - BitsInit &operator=(const BitsInit &Other) = delete; + BitsInit(const BitsInit &) = delete; + BitsInit &operator=(const BitsInit &) = delete; // Do not use sized deallocation due to trailing objects. void operator delete(void *p) { ::operator delete(p); } @@ -552,7 +534,6 @@ class BitsInit final : public TypedInit, public FoldingSetNode, }; /// '7' - Represent an initialization by a literal integer value. -/// class IntInit : public TypedInit { int64_t Value; @@ -560,8 +541,8 @@ class IntInit : public TypedInit { : TypedInit(IK_IntInit, IntRecTy::get()), Value(V) {} public: - IntInit(const IntInit &Other) = delete; - IntInit &operator=(const IntInit &Other) = delete; + IntInit(const IntInit &) = delete; + IntInit &operator=(const IntInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_IntInit; @@ -590,7 +571,6 @@ class IntInit : public TypedInit { }; /// "foo" - Represent an initialization by a string value. -/// class StringInit : public TypedInit { StringRef Value; @@ -598,8 +578,8 @@ class StringInit : public TypedInit { : TypedInit(IK_StringInit, StringRecTy::get()), Value(V) {} public: - StringInit(const StringInit &Other) = delete; - StringInit &operator=(const StringInit &Other) = delete; + StringInit(const StringInit &) = delete; + StringInit &operator=(const StringInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_StringInit; @@ -636,8 +616,8 @@ class CodeInit : public TypedInit { Value(V) {} public: - CodeInit(const StringInit &Other) = delete; - CodeInit &operator=(const StringInit &Other) = delete; + CodeInit(const StringInit &) = delete; + CodeInit &operator=(const StringInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_CodeInit; @@ -675,15 +655,15 @@ class ListInit final : public TypedInit, public FoldingSetNode, unsigned NumValues; public: - typedef Init *const *const_iterator; + using const_iterator = Init *const *; private: explicit ListInit(unsigned N, RecTy *EltTy) : TypedInit(IK_ListInit, ListRecTy::get(EltTy)), NumValues(N) {} public: - ListInit(const ListInit &Other) = delete; - ListInit &operator=(const ListInit &Other) = delete; + ListInit(const ListInit &) = delete; + ListInit &operator=(const ListInit &) = delete; // Do not use sized deallocation due to trailing objects. void operator delete(void *p) { ::operator delete(p); } @@ -744,8 +724,8 @@ class OpInit : public TypedInit { : TypedInit(K, Type, Opc) {} public: - OpInit(const OpInit &Other) = delete; - OpInit &operator=(OpInit &Other) = delete; + OpInit(const OpInit &) = delete; + OpInit &operator=(OpInit &) = delete; static bool classof(const Init *I) { return I->getKind() >= IK_FirstOpInit && @@ -781,8 +761,8 @@ class UnOpInit : public OpInit, public FoldingSetNode { : OpInit(IK_UnOpInit, Type, opc), LHS(lhs) {} public: - UnOpInit(const UnOpInit &Other) = delete; - UnOpInit &operator=(const UnOpInit &Other) = delete; + UnOpInit(const UnOpInit &) = delete; + UnOpInit &operator=(const UnOpInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_UnOpInit; @@ -819,7 +799,6 @@ class UnOpInit : public OpInit, public FoldingSetNode { }; /// !op (X, Y) - Combine two inits. -/// class BinOpInit : public OpInit, public FoldingSetNode { public: enum BinaryOp : uint8_t { ADD, AND, OR, SHL, SRA, SRL, LISTCONCAT, @@ -832,8 +811,8 @@ class BinOpInit : public OpInit, public FoldingSetNode { OpInit(IK_BinOpInit, Type, opc), LHS(lhs), RHS(rhs) {} public: - BinOpInit(const BinOpInit &Other) = delete; - BinOpInit &operator=(const BinOpInit &Other) = delete; + BinOpInit(const BinOpInit &) = delete; + BinOpInit &operator=(const BinOpInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_BinOpInit; @@ -874,7 +853,6 @@ class BinOpInit : public OpInit, public FoldingSetNode { }; /// !op (X, Y, Z) - Combine two inits. -/// class TernOpInit : public OpInit, public FoldingSetNode { public: enum TernaryOp : uint8_t { SUBST, FOREACH, IF }; @@ -887,8 +865,8 @@ class TernOpInit : public OpInit, public FoldingSetNode { OpInit(IK_TernOpInit, Type, opc), LHS(lhs), MHS(mhs), RHS(rhs) {} public: - TernOpInit(const TernOpInit &Other) = delete; - TernOpInit &operator=(const TernOpInit &Other) = delete; + TernOpInit(const TernOpInit &) = delete; + TernOpInit &operator=(const TernOpInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_TernOpInit; @@ -935,7 +913,6 @@ class TernOpInit : public OpInit, public FoldingSetNode { }; /// 'Opcode' - Represent a reference to an entire variable object. -/// class VarInit : public TypedInit { Init *VarName; @@ -943,8 +920,8 @@ class VarInit : public TypedInit { : TypedInit(IK_VarInit, T), VarName(VN) {} public: - VarInit(const VarInit &Other) = delete; - VarInit &operator=(const VarInit &Other) = delete; + VarInit(const VarInit &) = delete; + VarInit &operator=(const VarInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_VarInit; @@ -980,7 +957,6 @@ class VarInit : public TypedInit { }; /// Opcode{0} - Represent access to one bit of a variable or field. -/// class VarBitInit : public Init { TypedInit *TI; unsigned Bit; @@ -994,8 +970,8 @@ class VarBitInit : public Init { } public: - VarBitInit(const VarBitInit &Other) = delete; - VarBitInit &operator=(const VarBitInit &Other) = delete; + VarBitInit(const VarBitInit &) = delete; + VarBitInit &operator=(const VarBitInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_VarBitInit; @@ -1032,8 +1008,8 @@ class VarListElementInit : public TypedInit { } public: - VarListElementInit(const VarListElementInit &Other) = delete; - void operator=(const VarListElementInit &Other) = delete; + VarListElementInit(const VarListElementInit &) = delete; + VarListElementInit &operator=(const VarListElementInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_VarListElementInit; @@ -1057,17 +1033,16 @@ class VarListElementInit : public TypedInit { }; /// AL - Represent a reference to a 'def' in the description -/// class DefInit : public TypedInit { + friend class Record; + Record *Def; DefInit(Record *D, RecordRecTy *T) : TypedInit(IK_DefInit, T), Def(D) {} - friend class Record; - public: - DefInit(const DefInit &Other) = delete; - DefInit &operator=(const DefInit &Other) = delete; + DefInit(const DefInit &) = delete; + DefInit &operator=(const DefInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_DefInit; @@ -1101,7 +1076,6 @@ class DefInit : public TypedInit { }; /// X.Y - Represent a reference to a subfield of a variable -/// class FieldInit : public TypedInit { Init *Rec; // Record we are referring to StringInit *FieldName; // Field we are accessing @@ -1112,8 +1086,8 @@ class FieldInit : public TypedInit { } public: - FieldInit(const FieldInit &Other) = delete; - FieldInit &operator=(const FieldInit &Other) = delete; + FieldInit(const FieldInit &) = delete; + FieldInit &operator=(const FieldInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_FieldInit; @@ -1136,9 +1110,10 @@ class FieldInit : public TypedInit { /// (v a, b) - Represent a DAG tree value. DAG inits are required /// to have at least one value then a (possibly empty) list of arguments. Each /// argument can have a name associated with it. -/// class DagInit final : public TypedInit, public FoldingSetNode, public TrailingObjects { + friend TrailingObjects; + Init *Val; StringInit *ValName; unsigned NumArgs; @@ -1148,12 +1123,11 @@ class DagInit final : public TypedInit, public FoldingSetNode, : TypedInit(IK_DagInit, DagRecTy::get()), Val(V), ValName(VN), NumArgs(NumArgs), NumArgNames(NumArgNames) {} - friend TrailingObjects; size_t numTrailingObjects(OverloadToken) const { return NumArgs; } public: - DagInit(const DagInit &Other) = delete; - DagInit &operator=(const DagInit &Other) = delete; + DagInit(const DagInit &) = delete; + DagInit &operator=(const DagInit &) = delete; static bool classof(const Init *I) { return I->getKind() == IK_DagInit; @@ -1171,19 +1145,23 @@ class DagInit final : public TypedInit, public FoldingSetNode, Init *getOperator() const { return Val; } StringInit *getName() const { return ValName; } + StringRef getNameStr() const { return ValName ? ValName->getValue() : StringRef(); } unsigned getNumArgs() const { return NumArgs; } + Init *getArg(unsigned Num) const { assert(Num < NumArgs && "Arg number out of range!"); return getTrailingObjects()[Num]; } + StringInit *getArgName(unsigned Num) const { assert(Num < NumArgNames && "Arg number out of range!"); return getTrailingObjects()[Num]; } + StringRef getArgNameStr(unsigned Num) const { StringInit *Init = getArgName(Num); return Init ? Init->getValue() : StringRef(); @@ -1192,6 +1170,7 @@ class DagInit final : public TypedInit, public FoldingSetNode, ArrayRef getArgs() const { return makeArrayRef(getTrailingObjects(), NumArgs); } + ArrayRef getArgNames() const { return makeArrayRef(getTrailingObjects(), NumArgNames); } @@ -1200,8 +1179,8 @@ class DagInit final : public TypedInit, public FoldingSetNode, std::string getAsString() const override; - typedef SmallVectorImpl::const_iterator const_arg_iterator; - typedef SmallVectorImpl::const_iterator const_name_iterator; + using const_arg_iterator = SmallVectorImpl::const_iterator; + using const_name_iterator = SmallVectorImpl::const_iterator; inline const_arg_iterator arg_begin() const { return getArgs().begin(); } inline const_arg_iterator arg_end () const { return getArgs().end(); } @@ -1231,6 +1210,7 @@ class DagInit final : public TypedInit, public FoldingSetNode, class RecordVal { friend class Record; + Init *Name; PointerIntPair TyAndPrefix; Init *Value; @@ -1298,7 +1278,7 @@ class Record { // definitions that use them (e.g. Def). However, inside a multiclass they // can't be immediately resolved so we mark them ResolveFirst to fully // resolve them later as soon as the multiclass is instantiated. - bool ResolveFirst; + bool ResolveFirst = false; void init(); void checkName(); @@ -1308,7 +1288,7 @@ class Record { explicit Record(Init *N, ArrayRef locs, RecordKeeper &records, bool Anonymous = false) : Name(N), Locs(locs.begin(), locs.end()), TrackedRecords(records), - ID(LastID++), IsAnonymous(Anonymous), ResolveFirst(false) { + ID(LastID++), IsAnonymous(Anonymous) { init(); } @@ -1330,6 +1310,7 @@ class Record { unsigned getID() const { return ID; } StringRef getName() const; + Init *getNameInit() const { return Name; } @@ -1435,7 +1416,6 @@ class Record { /// If there are any field references that refer to fields /// that have been filled in, we can propagate the values now. - /// void resolveReferences() { resolveReferencesTo(nullptr); } /// If anything in this record refers to RV, replace the @@ -1468,7 +1448,6 @@ class Record { /// Return the initializer for a value with the specified name, /// or throw an exception if the field does not exist. - /// Init *getValueInit(StringRef FieldName) const; /// Return true if the named field is unset. @@ -1479,67 +1458,56 @@ class Record { /// This method looks up the specified field and returns /// its value as a string, throwing an exception if the field does not exist /// or if the value is not a string. - /// StringRef getValueAsString(StringRef FieldName) const; /// This method looks up the specified field and returns /// its value as a BitsInit, throwing an exception if the field does not exist /// or if the value is not the right type. - /// BitsInit *getValueAsBitsInit(StringRef FieldName) const; /// This method looks up the specified field and returns /// its value as a ListInit, throwing an exception if the field does not exist /// or if the value is not the right type. - /// ListInit *getValueAsListInit(StringRef FieldName) const; /// This method looks up the specified field and /// returns its value as a vector of records, throwing an exception if the /// field does not exist or if the value is not the right type. - /// std::vector getValueAsListOfDefs(StringRef FieldName) const; /// This method looks up the specified field and /// returns its value as a vector of integers, throwing an exception if the /// field does not exist or if the value is not the right type. - /// std::vector getValueAsListOfInts(StringRef FieldName) const; /// This method looks up the specified field and /// returns its value as a vector of strings, throwing an exception if the /// field does not exist or if the value is not the right type. - /// std::vector getValueAsListOfStrings(StringRef FieldName) const; /// This method looks up the specified field and returns its /// value as a Record, throwing an exception if the field does not exist or if /// the value is not the right type. - /// Record *getValueAsDef(StringRef FieldName) const; /// This method looks up the specified field and returns its /// value as a bit, throwing an exception if the field does not exist or if /// the value is not the right type. - /// bool getValueAsBit(StringRef FieldName) const; /// This method looks up the specified field and /// returns its value as a bit. If the field is unset, sets Unset to true and /// returns false. - /// bool getValueAsBitOrUnset(StringRef FieldName, bool &Unset) const; /// This method looks up the specified field and returns its /// value as an int64_t, throwing an exception if the field does not exist or /// if the value is not the right type. - /// int64_t getValueAsInt(StringRef FieldName) const; /// This method looks up the specified field and returns its /// value as an Dag, throwing an exception if the field does not exist or if /// the value is not the right type. - /// DagInit *getValueAsDag(StringRef FieldName) const; }; @@ -1547,7 +1515,7 @@ raw_ostream &operator<<(raw_ostream &OS, const Record &R); struct MultiClass { Record Rec; // Placeholder for template args and Name. - typedef std::vector> RecordVector; + using RecordVector = std::vector>; RecordVector DefPrototypes; void dump() const; @@ -1557,7 +1525,7 @@ struct MultiClass { }; class RecordKeeper { - typedef std::map> RecordMap; + using RecordMap = std::map>; RecordMap Classes, Defs; public: @@ -1600,7 +1568,6 @@ class RecordKeeper { }; /// Sorting predicate to sort record pointers by name. -/// struct LessRecord { bool operator()(const Record *Rec1, const Record *Rec2) const { return StringRef(Rec1->getName()).compare_numeric(Rec2->getName()) < 0; @@ -1619,7 +1586,6 @@ struct LessRecordByID { /// Sorting predicate to sort record pointers by their /// name field. -/// struct LessRecordFieldName { bool operator()(const Record *Rec1, const Record *Rec2) const { return Rec1->getValueAsString("Name") < Rec2->getValueAsString("Name"); diff --git a/include/llvm/TableGen/SetTheory.h b/include/llvm/TableGen/SetTheory.h index 818b0549b66a..4b32f9e3da8f 100644 --- a/include/llvm/TableGen/SetTheory.h +++ b/include/llvm/TableGen/SetTheory.h @@ -64,8 +64,8 @@ class Record; class SetTheory { public: - typedef std::vector RecVec; - typedef SmallSetVector RecSet; + using RecVec = std::vector; + using RecSet = SmallSetVector; /// Operator - A callback representing a DAG operator. class Operator { @@ -95,7 +95,7 @@ class SetTheory { private: // Map set defs to their fully expanded contents. This serves as a memoization // cache and it makes it possible to return const references on queries. - typedef std::map ExpandMap; + using ExpandMap = std::map; ExpandMap Expansions; // Known DAG operators by name. diff --git a/include/llvm/TableGen/StringMatcher.h b/include/llvm/TableGen/StringMatcher.h index 11a8ad8183aa..7c919ffec7b6 100644 --- a/include/llvm/TableGen/StringMatcher.h +++ b/include/llvm/TableGen/StringMatcher.h @@ -20,7 +20,8 @@ #include namespace llvm { - class raw_ostream; + +class raw_ostream; /// StringMatcher - Given a list of strings and code to execute when they match, /// output a simple switch tree to classify the input string. @@ -30,7 +31,7 @@ namespace llvm { /// class StringMatcher { public: - typedef std::pair StringPair; + using StringPair = std::pair; private: StringRef StrVariableName; @@ -49,6 +50,6 @@ class StringMatcher { unsigned CharNo, unsigned IndentCount) const; }; -} // end llvm namespace. +} // end namespace llvm -#endif +#endif // LLVM_TABLEGEN_STRINGMATCHER_H diff --git a/include/llvm/Target/TargetLoweringObjectFile.h b/include/llvm/Target/TargetLoweringObjectFile.h index 0ffd4b7f8c78..80d4d8e42e51 100644 --- a/include/llvm/Target/TargetLoweringObjectFile.h +++ b/include/llvm/Target/TargetLoweringObjectFile.h @@ -70,10 +70,9 @@ class TargetLoweringObjectFile : public MCObjectFileInfo { virtual void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &TM, const MCSymbol *Sym) const; - /// Emit the module flags that the platform cares about. - virtual void emitModuleFlags(MCStreamer &Streamer, - ArrayRef Flags, - const TargetMachine &TM) const {} + /// Emit the module-level metadata that the platform cares about. + virtual void emitModuleMetadata(MCStreamer &Streamer, Module &M, + const TargetMachine &TM) const {} /// Given a constant with the SectionKind, return a section that it should be /// placed in. diff --git a/include/llvm/Target/TargetRegisterInfo.h b/include/llvm/Target/TargetRegisterInfo.h index 4ce6d2ff5e26..86ad8ad53052 100644 --- a/include/llvm/Target/TargetRegisterInfo.h +++ b/include/llvm/Target/TargetRegisterInfo.h @@ -497,6 +497,16 @@ class TargetRegisterInfo : public MCRegisterInfo { /// function. Used by MachineRegisterInfo::isConstantPhysReg(). virtual bool isConstantPhysReg(unsigned PhysReg) const { return false; } + /// Physical registers that may be modified within a function but are + /// guaranteed to be restored before any uses. This is useful for targets that + /// have call sequences where a GOT register may be updated by the caller + /// prior to a call and is guaranteed to be restored (also by the caller) + /// after the call. + virtual bool isCallerPreservedPhysReg(unsigned PhysReg, + const MachineFunction &MF) const { + return false; + } + /// Prior to adding the live-out mask to a stackmap or patchpoint /// instruction, provide the target the opportunity to adjust it (mainly to /// remove pseudo-registers that should be ignored). diff --git a/include/llvm/Testing/Support/Error.h b/include/llvm/Testing/Support/Error.h new file mode 100644 index 000000000000..d52752901593 --- /dev/null +++ b/include/llvm/Testing/Support/Error.h @@ -0,0 +1,69 @@ +//===- llvm/Testing/Support/Error.h ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TESTING_SUPPORT_ERROR_H +#define LLVM_TESTING_SUPPORT_ERROR_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" +#include "llvm/Testing/Support/SupportHelpers.h" + +#include "gmock/gmock.h" +#include + +namespace llvm { +namespace detail { +ErrorHolder TakeError(Error Err); + +template ExpectedHolder TakeExpected(Expected &Exp) { + llvm::detail::ExpectedHolder Result; + auto &EH = static_cast(Result); + EH = TakeError(Exp.takeError()); + if (Result.Success) + Result.Value = &(*Exp); + return Result; +} + +template ExpectedHolder TakeExpected(const Expected &Exp) { + return TakeExpected(const_cast &>(Exp)); +} +} // namespace detail + +#define EXPECT_THAT_ERROR(Err, Matcher) \ + EXPECT_THAT(llvm::detail::TakeError(Err), Matcher) +#define ASSERT_THAT_ERROR(Err, Matcher) \ + ASSERT_THAT(llvm::detail::TakeError(Err), Matcher) + +#define EXPECT_THAT_EXPECTED(Err, Matcher) \ + EXPECT_THAT(llvm::detail::TakeExpected(Err), Matcher) +#define ASSERT_THAT_EXPECTED(Err, Matcher) \ + ASSERT_THAT(llvm::detail::TakeExpected(Err), Matcher) + +MATCHER(Succeeded, "") { return arg.Success; } +MATCHER(Failed, "") { return !arg.Success; } + +MATCHER_P(HasValue, value, + "succeeded with value " + testing::PrintToString(value)) { + if (!arg.Success) { + *result_listener << "operation failed"; + return false; + } + + assert(arg.Value.hasValue()); + if (**arg.Value != value) { + *result_listener << "but \"" + testing::PrintToString(**arg.Value) + + "\" != " + testing::PrintToString(value); + return false; + } + + return true; +} +} // namespace llvm + +#endif diff --git a/include/llvm/Testing/Support/SupportHelpers.h b/include/llvm/Testing/Support/SupportHelpers.h new file mode 100644 index 000000000000..c4dd414b80db --- /dev/null +++ b/include/llvm/Testing/Support/SupportHelpers.h @@ -0,0 +1,47 @@ +//===- Testing/Support/SupportHelpers.h -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TESTING_SUPPORT_SUPPORTHELPERS_H +#define LLVM_TESTING_SUPPORT_SUPPORTHELPERS_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "gtest/gtest-printers.h" + +namespace llvm { +namespace detail { +struct ErrorHolder { + bool Success; + std::string Message; +}; + +template struct ExpectedHolder : public ErrorHolder { + Optional Value; +}; + +inline void PrintTo(const ErrorHolder &Err, std::ostream *Out) { + *Out << (Err.Success ? "succeeded" : "failed"); + if (!Err.Success) { + *Out << " (" << StringRef(Err.Message).trim().str() << ")"; + } +} + +template +void PrintTo(const ExpectedHolder &Item, std::ostream *Out) { + if (Item.Success) { + *Out << "succeeded with value \"" << ::testing::PrintToString(**Item.Value) + << "\""; + } else { + PrintTo(static_cast(Item), Out); + } +} +} // namespace detail +} // namespace llvm + +#endif diff --git a/include/llvm/Transforms/Scalar/GVNExpression.h b/include/llvm/Transforms/Scalar/GVNExpression.h index 008341304995..f603ebcbca7c 100644 --- a/include/llvm/Transforms/Scalar/GVNExpression.h +++ b/include/llvm/Transforms/Scalar/GVNExpression.h @@ -121,10 +121,7 @@ class Expression { OS << "}"; } - LLVM_DUMP_METHOD void dump() const { - print(dbgs()); - dbgs() << "\n"; - } + LLVM_DUMP_METHOD void dump() const; }; inline raw_ostream &operator<<(raw_ostream &OS, const Expression &E) { diff --git a/include/llvm/Transforms/Utils/CodeExtractor.h b/include/llvm/Transforms/Utils/CodeExtractor.h index 7e23544af1ab..682b353ab5ae 100644 --- a/include/llvm/Transforms/Utils/CodeExtractor.h +++ b/include/llvm/Transforms/Utils/CodeExtractor.h @@ -106,15 +106,32 @@ template class ArrayRef; /// significant impact on the cost however. void findInputsOutputs(ValueSet &Inputs, ValueSet &Outputs, const ValueSet &Allocas) const; + + /// Check if life time marker nodes can be hoisted/sunk into the outline + /// region. + /// + /// Returns true if it is safe to do the code motion. + bool isLegalToShrinkwrapLifetimeMarkers(Instruction *AllocaAddr) const; /// Find the set of allocas whose life ranges are contained within the /// outlined region. /// /// Allocas which have life_time markers contained in the outlined region /// should be pushed to the outlined function. The address bitcasts that /// are used by the lifetime markers are also candidates for shrink- - /// wrapping. The instructions that need to be sinked are collected in + /// wrapping. The instructions that need to be sunk are collected in /// 'Allocas'. - void findAllocas(ValueSet &Allocas) const; + void findAllocas(ValueSet &SinkCands, ValueSet &HoistCands, + BasicBlock *&ExitBlock) const; + + /// Find or create a block within the outline region for placing hoisted + /// code. + /// + /// CommonExitBlock is block outside the outline region. It is the common + /// successor of blocks inside the region. If there exists a single block + /// inside the region that is the predecessor of CommonExitBlock, that block + /// will be returned. Otherwise CommonExitBlock will be split and the + /// original block will be added to the outline region. + BasicBlock *findOrCreateBlockForHoisting(BasicBlock *CommonExitBlock); private: void severSplitPHINodes(BasicBlock *&Header); diff --git a/include/llvm/Transforms/Utils/Mem2Reg.h b/include/llvm/Transforms/Utils/Mem2Reg.h index 456876b520b0..1fe186d6c3ad 100644 --- a/include/llvm/Transforms/Utils/Mem2Reg.h +++ b/include/llvm/Transforms/Utils/Mem2Reg.h @@ -25,4 +25,4 @@ class PromotePass : public PassInfoMixin { }; } -#endif // LLVM_TRANSFORMS_UTILS_MEM2REG_H \ No newline at end of file +#endif // LLVM_TRANSFORMS_UTILS_MEM2REG_H diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index f743cb234c45..dbb1b01b94ac 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/lib/Analysis/BasicAliasAnalysis.cpp @@ -1011,10 +1011,24 @@ static AliasResult aliasSameBasePointerGEPs(const GEPOperator *GEP1, // equal each other so we can exit early. if (C1 && C2) return NoAlias; - if (isKnownNonEqual(GEP1->getOperand(GEP1->getNumOperands() - 1), - GEP2->getOperand(GEP2->getNumOperands() - 1), - DL)) - return NoAlias; + { + Value *GEP1LastIdx = GEP1->getOperand(GEP1->getNumOperands() - 1); + Value *GEP2LastIdx = GEP2->getOperand(GEP2->getNumOperands() - 1); + if (isa(GEP1LastIdx) || isa(GEP2LastIdx)) { + // If one of the indices is a PHI node, be safe and only use + // computeKnownBits so we don't make any assumptions about the + // relationships between the two indices. This is important if we're + // asking about values from different loop iterations. See PR32314. + // TODO: We may be able to change the check so we only do this when + // we definitely looked through a PHINode. + KnownBits Known1 = computeKnownBits(GEP1LastIdx, DL); + KnownBits Known2 = computeKnownBits(GEP2LastIdx, DL); + if (Known1.Zero.intersects(Known2.One) || + Known1.One.intersects(Known2.Zero)) + return NoAlias; + } else if (isKnownNonEqual(GEP1LastIdx, GEP2LastIdx, DL)) + return NoAlias; + } return MayAlias; } else if (!LastIndexedStruct || !C1 || !C2) { return MayAlias; diff --git a/lib/Analysis/CallGraphSCCPass.cpp b/lib/Analysis/CallGraphSCCPass.cpp index 5896e6e0902f..facda246936d 100644 --- a/lib/Analysis/CallGraphSCCPass.cpp +++ b/lib/Analysis/CallGraphSCCPass.cpp @@ -608,18 +608,18 @@ namespace { } bool runOnSCC(CallGraphSCC &SCC) override { + bool BannerPrinted = false; auto PrintBannerOnce = [&] () { - static bool BannerPrinted = false; if (BannerPrinted) return; Out << Banner; BannerPrinted = true; }; for (CallGraphNode *CGN : SCC) { - if (CGN->getFunction()) { - if (isFunctionInPrintList(CGN->getFunction()->getName())) { + if (Function *F = CGN->getFunction()) { + if (!F->isDeclaration() && isFunctionInPrintList(F->getName())) { PrintBannerOnce(); - CGN->getFunction()->print(Out); + F->print(Out); } } else if (llvm::isFunctionInPrintList("*")) { PrintBannerOnce(); diff --git a/lib/Analysis/DivergenceAnalysis.cpp b/lib/Analysis/DivergenceAnalysis.cpp index 1b36569f7a07..2d39a0b02150 100644 --- a/lib/Analysis/DivergenceAnalysis.cpp +++ b/lib/Analysis/DivergenceAnalysis.cpp @@ -241,7 +241,7 @@ void DivergencePropagator::exploreDataDependency(Value *V) { // Follow def-use chains of V. for (User *U : V->users()) { Instruction *UserInst = cast(U); - if (DV.insert(UserInst).second) + if (!TTI.isAlwaysUniform(U) && DV.insert(UserInst).second) Worklist.push_back(UserInst); } } diff --git a/lib/Analysis/MemorySSA.cpp b/lib/Analysis/MemorySSA.cpp index e0e04a91410f..86d0d92799f2 100644 --- a/lib/Analysis/MemorySSA.cpp +++ b/lib/Analysis/MemorySSA.cpp @@ -1872,7 +1872,6 @@ MemorySSAPrinterLegacyPass::MemorySSAPrinterLegacyPass() : FunctionPass(ID) { void MemorySSAPrinterLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); - AU.addPreserved(); } bool MemorySSAPrinterLegacyPass::runOnFunction(Function &F) { @@ -1957,6 +1956,7 @@ MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( #ifdef EXPENSIVE_CHECKS MemoryAccess *NewNoCache = Walker.findClobber(StartingAccess, Q); assert(NewNoCache == New && "Cache made us hand back a different result?"); + (void)NewNoCache; #endif if (AutoResetWalker) resetClobberWalker(); diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index b9c4716b5528..aebc80a0a885 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -149,9 +149,9 @@ static cl::opt MaxValueCompareDepth( cl::init(2)); static cl::opt - MaxAddExprDepth("scalar-evolution-max-addexpr-depth", cl::Hidden, - cl::desc("Maximum depth of recursive AddExpr"), - cl::init(32)); + MaxArithDepth("scalar-evolution-max-arith-depth", cl::Hidden, + cl::desc("Maximum depth of recursive arithmetics"), + cl::init(32)); static cl::opt MaxConstantEvolvingDepth( "scalar-evolution-max-constant-evolving-depth", cl::Hidden, @@ -2276,8 +2276,8 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, if (Ops.size() == 1) return Ops[0]; } - // Limit recursion calls depth - if (Depth > MaxAddExprDepth) + // Limit recursion calls depth. + if (Depth > MaxArithDepth) return getOrCreateAddExpr(Ops, Flags); // Okay, check to see if the same value occurs in the operand list more than @@ -2293,7 +2293,7 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, ++Count; // Merge the values into a multiply. const SCEV *Scale = getConstant(Ty, Count); - const SCEV *Mul = getMulExpr(Scale, Ops[i]); + const SCEV *Mul = getMulExpr(Scale, Ops[i], SCEV::FlagAnyWrap, Depth + 1); if (Ops.size() == Count) return Mul; Ops[i] = Mul; @@ -2343,7 +2343,7 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, } } if (Ok) - LargeOps.push_back(getMulExpr(LargeMulOps)); + LargeOps.push_back(getMulExpr(LargeMulOps, SCEV::FlagAnyWrap, Depth + 1)); } else { Ok = false; break; @@ -2417,7 +2417,8 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, if (MulOp.first != 0) Ops.push_back(getMulExpr( getConstant(MulOp.first), - getAddExpr(MulOp.second, SCEV::FlagAnyWrap, Depth + 1))); + getAddExpr(MulOp.second, SCEV::FlagAnyWrap, Depth + 1), + SCEV::FlagAnyWrap, Depth + 1)); if (Ops.empty()) return getZero(Ty); if (Ops.size() == 1) @@ -2445,11 +2446,12 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, SmallVector MulOps(Mul->op_begin(), Mul->op_begin()+MulOp); MulOps.append(Mul->op_begin()+MulOp+1, Mul->op_end()); - InnerMul = getMulExpr(MulOps); + InnerMul = getMulExpr(MulOps, SCEV::FlagAnyWrap, Depth + 1); } SmallVector TwoOps = {getOne(Ty), InnerMul}; const SCEV *AddOne = getAddExpr(TwoOps, SCEV::FlagAnyWrap, Depth + 1); - const SCEV *OuterMul = getMulExpr(AddOne, MulOpSCEV); + const SCEV *OuterMul = getMulExpr(AddOne, MulOpSCEV, + SCEV::FlagAnyWrap, Depth + 1); if (Ops.size() == 2) return OuterMul; if (AddOp < Idx) { Ops.erase(Ops.begin()+AddOp); @@ -2478,19 +2480,20 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, SmallVector MulOps(Mul->op_begin(), Mul->op_begin()+MulOp); MulOps.append(Mul->op_begin()+MulOp+1, Mul->op_end()); - InnerMul1 = getMulExpr(MulOps); + InnerMul1 = getMulExpr(MulOps, SCEV::FlagAnyWrap, Depth + 1); } const SCEV *InnerMul2 = OtherMul->getOperand(OMulOp == 0); if (OtherMul->getNumOperands() != 2) { SmallVector MulOps(OtherMul->op_begin(), OtherMul->op_begin()+OMulOp); MulOps.append(OtherMul->op_begin()+OMulOp+1, OtherMul->op_end()); - InnerMul2 = getMulExpr(MulOps); + InnerMul2 = getMulExpr(MulOps, SCEV::FlagAnyWrap, Depth + 1); } SmallVector TwoOps = {InnerMul1, InnerMul2}; const SCEV *InnerMulSum = getAddExpr(TwoOps, SCEV::FlagAnyWrap, Depth + 1); - const SCEV *OuterMul = getMulExpr(MulOpSCEV, InnerMulSum); + const SCEV *OuterMul = getMulExpr(MulOpSCEV, InnerMulSum, + SCEV::FlagAnyWrap, Depth + 1); if (Ops.size() == 2) return OuterMul; Ops.erase(Ops.begin()+Idx); Ops.erase(Ops.begin()+OtherMulIdx-1); @@ -2621,6 +2624,27 @@ ScalarEvolution::getOrCreateAddExpr(SmallVectorImpl &Ops, return S; } +const SCEV * +ScalarEvolution::getOrCreateMulExpr(SmallVectorImpl &Ops, + SCEV::NoWrapFlags Flags) { + FoldingSetNodeID ID; + ID.AddInteger(scMulExpr); + for (unsigned i = 0, e = Ops.size(); i != e; ++i) + ID.AddPointer(Ops[i]); + void *IP = nullptr; + SCEVMulExpr *S = + static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); + if (!S) { + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + S = new (SCEVAllocator) SCEVMulExpr(ID.Intern(SCEVAllocator), + O, Ops.size()); + UniqueSCEVs.InsertNode(S, IP); + } + S->setNoWrapFlags(Flags); + return S; +} + static uint64_t umul_ov(uint64_t i, uint64_t j, bool &Overflow) { uint64_t k = i*j; if (j > 1 && k / j != i) Overflow = true; @@ -2673,7 +2697,8 @@ static bool containsConstantSomewhere(const SCEV *StartExpr) { /// Get a canonical multiply expression, or something simpler if possible. const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, - SCEV::NoWrapFlags Flags) { + SCEV::NoWrapFlags Flags, + unsigned Depth) { assert(Flags == maskFlags(Flags, SCEV::FlagNUW | SCEV::FlagNSW) && "only nuw or nsw allowed"); assert(!Ops.empty() && "Cannot get empty mul!"); @@ -2690,6 +2715,10 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, Flags = StrengthenNoWrapFlags(this, scMulExpr, Ops, Flags); + // Limit recursion calls depth. + if (Depth > MaxArithDepth) + return getOrCreateMulExpr(Ops, Flags); + // If there are any constants, fold them together. unsigned Idx = 0; if (const SCEVConstant *LHSC = dyn_cast(Ops[0])) { @@ -2701,8 +2730,11 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // apply this transformation as well. if (Add->getNumOperands() == 2) if (containsConstantSomewhere(Add)) - return getAddExpr(getMulExpr(LHSC, Add->getOperand(0)), - getMulExpr(LHSC, Add->getOperand(1))); + return getAddExpr(getMulExpr(LHSC, Add->getOperand(0), + SCEV::FlagAnyWrap, Depth + 1), + getMulExpr(LHSC, Add->getOperand(1), + SCEV::FlagAnyWrap, Depth + 1), + SCEV::FlagAnyWrap, Depth + 1); ++Idx; while (const SCEVConstant *RHSC = dyn_cast(Ops[Idx])) { @@ -2730,17 +2762,19 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, SmallVector NewOps; bool AnyFolded = false; for (const SCEV *AddOp : Add->operands()) { - const SCEV *Mul = getMulExpr(Ops[0], AddOp); + const SCEV *Mul = getMulExpr(Ops[0], AddOp, SCEV::FlagAnyWrap, + Depth + 1); if (!isa(Mul)) AnyFolded = true; NewOps.push_back(Mul); } if (AnyFolded) - return getAddExpr(NewOps); + return getAddExpr(NewOps, SCEV::FlagAnyWrap, Depth + 1); } else if (const auto *AddRec = dyn_cast(Ops[1])) { // Negation preserves a recurrence's no self-wrap property. SmallVector Operands; for (const SCEV *AddRecOp : AddRec->operands()) - Operands.push_back(getMulExpr(Ops[0], AddRecOp)); + Operands.push_back(getMulExpr(Ops[0], AddRecOp, SCEV::FlagAnyWrap, + Depth + 1)); return getAddRecExpr(Operands, AddRec->getLoop(), AddRec->getNoWrapFlags(SCEV::FlagNW)); @@ -2762,18 +2796,18 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, while (const SCEVMulExpr *Mul = dyn_cast(Ops[Idx])) { if (Ops.size() > MulOpsInlineThreshold) break; - // If we have an mul, expand the mul operands onto the end of the operands - // list. + // If we have an mul, expand the mul operands onto the end of the + // operands list. Ops.erase(Ops.begin()+Idx); Ops.append(Mul->op_begin(), Mul->op_end()); DeletedMul = true; } - // If we deleted at least one mul, we added operands to the end of the list, - // and they are not necessarily sorted. Recurse to resort and resimplify - // any operands we just acquired. + // If we deleted at least one mul, we added operands to the end of the + // list, and they are not necessarily sorted. Recurse to resort and + // resimplify any operands we just acquired. if (DeletedMul) - return getMulExpr(Ops); + return getMulExpr(Ops, SCEV::FlagAnyWrap, Depth + 1); } // If there are any add recurrences in the operands list, see if any other @@ -2784,8 +2818,8 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // Scan over all recurrences, trying to fold loop invariants into them. for (; Idx < Ops.size() && isa(Ops[Idx]); ++Idx) { - // Scan all of the other operands to this mul and add them to the vector if - // they are loop invariant w.r.t. the recurrence. + // Scan all of the other operands to this mul and add them to the vector + // if they are loop invariant w.r.t. the recurrence. SmallVector LIOps; const SCEVAddRecExpr *AddRec = cast(Ops[Idx]); const Loop *AddRecLoop = AddRec->getLoop(); @@ -2801,9 +2835,10 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // NLI * LI * {Start,+,Step} --> NLI * {LI*Start,+,LI*Step} SmallVector NewOps; NewOps.reserve(AddRec->getNumOperands()); - const SCEV *Scale = getMulExpr(LIOps); + const SCEV *Scale = getMulExpr(LIOps, SCEV::FlagAnyWrap, Depth + 1); for (unsigned i = 0, e = AddRec->getNumOperands(); i != e; ++i) - NewOps.push_back(getMulExpr(Scale, AddRec->getOperand(i))); + NewOps.push_back(getMulExpr(Scale, AddRec->getOperand(i), + SCEV::FlagAnyWrap, Depth + 1)); // Build the new addrec. Propagate the NUW and NSW flags if both the // outer mul and the inner addrec are guaranteed to have no overflow. @@ -2822,12 +2857,12 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, Ops[i] = NewRec; break; } - return getMulExpr(Ops); + return getMulExpr(Ops, SCEV::FlagAnyWrap, Depth + 1); } - // Okay, if there weren't any loop invariants to be folded, check to see if - // there are multiple AddRec's with the same loop induction variable being - // multiplied together. If so, we can fold them. + // Okay, if there weren't any loop invariants to be folded, check to see + // if there are multiple AddRec's with the same loop induction variable + // being multiplied together. If so, we can fold them. // {A1,+,A2,+,...,+,An} * {B1,+,B2,+,...,+,Bn} // = {x=1 in [ sum y=x..2x [ sum z=max(y-x, y-n)..min(x,n) [ @@ -2869,7 +2904,9 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, const SCEV *CoeffTerm = getConstant(Ty, Coeff); const SCEV *Term1 = AddRec->getOperand(y-z); const SCEV *Term2 = OtherAddRec->getOperand(z); - Term = getAddExpr(Term, getMulExpr(CoeffTerm, Term1,Term2)); + Term = getAddExpr(Term, getMulExpr(CoeffTerm, Term1, Term2, + SCEV::FlagAnyWrap, Depth + 1), + SCEV::FlagAnyWrap, Depth + 1); } } AddRecOps.push_back(Term); @@ -2887,7 +2924,7 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, } } if (OpsModified) - return getMulExpr(Ops); + return getMulExpr(Ops, SCEV::FlagAnyWrap, Depth + 1); // Otherwise couldn't fold anything into this recurrence. Move onto the // next one. @@ -2895,22 +2932,7 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // Okay, it looks like we really DO need an mul expr. Check to see if we // already have one, otherwise create a new one. - FoldingSetNodeID ID; - ID.AddInteger(scMulExpr); - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - ID.AddPointer(Ops[i]); - void *IP = nullptr; - SCEVMulExpr *S = - static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); - if (!S) { - const SCEV **O = SCEVAllocator.Allocate(Ops.size()); - std::uninitialized_copy(Ops.begin(), Ops.end(), O); - S = new (SCEVAllocator) SCEVMulExpr(ID.Intern(SCEVAllocator), - O, Ops.size()); - UniqueSCEVs.InsertNode(S, IP); - } - S->setNoWrapFlags(Flags); - return S; + return getOrCreateMulExpr(Ops, Flags); } /// Get a canonical unsigned division expression, or something simpler if @@ -3713,7 +3735,8 @@ const SCEV *ScalarEvolution::getNotSCEV(const SCEV *V) { } const SCEV *ScalarEvolution::getMinusSCEV(const SCEV *LHS, const SCEV *RHS, - SCEV::NoWrapFlags Flags) { + SCEV::NoWrapFlags Flags, + unsigned Depth) { // Fast path: X - X --> 0. if (LHS == RHS) return getZero(LHS->getType()); @@ -3747,7 +3770,7 @@ const SCEV *ScalarEvolution::getMinusSCEV(const SCEV *LHS, const SCEV *RHS, // larger scope than intended. auto NegFlags = RHSIsNotMinSigned ? SCEV::FlagNSW : SCEV::FlagAnyWrap; - return getAddExpr(LHS, getNegativeSCEV(RHS, NegFlags), AddFlags); + return getAddExpr(LHS, getNegativeSCEV(RHS, NegFlags), AddFlags, Depth); } const SCEV * diff --git a/lib/Analysis/TargetTransformInfo.cpp b/lib/Analysis/TargetTransformInfo.cpp index 488cb332a0b0..92328f6e5efd 100644 --- a/lib/Analysis/TargetTransformInfo.cpp +++ b/lib/Analysis/TargetTransformInfo.cpp @@ -103,6 +103,10 @@ bool TargetTransformInfo::isSourceOfDivergence(const Value *V) const { return TTIImpl->isSourceOfDivergence(V); } +bool llvm::TargetTransformInfo::isAlwaysUniform(const Value *V) const { + return TTIImpl->isAlwaysUniform(V); +} + unsigned TargetTransformInfo::getFlatAddressSpace() const { return TTIImpl->getFlatAddressSpace(); } diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index c0181662fd9d..b065f427b06c 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -852,7 +852,8 @@ static void computeKnownBitsFromShiftOperator( Optional ShifterOperandIsNonZero; // Early exit if we can't constrain any well-defined shift amount. - if (!(ShiftAmtKZ & (BitWidth - 1)) && !(ShiftAmtKO & (BitWidth - 1))) { + if (!(ShiftAmtKZ & (PowerOf2Ceil(BitWidth) - 1)) && + !(ShiftAmtKO & (PowerOf2Ceil(BitWidth) - 1))) { ShifterOperandIsNonZero = isKnownNonZero(I->getOperand(1), Depth + 1, Q); if (!*ShifterOperandIsNonZero) @@ -3026,7 +3027,7 @@ bool llvm::getConstantDataArrayInfo(const Value *V, if (GV->getInitializer()->isNullValue()) { Type *GVTy = GV->getValueType(); if ( (ArrayTy = dyn_cast(GVTy)) ) { - // A zeroinitializer for the array; There is no ConstantDataArray. + // A zeroinitializer for the array; there is no ConstantDataArray. Array = nullptr; } else { const DataLayout &DL = GV->getParent()->getDataLayout(); diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 95987fac74e1..0629c2d326ae 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -733,13 +733,13 @@ class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase { std::vector makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile); - Error parseEntireSummary(); + Error parseEntireSummary(unsigned ID); Error parseModuleStringTable(); std::pair getValueInfoFromValueId(unsigned ValueId); - ModulePathStringTableTy::iterator addThisModulePath(); + ModuleSummaryIndex::ModuleInfo *addThisModule(); }; } // end anonymous namespace @@ -2608,6 +2608,16 @@ Error BitcodeReader::materializeMetadata() { if (Error Err = MDLoader->parseModuleMetadata()) return Err; } + + // Upgrade "Linker Options" module flag to "llvm.linker.options" module-level + // metadata. + if (Metadata *Val = TheModule->getModuleFlag("Linker Options")) { + NamedMDNode *LinkerOpts = + TheModule->getOrInsertNamedMetadata("llvm.linker.options"); + for (const MDOperand &MDOptions : cast(Val)->operands()) + LinkerOpts->addOperand(cast(MDOptions)); + } + DeferredMetadataInfo.clear(); return Error::success(); } @@ -4691,9 +4701,9 @@ ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader( : BitcodeReaderBase(std::move(Cursor), Strtab), TheIndex(TheIndex), ModulePath(ModulePath), ModuleId(ModuleId) {} -ModulePathStringTableTy::iterator -ModuleSummaryIndexBitcodeReader::addThisModulePath() { - return TheIndex.addModulePath(ModulePath, ModuleId); +ModuleSummaryIndex::ModuleInfo * +ModuleSummaryIndexBitcodeReader::addThisModule() { + return TheIndex.addModule(ModulePath, ModuleId); } std::pair @@ -4844,6 +4854,7 @@ Error ModuleSummaryIndexBitcodeReader::parseModule() { return error("Invalid record"); break; case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: + case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID: assert(!SeenValueSymbolTable && "Already read VST when parsing summary block?"); // We might not have a VST if there were no values in the @@ -4856,7 +4867,7 @@ Error ModuleSummaryIndexBitcodeReader::parseModule() { SeenValueSymbolTable = true; } SeenGlobalValSummary = true; - if (Error Err = parseEntireSummary()) + if (Error Err = parseEntireSummary(Entry.ID)) return Err; break; case bitc::MODULE_STRTAB_BLOCK_ID: @@ -4889,7 +4900,7 @@ Error ModuleSummaryIndexBitcodeReader::parseModule() { case bitc::MODULE_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); - auto &Hash = addThisModulePath()->second.second; + auto &Hash = addThisModule()->second.second; int Pos = 0; for (auto &Val : Record) { assert(!(Val >> 32) && "Unexpected high bits set"); @@ -4964,8 +4975,8 @@ std::vector ModuleSummaryIndexBitcodeReader::makeCallLi // Eagerly parse the entire summary block. This populates the GlobalValueSummary // objects in the index. -Error ModuleSummaryIndexBitcodeReader::parseEntireSummary() { - if (Stream.EnterSubBlock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID)) +Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { + if (Stream.EnterSubBlock(ID)) return error("Invalid record"); SmallVector Record; @@ -5070,7 +5081,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary() { PendingTypeTestAssumeConstVCalls.clear(); PendingTypeCheckedLoadConstVCalls.clear(); auto VIAndOriginalGUID = getValueInfoFromValueId(ValueID); - FS->setModulePath(addThisModulePath()->first()); + FS->setModulePath(addThisModule()->first()); FS->setOriginalName(VIAndOriginalGUID.second); TheIndex.addGlobalValueSummary(VIAndOriginalGUID.first, std::move(FS)); break; @@ -5090,7 +5101,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary() { // string table section in the per-module index, we create a single // module path string table entry with an empty (0) ID to take // ownership. - AS->setModulePath(addThisModulePath()->first()); + AS->setModulePath(addThisModule()->first()); GlobalValue::GUID AliaseeGUID = getValueInfoFromValueId(AliaseeID).first.getGUID(); @@ -5113,7 +5124,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary() { std::vector Refs = makeRefList(ArrayRef(Record).slice(2)); auto FS = llvm::make_unique(Flags, std::move(Refs)); - FS->setModulePath(addThisModulePath()->first()); + FS->setModulePath(addThisModule()->first()); auto GUID = getValueInfoFromValueId(ValueID); FS->setOriginalName(GUID.second); TheIndex.addGlobalValueSummary(GUID.first, std::move(FS)); @@ -5241,6 +5252,20 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary() { {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}}); break; } + case bitc::FS_CFI_FUNCTION_DEFS: { + std::set &CfiFunctionDefs = TheIndex.cfiFunctionDefs(); + for (unsigned I = 0; I != Record.size(); I += 2) + CfiFunctionDefs.insert( + {Strtab.data() + Record[I], static_cast(Record[I + 1])}); + break; + } + case bitc::FS_CFI_FUNCTION_DECLS: { + std::set &CfiFunctionDecls = TheIndex.cfiFunctionDecls(); + for (unsigned I = 0; I != Record.size(); I += 2) + CfiFunctionDecls.insert( + {Strtab.data() + Record[I], static_cast(Record[I + 1])}); + break; + } } } llvm_unreachable("Exit infinite loop"); @@ -5255,7 +5280,7 @@ Error ModuleSummaryIndexBitcodeReader::parseModuleStringTable() { SmallVector Record; SmallString<128> ModulePath; - ModulePathStringTableTy::iterator LastSeenModulePath; + ModuleSummaryIndex::ModuleInfo *LastSeenModule = nullptr; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); @@ -5282,8 +5307,8 @@ Error ModuleSummaryIndexBitcodeReader::parseModuleStringTable() { if (convertToString(Record, 1, ModulePath)) return error("Invalid record"); - LastSeenModulePath = TheIndex.addModulePath(ModulePath, ModuleId); - ModuleIdMap[ModuleId] = LastSeenModulePath->first(); + LastSeenModule = TheIndex.addModule(ModulePath, ModuleId); + ModuleIdMap[ModuleId] = LastSeenModule->first(); ModulePath.clear(); break; @@ -5292,15 +5317,15 @@ Error ModuleSummaryIndexBitcodeReader::parseModuleStringTable() { case bitc::MST_CODE_HASH: { if (Record.size() != 5) return error("Invalid hash length " + Twine(Record.size()).str()); - if (LastSeenModulePath == TheIndex.modulePaths().end()) + if (!LastSeenModule) return error("Invalid hash that does not follow a module path"); int Pos = 0; for (auto &Val : Record) { assert(!(Val >> 32) && "Unexpected high bits set"); - LastSeenModulePath->second.second[Pos++] = Val; + LastSeenModule->second.second[Pos++] = Val; } - // Reset LastSeenModulePath to avoid overriding the hash unexpectedly. - LastSeenModulePath = TheIndex.modulePaths().end(); + // Reset LastSeenModule to avoid overriding the hash unexpectedly. + LastSeenModule = nullptr; break; } } @@ -5507,13 +5532,16 @@ BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata, } // Parse the specified bitcode buffer and merge the index into CombinedIndex. +// We don't use ModuleIdentifier here because the client may need to control the +// module path used in the combined summary (e.g. when reading summaries for +// regular LTO modules). Error BitcodeModule::readSummary(ModuleSummaryIndex &CombinedIndex, - unsigned ModuleId) { + StringRef ModulePath, uint64_t ModuleId) { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, CombinedIndex, - ModuleIdentifier, ModuleId); + ModulePath, ModuleId); return R.parseModule(); } @@ -5533,7 +5561,7 @@ Expected> BitcodeModule::getSummary() { } // Check if the given bitcode buffer contains a global value summary block. -Expected BitcodeModule::hasSummary() { +Expected BitcodeModule::getLTOInfo() { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); @@ -5547,11 +5575,14 @@ Expected BitcodeModule::hasSummary() { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: - return false; + return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false}; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) - return true; + return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true}; + + if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) + return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true}; // Ignore other sub-blocks. if (Stream.SkipBlock()) @@ -5638,12 +5669,12 @@ Expected llvm::getBitcodeProducerString(MemoryBufferRef Buffer) { Error llvm::readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, - unsigned ModuleId) { + uint64_t ModuleId) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); - return BM->readSummary(CombinedIndex, ModuleId); + return BM->readSummary(CombinedIndex, BM->getModuleIdentifier(), ModuleId); } Expected> @@ -5655,12 +5686,12 @@ llvm::getModuleSummaryIndex(MemoryBufferRef Buffer) { return BM->getSummary(); } -Expected llvm::hasGlobalValueSummary(MemoryBufferRef Buffer) { +Expected llvm::getBitcodeLTOInfo(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); - return BM->hasSummary(); + return BM->getLTOInfo(); } Expected> diff --git a/lib/Bitcode/Reader/MetadataLoader.cpp b/lib/Bitcode/Reader/MetadataLoader.cpp index ee2fe2a0cc18..b1504a8034e0 100644 --- a/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/lib/Bitcode/Reader/MetadataLoader.cpp @@ -407,6 +407,11 @@ void PlaceholderQueue::flush(BitcodeReaderMetadataList &MetadataList) { } // anonynous namespace +static Error error(const Twine &Message) { + return make_error( + Message, make_error_code(BitcodeError::CorruptedBitcode)); +} + class MetadataLoader::MetadataLoaderImpl { BitcodeReaderMetadataList MetadataList; BitcodeReaderValueList &ValueList; @@ -533,6 +538,88 @@ class MetadataLoader::MetadataLoaderImpl { } } + /// Upgrade the expression from previous versions. + Error upgradeDIExpression(uint64_t FromVersion, + MutableArrayRef &Expr, + SmallVectorImpl &Buffer) { + auto N = Expr.size(); + switch (FromVersion) { + default: + return error("Invalid record"); + case 0: + if (N >= 3 && Expr[N - 3] == dwarf::DW_OP_bit_piece) + Expr[N - 3] = dwarf::DW_OP_LLVM_fragment; + LLVM_FALLTHROUGH; + case 1: + // Move DW_OP_deref to the end. + if (N && Expr[0] == dwarf::DW_OP_deref) { + auto End = Expr.end(); + if (Expr.size() >= 3 && + *std::prev(End, 3) == dwarf::DW_OP_LLVM_fragment) + End = std::prev(End, 3); + std::move(std::next(Expr.begin()), End, Expr.begin()); + *std::prev(End) = dwarf::DW_OP_deref; + } + NeedDeclareExpressionUpgrade = true; + LLVM_FALLTHROUGH; + case 2: { + // Change DW_OP_plus to DW_OP_plus_uconst. + // Change DW_OP_minus to DW_OP_uconst, DW_OP_minus + auto SubExpr = ArrayRef(Expr); + while (!SubExpr.empty()) { + // Skip past other operators with their operands + // for this version of the IR, obtained from + // from historic DIExpression::ExprOperand::getSize(). + size_t HistoricSize; + switch (SubExpr.front()) { + default: + HistoricSize = 1; + break; + case dwarf::DW_OP_constu: + case dwarf::DW_OP_minus: + case dwarf::DW_OP_plus: + HistoricSize = 2; + break; + case dwarf::DW_OP_LLVM_fragment: + HistoricSize = 3; + break; + } + + // If the expression is malformed, make sure we don't + // copy more elements than we should. + HistoricSize = std::min(SubExpr.size(), HistoricSize); + ArrayRef Args = SubExpr.slice(1, HistoricSize-1); + + switch (SubExpr.front()) { + case dwarf::DW_OP_plus: + Buffer.push_back(dwarf::DW_OP_plus_uconst); + Buffer.append(Args.begin(), Args.end()); + break; + case dwarf::DW_OP_minus: + Buffer.push_back(dwarf::DW_OP_constu); + Buffer.append(Args.begin(), Args.end()); + Buffer.push_back(dwarf::DW_OP_minus); + break; + default: + Buffer.push_back(*SubExpr.begin()); + Buffer.append(Args.begin(), Args.end()); + break; + } + + // Continue with remaining elements. + SubExpr = SubExpr.slice(HistoricSize); + } + Expr = MutableArrayRef(Buffer); + LLVM_FALLTHROUGH; + } + case 3: + // Up-to-date! + break; + } + + return Error::success(); + } + void upgradeDebugInfo() { upgradeCUSubprograms(); upgradeCUVariables(); @@ -590,11 +677,6 @@ class MetadataLoader::MetadataLoaderImpl { void upgradeDebugIntrinsics(Function &F) { upgradeDeclareExpressions(F); } }; -static Error error(const Twine &Message) { - return make_error( - Message, make_error_code(BitcodeError::CorruptedBitcode)); -} - Expected MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() { IndexCursor = Stream; @@ -1551,34 +1633,13 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( IsDistinct = Record[0] & 1; uint64_t Version = Record[0] >> 1; auto Elts = MutableArrayRef(Record).slice(1); - unsigned N = Elts.size(); - // Perform various upgrades. - switch (Version) { - case 0: - if (N >= 3 && Elts[N - 3] == dwarf::DW_OP_bit_piece) - Elts[N - 3] = dwarf::DW_OP_LLVM_fragment; - LLVM_FALLTHROUGH; - case 1: - // Move DW_OP_deref to the end. - if (N && Elts[0] == dwarf::DW_OP_deref) { - auto End = Elts.end(); - if (Elts.size() >= 3 && *std::prev(End, 3) == dwarf::DW_OP_LLVM_fragment) - End = std::prev(End, 3); - std::move(std::next(Elts.begin()), End, Elts.begin()); - *std::prev(End) = dwarf::DW_OP_deref; - } - NeedDeclareExpressionUpgrade = true; - LLVM_FALLTHROUGH; - case 2: - // Up-to-date! - break; - default: - return error("Invalid record"); - } + + SmallVector Buffer; + if (Error Err = upgradeDIExpression(Version, Elts, Buffer)) + return Err; MetadataList.assignValue( - GET_OR_DISTINCT(DIExpression, (Context, makeArrayRef(Record).slice(1))), - NextMetadataNo); + GET_OR_DISTINCT(DIExpression, (Context, Elts)), NextMetadataNo); NextMetadataNo++; break; } diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index d5879fec95cb..feeba31908ae 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -77,10 +77,13 @@ class BitcodeWriterBase { /// The stream created and owned by the client. BitstreamWriter &Stream; + StringTableBuilder &StrtabBuilder; + public: /// Constructs a BitcodeWriterBase object that writes to the provided /// \p Stream. - BitcodeWriterBase(BitstreamWriter &Stream) : Stream(Stream) {} + BitcodeWriterBase(BitstreamWriter &Stream, StringTableBuilder &StrtabBuilder) + : Stream(Stream), StrtabBuilder(StrtabBuilder) {} protected: void writeBitcodeHeader(); @@ -97,8 +100,6 @@ class ModuleBitcodeWriter : public BitcodeWriterBase { /// Pointer to the buffer allocated by caller for bitcode writing. const SmallVectorImpl &Buffer; - StringTableBuilder &StrtabBuilder; - /// The Module to write to bitcode. const Module &M; @@ -142,8 +143,8 @@ class ModuleBitcodeWriter : public BitcodeWriterBase { BitstreamWriter &Stream, bool ShouldPreserveUseListOrder, const ModuleSummaryIndex *Index, bool GenerateHash, ModuleHash *ModHash = nullptr) - : BitcodeWriterBase(Stream), Buffer(Buffer), StrtabBuilder(StrtabBuilder), - M(*M), VE(*M, ShouldPreserveUseListOrder), Index(Index), + : BitcodeWriterBase(Stream, StrtabBuilder), Buffer(Buffer), M(*M), + VE(*M, ShouldPreserveUseListOrder), Index(Index), GenerateHash(GenerateHash), ModHash(ModHash), BitcodeStartBit(Stream.GetCurrentBitNo()) { // Assign ValueIds to any callee values in the index that came from @@ -331,10 +332,11 @@ class IndexBitcodeWriter : public BitcodeWriterBase { /// Constructs a IndexBitcodeWriter object for the given combined index, /// writing to the provided \p Buffer. When writing a subset of the index /// for a distributed backend, provide a \p ModuleToSummariesForIndex map. - IndexBitcodeWriter(BitstreamWriter &Stream, const ModuleSummaryIndex &Index, + IndexBitcodeWriter(BitstreamWriter &Stream, StringTableBuilder &StrtabBuilder, + const ModuleSummaryIndex &Index, const std::map *ModuleToSummariesForIndex = nullptr) - : BitcodeWriterBase(Stream), Index(Index), + : BitcodeWriterBase(Stream, StrtabBuilder), Index(Index), ModuleToSummariesForIndex(ModuleToSummariesForIndex) { // Assign unique value ids to all summaries to be written, for use // in writing out the call graph edges. Save the mapping from GUID @@ -1663,7 +1665,7 @@ void ModuleBitcodeWriter::writeDIExpression(const DIExpression *N, SmallVectorImpl &Record, unsigned Abbrev) { Record.reserve(N->getElements().size() + 1); - const uint64_t Version = 2 << 1; + const uint64_t Version = 3 << 1; Record.push_back((uint64_t)N->isDistinct() | Version); Record.append(N->elements_begin(), N->elements_end()); @@ -3595,6 +3597,24 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() { MaybeEmitOriginalName(*AS); } + if (!Index.cfiFunctionDefs().empty()) { + for (auto &S : Index.cfiFunctionDefs()) { + NameVals.push_back(StrtabBuilder.add(S)); + NameVals.push_back(S.size()); + } + Stream.EmitRecord(bitc::FS_CFI_FUNCTION_DEFS, NameVals); + NameVals.clear(); + } + + if (!Index.cfiFunctionDecls().empty()) { + for (auto &S : Index.cfiFunctionDecls()) { + NameVals.push_back(StrtabBuilder.add(S)); + NameVals.push_back(S.size()); + } + Stream.EmitRecord(bitc::FS_CFI_FUNCTION_DECLS, NameVals); + NameVals.clear(); + } + Stream.ExitBlock(); } @@ -3829,6 +3849,14 @@ void BitcodeWriter::writeModule(const Module *M, ModuleWriter.write(); } +void BitcodeWriter::writeIndex( + const ModuleSummaryIndex *Index, + const std::map *ModuleToSummariesForIndex) { + IndexBitcodeWriter IndexWriter(*Stream, StrtabBuilder, *Index, + ModuleToSummariesForIndex); + IndexWriter.write(); +} + /// WriteBitcodeToFile - Write the specified module to the specified output /// stream. void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out, @@ -3880,11 +3908,9 @@ void llvm::WriteIndexToFile( SmallVector Buffer; Buffer.reserve(256 * 1024); - BitstreamWriter Stream(Buffer); - writeBitcodeHeader(Stream); - - IndexBitcodeWriter IndexWriter(Stream, Index, ModuleToSummariesForIndex); - IndexWriter.write(); + BitcodeWriter Writer(Buffer); + Writer.writeIndex(&Index, ModuleToSummariesForIndex); + Writer.writeStrtab(); Out.write((char *)&Buffer.front(), Buffer.size()); } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f7c09be15fb7..946067e6358f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -24,3 +24,4 @@ add_subdirectory(Fuzzer) add_subdirectory(Passes) add_subdirectory(ToolDrivers) add_subdirectory(XRay) +add_subdirectory(Testing) diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 407d5623d670..ad348d723bae 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1286,11 +1286,7 @@ bool AsmPrinter::doFinalization(Module &M) { const TargetLoweringObjectFile &TLOF = getObjFileLowering(); - // Emit module flags. - SmallVector ModuleFlags; - M.getModuleFlagsMetadata(ModuleFlags); - if (!ModuleFlags.empty()) - TLOF.emitModuleFlags(*OutStreamer, ModuleFlags, TM); + TLOF.emitModuleMetadata(*OutStreamer, M, TM); if (TM.getTargetTriple().isOSBinFormatELF()) { MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo(); diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 04073b3aed68..dc39d1e6cb52 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -552,7 +552,7 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, int Offset = TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg); DwarfExpr.addFragmentOffset(Expr); SmallVector Ops; - Ops.push_back(dwarf::DW_OP_plus); + Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(Offset); Ops.append(Expr->elements_begin(), Expr->elements_end()); DIExpressionCursor Cursor(Ops); @@ -821,7 +821,7 @@ void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute, SmallVector Ops; if (Location.isIndirect() && Location.getOffset()) { - Ops.push_back(dwarf::DW_OP_plus); + Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(Location.getOffset()); } DIExpressionCursor Cursor(Ops); @@ -850,7 +850,7 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die, SmallVector Ops; if (Location.isIndirect() && Location.getOffset()) { - Ops.push_back(dwarf::DW_OP_plus); + Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(Location.getOffset()); } Ops.append(DIExpr->elements_begin(), DIExpr->elements_end()); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index e3fd21a1fd70..75eb355bfb54 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1511,7 +1511,7 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, DwarfExpr.setMemoryLocationKind(); SmallVector Ops; if (Location.isIndirect() && Location.getOffset()) { - Ops.push_back(dwarf::DW_OP_plus); + Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(Location.getOffset()); } Ops.append(DIExpr->elements_begin(), DIExpr->elements_end()); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index ebfba4cfc275..5dfe06c64ec2 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -134,6 +134,13 @@ class DbgVariable { assert(!FrameIndexExprs.empty() && "Expected an MMI entry"); assert(!V.FrameIndexExprs.empty() && "Expected an MMI entry"); + if (FrameIndexExprs.size()) { + auto *Expr = FrameIndexExprs.back().Expr; + // Get rid of duplicate non-fragment entries. More than one non-fragment + // dbg.declare makes no sense so ignore all but the first. + if (!Expr || !Expr->isFragment()) + return; + } FrameIndexExprs.append(V.FrameIndexExprs.begin(), V.FrameIndexExprs.end()); assert(all_of(FrameIndexExprs, [](FrameIndexExpr &FIE) { diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index d96479f43433..fe38ee805682 100644 --- a/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -248,15 +248,25 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI, assert(Reg.Size == 0 && "subregister has same size as superregister"); // Pattern-match combinations for which more efficient representations exist. - // [Reg, Offset, DW_OP_plus] --> [DW_OP_breg, Offset]. - // [Reg, Offset, DW_OP_minus] --> [DW_OP_breg, -Offset]. - // If Reg is a subregister we need to mask it out before subtracting. - if (Op && ((Op->getOp() == dwarf::DW_OP_plus) || - (Op->getOp() == dwarf::DW_OP_minus && !SubRegisterSizeInBits))) { - int Offset = Op->getArg(0); - SignedOffset = (Op->getOp() == dwarf::DW_OP_plus) ? Offset : -Offset; + // [Reg, DW_OP_plus_uconst, Offset] --> [DW_OP_breg, Offset]. + if (Op && (Op->getOp() == dwarf::DW_OP_plus_uconst)) { + SignedOffset = Op->getArg(0); ExprCursor.take(); } + + // [Reg, DW_OP_constu, Offset, DW_OP_plus] --> [DW_OP_breg, Offset] + // [Reg, DW_OP_constu, Offset, DW_OP_minus] --> [DW_OP_breg,-Offset] + // If Reg is a subregister we need to mask it out before subtracting. + if (Op && Op->getOp() == dwarf::DW_OP_constu) { + auto N = ExprCursor.peekNext(); + if (N && (N->getOp() == dwarf::DW_OP_plus || + (N->getOp() == dwarf::DW_OP_minus && !SubRegisterSizeInBits))) { + int Offset = Op->getArg(0); + SignedOffset = (N->getOp() == dwarf::DW_OP_minus) ? -Offset : Offset; + ExprCursor.consume(2); + } + } + if (FBReg) addFBReg(SignedOffset); else @@ -320,17 +330,14 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, LocationKind = Unknown; return; } - case dwarf::DW_OP_plus: + case dwarf::DW_OP_plus_uconst: assert(LocationKind != Register); emitOp(dwarf::DW_OP_plus_uconst); emitUnsigned(Op->getArg(0)); break; + case dwarf::DW_OP_plus: case dwarf::DW_OP_minus: - assert(LocationKind != Register); - // There is no DW_OP_minus_uconst. - emitOp(dwarf::DW_OP_constu); - emitUnsigned(Op->getArg(0)); - emitOp(dwarf::DW_OP_minus); + emitOp(Op->getOp()); break; case dwarf::DW_OP_deref: { assert(LocationKind != Register); diff --git a/lib/CodeGen/AsmPrinter/DwarfExpression.h b/lib/CodeGen/AsmPrinter/DwarfExpression.h index de8613200067..728f8ad9225b 100644 --- a/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -42,6 +42,9 @@ class DIExpressionCursor { DIExpressionCursor(ArrayRef Expr) : Start(Expr.begin()), End(Expr.end()) {} + DIExpressionCursor(const DIExpressionCursor &C) + : Start(C.Start), End(C.End) {} + /// Consume one operation. Optional take() { if (Start == End) diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 7f7d3e650e02..708f5f7536ff 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -475,7 +475,7 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die, SmallVector Ops; if (Location.isIndirect() && Location.getOffset()) { - Ops.push_back(dwarf::DW_OP_plus); + Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(Location.getOffset()); } // If we started with a pointer to the __Block_byref... struct, then @@ -487,7 +487,7 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die, // DW_OP_plus_uconst ForwardingFieldOffset. Note there's no point in // adding the offset if it's 0. if (forwardingFieldOffset > 0) { - Ops.push_back(dwarf::DW_OP_plus); + Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(forwardingFieldOffset); } @@ -499,7 +499,7 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die, // for the variable's field to get to the location of the actual variable: // DW_OP_plus_uconst varFieldOffset. Again, don't add if it's 0. if (varFieldOffset > 0) { - Ops.push_back(dwarf::DW_OP_plus); + Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(varFieldOffset); } diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp index c2037cb7f1ae..37e176099ea7 100644 --- a/lib/CodeGen/CodeGenPrepare.cpp +++ b/lib/CodeGen/CodeGenPrepare.cpp @@ -134,7 +134,7 @@ static cl::opt DisablePreheaderProtect( cl::desc("Disable protection against removing loop preheaders")); static cl::opt ProfileGuidedSectionPrefix( - "profile-guided-section-prefix", cl::Hidden, cl::init(true), + "profile-guided-section-prefix", cl::Hidden, cl::init(true), cl::ZeroOrMore, cl::desc("Use profile info to add section prefix for hot/cold functions")); static cl::opt FreqRatioToSkipMerge( diff --git a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index ef5818dabe23..1d0d3dffa4c5 100644 --- a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -82,6 +82,12 @@ static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) { case TargetOpcode::G_UDIV: assert(Size == 32 && "Unsupported size"); return RTLIB::UDIV_I32; + case TargetOpcode::G_SREM: + assert(Size == 32 && "Unsupported size"); + return RTLIB::SREM_I32; + case TargetOpcode::G_UREM: + assert(Size == 32 && "Unsupported size"); + return RTLIB::UREM_I32; case TargetOpcode::G_FADD: assert((Size == 32 || Size == 64) && "Unsupported size"); return Size == 64 ? RTLIB::ADD_F64 : RTLIB::ADD_F32; @@ -93,43 +99,57 @@ static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) { llvm_unreachable("Unknown libcall function"); } -static LegalizerHelper::LegalizeResult -simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, - Type *OpType) { +LegalizerHelper::LegalizeResult llvm::replaceWithLibcall( + MachineInstr &MI, MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall, + const CallLowering::ArgInfo &Result, ArrayRef Args) { auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering(); auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); - auto Libcall = getRTLibDesc(MI.getOpcode(), Size); const char *Name = TLI.getLibcallName(Libcall); MIRBuilder.getMF().getFrameInfo().setHasCalls(true); - CLI.lowerCall(MIRBuilder, TLI.getLibcallCallingConv(Libcall), - MachineOperand::CreateES(Name), - {MI.getOperand(0).getReg(), OpType}, - {{MI.getOperand(1).getReg(), OpType}, - {MI.getOperand(2).getReg(), OpType}}); + MIRBuilder.setInstr(MI); + if (!CLI.lowerCall(MIRBuilder, TLI.getLibcallCallingConv(Libcall), + MachineOperand::CreateES(Name), Result, Args)) + return LegalizerHelper::UnableToLegalize; + + // We're about to remove MI, so move the insert point after it. + MIRBuilder.setInsertPt(MIRBuilder.getMBB(), + std::next(MIRBuilder.getInsertPt())); + MI.eraseFromParent(); return LegalizerHelper::Legalized; } +static LegalizerHelper::LegalizeResult +simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, + Type *OpType) { + auto Libcall = getRTLibDesc(MI.getOpcode(), Size); + return replaceWithLibcall(MI, MIRBuilder, Libcall, + {MI.getOperand(0).getReg(), OpType}, + {{MI.getOperand(1).getReg(), OpType}, + {MI.getOperand(2).getReg(), OpType}}); +} + LegalizerHelper::LegalizeResult LegalizerHelper::libcall(MachineInstr &MI) { - LLT Ty = MRI.getType(MI.getOperand(0).getReg()); - unsigned Size = Ty.getSizeInBits(); + LLT LLTy = MRI.getType(MI.getOperand(0).getReg()); + unsigned Size = LLTy.getSizeInBits(); auto &Ctx = MIRBuilder.getMF().getFunction()->getContext(); - MIRBuilder.setInstr(MI); switch (MI.getOpcode()) { default: return UnableToLegalize; case TargetOpcode::G_SDIV: - case TargetOpcode::G_UDIV: { - Type *Ty = Type::getInt32Ty(Ctx); - return simpleLibcall(MI, MIRBuilder, Size, Ty); + case TargetOpcode::G_UDIV: + case TargetOpcode::G_SREM: + case TargetOpcode::G_UREM: { + Type *HLTy = Type::getInt32Ty(Ctx); + return simpleLibcall(MI, MIRBuilder, Size, HLTy); } case TargetOpcode::G_FADD: case TargetOpcode::G_FPOW: case TargetOpcode::G_FREM: { - Type *Ty = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx); - return simpleLibcall(MI, MIRBuilder, Size, Ty); + Type *HLTy = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx); + return simpleLibcall(MI, MIRBuilder, Size, HLTy); } } } @@ -237,17 +257,18 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, unsigned NarrowSize = NarrowTy.getSizeInBits(); int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize; - LLT NarrowPtrTy = LLT::pointer( - MRI.getType(MI.getOperand(1).getReg()).getAddressSpace(), NarrowSize); + LLT OffsetTy = LLT::scalar( + MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits()); SmallVector DstRegs; for (int i = 0; i < NumParts; ++i) { unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); - unsigned SrcReg = MRI.createGenericVirtualRegister(NarrowPtrTy); - unsigned Offset = MRI.createGenericVirtualRegister(LLT::scalar(64)); + unsigned SrcReg = 0; + unsigned Adjustment = i * NarrowSize / 8; + + MIRBuilder.materializeGEP(SrcReg, MI.getOperand(1).getReg(), OffsetTy, + Adjustment); - MIRBuilder.buildConstant(Offset, i * NarrowSize / 8); - MIRBuilder.buildGEP(SrcReg, MI.getOperand(1).getReg(), Offset); // TODO: This is conservatively correct, but we probably want to split the // memory operands in the future. MIRBuilder.buildLoad(DstReg, SrcReg, **MI.memoperands_begin()); @@ -263,17 +284,19 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, unsigned NarrowSize = NarrowTy.getSizeInBits(); int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize; - LLT NarrowPtrTy = LLT::pointer( - MRI.getType(MI.getOperand(1).getReg()).getAddressSpace(), NarrowSize); + LLT OffsetTy = LLT::scalar( + MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits()); SmallVector SrcRegs; extractParts(MI.getOperand(0).getReg(), NarrowTy, NumParts, SrcRegs); for (int i = 0; i < NumParts; ++i) { - unsigned DstReg = MRI.createGenericVirtualRegister(NarrowPtrTy); - unsigned Offset = MRI.createGenericVirtualRegister(LLT::scalar(64)); - MIRBuilder.buildConstant(Offset, i * NarrowSize / 8); - MIRBuilder.buildGEP(DstReg, MI.getOperand(1).getReg(), Offset); + unsigned DstReg = 0; + unsigned Adjustment = i * NarrowSize / 8; + + MIRBuilder.materializeGEP(DstReg, MI.getOperand(1).getReg(), OffsetTy, + Adjustment); + // TODO: This is conservatively correct, but we probably want to split the // memory operands in the future. MIRBuilder.buildStore(SrcRegs[i], DstReg, **MI.memoperands_begin()); diff --git a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 54ef7e5c5a1b..79d312fb52ca 100644 --- a/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -191,6 +191,24 @@ MachineInstrBuilder MachineIRBuilder::buildGEP(unsigned Res, unsigned Op0, .addUse(Op1); } +Optional +MachineIRBuilder::materializeGEP(unsigned &Res, unsigned Op0, + const LLT &ValueTy, uint64_t Value) { + assert(Res == 0 && "Res is a result argument"); + assert(ValueTy.isScalar() && "invalid offset type"); + + if (Value == 0) { + Res = Op0; + return None; + } + + Res = MRI->createGenericVirtualRegister(MRI->getType(Op0)); + unsigned TmpReg = MRI->createGenericVirtualRegister(ValueTy); + + buildConstant(TmpReg, Value); + return buildGEP(Res, Op0, TmpReg); +} + MachineInstrBuilder MachineIRBuilder::buildPtrMask(unsigned Res, unsigned Op0, uint32_t NumBits) { assert(MRI->getType(Res).isPointer() && diff --git a/lib/CodeGen/MachineBlockPlacement.cpp b/lib/CodeGen/MachineBlockPlacement.cpp index fc52b0da0d61..2d4b95974cc6 100644 --- a/lib/CodeGen/MachineBlockPlacement.cpp +++ b/lib/CodeGen/MachineBlockPlacement.cpp @@ -594,8 +594,8 @@ BranchProbability MachineBlockPlacement::collectViableSuccessors( // Assume A->C is very hot (>90%), and C->D has a 50% probability, then after // A->C is chosen as a fall-through, D won't be selected as a successor of C // due to CFG constraint (the probability of C->D is not greater than - // HotProb to break top-order). If we exclude E that is not in BlockFilter - // when calculating the probability of C->D, D will be selected and we + // HotProb to break topo-order). If we exclude E that is not in BlockFilter + // when calculating the probability of C->D, D will be selected and we // will get A C D B as the layout of this loop. auto AdjustedSumProb = BranchProbability::getOne(); for (MachineBasicBlock *Succ : BB->successors()) { @@ -1156,7 +1156,7 @@ void MachineBlockPlacement::precomputeTriangleChains() { continue; // Now we have an interesting triangle. Insert it if it's not part of an - // existing chain + // existing chain. // Note: This cannot be replaced with a call insert() or emplace() because // the find key is BB, but the insert/emplace key is PDom. auto Found = TriangleChainMap.find(&BB); @@ -1298,9 +1298,9 @@ bool MachineBlockPlacement::hasBetterLayoutPredecessor( // | | | | // ---BB | | BB // | | | | - // | pred-- | Succ-- + // | Pred-- | Succ-- // | | | | - // ---succ ---pred-- + // ---Succ ---Pred-- // // cost = freq(S->Pred) + freq(BB->Succ) cost = 2 * freq (S->Pred) // = freq(S->Pred) + freq(S->BB) diff --git a/lib/CodeGen/MachineLICM.cpp b/lib/CodeGen/MachineLICM.cpp index 52d5819f8dbc..c7113f1fdc47 100644 --- a/lib/CodeGen/MachineLICM.cpp +++ b/lib/CodeGen/MachineLICM.cpp @@ -895,8 +895,11 @@ bool MachineLICM::IsLoopInvariantInst(MachineInstr &I) { // If the physreg has no defs anywhere, it's just an ambient register // and we can freely move its uses. Alternatively, if it's allocatable, // it could get allocated to something with a def during allocation. - if (!MRI->isConstantPhysReg(Reg)) - return false; + // However, if the physreg is known to always be caller saved/restored + // then this use is safe to hoist. + if (!MRI->isConstantPhysReg(Reg) && + !(TRI->isCallerPreservedPhysReg(Reg, *I.getParent()->getParent()))) + return false; // Otherwise it's safe to move. continue; } else if (!MO.isDead()) { diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index a0967f574006..2d4422d94a17 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -2217,7 +2217,8 @@ SDValue DAGCombiner::visitADDCARRYLike(SDValue N0, SDValue N1, SDValue CarryIn, SDNode *N) { // Iff the flag result is dead: // (addcarry (add|uaddo X, Y), 0, Carry) -> (addcarry X, Y, Carry) - if ((N0.getOpcode() == ISD::ADD || N0.getOpcode() == ISD::UADDO) && + if ((N0.getOpcode() == ISD::ADD || + (N0.getOpcode() == ISD::UADDO && N0.getResNo() == 0)) && isNullConstant(N1) && !N->hasAnyUseOfValue(1)) return DAG.getNode(ISD::ADDCARRY, SDLoc(N), N->getVTList(), N0.getOperand(0), N0.getOperand(1), CarryIn); @@ -12460,10 +12461,27 @@ bool DAGCombiner::MergeStoresOfConstantsOrVecElts( LSBaseSDNode *FirstInChain = StoreNodes[0].MemNode; SDValue NewChain = getMergeStoreChains(StoreNodes, NumStores); - SDValue NewStore = DAG.getStore(NewChain, DL, StoredVal, - FirstInChain->getBasePtr(), - FirstInChain->getPointerInfo(), - FirstInChain->getAlignment()); + + // make sure we use trunc store if it's necessary to be legal. + SDValue NewStore; + if (TLI.isTypeLegal(StoredVal.getValueType())) { + NewStore = DAG.getStore(NewChain, DL, StoredVal, FirstInChain->getBasePtr(), + FirstInChain->getPointerInfo(), + FirstInChain->getAlignment()); + } else { // Must be realized as a trunc store + EVT LegalizedStoredValueTy = + TLI.getTypeToTransformTo(*DAG.getContext(), StoredVal.getValueType()); + unsigned LegalizedStoreSize = LegalizedStoredValueTy.getSizeInBits(); + ConstantSDNode *C = cast(StoredVal); + SDValue ExtendedStoreVal = + DAG.getConstant(C->getAPIntValue().zextOrTrunc(LegalizedStoreSize), DL, + LegalizedStoredValueTy); + NewStore = DAG.getTruncStore( + NewChain, DL, ExtendedStoreVal, FirstInChain->getBasePtr(), + FirstInChain->getPointerInfo(), StoredVal.getValueType() /*TVT*/, + FirstInChain->getAlignment(), + FirstInChain->getMemOperand()->getFlags()); + } // Replace all merged stores with the new store. for (unsigned i = 0; i < NumStores; ++i) @@ -12731,8 +12749,7 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { IsFast) { LastLegalType = i + 1; // Or check whether a truncstore is legal. - } else if (!LegalTypes && - TLI.getTypeAction(Context, StoreTy) == + } else if (TLI.getTypeAction(Context, StoreTy) == TargetLowering::TypePromoteInteger) { EVT LegalizedStoredValueTy = TLI.getTypeToTransformTo(Context, StoredVal.getValueType()); @@ -12947,8 +12964,7 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { else if (TLI.getTypeAction(Context, StoreTy) == TargetLowering::TypePromoteInteger) { EVT LegalizedStoredValueTy = TLI.getTypeToTransformTo(Context, StoreTy); - if (!LegalTypes && - TLI.isTruncStoreLegal(LegalizedStoredValueTy, StoreTy) && + if (TLI.isTruncStoreLegal(LegalizedStoredValueTy, StoreTy) && TLI.canMergeStoresTo(FirstStoreAS, LegalizedStoredValueTy) && TLI.isLoadExtLegal(ISD::ZEXTLOAD, LegalizedStoredValueTy, StoreTy) && @@ -12958,8 +12974,8 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { TLI.allowsMemoryAccess(Context, DL, LegalizedStoredValueTy, FirstStoreAS, FirstStoreAlign, &IsFastSt) && IsFastSt && - TLI.allowsMemoryAccess(Context, DL, LegalizedStoredValueTy, - FirstLoadAS, FirstLoadAlign, &IsFastLd) && + TLI.allowsMemoryAccess(Context, DL, StoreTy, FirstLoadAS, + FirstLoadAlign, &IsFastLd) && IsFastLd) LastLegalIntegerType = i + 1; } @@ -13189,10 +13205,6 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { Chain = ST->getChain(); } - // Try transforming N to an indexed store. - if (CombineToPreIndexedLoadStore(N) || CombineToPostIndexedLoadStore(N)) - return SDValue(N, 0); - // FIXME: is there such a thing as a truncating indexed store? if (ST->isTruncatingStore() && ST->isUnindexed() && Value.getValueType().isInteger()) { @@ -13287,6 +13299,10 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { } } + // Try transforming N to an indexed store. + if (CombineToPreIndexedLoadStore(N) || CombineToPostIndexedLoadStore(N)) + return SDValue(N, 0); + // Turn 'store float 1.0, Ptr' -> 'store int 0x12345678, Ptr' // // Make sure to do this only after attempting to merge stores in order to @@ -14692,21 +14708,7 @@ static SDValue narrowExtractedVectorLoad(SDNode *Extract, SelectionDAG &DAG) { MachineMemOperand *MMO = MF.getMachineMemOperand(Ld->getMemOperand(), Offset, VT.getStoreSize()); SDValue NewLd = DAG.getLoad(VT, DL, Ld->getChain(), NewAddr, MMO); - - // The new load must have the same position as the old load in terms of memory - // dependency. Create a TokenFactor for Ld and NewLd and update uses of Ld's - // output chain to use that TokenFactor. - // TODO: This code is based on a similar sequence in x86 lowering. It should - // be moved to a helper function, so it can be shared and reused. - if (Ld->hasAnyUseOfValue(1)) { - SDValue OldChain = SDValue(Ld, 1); - SDValue NewChain = SDValue(NewLd.getNode(), 1); - SDValue TokenFactor = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, - OldChain, NewChain); - DAG.ReplaceAllUsesOfValueWith(OldChain, TokenFactor); - DAG.UpdateNodeOperands(TokenFactor.getNode(), OldChain, NewChain); - } - + DAG.makeEquivalentMemoryOrdering(Ld, NewLd); return NewLd; } diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 606b8952f3c1..b736037d71dd 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -523,3 +523,29 @@ void FunctionLoweringInfo::setCurrentSwiftErrorVReg( const MachineBasicBlock *MBB, const Value *Val, unsigned VReg) { SwiftErrorVRegDefMap[std::make_pair(MBB, Val)] = VReg; } + +std::pair +FunctionLoweringInfo::getOrCreateSwiftErrorVRegDefAt(const Instruction *I) { + auto Key = PointerIntPair(I, true); + auto It = SwiftErrorVRegDefUses.find(Key); + if (It == SwiftErrorVRegDefUses.end()) { + auto &DL = MF->getDataLayout(); + const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL)); + unsigned VReg = MF->getRegInfo().createVirtualRegister(RC); + SwiftErrorVRegDefUses[Key] = VReg; + return std::make_pair(VReg, true); + } + return std::make_pair(It->second, false); +} + +std::pair +FunctionLoweringInfo::getOrCreateSwiftErrorVRegUseAt(const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) { + auto Key = PointerIntPair(I, false); + auto It = SwiftErrorVRegDefUses.find(Key); + if (It == SwiftErrorVRegDefUses.end()) { + unsigned VReg = getOrCreateSwiftErrorVReg(MBB, Val); + SwiftErrorVRegDefUses[Key] = VReg; + return std::make_pair(VReg, true); + } + return std::make_pair(It->second, false); +} diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index e54eaa3b81be..15e87b7af18d 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -2192,19 +2192,6 @@ static bool isSinCosLibcallAvailable(SDNode *Node, const TargetLowering &TLI) { return TLI.getLibcallName(LC) != nullptr; } -/// Return true if sincos libcall is available and can be used to combine sin -/// and cos. -static bool canCombineSinCosLibcall(SDNode *Node, const TargetLowering &TLI, - const TargetMachine &TM) { - if (!isSinCosLibcallAvailable(Node, TLI)) - return false; - // GNU sin/cos functions set errno while sincos does not. Therefore - // combining sin and cos is only safe if unsafe-fpmath is enabled. - if (TM.getTargetTriple().isGNUEnvironment() && !TM.Options.UnsafeFPMath) - return false; - return true; -} - /// Only issue sincos libcall if both sin and cos are needed. static bool useSinCos(SDNode *Node) { unsigned OtherOpcode = Node->getOpcode() == ISD::FSIN @@ -3247,7 +3234,7 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) { // Turn fsin / fcos into ISD::FSINCOS node if there are a pair of fsin / // fcos which share the same operand and both are used. if ((TLI.isOperationLegalOrCustom(ISD::FSINCOS, VT) || - canCombineSinCosLibcall(Node, TLI, TM)) + isSinCosLibcallAvailable(Node, TLI)) && useSinCos(Node)) { SDVTList VTs = DAG.getVTList(VT, VT); Tmp1 = DAG.getNode(ISD::FSINCOS, dl, VTs, Node->getOperand(0)); diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index 0d5e07ded25c..a3ba52a148ee 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1828,10 +1828,11 @@ void DAGTypeLegalizer::ExpandIntRes_ADDSUB(SDNode *N, TLI.isOperationLegalOrCustom(N->getOpcode() == ISD::ADD ? ISD::UADDO : ISD::USUBO, TLI.getTypeToExpandTo(*DAG.getContext(), NVT)); + TargetLoweringBase::BooleanContent BoolType = TLI.getBooleanContents(NVT); + if (hasOVF) { EVT OvfVT = getSetCCResultType(NVT); SDVTList VTList = DAG.getVTList(NVT, OvfVT); - TargetLoweringBase::BooleanContent BoolType = TLI.getBooleanContents(NVT); int RevOpc; if (N->getOpcode() == ISD::ADD) { RevOpc = ISD::SUB; @@ -1864,6 +1865,13 @@ void DAGTypeLegalizer::ExpandIntRes_ADDSUB(SDNode *N, Hi = DAG.getNode(ISD::ADD, dl, NVT, makeArrayRef(HiOps, 2)); SDValue Cmp1 = DAG.getSetCC(dl, getSetCCResultType(NVT), Lo, LoOps[0], ISD::SETULT); + + if (BoolType == TargetLoweringBase::ZeroOrOneBooleanContent) { + SDValue Carry = DAG.getZExtOrTrunc(Cmp1, dl, NVT); + Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, Carry); + return; + } + SDValue Carry1 = DAG.getSelect(dl, NVT, Cmp1, DAG.getConstant(1, dl, NVT), DAG.getConstant(0, dl, NVT)); @@ -1878,9 +1886,14 @@ void DAGTypeLegalizer::ExpandIntRes_ADDSUB(SDNode *N, SDValue Cmp = DAG.getSetCC(dl, getSetCCResultType(LoOps[0].getValueType()), LoOps[0], LoOps[1], ISD::SETULT); - SDValue Borrow = DAG.getSelect(dl, NVT, Cmp, - DAG.getConstant(1, dl, NVT), - DAG.getConstant(0, dl, NVT)); + + SDValue Borrow; + if (BoolType == TargetLoweringBase::ZeroOrOneBooleanContent) + Borrow = DAG.getZExtOrTrunc(Cmp, dl, NVT); + else + Borrow = DAG.getSelect(dl, NVT, Cmp, DAG.getConstant(1, dl, NVT), + DAG.getConstant(0, dl, NVT)); + Hi = DAG.getNode(ISD::SUB, dl, NVT, Hi, Borrow); } } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index dff8bd2ad37d..7abdc76cb004 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -7244,6 +7244,24 @@ void SelectionDAG::TransferDbgValues(SDValue From, SDValue To) { AddDbgValue(I, ToNode, false); } +void SelectionDAG::makeEquivalentMemoryOrdering(LoadSDNode *OldLoad, + SDValue NewMemOp) { + assert(isa(NewMemOp.getNode()) && "Expected a memop node"); + if (!OldLoad->hasAnyUseOfValue(1)) + return; + + // The new memory operation must have the same position as the old load in + // terms of memory dependency. Create a TokenFactor for the old load and new + // memory operation and update uses of the old load's output chain to use that + // TokenFactor. + SDValue OldChain = SDValue(OldLoad, 1); + SDValue NewChain = SDValue(NewMemOp.getNode(), 1); + SDValue TokenFactor = + getNode(ISD::TokenFactor, SDLoc(OldLoad), MVT::Other, OldChain, NewChain); + ReplaceAllUsesOfValueWith(OldChain, TokenFactor); + UpdateNodeOperands(TokenFactor.getNode(), OldChain, NewChain); +} + //===----------------------------------------------------------------------===// // SDNode Class //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index d34ac40b9496..f9f431db55be 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1496,9 +1496,10 @@ void SelectionDAGBuilder::visitRet(const ReturnInst &I) { true /*isfixed*/, 1 /*origidx*/, 0 /*partOffs*/)); // Create SDNode for the swifterror virtual register. - OutVals.push_back(DAG.getRegister(FuncInfo.getOrCreateSwiftErrorVReg( - FuncInfo.MBB, FuncInfo.SwiftErrorArg), - EVT(TLI.getPointerTy(DL)))); + OutVals.push_back( + DAG.getRegister(FuncInfo.getOrCreateSwiftErrorVRegUseAt( + &I, FuncInfo.MBB, FuncInfo.SwiftErrorArg).first, + EVT(TLI.getPointerTy(DL)))); } bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg(); @@ -3581,8 +3582,7 @@ void SelectionDAGBuilder::visitLoad(const LoadInst &I) { } void SelectionDAGBuilder::visitStoreToSwiftError(const StoreInst &I) { - const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - assert(TLI.supportSwiftError() && + assert(DAG.getTargetLoweringInfo().supportSwiftError() && "call visitStoreToSwiftError when backend supports swifterror"); SmallVector ValueVTs; @@ -3595,15 +3595,15 @@ void SelectionDAGBuilder::visitStoreToSwiftError(const StoreInst &I) { SDValue Src = getValue(SrcV); // Create a virtual register, then update the virtual register. - auto &DL = DAG.getDataLayout(); - const TargetRegisterClass *RC = TLI.getRegClassFor(TLI.getPointerTy(DL)); - unsigned VReg = FuncInfo.MF->getRegInfo().createVirtualRegister(RC); + unsigned VReg; bool CreatedVReg; + std::tie(VReg, CreatedVReg) = FuncInfo.getOrCreateSwiftErrorVRegDefAt(&I); // Chain, DL, Reg, N or Chain, DL, Reg, N, Glue // Chain can be getRoot or getControlRoot. SDValue CopyNode = DAG.getCopyToReg(getRoot(), getCurSDLoc(), VReg, SDValue(Src.getNode(), Src.getResNo())); DAG.setRoot(CopyNode); - FuncInfo.setCurrentSwiftErrorVReg(FuncInfo.MBB, I.getOperand(1), VReg); + if (CreatedVReg) + FuncInfo.setCurrentSwiftErrorVReg(FuncInfo.MBB, I.getOperand(1), VReg); } void SelectionDAGBuilder::visitLoadFromSwiftError(const LoadInst &I) { @@ -3633,7 +3633,8 @@ void SelectionDAGBuilder::visitLoadFromSwiftError(const LoadInst &I) { // Chain, DL, Reg, VT, Glue or Chain, DL, Reg, VT SDValue L = DAG.getCopyFromReg( getRoot(), getCurSDLoc(), - FuncInfo.getOrCreateSwiftErrorVReg(FuncInfo.MBB, SV), ValueVTs[0]); + FuncInfo.getOrCreateSwiftErrorVRegUseAt(&I, FuncInfo.MBB, SV).first, + ValueVTs[0]); setValue(&I, L); } @@ -4942,11 +4943,12 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { updateDAGForMaybeTailCall(MM); return nullptr; } - case Intrinsic::memcpy_element_atomic: { - SDValue Dst = getValue(I.getArgOperand(0)); - SDValue Src = getValue(I.getArgOperand(1)); - SDValue NumElements = getValue(I.getArgOperand(2)); - SDValue ElementSize = getValue(I.getArgOperand(3)); + case Intrinsic::memcpy_element_unordered_atomic: { + const ElementUnorderedAtomicMemCpyInst &MI = + cast(I); + SDValue Dst = getValue(MI.getRawDest()); + SDValue Src = getValue(MI.getRawSource()); + SDValue Length = getValue(MI.getLength()); // Emit a library call. TargetLowering::ArgListTy Args; @@ -4958,18 +4960,13 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { Entry.Node = Src; Args.push_back(Entry); - Entry.Ty = I.getArgOperand(2)->getType(); - Entry.Node = NumElements; + Entry.Ty = MI.getLength()->getType(); + Entry.Node = Length; Args.push_back(Entry); - Entry.Ty = Type::getInt32Ty(*DAG.getContext()); - Entry.Node = ElementSize; - Args.push_back(Entry); - - uint64_t ElementSizeConstant = - cast(I.getArgOperand(3))->getZExtValue(); + uint64_t ElementSizeConstant = MI.getElementSizeInBytes(); RTLIB::Libcall LibraryCall = - RTLIB::getMEMCPY_ELEMENT_ATOMIC(ElementSizeConstant); + RTLIB::getMEMCPY_ELEMENT_UNORDERED_ATOMIC(ElementSizeConstant); if (LibraryCall == RTLIB::UNKNOWN_LIBCALL) report_fatal_error("Unsupported element size"); @@ -6030,9 +6027,11 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, SwiftErrorVal = V; // We find the virtual register for the actual swifterror argument. // Instead of using the Value, we use the virtual register instead. - Entry.Node = - DAG.getRegister(FuncInfo.getOrCreateSwiftErrorVReg(FuncInfo.MBB, V), - EVT(TLI.getPointerTy(DL))); + Entry.Node = DAG.getRegister(FuncInfo + .getOrCreateSwiftErrorVRegUseAt( + CS.getInstruction(), FuncInfo.MBB, V) + .first, + EVT(TLI.getPointerTy(DL))); } Args.push_back(Entry); @@ -6073,11 +6072,13 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, if (SwiftErrorVal && TLI.supportSwiftError()) { // Get the last element of InVals. SDValue Src = CLI.InVals.back(); - const TargetRegisterClass *RC = TLI.getRegClassFor(TLI.getPointerTy(DL)); - unsigned VReg = FuncInfo.MF->getRegInfo().createVirtualRegister(RC); + unsigned VReg; bool CreatedVReg; + std::tie(VReg, CreatedVReg) = + FuncInfo.getOrCreateSwiftErrorVRegDefAt(CS.getInstruction()); SDValue CopyNode = CLI.DAG.getCopyToReg(Result.second, CLI.DL, VReg, Src); // We update the virtual register for the actual swifterror argument. - FuncInfo.setCurrentSwiftErrorVReg(FuncInfo.MBB, SwiftErrorVal, VReg); + if (CreatedVReg) + FuncInfo.setCurrentSwiftErrorVReg(FuncInfo.MBB, SwiftErrorVal, VReg); DAG.setRoot(CopyNode); } } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index b67f11f85b70..dcccd17bb98e 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1055,6 +1055,7 @@ static void setupSwiftErrorVals(const Function &Fn, const TargetLowering *TLI, FuncInfo->SwiftErrorVals.clear(); FuncInfo->SwiftErrorVRegDefMap.clear(); FuncInfo->SwiftErrorVRegUpwardsUse.clear(); + FuncInfo->SwiftErrorVRegDefUses.clear(); FuncInfo->SwiftErrorArg = nullptr; // Check if function has a swifterror argument. @@ -1278,6 +1279,80 @@ static void propagateSwiftErrorVRegs(FunctionLoweringInfo *FuncInfo) { } } +void preassignSwiftErrorRegs(const TargetLowering *TLI, + FunctionLoweringInfo *FuncInfo, + BasicBlock::const_iterator Begin, + BasicBlock::const_iterator End) { + if (!TLI->supportSwiftError() || FuncInfo->SwiftErrorVals.empty()) + return; + + // Iterator over instructions and assign vregs to swifterror defs and uses. + for (auto It = Begin; It != End; ++It) { + ImmutableCallSite CS(&*It); + if (CS) { + // A call-site with a swifterror argument is both use and def. + const Value *SwiftErrorAddr = nullptr; + for (auto &Arg : CS.args()) { + if (!Arg->isSwiftError()) + continue; + // Use of swifterror. + assert(!SwiftErrorAddr && "Cannot have multiple swifterror arguments"); + SwiftErrorAddr = &*Arg; + assert(SwiftErrorAddr->isSwiftError() && + "Must have a swifterror value argument"); + unsigned VReg; bool CreatedReg; + std::tie(VReg, CreatedReg) = FuncInfo->getOrCreateSwiftErrorVRegUseAt( + &*It, FuncInfo->MBB, SwiftErrorAddr); + assert(CreatedReg); + } + if (!SwiftErrorAddr) + continue; + + // Def of swifterror. + unsigned VReg; bool CreatedReg; + std::tie(VReg, CreatedReg) = + FuncInfo->getOrCreateSwiftErrorVRegDefAt(&*It); + assert(CreatedReg); + FuncInfo->setCurrentSwiftErrorVReg(FuncInfo->MBB, SwiftErrorAddr, VReg); + + // A load is a use. + } else if (const LoadInst *LI = dyn_cast(&*It)) { + const Value *V = LI->getOperand(0); + if (!V->isSwiftError()) + continue; + + unsigned VReg; bool CreatedReg; + std::tie(VReg, CreatedReg) = + FuncInfo->getOrCreateSwiftErrorVRegUseAt(LI, FuncInfo->MBB, V); + assert(CreatedReg); + + // A store is a def. + } else if (const StoreInst *SI = dyn_cast(&*It)) { + const Value *SwiftErrorAddr = SI->getOperand(1); + if (!SwiftErrorAddr->isSwiftError()) + continue; + + // Def of swifterror. + unsigned VReg; bool CreatedReg; + std::tie(VReg, CreatedReg) = + FuncInfo->getOrCreateSwiftErrorVRegDefAt(&*It); + assert(CreatedReg); + FuncInfo->setCurrentSwiftErrorVReg(FuncInfo->MBB, SwiftErrorAddr, VReg); + + // A return in a swiferror returning function is a use. + } else if (const ReturnInst *R = dyn_cast(&*It)) { + const Function *F = R->getParent()->getParent(); + if(!F->getAttributes().hasAttrSomewhere(Attribute::SwiftError)) + continue; + + unsigned VReg; bool CreatedReg; + std::tie(VReg, CreatedReg) = FuncInfo->getOrCreateSwiftErrorVRegUseAt( + R, FuncInfo->MBB, FuncInfo->SwiftErrorArg); + assert(CreatedReg); + } + } +} + void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { FastISelFailed = false; // Initialize the Fast-ISel state, if needed. @@ -1384,6 +1459,10 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { FastIS->startNewBlock(); unsigned NumFastIselRemaining = std::distance(Begin, End); + + // Pre-assign swifterror vregs. + preassignSwiftErrorRegs(TLI, FuncInfo, Begin, End); + // Do FastISel on as many instructions as possible. for (; BI != Begin; --BI) { const Instruction *Inst = &*std::prev(BI); diff --git a/lib/CodeGen/SplitKit.cpp b/lib/CodeGen/SplitKit.cpp index 3a50aaa69985..008b984dd961 100644 --- a/lib/CodeGen/SplitKit.cpp +++ b/lib/CodeGen/SplitKit.cpp @@ -569,8 +569,7 @@ SlotIndex SplitEditor::buildCopy(unsigned FromReg, unsigned ToReg, // Greedy heuristic: Keep iterating keeping the best covering subreg index // each time. - LaneBitmask LanesLeft = - LaneMask & ~(TRI.getSubRegIndexLaneMask(BestCover)); + LaneBitmask LanesLeft = LaneMask & ~(TRI.getSubRegIndexLaneMask(BestIdx)); while (LanesLeft.any()) { unsigned BestIdx = 0; int BestCover = INT_MIN; diff --git a/lib/CodeGen/StackColoring.cpp b/lib/CodeGen/StackColoring.cpp index acb3676fdd71..6bac39c7ee77 100644 --- a/lib/CodeGen/StackColoring.cpp +++ b/lib/CodeGen/StackColoring.cpp @@ -86,10 +86,134 @@ STATISTIC(StackSpaceSaved, "Number of bytes saved due to merging slots."); STATISTIC(StackSlotMerged, "Number of stack slot merged."); STATISTIC(EscapedAllocas, "Number of allocas that escaped the lifetime region"); +//===----------------------------------------------------------------------===// +// StackColoring Pass +//===----------------------------------------------------------------------===// +// +// Stack Coloring reduces stack usage by merging stack slots when they +// can't be used together. For example, consider the following C program: +// +// void bar(char *, int); +// void foo(bool var) { +// A: { +// char z[4096]; +// bar(z, 0); +// } +// +// char *p; +// char x[4096]; +// char y[4096]; +// if (var) { +// p = x; +// } else { +// bar(y, 1); +// p = y + 1024; +// } +// B: +// bar(p, 2); +// } +// +// Naively-compiled, this program would use 12k of stack space. However, the +// stack slot corresponding to `z` is always destroyed before either of the +// stack slots for `x` or `y` are used, and then `x` is only used if `var` +// is true, while `y` is only used if `var` is false. So in no time are 2 +// of the stack slots used together, and therefore we can merge them, +// compiling the function using only a single 4k alloca: +// +// void foo(bool var) { // equivalent +// char x[4096]; +// char *p; +// bar(x, 0); +// if (var) { +// p = x; +// } else { +// bar(x, 1); +// p = x + 1024; +// } +// bar(p, 2); +// } +// +// This is an important optimization if we want stack space to be under +// control in large functions, both open-coded ones and ones created by +// inlining. // // Implementation Notes: // --------------------- // +// An important part of the above reasoning is that `z` can't be accessed +// while the latter 2 calls to `bar` are running. This is justified because +// `z`'s lifetime is over after we exit from block `A:`, so any further +// accesses to it would be UB. The way we represent this information +// in LLVM is by having frontends delimit blocks with `lifetime.start` +// and `lifetime.end` intrinsics. +// +// The effect of these intrinsics seems to be as follows (maybe I should +// specify this in the reference?): +// +// L1) at start, each stack-slot is marked as *out-of-scope*, unless no +// lifetime intrinsic refers to that stack slot, in which case +// it is marked as *in-scope*. +// L2) on a `lifetime.start`, a stack slot is marked as *in-scope* and +// the stack slot is overwritten with `undef`. +// L3) on a `lifetime.end`, a stack slot is marked as *out-of-scope*. +// L4) on function exit, all stack slots are marked as *out-of-scope*. +// L5) `lifetime.end` is a no-op when called on a slot that is already +// *out-of-scope*. +// L6) memory accesses to *out-of-scope* stack slots are UB. +// L7) when a stack-slot is marked as *out-of-scope*, all pointers to it +// are invalidated, unless the slot is "degenerate". This is used to +// justify not marking slots as in-use until the pointer to them is +// used, but feels a bit hacky in the presence of things like LICM. See +// the "Degenerate Slots" section for more details. +// +// Now, let's ground stack coloring on these rules. We'll define a slot +// as *in-use* at a (dynamic) point in execution if it either can be +// written to at that point, or if it has a live and non-undef content +// at that point. +// +// Obviously, slots that are never *in-use* together can be merged, and +// in our example `foo`, the slots for `x`, `y` and `z` are never +// in-use together (of course, sometimes slots that *are* in-use together +// might still be mergable, but we don't care about that here). +// +// In this implementation, we successively merge pairs of slots that are +// not *in-use* together. We could be smarter - for example, we could merge +// a single large slot with 2 small slots, or we could construct the +// interference graph and run a "smart" graph coloring algorithm, but with +// that aside, how do we find out whether a pair of slots might be *in-use* +// together? +// +// From our rules, we see that *out-of-scope* slots are never *in-use*, +// and from (L7) we see that "non-degenerate" slots remain non-*in-use* +// until their address is taken. Therefore, we can approximate slot activity +// using dataflow. +// +// A subtle point: naively, we might try to figure out which pairs of +// stack-slots interfere by propagating `S in-use` through the CFG for every +// stack-slot `S`, and having `S` and `T` interfere if there is a CFG point in +// which they are both *in-use*. +// +// That is sound, but overly conservative in some cases: in our (artificial) +// example `foo`, either `x` or `y` might be in use at the label `B:`, but +// as `x` is only in use if we came in from the `var` edge and `y` only +// if we came from the `!var` edge, they still can't be in use together. +// See PR32488 for an important real-life case. +// +// If we wanted to find all points of interference precisely, we could +// propagate `S in-use` and `S&T in-use` predicates through the CFG. That +// would be precise, but requires propagating `O(n^2)` dataflow facts. +// +// However, we aren't interested in the *set* of points of interference +// between 2 stack slots, only *whether* there *is* such a point. So we +// can rely on a little trick: for `S` and `T` to be in-use together, +// one of them needs to become in-use while the other is in-use (or +// they might both become in use simultaneously). We can check this +// by also keeping track of the points at which a stack slot might *start* +// being in-use. +// +// Exact first use: +// ---------------- +// // Consider the following motivating example: // // int foo() { @@ -158,6 +282,9 @@ STATISTIC(EscapedAllocas, "Number of allocas that escaped the lifetime region"); // lifetime, we can additionally overlap b1 and b5, giving us a 3*1024 // byte stack (better). // +// Degenerate Slots: +// ----------------- +// // Relying entirely on first-use of stack slots is problematic, // however, due to the fact that optimizations can sometimes migrate // uses of a variable outside of its lifetime start/end region. Here @@ -237,10 +364,6 @@ STATISTIC(EscapedAllocas, "Number of allocas that escaped the lifetime region"); // for "b" then it will appear that 'b' has a degenerate lifetime. // -//===----------------------------------------------------------------------===// -// StackColoring Pass -//===----------------------------------------------------------------------===// - namespace { /// StackColoring - A machine pass for merging disjoint stack allocations, /// marked by the LIFETIME_START and LIFETIME_END pseudo instructions. @@ -271,8 +394,11 @@ class StackColoring : public MachineFunctionPass { /// Maps basic blocks to a serial number. SmallVector BasicBlockNumbering; - /// Maps liveness intervals for each slot. + /// Maps slots to their use interval. Outside of this interval, slots + /// values are either dead or `undef` and they will not be written to. SmallVector, 16> Intervals; + /// Maps slots to the points where they can become in-use. + SmallVector, 16> LiveStarts; /// VNInfo is used for the construction of LiveIntervals. VNInfo::Allocator VNInfoAllocator; /// SlotIndex analysis object. @@ -672,15 +798,22 @@ void StackColoring::calculateLocalLiveness() void StackColoring::calculateLiveIntervals(unsigned NumSlots) { SmallVector Starts; - SmallVector Finishes; + SmallVector DefinitelyInUse; // For each block, find which slots are active within this block // and update the live intervals. for (const MachineBasicBlock &MBB : *MF) { Starts.clear(); Starts.resize(NumSlots); - Finishes.clear(); - Finishes.resize(NumSlots); + DefinitelyInUse.clear(); + DefinitelyInUse.resize(NumSlots); + + // Start the interval of the slots that we previously found to be 'in-use'. + BlockLifetimeInfo &MBBLiveness = BlockLiveness[&MBB]; + for (int pos = MBBLiveness.LiveIn.find_first(); pos != -1; + pos = MBBLiveness.LiveIn.find_next(pos)) { + Starts[pos] = Indexes->getMBBStartIdx(&MBB); + } // Create the interval for the basic blocks containing lifetime begin/end. for (const MachineInstr &MI : MBB) { @@ -692,66 +825,35 @@ void StackColoring::calculateLiveIntervals(unsigned NumSlots) { SlotIndex ThisIndex = Indexes->getInstructionIndex(MI); for (auto Slot : slots) { if (IsStart) { - if (!Starts[Slot].isValid() || Starts[Slot] > ThisIndex) + // If a slot is already definitely in use, we don't have to emit + // a new start marker because there is already a pre-existing + // one. + if (!DefinitelyInUse[Slot]) { + LiveStarts[Slot].push_back(ThisIndex); + DefinitelyInUse[Slot] = true; + } + if (!Starts[Slot].isValid()) Starts[Slot] = ThisIndex; } else { - if (!Finishes[Slot].isValid() || Finishes[Slot] < ThisIndex) - Finishes[Slot] = ThisIndex; + if (Starts[Slot].isValid()) { + VNInfo *VNI = Intervals[Slot]->getValNumInfo(0); + Intervals[Slot]->addSegment( + LiveInterval::Segment(Starts[Slot], ThisIndex, VNI)); + Starts[Slot] = SlotIndex(); // Invalidate the start index + DefinitelyInUse[Slot] = false; + } } } } - // Create the interval of the blocks that we previously found to be 'alive'. - BlockLifetimeInfo &MBBLiveness = BlockLiveness[&MBB]; - for (unsigned pos : MBBLiveness.LiveIn.set_bits()) { - Starts[pos] = Indexes->getMBBStartIdx(&MBB); - } - for (unsigned pos : MBBLiveness.LiveOut.set_bits()) { - Finishes[pos] = Indexes->getMBBEndIdx(&MBB); - } - + // Finish up started segments for (unsigned i = 0; i < NumSlots; ++i) { - // - // When LifetimeStartOnFirstUse is turned on, data flow analysis - // is forward (from starts to ends), not bidirectional. A - // consequence of this is that we can wind up in situations - // where Starts[i] is invalid but Finishes[i] is valid and vice - // versa. Example: - // - // LIFETIME_START x - // if (...) { - // - // throw ...; - // } - // LIFETIME_END x - // return 2; - // - // - // Here the slot for "x" will not be live into the block - // containing the "return 2" (since lifetimes start with first - // use, not at the dominating LIFETIME_START marker). - // - if (Starts[i].isValid() && !Finishes[i].isValid()) { - Finishes[i] = Indexes->getMBBEndIdx(&MBB); - } if (!Starts[i].isValid()) continue; - assert(Starts[i] && Finishes[i] && "Invalid interval"); - VNInfo *ValNum = Intervals[i]->getValNumInfo(0); - SlotIndex S = Starts[i]; - SlotIndex F = Finishes[i]; - if (S < F) { - // We have a single consecutive region. - Intervals[i]->addSegment(LiveInterval::Segment(S, F, ValNum)); - } else { - // We have two non-consecutive regions. This happens when - // LIFETIME_START appears after the LIFETIME_END marker. - SlotIndex NewStart = Indexes->getMBBStartIdx(&MBB); - SlotIndex NewFin = Indexes->getMBBEndIdx(&MBB); - Intervals[i]->addSegment(LiveInterval::Segment(NewStart, F, ValNum)); - Intervals[i]->addSegment(LiveInterval::Segment(S, NewFin, ValNum)); - } + SlotIndex EndIdx = Indexes->getMBBEndIdx(&MBB); + VNInfo *VNI = Intervals[i]->getValNumInfo(0); + Intervals[i]->addSegment(LiveInterval::Segment(Starts[i], EndIdx, VNI)); } } } @@ -981,6 +1083,7 @@ bool StackColoring::runOnMachineFunction(MachineFunction &Func) { BasicBlockNumbering.clear(); Markers.clear(); Intervals.clear(); + LiveStarts.clear(); VNInfoAllocator.Reset(); unsigned NumSlots = MFI->getObjectIndexEnd(); @@ -992,6 +1095,7 @@ bool StackColoring::runOnMachineFunction(MachineFunction &Func) { SmallVector SortedSlots; SortedSlots.reserve(NumSlots); Intervals.reserve(NumSlots); + LiveStarts.resize(NumSlots); unsigned NumMarkers = collectMarkers(NumSlots); @@ -1063,6 +1167,9 @@ bool StackColoring::runOnMachineFunction(MachineFunction &Func) { return MFI->getObjectSize(LHS) > MFI->getObjectSize(RHS); }); + for (auto &s : LiveStarts) + std::sort(s.begin(), s.end()); + bool Changed = true; while (Changed) { Changed = false; @@ -1078,12 +1185,22 @@ bool StackColoring::runOnMachineFunction(MachineFunction &Func) { int SecondSlot = SortedSlots[J]; LiveInterval *First = &*Intervals[FirstSlot]; LiveInterval *Second = &*Intervals[SecondSlot]; + auto &FirstS = LiveStarts[FirstSlot]; + auto &SecondS = LiveStarts[SecondSlot]; assert (!First->empty() && !Second->empty() && "Found an empty range"); - // Merge disjoint slots. - if (!First->overlaps(*Second)) { + // Merge disjoint slots. This is a little bit tricky - see the + // Implementation Notes section for an explanation. + if (!First->isLiveAtIndexes(SecondS) && + !Second->isLiveAtIndexes(FirstS)) { Changed = true; First->MergeSegmentsInAsValue(*Second, First->getValNumInfo(0)); + + int OldSize = FirstS.size(); + FirstS.append(SecondS.begin(), SecondS.end()); + auto Mid = FirstS.begin() + OldSize; + std::inplace_merge(FirstS.begin(), Mid, FirstS.end()); + SlotRemap[SecondSlot] = FirstSlot; SortedSlots[J] = -1; DEBUG(dbgs()<<"Merging #"< ModuleFlags, - unsigned &Version, unsigned &Flags, +static void GetObjCImageInfo(Module &M, unsigned &Version, unsigned &Flags, StringRef &Section) { + SmallVector ModuleFlags; + M.getModuleFlagsMetadata(ModuleFlags); + for (const auto &MFE: ModuleFlags) { // Ignore flags with 'Require' behaviour. if (MFE.Behavior == Module::Require) @@ -88,14 +90,13 @@ static void GetObjCImageInfo(ArrayRef ModuleFlags, // ELF //===----------------------------------------------------------------------===// -void TargetLoweringObjectFileELF::emitModuleFlags( - MCStreamer &Streamer, ArrayRef ModuleFlags, - const TargetMachine &TM) const { +void TargetLoweringObjectFileELF::emitModuleMetadata( + MCStreamer &Streamer, Module &M, const TargetMachine &TM) const { unsigned Version = 0; unsigned Flags = 0; StringRef Section; - GetObjCImageInfo(ModuleFlags, Version, Flags, Section); + GetObjCImageInfo(M, Version, Flags, Section); if (Section.empty()) return; @@ -618,20 +619,10 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, } } -/// emitModuleFlags - Perform code emission for module flags. -void TargetLoweringObjectFileMachO::emitModuleFlags( - MCStreamer &Streamer, ArrayRef ModuleFlags, - const TargetMachine &TM) const { - MDNode *LinkerOptions = nullptr; - - for (const auto &MFE : ModuleFlags) { - StringRef Key = MFE.Key->getString(); - if (Key == "Linker Options") - LinkerOptions = cast(MFE.Val); - } - +void TargetLoweringObjectFileMachO::emitModuleMetadata( + MCStreamer &Streamer, Module &M, const TargetMachine &TM) const { // Emit the linker options if present. - if (LinkerOptions) { + if (auto *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { for (const auto &Option : LinkerOptions->operands()) { SmallVector StrOptions; for (const auto &Piece : cast(Option)->operands()) @@ -643,7 +634,8 @@ void TargetLoweringObjectFileMachO::emitModuleFlags( unsigned VersionVal = 0; unsigned ImageInfoFlags = 0; StringRef SectionVal; - GetObjCImageInfo(ModuleFlags, VersionVal, ImageInfoFlags, SectionVal); + + GetObjCImageInfo(M, VersionVal, ImageInfoFlags, SectionVal); // The section is mandatory. If we don't have it, then we don't have GC info. if (SectionVal.empty()) @@ -1159,18 +1151,9 @@ MCSection *TargetLoweringObjectFileCOFF::getSectionForJumpTable( COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE, UniqueID); } -void TargetLoweringObjectFileCOFF::emitModuleFlags( - MCStreamer &Streamer, ArrayRef ModuleFlags, - const TargetMachine &TM) const { - MDNode *LinkerOptions = nullptr; - - for (const auto &MFE : ModuleFlags) { - StringRef Key = MFE.Key->getString(); - if (Key == "Linker Options") - LinkerOptions = cast(MFE.Val); - } - - if (LinkerOptions) { +void TargetLoweringObjectFileCOFF::emitModuleMetadata( + MCStreamer &Streamer, Module &M, const TargetMachine &TM) const { + if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { // Emit the linker options to the linker .drectve section. According to the // spec, this section is a space-separated string containing flags for // linker. @@ -1190,7 +1173,7 @@ void TargetLoweringObjectFileCOFF::emitModuleFlags( unsigned Flags = 0; StringRef Section; - GetObjCImageInfo(ModuleFlags, Version, Flags, Section); + GetObjCImageInfo(M, Version, Flags, Section); if (Section.empty()) return; diff --git a/lib/DebugInfo/CodeView/CMakeLists.txt b/lib/DebugInfo/CodeView/CMakeLists.txt index 2f9e8981b698..f916695a8439 100644 --- a/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/lib/DebugInfo/CodeView/CMakeLists.txt @@ -20,6 +20,7 @@ add_llvm_library(LLVMDebugInfoCodeView LazyRandomTypeCollection.cpp Line.cpp RecordSerialization.cpp + StringsAndChecksums.cpp SymbolRecordMapping.cpp SymbolDumper.cpp SymbolSerializer.cpp @@ -32,7 +33,7 @@ add_llvm_library(LLVMDebugInfoCodeView TypeSerializer.cpp TypeStreamMerger.cpp TypeTableCollection.cpp - + ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView ) diff --git a/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp b/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp index 6e647c4b976b..de02525270c4 100644 --- a/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp +++ b/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp @@ -58,6 +58,10 @@ Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const { uint32_t Begin = Writer.getOffset(); uint32_t End = Begin + StringSize; + // Write a null string at the beginning. + if (auto EC = Writer.writeCString(StringRef())) + return EC; + for (auto &Pair : Strings) { StringRef S = Pair.getKey(); uint32_t Offset = Begin + Pair.getValue(); @@ -68,6 +72,7 @@ Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const { } Writer.setOffset(End); + assert((End - Begin) == StringSize); return Error::success(); } diff --git a/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp b/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp index e9124e68fe82..334c5e002bbc 100644 --- a/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp +++ b/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp @@ -50,7 +50,7 @@ DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; } BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; } DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder( - std::unique_ptr Subsection, CodeViewContainer Container) + std::shared_ptr Subsection, CodeViewContainer Container) : Subsection(std::move(Subsection)), Container(Container) {} uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() { diff --git a/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp b/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp index 8550107741ce..9b824333369b 100644 --- a/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp +++ b/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp @@ -26,40 +26,9 @@ using namespace llvm; using namespace llvm::codeview; -DebugSubsectionState::DebugSubsectionState() {} - -DebugSubsectionState::DebugSubsectionState( - const DebugStringTableSubsectionRef &Strings) - : Strings(&Strings) {} - -DebugSubsectionState::DebugSubsectionState( - const DebugStringTableSubsectionRef &Strings, - const DebugChecksumsSubsectionRef &Checksums) - : Strings(&Strings), Checksums(&Checksums) {} - -void DebugSubsectionState::initializeStrings(const DebugSubsectionRecord &SR) { - assert(SR.kind() == DebugSubsectionKind::StringTable); - assert(!Strings && "Found a string table even though we already have one!"); - - OwnedStrings = llvm::make_unique(); - consumeError(OwnedStrings->initialize(SR.getRecordData())); - Strings = OwnedStrings.get(); -} - -void DebugSubsectionState::initializeChecksums( - const DebugSubsectionRecord &FCR) { - assert(FCR.kind() == DebugSubsectionKind::FileChecksums); - if (Checksums) - return; - - OwnedChecksums = llvm::make_unique(); - consumeError(OwnedChecksums->initialize(FCR.getRecordData())); - Checksums = OwnedChecksums.get(); -} - -Error llvm::codeview::visitDebugSubsection(const DebugSubsectionRecord &R, - DebugSubsectionVisitor &V, - const DebugSubsectionState &State) { +Error llvm::codeview::visitDebugSubsection( + const DebugSubsectionRecord &R, DebugSubsectionVisitor &V, + const StringsAndChecksumsRef &State) { BinaryStreamReader Reader(R.getRecordData()); switch (R.kind()) { case DebugSubsectionKind::Lines: { diff --git a/lib/DebugInfo/CodeView/StringsAndChecksums.cpp b/lib/DebugInfo/CodeView/StringsAndChecksums.cpp new file mode 100644 index 000000000000..928bf8c94f73 --- /dev/null +++ b/lib/DebugInfo/CodeView/StringsAndChecksums.cpp @@ -0,0 +1,55 @@ +//===- StringsAndChecksums.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" + +using namespace llvm; +using namespace llvm::codeview; + +StringsAndChecksumsRef::StringsAndChecksumsRef() {} + +StringsAndChecksumsRef::StringsAndChecksumsRef( + const DebugStringTableSubsectionRef &Strings) + : Strings(&Strings) {} + +StringsAndChecksumsRef::StringsAndChecksumsRef( + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums) + : Strings(&Strings), Checksums(&Checksums) {} + +void StringsAndChecksumsRef::initializeStrings( + const DebugSubsectionRecord &SR) { + assert(SR.kind() == DebugSubsectionKind::StringTable); + assert(!Strings && "Found a string table even though we already have one!"); + + OwnedStrings = llvm::make_unique(); + consumeError(OwnedStrings->initialize(SR.getRecordData())); + Strings = OwnedStrings.get(); +} + +void StringsAndChecksumsRef::setChecksums( + const DebugChecksumsSubsectionRef &CS) { + OwnedChecksums = llvm::make_unique(); + *OwnedChecksums = CS; + Checksums = OwnedChecksums.get(); +} + +void StringsAndChecksumsRef::initializeChecksums( + const DebugSubsectionRecord &FCR) { + assert(FCR.kind() == DebugSubsectionKind::FileChecksums); + if (Checksums) + return; + + OwnedChecksums = llvm::make_unique(); + consumeError(OwnedChecksums->initialize(FCR.getRecordData())); + Checksums = OwnedChecksums.get(); +} diff --git a/lib/DebugInfo/CodeView/SymbolDumper.cpp b/lib/DebugInfo/CodeView/SymbolDumper.cpp index 66045933ce9b..36abafc079ed 100644 --- a/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -212,7 +212,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, FileStaticSym &FileStatic) { DictScope S(W, "FileStatic"); - W.printNumber("Index", FileStatic.Index); + printTypeIndex("Index", FileStatic.Index); W.printNumber("ModFilenameOffset", FileStatic.ModFilenameOffset); W.printFlags("Flags", uint16_t(FileStatic.Flags), getLocalFlagNames()); W.printString("Name", FileStatic.Name); @@ -516,7 +516,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, RegisterSym &Register) { DictScope S(W, "RegisterSym"); - W.printNumber("Type", Register.Index); + printTypeIndex("Type", Register.Index); W.printEnum("Seg", uint16_t(Register.Register), getRegisterNames()); W.printString("Name", Register.Name); return Error::success(); @@ -524,7 +524,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) { DictScope S(W, "PublicSym"); - W.printNumber("Type", Public.Index); + printTypeIndex("Type", Public.Index); W.printNumber("Seg", Public.Segment); W.printNumber("Off", Public.Offset); W.printString("Name", Public.Name); @@ -631,7 +631,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, W.printHex("Offset", RegRel.Offset); printTypeIndex("Type", RegRel.Type); - W.printHex("Register", RegRel.Register); + W.printEnum("Register", uint16_t(RegRel.Register), getRegisterNames()); W.printString("VarName", RegRel.Name); return Error::success(); } diff --git a/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp index ea46841a70f6..d731dc1b0a37 100644 --- a/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp +++ b/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp @@ -307,7 +307,7 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, error(IO.mapInteger(FrameCookie.CodeOffset)); error(IO.mapInteger(FrameCookie.Register)); - error(IO.mapInteger(FrameCookie.CookieKind)); + error(IO.mapEnum(FrameCookie.CookieKind)); error(IO.mapInteger(FrameCookie.Flags)); return Error::success(); @@ -439,7 +439,7 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, error(IO.mapInteger(RegRel.Offset)); error(IO.mapInteger(RegRel.Type)); - error(IO.mapInteger(RegRel.Register)); + error(IO.mapEnum(RegRel.Register)); error(IO.mapStringZ(RegRel.Name)); return Error::success(); diff --git a/lib/DebugInfo/CodeView/TypeDatabase.cpp b/lib/DebugInfo/CodeView/TypeDatabase.cpp index af05d2dc294b..08f848b36a9d 100644 --- a/lib/DebugInfo/CodeView/TypeDatabase.cpp +++ b/lib/DebugInfo/CodeView/TypeDatabase.cpp @@ -12,59 +12,6 @@ using namespace llvm; using namespace llvm::codeview; -namespace { -struct SimpleTypeEntry { - StringRef Name; - SimpleTypeKind Kind; -}; -} - -/// The names here all end in "*". If the simple type is a pointer type, we -/// return the whole name. Otherwise we lop off the last character in our -/// StringRef. -static const SimpleTypeEntry SimpleTypeNames[] = { - {"void*", SimpleTypeKind::Void}, - {"*", SimpleTypeKind::NotTranslated}, - {"HRESULT*", SimpleTypeKind::HResult}, - {"signed char*", SimpleTypeKind::SignedCharacter}, - {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, - {"char*", SimpleTypeKind::NarrowCharacter}, - {"wchar_t*", SimpleTypeKind::WideCharacter}, - {"char16_t*", SimpleTypeKind::Character16}, - {"char32_t*", SimpleTypeKind::Character32}, - {"__int8*", SimpleTypeKind::SByte}, - {"unsigned __int8*", SimpleTypeKind::Byte}, - {"short*", SimpleTypeKind::Int16Short}, - {"unsigned short*", SimpleTypeKind::UInt16Short}, - {"__int16*", SimpleTypeKind::Int16}, - {"unsigned __int16*", SimpleTypeKind::UInt16}, - {"long*", SimpleTypeKind::Int32Long}, - {"unsigned long*", SimpleTypeKind::UInt32Long}, - {"int*", SimpleTypeKind::Int32}, - {"unsigned*", SimpleTypeKind::UInt32}, - {"__int64*", SimpleTypeKind::Int64Quad}, - {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, - {"__int64*", SimpleTypeKind::Int64}, - {"unsigned __int64*", SimpleTypeKind::UInt64}, - {"__int128*", SimpleTypeKind::Int128}, - {"unsigned __int128*", SimpleTypeKind::UInt128}, - {"__half*", SimpleTypeKind::Float16}, - {"float*", SimpleTypeKind::Float32}, - {"float*", SimpleTypeKind::Float32PartialPrecision}, - {"__float48*", SimpleTypeKind::Float48}, - {"double*", SimpleTypeKind::Float64}, - {"long double*", SimpleTypeKind::Float80}, - {"__float128*", SimpleTypeKind::Float128}, - {"_Complex float*", SimpleTypeKind::Complex32}, - {"_Complex double*", SimpleTypeKind::Complex64}, - {"_Complex long double*", SimpleTypeKind::Complex80}, - {"_Complex __float128*", SimpleTypeKind::Complex128}, - {"bool*", SimpleTypeKind::Boolean8}, - {"__bool16*", SimpleTypeKind::Boolean16}, - {"__bool32*", SimpleTypeKind::Boolean32}, - {"__bool64*", SimpleTypeKind::Boolean64}, -}; - TypeDatabase::TypeDatabase(uint32_t Capacity) : TypeNameStorage(Allocator) { CVUDTNames.resize(Capacity); TypeRecords.resize(Capacity); @@ -103,22 +50,8 @@ StringRef TypeDatabase::saveTypeName(StringRef TypeName) { } StringRef TypeDatabase::getTypeName(TypeIndex Index) const { - if (Index.isNoneType()) - return ""; - - if (Index.isSimple()) { - // This is a simple type. - for (const auto &SimpleTypeName : SimpleTypeNames) { - if (SimpleTypeName.Kind == Index.getSimpleKind()) { - if (Index.getSimpleMode() == SimpleTypeMode::Direct) - return SimpleTypeName.Name.drop_back(1); - // Otherwise, this is a pointer type. We gloss over the distinction - // between near, far, 64, 32, etc, and just give a pointer type. - return SimpleTypeName.Name; - } - } - return ""; - } + if (Index.isNoneType() || Index.isSimple()) + return TypeIndex::simpleTypeName(Index); if (contains(Index)) return CVUDTNames[Index.toArrayIndex()]; diff --git a/lib/DebugInfo/CodeView/TypeIndex.cpp b/lib/DebugInfo/CodeView/TypeIndex.cpp index 20ba6470cd5b..24fe5fcb28d4 100644 --- a/lib/DebugInfo/CodeView/TypeIndex.cpp +++ b/lib/DebugInfo/CodeView/TypeIndex.cpp @@ -15,11 +15,88 @@ using namespace llvm; using namespace llvm::codeview; +namespace { +struct SimpleTypeEntry { + StringRef Name; + SimpleTypeKind Kind; +}; + +/// The names here all end in "*". If the simple type is a pointer type, we +/// return the whole name. Otherwise we lop off the last character in our +/// StringRef. +static const SimpleTypeEntry SimpleTypeNames[] = { + {"void*", SimpleTypeKind::Void}, + {"*", SimpleTypeKind::NotTranslated}, + {"HRESULT*", SimpleTypeKind::HResult}, + {"signed char*", SimpleTypeKind::SignedCharacter}, + {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, + {"char*", SimpleTypeKind::NarrowCharacter}, + {"wchar_t*", SimpleTypeKind::WideCharacter}, + {"char16_t*", SimpleTypeKind::Character16}, + {"char32_t*", SimpleTypeKind::Character32}, + {"__int8*", SimpleTypeKind::SByte}, + {"unsigned __int8*", SimpleTypeKind::Byte}, + {"short*", SimpleTypeKind::Int16Short}, + {"unsigned short*", SimpleTypeKind::UInt16Short}, + {"__int16*", SimpleTypeKind::Int16}, + {"unsigned __int16*", SimpleTypeKind::UInt16}, + {"long*", SimpleTypeKind::Int32Long}, + {"unsigned long*", SimpleTypeKind::UInt32Long}, + {"int*", SimpleTypeKind::Int32}, + {"unsigned*", SimpleTypeKind::UInt32}, + {"__int64*", SimpleTypeKind::Int64Quad}, + {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, + {"__int64*", SimpleTypeKind::Int64}, + {"unsigned __int64*", SimpleTypeKind::UInt64}, + {"__int128*", SimpleTypeKind::Int128}, + {"unsigned __int128*", SimpleTypeKind::UInt128}, + {"__half*", SimpleTypeKind::Float16}, + {"float*", SimpleTypeKind::Float32}, + {"float*", SimpleTypeKind::Float32PartialPrecision}, + {"__float48*", SimpleTypeKind::Float48}, + {"double*", SimpleTypeKind::Float64}, + {"long double*", SimpleTypeKind::Float80}, + {"__float128*", SimpleTypeKind::Float128}, + {"_Complex float*", SimpleTypeKind::Complex32}, + {"_Complex double*", SimpleTypeKind::Complex64}, + {"_Complex long double*", SimpleTypeKind::Complex80}, + {"_Complex __float128*", SimpleTypeKind::Complex128}, + {"bool*", SimpleTypeKind::Boolean8}, + {"__bool16*", SimpleTypeKind::Boolean16}, + {"__bool32*", SimpleTypeKind::Boolean32}, + {"__bool64*", SimpleTypeKind::Boolean64}, +}; +} // namespace + +StringRef TypeIndex::simpleTypeName(TypeIndex TI) { + assert(TI.isNoneType() || TI.isSimple()); + + if (TI.isNoneType()) + return ""; + + // This is a simple type. + for (const auto &SimpleTypeName : SimpleTypeNames) { + if (SimpleTypeName.Kind == TI.getSimpleKind()) { + if (TI.getSimpleMode() == SimpleTypeMode::Direct) + return SimpleTypeName.Name.drop_back(1); + // Otherwise, this is a pointer type. We gloss over the distinction + // between near, far, 64, 32, etc, and just give a pointer type. + return SimpleTypeName.Name; + } + } + return ""; +} + void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI, TypeCollection &Types) { StringRef TypeName; - if (!TI.isNoneType()) - TypeName = Types.getTypeName(TI); + if (!TI.isNoneType()) { + if (TI.isSimple()) + TypeName = TypeIndex::simpleTypeName(TI); + else + TypeName = Types.getTypeName(TI); + } + if (!TypeName.empty()) Printer.printHex(FieldName, TypeName, TI.getIndex()); else diff --git a/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp index 11e2e215303c..8704cea60786 100644 --- a/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp +++ b/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp @@ -34,7 +34,7 @@ static inline PointerMode getPointerMode(uint32_t Attrs) { static inline bool isMemberPointer(uint32_t Attrs) { PointerMode Mode = getPointerMode(Attrs); return Mode == PointerMode::PointerToDataMember || - Mode == PointerMode::PointerToDataMember; + Mode == PointerMode::PointerToMemberFunction; } static inline uint32_t getEncodedIntegerLength(ArrayRef Data) { diff --git a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 97b52f0fbdd6..87009bf1b6a1 100644 --- a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -55,6 +55,13 @@ bool DWARFAcceleratorTable::extract() { return true; } +uint32_t DWARFAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; } +uint32_t DWARFAcceleratorTable::getNumHashes() { return Hdr.NumHashes; } +uint32_t DWARFAcceleratorTable::getSizeHdr() { return sizeof(Hdr); } +uint32_t DWARFAcceleratorTable::getHeaderDataLength() { + return Hdr.HeaderDataLength; +} + LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { // Dump the header. OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n' diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp index 42ab48808f9a..9bafcde57f0a 100644 --- a/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -425,248 +425,6 @@ DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) { return DWARFDie(); } -namespace { - -class Verifier { - raw_ostream &OS; - DWARFContext &DCtx; -public: - Verifier(raw_ostream &S, DWARFContext &D) : OS(S), DCtx(D) {} - - bool HandleDebugInfo() { - bool Success = true; - // A map that tracks all references (converted absolute references) so we - // can verify each reference points to a valid DIE and not an offset that - // lies between to valid DIEs. - std::map> ReferenceToDIEOffsets; - - OS << "Verifying .debug_info...\n"; - for (const auto &CU : DCtx.compile_units()) { - unsigned NumDies = CU->getNumDIEs(); - for (unsigned I = 0; I < NumDies; ++I) { - auto Die = CU->getDIEAtIndex(I); - const auto Tag = Die.getTag(); - if (Tag == DW_TAG_null) - continue; - for (auto AttrValue : Die.attributes()) { - const auto Attr = AttrValue.Attr; - const auto Form = AttrValue.Value.getForm(); - switch (Attr) { - case DW_AT_ranges: - // Make sure the offset in the DW_AT_ranges attribute is valid. - if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - if (*SectionOffset >= DCtx.getRangeSection().Data.size()) { - Success = false; - OS << "error: DW_AT_ranges offset is beyond .debug_ranges " - "bounds:\n"; - Die.dump(OS, 0); - OS << "\n"; - } - } else { - Success = false; - OS << "error: DIE has invalid DW_AT_ranges encoding:\n"; - Die.dump(OS, 0); - OS << "\n"; - } - break; - case DW_AT_stmt_list: - // Make sure the offset in the DW_AT_stmt_list attribute is valid. - if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - if (*SectionOffset >= DCtx.getLineSection().Data.size()) { - Success = false; - OS << "error: DW_AT_stmt_list offset is beyond .debug_line " - "bounds: " - << format("0x%08" PRIx32, *SectionOffset) << "\n"; - CU->getUnitDIE().dump(OS, 0); - OS << "\n"; - } - } else { - Success = false; - OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n"; - Die.dump(OS, 0); - OS << "\n"; - } - break; - - default: - break; - } - switch (Form) { - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_udata: { - // Verify all CU relative references are valid CU offsets. - Optional RefVal = AttrValue.Value.getAsReference(); - assert(RefVal); - if (RefVal) { - auto DieCU = Die.getDwarfUnit(); - auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); - auto CUOffset = AttrValue.Value.getRawUValue(); - if (CUOffset >= CUSize) { - Success = false; - OS << "error: " << FormEncodingString(Form) << " CU offset " - << format("0x%08" PRIx32, CUOffset) - << " is invalid (must be less than CU size of " - << format("0x%08" PRIx32, CUSize) << "):\n"; - Die.dump(OS, 0); - OS << "\n"; - } else { - // Valid reference, but we will verify it points to an actual - // DIE later. - ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); - } - } - break; - } - case DW_FORM_ref_addr: { - // Verify all absolute DIE references have valid offsets in the - // .debug_info section. - Optional RefVal = AttrValue.Value.getAsReference(); - assert(RefVal); - if (RefVal) { - if(*RefVal >= DCtx.getInfoSection().Data.size()) { - Success = false; - OS << "error: DW_FORM_ref_addr offset beyond .debug_info " - "bounds:\n"; - Die.dump(OS, 0); - OS << "\n"; - } else { - // Valid reference, but we will verify it points to an actual - // DIE later. - ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); - } - } - break; - } - case DW_FORM_strp: { - auto SecOffset = AttrValue.Value.getAsSectionOffset(); - assert(SecOffset); // DW_FORM_strp is a section offset. - if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) { - Success = false; - OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n"; - Die.dump(OS, 0); - OS << "\n"; - } - break; - } - default: - break; - } - } - } - } - - // Take all references and make sure they point to an actual DIE by - // getting the DIE by offset and emitting an error - OS << "Verifying .debug_info references...\n"; - for (auto Pair: ReferenceToDIEOffsets) { - auto Die = DCtx.getDIEForOffset(Pair.first); - if (Die) - continue; - Success = false; - OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first) - << ". Offset is in between DIEs:\n"; - for (auto Offset: Pair.second) { - auto ReferencingDie = DCtx.getDIEForOffset(Offset); - ReferencingDie.dump(OS, 0); - OS << "\n"; - } - OS << "\n"; - } - return Success; - } - - bool HandleDebugLine() { - std::map StmtListToDie; - bool Success = true; - OS << "Verifying .debug_line...\n"; - for (const auto &CU : DCtx.compile_units()) { - uint32_t LineTableOffset = 0; - auto CUDie = CU->getUnitDIE(); - auto StmtFormValue = CUDie.find(DW_AT_stmt_list); - if (!StmtFormValue) { - // No line table for this compile unit. - continue; - } - // Get the attribute value as a section offset. No need to produce an - // error here if the encoding isn't correct because we validate this in - // the .debug_info verifier. - if (auto StmtSectionOffset = toSectionOffset(StmtFormValue)) { - LineTableOffset = *StmtSectionOffset; - if (LineTableOffset >= DCtx.getLineSection().Data.size()) { - // Make sure we don't get a valid line table back if the offset - // is wrong. - assert(DCtx.getLineTableForUnit(CU.get()) == nullptr); - // Skip this line table as it isn't valid. No need to create an error - // here because we validate this in the .debug_info verifier. - continue; - } else { - auto Iter = StmtListToDie.find(LineTableOffset); - if (Iter != StmtListToDie.end()) { - Success = false; - OS << "error: two compile unit DIEs, " - << format("0x%08" PRIx32, Iter->second.getOffset()) << " and " - << format("0x%08" PRIx32, CUDie.getOffset()) - << ", have the same DW_AT_stmt_list section offset:\n"; - Iter->second.dump(OS, 0); - CUDie.dump(OS, 0); - OS << '\n'; - // Already verified this line table before, no need to do it again. - continue; - } - StmtListToDie[LineTableOffset] = CUDie; - } - } - auto LineTable = DCtx.getLineTableForUnit(CU.get()); - if (!LineTable) { - Success = false; - OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset) - << "] was not able to be parsed for CU:\n"; - CUDie.dump(OS, 0); - OS << '\n'; - continue; - } - uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size(); - uint64_t PrevAddress = 0; - uint32_t RowIndex = 0; - for (const auto &Row : LineTable->Rows) { - if (Row.Address < PrevAddress) { - Success = false; - OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset) - << "] row[" << RowIndex - << "] decreases in address from previous row:\n"; - - DWARFDebugLine::Row::dumpTableHeader(OS); - if (RowIndex > 0) - LineTable->Rows[RowIndex - 1].dump(OS); - Row.dump(OS); - OS << '\n'; - } - - if (Row.File > MaxFileIndex) { - Success = false; - OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset) - << "][" << RowIndex << "] has invalid file index " << Row.File - << " (valid values are [1," << MaxFileIndex << "]):\n"; - DWARFDebugLine::Row::dumpTableHeader(OS); - Row.dump(OS); - OS << '\n'; - } - if (Row.EndSequence) - PrevAddress = 0; - else - PrevAddress = Row.Address; - ++RowIndex; - } - } - return Success; - } -}; - -} // anonymous namespace - bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) { bool Success = true; DWARFVerifier verifier(OS, *this); @@ -678,8 +436,13 @@ bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) { if (!verifier.handleDebugLine()) Success = false; } + if (DumpType == DIDT_All || DumpType == DIDT_AppleNames) { + if (!verifier.handleAppleNames()) + Success = false; + } return Success; } + const DWARFUnitIndex &DWARFContext::getCUIndex() { if (CUIndex) return *CUIndex; @@ -1250,7 +1013,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, continue; RelSecName = RelSecName.substr( - RelSecName.find_first_not_of("._")); // Skip . and _ prefixes. + RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes. // TODO: Add support for relocations in other sections as needed. // Record relocations for the debug_info and debug_line sections. diff --git a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index e6e007896cc8..cf9fec2b3254 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -514,6 +514,20 @@ static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset, } } +// This is a workaround for old compilers which do not allow +// noreturn attribute usage in lambdas. Once the support for those +// compilers are phased out, we can remove this and return back to +// a ReportError lambda: [StartOffset](const char *ErrorMsg). +#define ReportError(ErrorMsg) ReportErrorImpl(StartOffset,ErrorMsg) +static void LLVM_ATTRIBUTE_NORETURN +ReportErrorImpl(uint32_t StartOffset, const char *ErrorMsg) { + std::string Str; + raw_string_ostream OS(Str); + OS << format(ErrorMsg, StartOffset); + OS.flush(); + report_fatal_error(Str); +} + void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; DenseMap CIEs; @@ -521,14 +535,6 @@ void DWARFDebugFrame::parse(DataExtractor Data) { while (Data.isValidOffset(Offset)) { uint32_t StartOffset = Offset; - auto ReportError = [StartOffset](const char *ErrorMsg) { - std::string Str; - raw_string_ostream OS(Str); - OS << format(ErrorMsg, StartOffset); - OS.flush(); - report_fatal_error(Str); - }; - bool IsDWARF64 = false; uint64_t Length = Data.getU32(&Offset); uint64_t Id; @@ -585,7 +591,6 @@ void DWARFDebugFrame::parse(DataExtractor Data) { switch (AugmentationString[i]) { default: ReportError("Unknown augmentation character in entry at %lx"); - llvm_unreachable("ReportError should not return."); case 'L': LSDAPointerEncoding = Data.getU8(&Offset); break; diff --git a/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 8a544296f65c..a6240fb60143 100644 --- a/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -275,3 +276,36 @@ bool DWARFVerifier::handleDebugLine() { verifyDebugLineRows(); return NumDebugLineErrors == 0; } + +bool DWARFVerifier::handleAppleNames() { + NumAppleNamesErrors = 0; + OS << "Verifying .apple_names...\n"; + + DataExtractor AppleNamesSection(DCtx.getAppleNamesSection().Data, + DCtx.isLittleEndian(), 0); + DataExtractor StrData(DCtx.getStringSection(), DCtx.isLittleEndian(), 0); + DWARFAcceleratorTable AppleNames(AppleNamesSection, StrData, + DCtx.getAppleNamesSection().Relocs); + + if (!AppleNames.extract()) { + OS << "error: cannot extract .apple_names accelerator table\n"; + return false; + } + + // Verify that all buckets have a valid hash index or are empty + uint32_t NumBuckets = AppleNames.getNumBuckets(); + uint32_t NumHashes = AppleNames.getNumHashes(); + + uint32_t BucketsOffset = + AppleNames.getSizeHdr() + AppleNames.getHeaderDataLength(); + + for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) { + uint32_t HashIdx = AppleNamesSection.getU32(&BucketsOffset); + if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { + OS << format("error: Bucket[%d] has invalid hash index: [%d]\n", + BucketIdx, HashIdx); + ++NumAppleNamesErrors; + } + } + return NumAppleNamesErrors == 0; +} diff --git a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 396dffaa68b1..81a9d3eeec61 100644 --- a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -177,7 +177,7 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter, } void DbiModuleDescriptorBuilder::addDebugSubsection( - std::unique_ptr Subsection) { + std::shared_ptr Subsection) { assert(Subsection); C13Builders.push_back(llvm::make_unique( std::move(Subsection), CodeViewContainer::Pdb)); diff --git a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index 355c7b57f4d1..e7304b444f23 100644 --- a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -45,10 +45,6 @@ void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; } void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } -void DbiStreamBuilder::setSectionContribs(ArrayRef Arr) { - SectionContribs = Arr; -} - void DbiStreamBuilder::setSectionMap(ArrayRef SecMap) { SectionMap = SecMap; } @@ -293,23 +289,17 @@ static uint16_t toSecMapFlags(uint32_t Flags) { return Ret; } -// A utility function to create Section Contributions -// for a given input sections. -std::vector DbiStreamBuilder::createSectionContribs( - ArrayRef SecHdrs) { - std::vector Ret; - - // Create a SectionContrib for each input section. - for (auto &Sec : SecHdrs) { - Ret.emplace_back(); - auto &Entry = Ret.back(); - memset(&Entry, 0, sizeof(Entry)); - - Entry.Off = Sec.PointerToRawData; - Entry.Size = Sec.SizeOfRawData; - Entry.Characteristics = Sec.Characteristics; - } - return Ret; +void DbiStreamBuilder::addSectionContrib(DbiModuleDescriptorBuilder *ModuleDbi, + const object::coff_section *SecHdr) { + SectionContrib SC; + memset(&SC, 0, sizeof(SC)); + SC.ISect = (uint16_t)~0U; // This represents nil. + SC.Off = SecHdr->PointerToRawData; + SC.Size = SecHdr->SizeOfRawData; + SC.Characteristics = SecHdr->Characteristics; + // Use the module index in the module dbi stream or nil (-1). + SC.Imod = ModuleDbi ? ModuleDbi->getModuleIndex() : (uint16_t)~0U; + SectionContribs.emplace_back(SC); } // A utility function to create a Section Map for a given list of COFF sections. @@ -372,7 +362,7 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, if (!SectionContribs.empty()) { if (auto EC = Writer.writeEnum(DbiSecContribVer60)) return EC; - if (auto EC = Writer.writeArray(SectionContribs)) + if (auto EC = Writer.writeArray(makeArrayRef(SectionContribs))) return EC; } diff --git a/lib/DebugInfo/PDB/Native/InfoStream.cpp b/lib/DebugInfo/PDB/Native/InfoStream.cpp index 7c6069652da6..a3979d480bf4 100644 --- a/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ b/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -102,6 +102,10 @@ InfoStream::named_streams() const { return NamedStreams.entries(); } +bool InfoStream::containsIdStream() const { + return !!(Features & PdbFeatureContainsIdStream); +} + PdbRaw_ImplVer InfoStream::getVersion() const { return static_cast(Version); } diff --git a/lib/DebugInfo/PDB/Native/PDBFile.cpp b/lib/DebugInfo/PDB/Native/PDBFile.cpp index 1254e23c73eb..a9597cdf4c4d 100644 --- a/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -363,6 +363,16 @@ Expected PDBFile::getStringTable() { return *Strings; } +uint32_t PDBFile::getPointerSize() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return 0; + PDB_Machine Machine = DbiS->getMachineType(); + if (Machine == PDB_Machine::Amd64) + return 8; + return 4; +} + bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); } bool PDBFile::hasPDBGlobalsStream() { diff --git a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index 2c6465e6fb2a..12b0c3b36c1d 100644 --- a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -80,6 +80,16 @@ Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { } Expected PDBFileBuilder::finalizeMsfLayout() { + + if (Ipi && Ipi->getRecordCount() > 0) { + // In theory newer PDBs always have an ID stream, but by saying that we're + // only going to *really* have an ID stream if there is at least one ID + // record, we leave open the opportunity to test older PDBs such as those + // that don't have an ID stream. + auto &Info = getInfoBuilder(); + Info.addFeature(PdbRaw_FeatureSig::VC140); + } + uint32_t StringsLen = Strings.calculateSerializedSize(); if (auto EC = addNamedStream("/names", StringsLen)) diff --git a/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/lib/DebugInfo/PDB/Native/PDBStringTable.cpp index 6013c342cf02..f9f8ac219d35 100644 --- a/lib/DebugInfo/PDB/Native/PDBStringTable.cpp +++ b/lib/DebugInfo/PDB/Native/PDBStringTable.cpp @@ -56,7 +56,8 @@ Error PDBStringTable::readStrings(BinaryStreamReader &Reader) { return Error::success(); } -codeview::DebugStringTableSubsectionRef PDBStringTable::getStringTable() const { +const codeview::DebugStringTableSubsectionRef & +PDBStringTable::getStringTable() const { return Strings; } diff --git a/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp index a472181a4895..90acfadd311f 100644 --- a/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp @@ -52,6 +52,11 @@ uint32_t PDBStringTableBuilder::calculateSerializedSize() const { return Size; } +void PDBStringTableBuilder::setStrings( + const codeview::DebugStringTableSubsection &Strings) { + this->Strings = Strings; +} + Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const { // Write a header PDBStringTableHeader H; diff --git a/lib/DebugInfo/PDB/Native/PublicsStream.cpp b/lib/DebugInfo/PDB/Native/PublicsStream.cpp index 091ac67035dc..8f3474b9ce19 100644 --- a/lib/DebugInfo/PDB/Native/PublicsStream.cpp +++ b/lib/DebugInfo/PDB/Native/PublicsStream.cpp @@ -130,4 +130,13 @@ PublicsStream::getSymbols(bool *HadError) const { return SS.getSymbols(HadError); } +Expected +PublicsStream::getSymbolArray() const { + auto SymbolS = Pdb.getPDBSymbolStream(); + if (!SymbolS) + return SymbolS.takeError(); + + return SymbolS->getSymbolArray(); +} + Error PublicsStream::commit() { return Error::success(); } diff --git a/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/lib/DebugInfo/PDB/Native/TpiHashing.cpp index 16904a5a27ed..91b8d648fcf9 100644 --- a/lib/DebugInfo/PDB/Native/TpiHashing.cpp +++ b/lib/DebugInfo/PDB/Native/TpiHashing.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" diff --git a/lib/DebugInfo/PDB/UDTLayout.cpp b/lib/DebugInfo/PDB/UDTLayout.cpp index aacefae80c3a..da353cb6977c 100644 --- a/lib/DebugInfo/PDB/UDTLayout.cpp +++ b/lib/DebugInfo/PDB/UDTLayout.cpp @@ -181,13 +181,14 @@ void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { if (Data->getDataKind() == PDB_DataKind::Member) Members.push_back(std::move(Data)); else - Other.push_back(std::move(Child)); + Other.push_back(std::move(Data)); } else if (auto VT = unique_dyn_cast(Child)) VTables.push_back(std::move(VT)); else if (auto Func = unique_dyn_cast(Child)) Funcs.push_back(std::move(Func)); - else + else { Other.push_back(std::move(Child)); + } } // We don't want to have any re-allocations in the list of bases, so make diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp index 9aad3771784d..0453a7f443b5 100644 --- a/lib/Fuzzer/FuzzerDriver.cpp +++ b/lib/Fuzzer/FuzzerDriver.cpp @@ -553,12 +553,12 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); const size_t kMaxSaneLen = 1 << 20; - const size_t kMinDefaultLen = 64; + const size_t kMinDefaultLen = 4096; FuzzingOptions Options; Options.Verbosity = Flags.verbosity; Options.MaxLen = Flags.max_len; Options.ExperimentalLenControl = Flags.experimental_len_control; - if (Flags.experimental_len_control && Flags.max_len == 64) + if (Flags.experimental_len_control && Flags.max_len == kMinDefaultLen) Options.MaxLen = 1 << 20; Options.UnitTimeoutSec = Flags.timeout; Options.ErrorExitCode = Flags.error_exitcode; diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index f6083282ab61..fbf18357ede6 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -301,7 +301,9 @@ void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { this->MaxInputLen = MaxInputLen; this->MaxMutationLen = MaxInputLen; AllocateCurrentUnitData(); - Printf("INFO: -max_len is not provided, using %zd\n", MaxInputLen); + Printf("INFO: -max_len is not provided; " + "libFuzzer will not generate inputs larger than %zd bytes\n", + MaxInputLen); } void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { diff --git a/lib/Fuzzer/FuzzerTracePC.cpp b/lib/Fuzzer/FuzzerTracePC.cpp index ea93468ea0ed..6f5c7be41062 100644 --- a/lib/Fuzzer/FuzzerTracePC.cpp +++ b/lib/Fuzzer/FuzzerTracePC.cpp @@ -53,6 +53,17 @@ size_t TracePC::GetTotalPCCoverage() { return Res; } + +void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) { + if (Start == Stop) return; + if (NumModulesWithInline8bitCounters && + ModuleCounters[NumModulesWithInline8bitCounters-1].Start == Start) return; + assert(NumModulesWithInline8bitCounters < + sizeof(ModuleCounters) / sizeof(ModuleCounters[0])); + ModuleCounters[NumModulesWithInline8bitCounters++] = {Start, Stop}; + NumInline8bitCounters += Stop - Start; +} + void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) { if (Start == Stop || *Start) return; assert(NumModules < sizeof(Modules) / sizeof(Modules[0])); @@ -76,6 +87,13 @@ void TracePC::PrintModuleInfo() { for (size_t i = 0; i < NumModules; i++) Printf("[%p, %p), ", Modules[i].Start, Modules[i].Stop); Printf("\n"); + if (NumModulesWithInline8bitCounters) { + Printf("INFO: Loaded %zd modules with %zd inline 8-bit counters\n", + NumModulesWithInline8bitCounters, NumInline8bitCounters); + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) + Printf("[%p, %p), ", ModuleCounters[i].Start, ModuleCounters[i].Stop); + Printf("\n"); + } } ATTRIBUTE_NO_SANITIZE_ALL @@ -303,6 +321,11 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) { fuzzer::TPC.HandleInit(Start, Stop); } +ATTRIBUTE_INTERFACE +void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) { + fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop); +} + ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { diff --git a/lib/Fuzzer/FuzzerTracePC.h b/lib/Fuzzer/FuzzerTracePC.h index 6523fa06005c..5ec8c590b4df 100644 --- a/lib/Fuzzer/FuzzerTracePC.h +++ b/lib/Fuzzer/FuzzerTracePC.h @@ -51,7 +51,8 @@ class TracePC { // How many bits of PC are used from __sanitizer_cov_trace_pc. static const size_t kTracePcBits = 18; - void HandleInit(uint32_t *start, uint32_t *stop); + void HandleInit(uint32_t *Start, uint32_t *Stop); + void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop); void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); template void HandleCmp(uintptr_t PC, T Arg1, T Arg2); size_t GetTotalPCCoverage(); @@ -104,6 +105,10 @@ class TracePC { size_t NumModules; // linker-initialized. size_t NumGuards; // linker-initialized. + struct { uint8_t *Start, *Stop; } ModuleCounters[4096]; + size_t NumModulesWithInline8bitCounters; // linker-initialized. + size_t NumInline8bitCounters; + uint8_t *Counters() const; uintptr_t *PCs() const; @@ -118,12 +123,24 @@ void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End, size_t FirstFeature, Callback Handle8bitCounter) { typedef uintptr_t LargeType; const size_t Step = sizeof(LargeType) / sizeof(uint8_t); - assert(!(reinterpret_cast(Begin) % 64)); - for (auto P = Begin; P < End; P += Step) + const size_t StepMask = Step - 1; + auto P = Begin; + // Iterate by 1 byte until either the alignment boundary or the end. + for (; reinterpret_cast(P) & StepMask && P < End; P++) + if (uint8_t V = *P) + Handle8bitCounter(FirstFeature + P - Begin, V); + + // Iterate by Step bytes at a time. + for (; P < End; P += Step) if (LargeType Bundle = *reinterpret_cast(P)) for (size_t I = 0; I < Step; I++, Bundle >>= 8) if (uint8_t V = Bundle & 0xff) Handle8bitCounter(FirstFeature + P - Begin + I, V); + + // Iterate by 1 byte until the end. + for (; P < End; P++) + if (uint8_t V = *P) + Handle8bitCounter(FirstFeature + P - Begin, V); } template // bool Callback(size_t Feature) @@ -145,8 +162,16 @@ void TracePC::CollectFeatures(Callback HandleFeature) const { HandleFeature(Idx * 8 + Bit); }; - ForEachNonZeroByte(Counters, Counters + N, 0, Handle8bitCounter); - ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), N * 8, + size_t FirstFeature = 0; + ForEachNonZeroByte(Counters, Counters + N, FirstFeature, Handle8bitCounter); + FirstFeature += N * 8; + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { + ForEachNonZeroByte(ModuleCounters[i].Start, ModuleCounters[i].Stop, + FirstFeature, Handle8bitCounter); + FirstFeature += 8 * (ModuleCounters[i].Stop - ModuleCounters[i].Start); + } + + ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), FirstFeature, Handle8bitCounter); if (UseValueProfile) diff --git a/lib/Fuzzer/test/AbsNegAndConstant64Test.cpp b/lib/Fuzzer/test/AbsNegAndConstant64Test.cpp index dfb6007b7970..b5a61ddca715 100644 --- a/lib/Fuzzer/test/AbsNegAndConstant64Test.cpp +++ b/lib/Fuzzer/test/AbsNegAndConstant64Test.cpp @@ -9,7 +9,7 @@ #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 16) return 0; + if (Size < 16 || Size > 64) return 0; int64_t x; uint64_t y; memcpy(&x, Data, sizeof(x)); diff --git a/lib/Fuzzer/test/CMakeLists.txt b/lib/Fuzzer/test/CMakeLists.txt index b39938a705f6..1cf6c9502a2b 100644 --- a/lib/Fuzzer/test/CMakeLists.txt +++ b/lib/Fuzzer/test/CMakeLists.txt @@ -206,6 +206,9 @@ include_directories(..) add_subdirectory(no-coverage) add_subdirectory(trace-pc) add_subdirectory(ubsan) +if (NOT MSVC) + add_subdirectory(inline-8bit-counters) +endif() add_library(LLVMFuzzer-DSO1 SHARED DSO1.cpp) add_library(LLVMFuzzer-DSO2 SHARED DSO2.cpp) diff --git a/lib/Fuzzer/test/FourIndependentBranchesTest.cpp b/lib/Fuzzer/test/FourIndependentBranchesTest.cpp index bbf5ea235c7a..ba963d9b1de8 100644 --- a/lib/Fuzzer/test/FourIndependentBranchesTest.cpp +++ b/lib/Fuzzer/test/FourIndependentBranchesTest.cpp @@ -8,6 +8,7 @@ #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 64) return 0; int bits = 0; if (Size > 0 && Data[0] == 'F') bits |= 1; if (Size > 1 && Data[1] == 'U') bits |= 2; diff --git a/lib/Fuzzer/test/FuzzerUnittest.cpp b/lib/Fuzzer/test/FuzzerUnittest.cpp index c8beb4331bfa..812894fd947f 100644 --- a/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -772,4 +772,16 @@ TEST(Fuzzer, ForEachNonZeroByte) { Expected = {{108, 1}, {109, 2}, {118, 3}, {120, 4}, {135, 5}, {137, 6}, {146, 7}, {163, 8}}; EXPECT_EQ(Res, Expected); + + Res.clear(); + ForEachNonZeroByte(Ar + 9, Ar + N, 109, CB); + Expected = { {109, 2}, {118, 3}, {120, 4}, + {135, 5}, {137, 6}, {146, 7}, {163, 8}}; + EXPECT_EQ(Res, Expected); + + Res.clear(); + ForEachNonZeroByte(Ar + 9, Ar + N - 9, 109, CB); + Expected = { {109, 2}, {118, 3}, {120, 4}, + {135, 5}, {137, 6}, {146, 7}}; + EXPECT_EQ(Res, Expected); } diff --git a/lib/Fuzzer/test/ShrinkControlFlowTest.cpp b/lib/Fuzzer/test/ShrinkControlFlowTest.cpp index d09542963626..37eeede7cbff 100644 --- a/lib/Fuzzer/test/ShrinkControlFlowTest.cpp +++ b/lib/Fuzzer/test/ShrinkControlFlowTest.cpp @@ -11,6 +11,7 @@ static volatile int Sink; extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 64) return 0; int8_t Ids[256]; memset(Ids, -1, sizeof(Ids)); for (size_t i = 0; i < Size; i++) diff --git a/lib/Fuzzer/test/SimpleHashTest.cpp b/lib/Fuzzer/test/SimpleHashTest.cpp index 99e96cb25dcd..a3f4211ebeef 100644 --- a/lib/Fuzzer/test/SimpleHashTest.cpp +++ b/lib/Fuzzer/test/SimpleHashTest.cpp @@ -26,7 +26,7 @@ static uint32_t simple_hash(const uint8_t *Data, size_t Size) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 14) + if (Size < 14 || Size > 64) return 0; uint32_t Hash = simple_hash(&Data[0], Size - 4); diff --git a/lib/Fuzzer/test/SingleStrncmpTest.cpp b/lib/Fuzzer/test/SingleStrncmpTest.cpp index b302670fb743..b38c7995d8ff 100644 --- a/lib/Fuzzer/test/SingleStrncmpTest.cpp +++ b/lib/Fuzzer/test/SingleStrncmpTest.cpp @@ -8,6 +8,7 @@ #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 64) return 0; char *S = (char*)Data; volatile auto Strncmp = &(strncmp); // Make sure strncmp is not inlined. if (Size >= 6 && !Strncmp(S, "qwerty", 6)) { diff --git a/lib/Fuzzer/test/TableLookupTest.cpp b/lib/Fuzzer/test/TableLookupTest.cpp index 8126eeabaf42..4d8ab0611cde 100644 --- a/lib/Fuzzer/test/TableLookupTest.cpp +++ b/lib/Fuzzer/test/TableLookupTest.cpp @@ -15,7 +15,6 @@ const size_t N = 1 << 12; // Define an array of counters that will be understood by libFuzzer // as extra coverage signal. The array must be: // * uint8_t -// * aligned by 64 // * in the section named __libfuzzer_extra_counters. // The target code may declare more than one such array. // @@ -23,7 +22,7 @@ const size_t N = 1 << 12; // depending on whether multiple occurrences of the event 'Idx' // is important to distinguish from one occurrence. #ifdef __linux__ -alignas(64) __attribute__((section("__libfuzzer_extra_counters"))) +__attribute__((section("__libfuzzer_extra_counters"))) #endif static uint8_t Counters[N]; diff --git a/lib/Fuzzer/test/fuzzer-dirs.test b/lib/Fuzzer/test/fuzzer-dirs.test index 3de64f278f5d..622ff5da3a29 100644 --- a/lib/Fuzzer/test/fuzzer-dirs.test +++ b/lib/Fuzzer/test/fuzzer-dirs.test @@ -5,9 +5,13 @@ RUN: echo b > %t/SUB1/SUB2/b RUN: echo c > %t/SUB1/SUB2/SUB3/c RUN: LLVMFuzzer-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=SUBDIRS SUBDIRS: READ units: 3 -RUN: echo -n zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz > %t/SUB1/long +RUN: echo -n zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz > %t/SUB1/f64 +RUN: cat %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 > %t/SUB1/f256 +RUN: cat %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 > %t/SUB1/f1024 +RUN: cat %t/SUB1/f1024 %t/SUB1/f1024 %t/SUB1/f1024 %t/SUB1/f1024 > %t/SUB1/f4096 +RUN: cat %t/SUB1/f4096 %t/SUB1/f4096 > %t/SUB1/f8192 RUN: LLVMFuzzer-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=LONG -LONG: INFO: -max_len is not provided, using 93 +LONG: INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 8192 bytes RUN: rm -rf %t/SUB1 RUN: not LLVMFuzzer-SimpleTest NONEXISTENT_DIR 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR diff --git a/lib/Fuzzer/test/inline-8bit-counters.test b/lib/Fuzzer/test/inline-8bit-counters.test new file mode 100644 index 000000000000..8747af81451f --- /dev/null +++ b/lib/Fuzzer/test/inline-8bit-counters.test @@ -0,0 +1,4 @@ +REQUIRES: linux +CHECK: INFO: Loaded 1 modules with {{.*}} inline 8-bit counters +CHECK: BINGO +RUN: LLVMFuzzer-SimpleTest-Inline8bitCounters -runs=1000000 -seed=1 2>&1 | FileCheck %s diff --git a/lib/Fuzzer/test/inline-8bit-counters/CMakeLists.txt b/lib/Fuzzer/test/inline-8bit-counters/CMakeLists.txt new file mode 100644 index 000000000000..088ab04fe6a0 --- /dev/null +++ b/lib/Fuzzer/test/inline-8bit-counters/CMakeLists.txt @@ -0,0 +1,12 @@ +# These tests are instrumented with -fsanitize-coverage=inline-8bit-counters + +set(CMAKE_CXX_FLAGS + "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=trace-pc-guard -fsanitize-coverage=inline-8bit-counters") + +set(Inline8bitCounterTests + SimpleTest + ) + +foreach(Test ${Inline8bitCounterTests}) + add_libfuzzer_test(${Test}-Inline8bitCounters SOURCES ../${Test}.cpp) +endforeach() diff --git a/lib/Fuzzer/test/trace-pc/CMakeLists.txt b/lib/Fuzzer/test/trace-pc/CMakeLists.txt index e800f82cc5dc..572fcc983654 100644 --- a/lib/Fuzzer/test/trace-pc/CMakeLists.txt +++ b/lib/Fuzzer/test/trace-pc/CMakeLists.txt @@ -1,5 +1,4 @@ -# These tests are not instrumented with coverage and don't -# have coverage rt in the binary. +# These tests are instrumented with -fsanitize-coverage=trace-pc set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard -fsanitize-coverage=trace-pc") diff --git a/lib/IR/ConstantFold.cpp b/lib/IR/ConstantFold.cpp index a20f3f811c8d..3469026ad7ed 100644 --- a/lib/IR/ConstantFold.cpp +++ b/lib/IR/ConstantFold.cpp @@ -348,8 +348,7 @@ static Constant *ExtractConstantBytes(Constant *C, unsigned ByteStart, /// factors factored out. If Folded is false, return null if no factoring was /// possible, to avoid endlessly bouncing an unfoldable expression back into the /// top-level folder. -static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, - bool Folded) { +static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded) { if (ArrayType *ATy = dyn_cast(Ty)) { Constant *N = ConstantInt::get(DestTy, ATy->getNumElements()); Constant *E = getFoldedSizeOf(ATy->getElementType(), DestTy, true); @@ -404,8 +403,7 @@ static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, /// factors factored out. If Folded is false, return null if no factoring was /// possible, to avoid endlessly bouncing an unfoldable expression back into the /// top-level folder. -static Constant *getFoldedAlignOf(Type *Ty, Type *DestTy, - bool Folded) { +static Constant *getFoldedAlignOf(Type *Ty, Type *DestTy, bool Folded) { // The alignment of an array is equal to the alignment of the // array element. Note that this is not always true for vectors. if (ArrayType *ATy = dyn_cast(Ty)) { @@ -469,8 +467,7 @@ static Constant *getFoldedAlignOf(Type *Ty, Type *DestTy, /// any known factors factored out. If Folded is false, return null if no /// factoring was possible, to avoid endlessly bouncing an unfoldable expression /// back into the top-level folder. -static Constant *getFoldedOffsetOf(Type *Ty, Constant *FieldNo, - Type *DestTy, +static Constant *getFoldedOffsetOf(Type *Ty, Constant *FieldNo, Type *DestTy, bool Folded) { if (ArrayType *ATy = dyn_cast(Ty)) { Constant *N = ConstantExpr::getCast(CastInst::getCastOpcode(FieldNo, false, diff --git a/lib/IR/ConstantsContext.h b/lib/IR/ConstantsContext.h index 6c189cf656de..6585304e7674 100644 --- a/lib/IR/ConstantsContext.h +++ b/lib/IR/ConstantsContext.h @@ -55,8 +55,6 @@ class UnaryConstantExpr : public ConstantExpr { return User::operator new(s, 1); } - void *operator new(size_t, unsigned) = delete; - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; @@ -77,8 +75,6 @@ class BinaryConstantExpr : public ConstantExpr { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; @@ -99,8 +95,6 @@ class SelectConstantExpr : public ConstantExpr { return User::operator new(s, 3); } - void *operator new(size_t, unsigned) = delete; - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; @@ -122,8 +116,6 @@ class ExtractElementConstantExpr : public ConstantExpr { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; @@ -146,8 +138,6 @@ class InsertElementConstantExpr : public ConstantExpr { return User::operator new(s, 3); } - void *operator new(size_t, unsigned) = delete; - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; @@ -173,8 +163,6 @@ class ShuffleVectorConstantExpr : public ConstantExpr { return User::operator new(s, 3); } - void *operator new(size_t, unsigned) = delete; - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); }; @@ -196,8 +184,6 @@ class ExtractValueConstantExpr : public ConstantExpr { return User::operator new(s, 1); } - void *operator new(size_t, unsigned) = delete; - /// Indices - These identify which value to extract. const SmallVector Indices; @@ -230,8 +216,6 @@ class InsertValueConstantExpr : public ConstantExpr { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - /// Indices - These identify the position for the insertion. const SmallVector Indices; @@ -297,8 +281,6 @@ class CompareConstantExpr : public ConstantExpr { return User::operator new(s, 2); } - void *operator new(size_t, unsigned) = delete; - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); diff --git a/lib/IR/DebugInfoMetadata.cpp b/lib/IR/DebugInfoMetadata.cpp index e6c49cad0722..0bf68b4c53bb 100644 --- a/lib/IR/DebugInfoMetadata.cpp +++ b/lib/IR/DebugInfoMetadata.cpp @@ -598,8 +598,7 @@ unsigned DIExpression::ExprOperand::getSize() const { case dwarf::DW_OP_LLVM_fragment: return 3; case dwarf::DW_OP_constu: - case dwarf::DW_OP_plus: - case dwarf::DW_OP_minus: + case dwarf::DW_OP_plus_uconst: return 2; default: return 1; @@ -641,6 +640,7 @@ bool DIExpression::isValid() const { break; } case dwarf::DW_OP_constu: + case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus: case dwarf::DW_OP_minus: case dwarf::DW_OP_deref: @@ -664,11 +664,12 @@ DIExpression::getFragmentInfo(expr_op_iterator Start, expr_op_iterator End) { void DIExpression::appendOffset(SmallVectorImpl &Ops, int64_t Offset) { if (Offset > 0) { - Ops.push_back(dwarf::DW_OP_plus); + Ops.push_back(dwarf::DW_OP_plus_uconst); Ops.push_back(Offset); } else if (Offset < 0) { - Ops.push_back(dwarf::DW_OP_minus); + Ops.push_back(dwarf::DW_OP_constu); Ops.push_back(-Offset); + Ops.push_back(dwarf::DW_OP_minus); } } @@ -677,16 +678,23 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const { Offset = 0; return true; } - if (getNumElements() != 2) - return false; - if (Elements[0] == dwarf::DW_OP_plus) { + + if (getNumElements() == 2 && Elements[0] == dwarf::DW_OP_plus_uconst) { Offset = Elements[1]; return true; } - if (Elements[0] == dwarf::DW_OP_minus) { - Offset = -Elements[1]; - return true; + + if (getNumElements() == 3 && Elements[0] == dwarf::DW_OP_constu) { + if (Elements[2] == dwarf::DW_OP_plus) { + Offset = Elements[1]; + return true; + } + if (Elements[2] == dwarf::DW_OP_minus) { + Offset = -Elements[1]; + return true; + } } + return false; } diff --git a/lib/IR/IRBuilder.cpp b/lib/IR/IRBuilder.cpp index 81b02946e1d5..b7fa07c6ffac 100644 --- a/lib/IR/IRBuilder.cpp +++ b/lib/IR/IRBuilder.cpp @@ -134,18 +134,17 @@ CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align, return CI; } -CallInst *IRBuilderBase::CreateElementAtomicMemCpy( - Value *Dst, Value *Src, Value *NumElements, uint32_t ElementSize, - MDNode *TBAATag, MDNode *TBAAStructTag, MDNode *ScopeTag, - MDNode *NoAliasTag) { +CallInst *IRBuilderBase::CreateElementUnorderedAtomicMemCpy( + Value *Dst, Value *Src, Value *Size, uint32_t ElementSize, MDNode *TBAATag, + MDNode *TBAAStructTag, MDNode *ScopeTag, MDNode *NoAliasTag) { Dst = getCastedInt8PtrValue(Dst); Src = getCastedInt8PtrValue(Src); - Value *Ops[] = {Dst, Src, NumElements, getInt32(ElementSize)}; - Type *Tys[] = {Dst->getType(), Src->getType()}; + Value *Ops[] = {Dst, Src, Size, getInt32(ElementSize)}; + Type *Tys[] = {Dst->getType(), Src->getType(), Size->getType()}; Module *M = BB->getParent()->getParent(); - Value *TheFn = - Intrinsic::getDeclaration(M, Intrinsic::memcpy_element_atomic, Tys); + Value *TheFn = Intrinsic::getDeclaration( + M, Intrinsic::memcpy_element_unordered_atomic, Tys); CallInst *CI = createCallHelper(TheFn, Ops, this); diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index 0b1bc9a8c270..92e5798dcf21 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -1470,7 +1470,7 @@ void GlobalObject::copyMetadata(const GlobalObject *Other, unsigned Offset) { if (E) OrigElements = E->getElements(); std::vector Elements(OrigElements.size() + 2); - Elements[0] = dwarf::DW_OP_plus; + Elements[0] = dwarf::DW_OP_plus_uconst; Elements[1] = Offset; std::copy(OrigElements.begin(), OrigElements.end(), Elements.begin() + 2); E = DIExpression::get(getContext(), Elements); diff --git a/lib/IR/ModuleSummaryIndex.cpp b/lib/IR/ModuleSummaryIndex.cpp index 9dd712f9ca13..51c4bae3332e 100644 --- a/lib/IR/ModuleSummaryIndex.cpp +++ b/lib/IR/ModuleSummaryIndex.cpp @@ -56,3 +56,16 @@ ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID, auto &Summary = VI.getSummaryList()[0]; return Summary.get(); } + +bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const { + auto VI = getValueInfo(GUID); + if (!VI) + return true; + const auto &SummaryList = VI.getSummaryList(); + if (SummaryList.empty()) + return true; + for (auto &I : SummaryList) + if (isGlobalValueLive(I.get())) + return true; + return false; +} diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 5c1b3412840d..819f63520c74 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -1330,6 +1330,14 @@ Verifier::visitModuleFlag(const MDNode *Op, = mdconst::dyn_extract_or_null(Op->getOperand(2)); Assert(Value, "wchar_size metadata requires constant integer argument"); } + + if (ID->getString() == "Linker Options") { + // If the llvm.linker.options named metadata exists, we assume that the + // bitcode reader has upgraded the module flag. Otherwise the flag might + // have been created by a client directly. + Assert(M.getNamedMetadata("llvm.linker.options"), + "'Linker Options' named metadata no longer supported"); + } } /// Return true if this attribute kind only applies to functions. @@ -4004,10 +4012,16 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { CS); break; } - case Intrinsic::memcpy_element_atomic: { - ConstantInt *ElementSizeCI = dyn_cast(CS.getArgOperand(3)); - Assert(ElementSizeCI, "element size of the element-wise atomic memory " - "intrinsic must be a constant int", + case Intrinsic::memcpy_element_unordered_atomic: { + const ElementUnorderedAtomicMemCpyInst *MI = + cast(CS.getInstruction()); + ; + + ConstantInt *ElementSizeCI = + dyn_cast(MI->getRawElementSizeInBytes()); + Assert(ElementSizeCI, + "element size of the element-wise unordered atomic memory " + "intrinsic must be a constant int", CS); const APInt &ElementSizeVal = ElementSizeCI->getValue(); Assert(ElementSizeVal.isPowerOf2(), @@ -4015,19 +4029,24 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { "must be a power of 2", CS); + if (auto *LengthCI = dyn_cast(MI->getLength())) { + uint64_t Length = LengthCI->getZExtValue(); + uint64_t ElementSize = MI->getElementSizeInBytes(); + Assert((Length % ElementSize) == 0, + "constant length must be a multiple of the element size in the " + "element-wise atomic memory intrinsic", + CS); + } + auto IsValidAlignment = [&](uint64_t Alignment) { return isPowerOf2_64(Alignment) && ElementSizeVal.ule(Alignment); }; - uint64_t DstAlignment = CS.getParamAlignment(0), SrcAlignment = CS.getParamAlignment(1); - Assert(IsValidAlignment(DstAlignment), - "incorrect alignment of the destination argument", - CS); + "incorrect alignment of the destination argument", CS); Assert(IsValidAlignment(SrcAlignment), - "incorrect alignment of the source argument", - CS); + "incorrect alignment of the source argument", CS); break; } case Intrinsic::gcroot: diff --git a/lib/LLVMBuild.txt b/lib/LLVMBuild.txt index 9e586465025e..1d22c2a11f13 100644 --- a/lib/LLVMBuild.txt +++ b/lib/LLVMBuild.txt @@ -39,6 +39,7 @@ subdirectories = Support TableGen Target + Testing ToolDrivers Transforms diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index 9d2a44045d6a..35032fdd33e1 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -364,31 +364,40 @@ LTO::LTO(Config Conf, ThinBackend Backend, // Requires a destructor for MapVector. LTO::~LTO() = default; -// Add the given symbol to the GlobalResolutions map, and resolve its partition. -void LTO::addSymbolToGlobalRes(const InputFile::Symbol &Sym, - SymbolResolution Res, unsigned Partition) { - auto &GlobalRes = GlobalResolutions[Sym.getName()]; - GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr(); - if (Res.Prevailing) - GlobalRes.IRName = Sym.getIRName(); +// Add the symbols in the given module to the GlobalResolutions map, and resolve +// their partitions. +void LTO::addModuleToGlobalRes(ArrayRef Syms, + ArrayRef Res, + unsigned Partition, bool InSummary) { + auto *ResI = Res.begin(); + auto *ResE = Res.end(); + (void)ResE; + for (const InputFile::Symbol &Sym : Syms) { + assert(ResI != ResE); + SymbolResolution Res = *ResI++; - // Set the partition to external if we know it is re-defined by the linker - // with -defsym or -wrap options, used elsewhere, e.g. it is visible to a - // regular object, is referenced from llvm.compiler_used, or was already - // recorded as being referenced from a different partition. - if (Res.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() || - (GlobalRes.Partition != GlobalResolution::Unknown && - GlobalRes.Partition != Partition)) { - GlobalRes.Partition = GlobalResolution::External; - } else - // First recorded reference, save the current partition. - GlobalRes.Partition = Partition; + auto &GlobalRes = GlobalResolutions[Sym.getName()]; + GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr(); + if (Res.Prevailing) + GlobalRes.IRName = Sym.getIRName(); - // Flag as visible outside of ThinLTO if visible from a regular object or - // if this is a reference in the regular LTO partition. - GlobalRes.VisibleOutsideThinLTO |= - (Res.VisibleToRegularObj || Sym.isUsed() || - Partition == GlobalResolution::RegularLTO); + // Set the partition to external if we know it is re-defined by the linker + // with -defsym or -wrap options, used elsewhere, e.g. it is visible to a + // regular object, is referenced from llvm.compiler_used, or was already + // recorded as being referenced from a different partition. + if (Res.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() || + (GlobalRes.Partition != GlobalResolution::Unknown && + GlobalRes.Partition != Partition)) { + GlobalRes.Partition = GlobalResolution::External; + } else + // First recorded reference, save the current partition. + GlobalRes.Partition = Partition; + + // Flag as visible outside of summary if visible from a regular object or + // from a module that does not have a summary. + GlobalRes.VisibleOutsideSummary |= + (Res.VisibleToRegularObj || Sym.isUsed() || !InSummary); + } } static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, @@ -434,46 +443,61 @@ Error LTO::add(std::unique_ptr Input, Error LTO::addModule(InputFile &Input, unsigned ModI, const SymbolResolution *&ResI, const SymbolResolution *ResE) { - Expected HasThinLTOSummary = Input.Mods[ModI].hasSummary(); - if (!HasThinLTOSummary) - return HasThinLTOSummary.takeError(); + Expected LTOInfo = Input.Mods[ModI].getLTOInfo(); + if (!LTOInfo) + return LTOInfo.takeError(); + BitcodeModule BM = Input.Mods[ModI]; auto ModSyms = Input.module_symbols(ModI); - if (*HasThinLTOSummary) - return addThinLTO(Input.Mods[ModI], ModSyms, ResI, ResE); - else - return addRegularLTO(Input.Mods[ModI], ModSyms, ResI, ResE); + addModuleToGlobalRes(ModSyms, {ResI, ResE}, + LTOInfo->IsThinLTO ? ThinLTO.ModuleMap.size() + 1 : 0, + LTOInfo->HasSummary); + + if (LTOInfo->IsThinLTO) + return addThinLTO(BM, ModSyms, ResI, ResE); + + Expected ModOrErr = + addRegularLTO(BM, ModSyms, ResI, ResE); + if (!ModOrErr) + return ModOrErr.takeError(); + + if (!LTOInfo->HasSummary) + return linkRegularLTO(std::move(*ModOrErr), /*LivenessFromIndex=*/false); + + // Regular LTO module summaries are added to a dummy module that represents + // the combined regular LTO module. + if (Error Err = BM.readSummary(ThinLTO.CombinedIndex, "", -1ull)) + return Err; + RegularLTO.ModsWithSummaries.push_back(std::move(*ModOrErr)); + return Error::success(); } // Add a regular LTO object to the link. -Error LTO::addRegularLTO(BitcodeModule BM, - ArrayRef Syms, - const SymbolResolution *&ResI, - const SymbolResolution *ResE) { - if (!RegularLTO.CombinedModule) { - RegularLTO.CombinedModule = - llvm::make_unique("ld-temp.o", RegularLTO.Ctx); - RegularLTO.Mover = llvm::make_unique(*RegularLTO.CombinedModule); - } +// The resulting module needs to be linked into the combined LTO module with +// linkRegularLTO. +Expected +LTO::addRegularLTO(BitcodeModule BM, ArrayRef Syms, + const SymbolResolution *&ResI, + const SymbolResolution *ResE) { + RegularLTOState::AddedModule Mod; Expected> MOrErr = BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true, /*IsImporting*/ false); if (!MOrErr) return MOrErr.takeError(); - Module &M = **MOrErr; + Mod.M = std::move(*MOrErr); + if (Error Err = M.materializeMetadata()) - return Err; + return std::move(Err); UpgradeDebugInfo(M); ModuleSymbolTable SymTab; SymTab.addModule(&M); - std::vector Keep; - for (GlobalVariable &GV : M.globals()) if (GV.hasAppendingLinkage()) - Keep.push_back(&GV); + Mod.Keep.push_back(&GV); DenseSet AliasedGlobals; for (auto &GA : M.aliases()) @@ -502,7 +526,6 @@ Error LTO::addRegularLTO(BitcodeModule BM, for (const InputFile::Symbol &Sym : Syms) { assert(ResI != ResE); SymbolResolution Res = *ResI++; - addSymbolToGlobalRes(Sym, Res, 0); assert(MsymI != MsymE); ModuleSymbolTable::Symbol Msym = *MsymI++; @@ -512,7 +535,7 @@ Error LTO::addRegularLTO(BitcodeModule BM, if (Res.Prevailing) { if (Sym.isUndefined()) continue; - Keep.push_back(GV); + Mod.Keep.push_back(GV); // For symbols re-defined with linker -wrap and -defsym options, // set the linkage to weak to inhibit IPO. The linkage will be // restored by the linker. @@ -527,17 +550,14 @@ Error LTO::addRegularLTO(BitcodeModule BM, (GV->hasLinkOnceODRLinkage() || GV->hasWeakODRLinkage() || GV->hasAvailableExternallyLinkage()) && !AliasedGlobals.count(cast(GV))) { - // Either of the above three types of linkage indicates that the + // Any of the above three types of linkage indicates that the // chosen prevailing symbol will have the same semantics as this copy of - // the symbol, so we can link it with available_externally linkage. We - // only need to do this if the symbol is undefined. - GlobalValue *CombinedGV = - RegularLTO.CombinedModule->getNamedValue(GV->getName()); - if (!CombinedGV || CombinedGV->isDeclaration()) { - Keep.push_back(GV); - GV->setLinkage(GlobalValue::AvailableExternallyLinkage); - cast(GV)->setComdat(nullptr); - } + // the symbol, so we may be able to link it with available_externally + // linkage. We will decide later whether to do that when we link this + // module (in linkRegularLTO), based on whether it is undefined. + Mod.Keep.push_back(GV); + GV->setLinkage(GlobalValue::AvailableExternallyLinkage); + cast(GV)->setComdat(nullptr); } } // Common resolution: collect the maximum size/alignment over all commons. @@ -555,25 +575,54 @@ Error LTO::addRegularLTO(BitcodeModule BM, // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit. } assert(MsymI == MsymE); + return std::move(Mod); +} - return RegularLTO.Mover->move(std::move(*MOrErr), Keep, +Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod, + bool LivenessFromIndex) { + if (!RegularLTO.CombinedModule) { + RegularLTO.CombinedModule = + llvm::make_unique("ld-temp.o", RegularLTO.Ctx); + RegularLTO.Mover = llvm::make_unique(*RegularLTO.CombinedModule); + } + + std::vector Keep; + for (GlobalValue *GV : Mod.Keep) { + if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) + continue; + + if (!GV->hasAvailableExternallyLinkage()) { + Keep.push_back(GV); + continue; + } + + // Only link available_externally definitions if we don't already have a + // definition. + GlobalValue *CombinedGV = + RegularLTO.CombinedModule->getNamedValue(GV->getName()); + if (CombinedGV && !CombinedGV->isDeclaration()) + continue; + + Keep.push_back(GV); + } + + return RegularLTO.Mover->move(std::move(Mod.M), Keep, [](GlobalValue &, IRMover::ValueAdder) {}, /* IsPerformingImport */ false); } -// Add a ThinLTO object to the link. -Error LTO::addThinLTO(BitcodeModule BM, - ArrayRef Syms, +// Add a ThinLTO module to the link. +Error LTO::addThinLTO(BitcodeModule BM, ArrayRef Syms, const SymbolResolution *&ResI, const SymbolResolution *ResE) { if (Error Err = - BM.readSummary(ThinLTO.CombinedIndex, ThinLTO.ModuleMap.size())) + BM.readSummary(ThinLTO.CombinedIndex, BM.getModuleIdentifier(), + ThinLTO.ModuleMap.size())) return Err; for (const InputFile::Symbol &Sym : Syms) { assert(ResI != ResE); SymbolResolution Res = *ResI++; - addSymbolToGlobalRes(Sym, Res, ThinLTO.ModuleMap.size() + 1); if (Res.Prevailing) { if (!Sym.getIRName().empty()) { @@ -601,7 +650,7 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { // Compute "dead" symbols, we don't want to import/export these! DenseSet GUIDPreservedSymbols; for (auto &Res : GlobalResolutions) { - if (Res.second.VisibleOutsideThinLTO && + if (Res.second.VisibleOutsideSummary && // IRName will be defined if we have seen the prevailing copy of // this value. If not, no need to preserve any ThinLTO copies. !Res.second.IRName.empty()) @@ -614,7 +663,8 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { // Save the status of having a regularLTO combined module, as // this is needed for generating the ThinLTO Task ID, and // the CombinedModule will be moved at the end of runRegularLTO. - bool HasRegularLTO = RegularLTO.CombinedModule != nullptr; + bool HasRegularLTO = RegularLTO.CombinedModule != nullptr || + !RegularLTO.ModsWithSummaries.empty(); // Invoke regular LTO if there was a regular LTO module to start with. if (HasRegularLTO) if (auto E = runRegularLTO(AddStream)) @@ -623,6 +673,11 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { } Error LTO::runRegularLTO(AddStreamFn AddStream) { + for (auto &M : RegularLTO.ModsWithSummaries) + if (Error Err = linkRegularLTO(std::move(M), + /*LivenessFromIndex=*/true)) + return Err; + // Make sure commons have the right size/alignment: we kept the largest from // all the prevailing when adding the inputs, and we apply it here. const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout(); @@ -920,17 +975,6 @@ ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix, }; } -static bool IsLiveByGUID(const ModuleSummaryIndex &Index, - GlobalValue::GUID GUID) { - auto VI = Index.getValueInfo(GUID); - if (!VI) - return false; - for (auto &I : VI.getSummaryList()) - if (Index.isGlobalValueLive(I.get())) - return true; - return false; -} - Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, bool HasRegularLTO) { if (ThinLTO.ModuleMap.empty()) @@ -979,7 +1023,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, auto GUID = GlobalValue::getGUID( GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); // Mark exported unless index-based analysis determined it to be dead. - if (IsLiveByGUID(ThinLTO.CombinedIndex, GUID)) + if (ThinLTO.CombinedIndex.isGUIDLive(GUID)) ExportedGUIDs.insert(GUID); } diff --git a/lib/LTO/LTOModule.cpp b/lib/LTO/LTOModule.cpp index 11f0982c6a60..3cc8b7d0e770 100644 --- a/lib/LTO/LTOModule.cpp +++ b/lib/LTO/LTOModule.cpp @@ -77,14 +77,12 @@ bool LTOModule::isBitcodeFile(StringRef Path) { } bool LTOModule::isThinLTO() { - // Right now the detection is only based on the summary presence. We may want - // to add a dedicated flag at some point. - Expected Result = hasGlobalValueSummary(MBRef); + Expected Result = getBitcodeLTOInfo(MBRef); if (!Result) { logAllUnhandledErrors(Result.takeError(), errs(), ""); return false; } - return *Result; + return Result->IsThinLTO; } bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer, @@ -637,10 +635,10 @@ void LTOModule::parseMetadata() { raw_string_ostream OS(LinkerOpts); // Linker Options - if (Metadata *Val = getModule().getModuleFlag("Linker Options")) { - MDNode *LinkerOptions = cast(Val); + if (NamedMDNode *LinkerOptions = + getModule().getNamedMetadata("llvm.linker.options")) { for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) { - MDNode *MDOptions = cast(LinkerOptions->getOperand(i)); + MDNode *MDOptions = LinkerOptions->getOperand(i); for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) { MDString *MDOption = cast(MDOptions->getOperand(ii)); OS << " " << MDOption->getString(); diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index f1dfb91aafbb..a407691b0bd1 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -603,6 +603,8 @@ bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { Type = ELF::SHT_NOTE; else if (TypeName == "unwind") Type = ELF::SHT_X86_64_UNWIND; + else if (TypeName == "llvm_odrtab") + Type = ELF::SHT_LLVM_ODRTAB; else if (TypeName.getAsInteger(0, Type)) return TokError("unknown section type"); } diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp index a75068ebf05a..2f4f61aa4d50 100644 --- a/lib/MC/MCSectionELF.cpp +++ b/lib/MC/MCSectionELF.cpp @@ -147,6 +147,8 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, // Print hex value of the flag while we do not have // any standard symbolic representation of the flag. OS << "0x7000001e"; + else if (Type == ELF::SHT_LLVM_ODRTAB) + OS << "llvm_odrtab"; else report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) + " for section " + getSectionName()); diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index 4b3dc6e0c211..db304c027f99 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -181,7 +181,10 @@ class WasmObjectWriter : public MCObjectWriter { // Index values to use for fixing up call_indirect type indices. // Maps function symbols to the index of the type of the function DenseMap TypeIndices; - + // Maps function symbols to the table element index space. Used + // for TABLE_INDEX relocation types (i.e. address taken functions). + DenseMap IndirectSymbolIndices; + // Maps function/global symbols to the function/global index space. DenseMap SymbolIndices; DenseMap @@ -189,9 +192,8 @@ class WasmObjectWriter : public MCObjectWriter { // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } - unsigned getRelocType(MCContext &Ctx, const MCValue &Target, - const MCFixup &Fixup, bool IsPCRel) const { - return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); + unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const { + return TargetObjectWriter->getRelocType(Target, Fixup); } void startSection(SectionBookkeeping &Section, unsigned SectionId, @@ -210,6 +212,7 @@ class WasmObjectWriter : public MCObjectWriter { DataRelocations.clear(); TypeIndices.clear(); SymbolIndices.clear(); + IndirectSymbolIndices.clear(); FunctionTypeIndices.clear(); MCObjectWriter::reset(); } @@ -233,7 +236,7 @@ class WasmObjectWriter : public MCObjectWriter { void writeTypeSection(const SmallVector &FunctionTypes); void writeImportSection(const SmallVector &Imports); void writeFunctionSection(const SmallVector &Functions); - void writeTableSection(const SmallVector &TableElems); + void writeTableSection(uint32_t NumElements); void writeMemorySection(const SmallVector &DataBytes); void writeGlobalSection(const SmallVector &Globals); void writeExportSection(const SmallVector &Exports); @@ -402,7 +405,9 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, SymA->setUsedInReloc(); } - unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel); + assert(!IsPCRel); + unsigned Type = getRelocType(Target, Fixup); + WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); if (FixupSection.hasInstructions()) @@ -464,9 +469,11 @@ static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) { uint32_t WasmObjectWriter::getRelocationIndexValue( const WasmRelocationEntry &RelEntry) { switch (RelEntry.Type) { - case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + assert(IndirectSymbolIndices.count(RelEntry.Symbol)); + return IndirectSymbolIndices[RelEntry.Symbol]; + case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: @@ -617,21 +624,19 @@ void WasmObjectWriter::writeFunctionSection( endSection(Section); } -void WasmObjectWriter::writeTableSection( - const SmallVector &TableElems) { +void WasmObjectWriter::writeTableSection(uint32_t NumElements) { // For now, always emit the table section, since indirect calls are not // valid without it. In the future, we could perhaps be more clever and omit // it if there are no indirect calls. + SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_TABLE); - // The number of tables, fixed to 1 for now. - encodeULEB128(1, getStream()); - - encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream()); - - encodeULEB128(0, getStream()); // flags - encodeULEB128(TableElems.size(), getStream()); // initial + encodeULEB128(1, getStream()); // The number of tables. + // Fixed to 1 for now. + encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream()); // Type of table + encodeULEB128(0, getStream()); // flags + encodeULEB128(NumElements, getStream()); // initial endSection(Section); } @@ -1072,8 +1077,10 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, } // If needed, prepare the function to be called indirectly. - if (IsAddressTaken.count(&WS)) + if (IsAddressTaken.count(&WS)) { + IndirectSymbolIndices[&WS] = TableElems.size(); TableElems.push_back(Index); + } } else { if (WS.isTemporary() && !WS.getSize()) continue; @@ -1180,7 +1187,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, writeTypeSection(FunctionTypes); writeImportSection(Imports); writeFunctionSection(Functions); - writeTableSection(TableElems); + writeTableSection(TableElems.size()); writeMemorySection(DataBytes); writeGlobalSection(Globals); writeExportSection(Exports); diff --git a/lib/Object/ArchiveWriter.cpp b/lib/Object/ArchiveWriter.cpp index e1c35ed6a6a0..4034f9039dda 100644 --- a/lib/Object/ArchiveWriter.cpp +++ b/lib/Object/ArchiveWriter.cpp @@ -36,7 +36,8 @@ using namespace llvm; NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef) - : Buf(MemoryBuffer::getMemBuffer(BufRef, false)) {} + : Buf(MemoryBuffer::getMemBuffer(BufRef, false)), + MemberName(BufRef.getBufferIdentifier()) {} Expected NewArchiveMember::getOldMember(const object::Archive::Child &OldMember, @@ -48,6 +49,7 @@ NewArchiveMember::getOldMember(const object::Archive::Child &OldMember, NewArchiveMember M; assert(M.IsNew == false); M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false); + M.MemberName = M.Buf->getBufferIdentifier(); if (!Deterministic) { auto ModTimeOrErr = OldMember.getLastModified(); if (!ModTimeOrErr) @@ -97,6 +99,7 @@ Expected NewArchiveMember::getFile(StringRef FileName, NewArchiveMember M; M.IsNew = true; M.Buf = std::move(*MemberBufferOrErr); + M.MemberName = M.Buf->getBufferIdentifier(); if (!Deterministic) { M.ModTime = std::chrono::time_point_cast( Status.getLastModificationTime()); @@ -185,7 +188,7 @@ printBSDMemberHeader(raw_fd_ostream &Out, StringRef Name, } static bool useStringTable(bool Thin, StringRef Name) { - return Thin || Name.size() >= 16; + return Thin || Name.size() >= 16 || Name.contains('/'); } static void @@ -239,7 +242,7 @@ static void writeStringTable(raw_fd_ostream &Out, StringRef ArcName, unsigned StartOffset = 0; for (const NewArchiveMember &M : Members) { StringRef Path = M.Buf->getBufferIdentifier(); - StringRef Name = sys::path::filename(Path); + StringRef Name = M.MemberName; if (!useStringTable(Thin, Name)) continue; if (StartOffset == 0) { @@ -423,9 +426,8 @@ llvm::writeArchive(StringRef ArcName, if (Kind == object::Archive::K_DARWIN) Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8); - printMemberHeader(Out, Kind, Thin, - sys::path::filename(M.Buf->getBufferIdentifier()), - StringMapIndexIter, M.ModTime, M.UID, M.GID, M.Perms, + printMemberHeader(Out, Kind, Thin, M.MemberName, StringMapIndexIter, + M.ModTime, M.UID, M.GID, M.Perms, M.Buf->getBufferSize() + Padding); if (!Thin) diff --git a/lib/Object/ELF.cpp b/lib/Object/ELF.cpp index 9bc28dc14a29..448fb1bd6b56 100644 --- a/lib/Object/ELF.cpp +++ b/lib/Object/ELF.cpp @@ -192,6 +192,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { STRINGIFY_ENUM_CASE(ELF, SHT_PREINIT_ARRAY); STRINGIFY_ENUM_CASE(ELF, SHT_GROUP); STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX); + STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef); diff --git a/lib/Object/IRSymtab.cpp b/lib/Object/IRSymtab.cpp index d21acdb1d556..a6cd5dda12d3 100644 --- a/lib/Object/IRSymtab.cpp +++ b/lib/Object/IRSymtab.cpp @@ -109,9 +109,9 @@ Error Builder::addModule(Module *M) { if (TT.isOSBinFormatCOFF()) { if (auto E = M->materializeMetadata()) return E; - if (Metadata *Val = M->getModuleFlag("Linker Options")) { - MDNode *LinkerOptions = cast(Val); - for (const MDOperand &MDOptions : LinkerOptions->operands()) + if (NamedMDNode *LinkerOptions = + M->getNamedMetadata("llvm.linker.options")) { + for (MDNode *MDOptions : LinkerOptions->operands()) for (const MDOperand &MDOption : cast(MDOptions)->operands()) COFFLinkerOptsOS << " " << cast(MDOption)->getString(); } diff --git a/lib/Object/WindowsResource.cpp b/lib/Object/WindowsResource.cpp index 041659e7aa23..3f6080d48f9d 100644 --- a/lib/Object/WindowsResource.cpp +++ b/lib/Object/WindowsResource.cpp @@ -30,6 +30,10 @@ namespace object { const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); +// COFF files seem to be inconsistent with alignment between sections, just use +// 8-byte because it makes everyone happy. +const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t); + static const size_t ResourceMagicSize = 16; static const size_t NullEntrySize = 16; @@ -66,7 +70,7 @@ ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner, Error &Err) : Reader(Ref), OwningRes(Owner) { if (loadNext()) - Err = make_error("Could not read first entry.", + Err = make_error("Could not read first entry.\n", object_error::unexpected_eof); } @@ -133,31 +137,35 @@ Error WindowsResourceParser::parse(WindowsResource *WR) { ResourceEntryRef Entry = EntryOrErr.get(); bool End = false; while (!End) { - Data.push_back(Entry.getData()); - if (Entry.checkTypeString()) + bool IsNewTypeString = false; + bool IsNewNameString = false; + + Root.addEntry(Entry, IsNewTypeString, IsNewNameString); + + if (IsNewTypeString) StringTable.push_back(Entry.getTypeString()); - if (Entry.checkNameString()) + if (IsNewNameString) StringTable.push_back(Entry.getNameString()); - Root.addEntry(Entry); - RETURN_IF_ERROR(Entry.moveNext(End)); } return Error::success(); } -void WindowsResourceParser::printTree() const { - ScopedPrinter Writer(outs()); +void WindowsResourceParser::printTree(raw_ostream &OS) const { + ScopedPrinter Writer(OS); Root.print(Writer, "Resource Tree"); } -void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry) { - TreeNode &TypeNode = addTypeNode(Entry); - TreeNode &NameNode = TypeNode.addNameNode(Entry); +void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry, + bool &IsNewTypeString, + bool &IsNewNameString) { + TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString); + TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString); NameNode.addLanguageNode(Entry); } @@ -171,7 +179,6 @@ WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion, uint32_t Characteristics) : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion), Characteristics(Characteristics) { - if (IsDataNode) DataIndex = DataCount++; } @@ -194,17 +201,19 @@ WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion, } WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) { +WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry, + bool &IsNewTypeString) { if (Entry.checkTypeString()) - return addChild(Entry.getTypeString()); + return addChild(Entry.getTypeString(), IsNewTypeString); else return addChild(Entry.getTypeID()); } WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry) { +WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry, + bool &IsNewNameString) { if (Entry.checkNameString()) - return addChild(Entry.getNameString()); + return addChild(Entry.getNameString(), IsNewNameString); else return addChild(Entry.getNameID()); } @@ -232,7 +241,8 @@ WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild( } WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addChild(ArrayRef NameRef) { +WindowsResourceParser::TreeNode::addChild(ArrayRef NameRef, + bool &IsNewString) { std::string NameString; ArrayRef CorrectedName; std::vector EndianCorrectedName; @@ -248,6 +258,7 @@ WindowsResourceParser::TreeNode::addChild(ArrayRef NameRef) { auto Child = StringChildren.find(NameString); if (Child == StringChildren.end()) { auto NewChild = createStringNode(); + IsNewString = true; WindowsResourceParser::TreeNode &Node = *NewChild; StringChildren.emplace(NameString, std::move(NewChild)); return Node; @@ -296,7 +307,6 @@ class WindowsResourceCOFFWriter { public: WindowsResourceCOFFWriter(StringRef OutputFile, Machine MachineType, const WindowsResourceParser &Parser, Error &E); - Error write(); private: @@ -314,7 +324,8 @@ class WindowsResourceCOFFWriter { void writeDirectoryStringTable(); void writeFirstSectionRelocations(); std::unique_ptr Buffer; - uint8_t *Current; + uint8_t *BufferStart; + uint64_t CurrentOffset = 0; Machine MachineType; const WindowsResourceParser::TreeNode &Resources; const ArrayRef> Data; @@ -386,6 +397,7 @@ void WindowsResourceCOFFWriter::performSectionOneLayout() { FileSize += SectionOneSize; FileSize += Data.size() * llvm::COFF::RelocationSize; // one relocation for each resource. + FileSize = alignTo(FileSize, SECTION_ALIGNMENT); } void WindowsResourceCOFFWriter::performSectionTwoLayout() { @@ -398,6 +410,7 @@ void WindowsResourceCOFFWriter::performSectionTwoLayout() { SectionTwoSize += llvm::alignTo(Entry.size(), sizeof(uint64_t)); } FileSize += SectionTwoSize; + FileSize = alignTo(FileSize, SECTION_ALIGNMENT); } static std::time_t getTime() { @@ -408,7 +421,7 @@ static std::time_t getTime() { } Error WindowsResourceCOFFWriter::write() { - Current = Buffer->getBufferStart(); + BufferStart = Buffer->getBufferStart(); writeCOFFHeader(); writeFirstSectionHeader(); @@ -427,7 +440,8 @@ Error WindowsResourceCOFFWriter::write() { void WindowsResourceCOFFWriter::writeCOFFHeader() { // Write the COFF header. - auto *Header = reinterpret_cast(Current); + auto *Header = + reinterpret_cast(BufferStart); switch (MachineType) { case Machine::ARM: Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; @@ -452,9 +466,9 @@ void WindowsResourceCOFFWriter::writeCOFFHeader() { void WindowsResourceCOFFWriter::writeFirstSectionHeader() { // Write the first section header. - Current += sizeof(llvm::object::coff_file_header); - auto *SectionOneHeader = - reinterpret_cast(Current); + CurrentOffset += sizeof(llvm::object::coff_file_header); + auto *SectionOneHeader = reinterpret_cast( + BufferStart + CurrentOffset); strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)llvm::COFF::NameSize); SectionOneHeader->VirtualSize = 0; SectionOneHeader->VirtualAddress = 0; @@ -473,9 +487,9 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() { void WindowsResourceCOFFWriter::writeSecondSectionHeader() { // Write the second section header. - Current += sizeof(llvm::object::coff_section); - auto *SectionTwoHeader = - reinterpret_cast(Current); + CurrentOffset += sizeof(llvm::object::coff_section); + auto *SectionTwoHeader = reinterpret_cast( + BufferStart + CurrentOffset); strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)llvm::COFF::NameSize); SectionTwoHeader->VirtualSize = 0; SectionTwoHeader->VirtualAddress = 0; @@ -492,75 +506,85 @@ void WindowsResourceCOFFWriter::writeSecondSectionHeader() { void WindowsResourceCOFFWriter::writeFirstSection() { // Write section one. - Current += sizeof(llvm::object::coff_section); + CurrentOffset += sizeof(llvm::object::coff_section); writeDirectoryTree(); writeDirectoryStringTable(); writeFirstSectionRelocations(); + + CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); } void WindowsResourceCOFFWriter::writeSecondSection() { // Now write the .rsrc$02 section. for (auto const &RawDataEntry : Data) { - std::copy(RawDataEntry.begin(), RawDataEntry.end(), Current); - Current += alignTo(RawDataEntry.size(), sizeof(uint64_t)); + std::copy(RawDataEntry.begin(), RawDataEntry.end(), + BufferStart + CurrentOffset); + CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t)); } + + CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); } void WindowsResourceCOFFWriter::writeSymbolTable() { // Now write the symbol table. // First, the feat symbol. - auto *Symbol = reinterpret_cast(Current); + auto *Symbol = reinterpret_cast(BufferStart + + CurrentOffset); strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)llvm::COFF::NameSize); Symbol->Value = 0x11; Symbol->SectionNumber = 0xffff; Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL; Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC; Symbol->NumberOfAuxSymbols = 0; - Current += sizeof(llvm::object::coff_symbol16); + CurrentOffset += sizeof(llvm::object::coff_symbol16); // Now write the .rsrc1 symbol + aux. - Symbol = reinterpret_cast(Current); + Symbol = reinterpret_cast(BufferStart + + CurrentOffset); strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)llvm::COFF::NameSize); Symbol->Value = 0; Symbol->SectionNumber = 1; Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL; Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC; Symbol->NumberOfAuxSymbols = 1; - Current += sizeof(llvm::object::coff_symbol16); - auto *Aux = - reinterpret_cast(Current); + CurrentOffset += sizeof(llvm::object::coff_symbol16); + auto *Aux = reinterpret_cast( + BufferStart + CurrentOffset); Aux->Length = SectionOneSize; Aux->NumberOfRelocations = Data.size(); Aux->NumberOfLinenumbers = 0; Aux->CheckSum = 0; Aux->NumberLowPart = 0; Aux->Selection = 0; - Current += sizeof(llvm::object::coff_aux_section_definition); + CurrentOffset += sizeof(llvm::object::coff_aux_section_definition); // Now write the .rsrc2 symbol + aux. - Symbol = reinterpret_cast(Current); + Symbol = reinterpret_cast(BufferStart + + CurrentOffset); strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)llvm::COFF::NameSize); Symbol->Value = 0; Symbol->SectionNumber = 2; Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL; Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC; Symbol->NumberOfAuxSymbols = 1; - Current += sizeof(llvm::object::coff_symbol16); - Aux = reinterpret_cast(Current); + CurrentOffset += sizeof(llvm::object::coff_symbol16); + Aux = reinterpret_cast( + BufferStart + CurrentOffset); Aux->Length = SectionTwoSize; Aux->NumberOfRelocations = 0; Aux->NumberOfLinenumbers = 0; Aux->CheckSum = 0; Aux->NumberLowPart = 0; Aux->Selection = 0; - Current += sizeof(llvm::object::coff_aux_section_definition); + CurrentOffset += sizeof(llvm::object::coff_aux_section_definition); // Now write a symbol for each relocation. for (unsigned i = 0; i < Data.size(); i++) { char RelocationName[9]; sprintf(RelocationName, "$R%06X", DataOffsets[i]); - Symbol = reinterpret_cast(Current); + Symbol = reinterpret_cast(BufferStart + + CurrentOffset); strncpy(Symbol->Name.ShortName, RelocationName, (size_t)llvm::COFF::NameSize); Symbol->Value = DataOffsets[i]; @@ -568,14 +592,14 @@ void WindowsResourceCOFFWriter::writeSymbolTable() { Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL; Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC; Symbol->NumberOfAuxSymbols = 0; - Current += sizeof(llvm::object::coff_symbol16); + CurrentOffset += sizeof(llvm::object::coff_symbol16); } } void WindowsResourceCOFFWriter::writeStringTable() { // Just 4 null bytes for the string table. - auto COFFStringTable = reinterpret_cast(Current); - *COFFStringTable = 0; + auto COFFStringTable = reinterpret_cast(BufferStart + CurrentOffset); + memset(COFFStringTable, 0, 4); } void WindowsResourceCOFFWriter::writeDirectoryTree() { @@ -593,8 +617,8 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() { while (!Queue.empty()) { auto CurrentNode = Queue.front(); Queue.pop(); - auto *Table = - reinterpret_cast(Current); + auto *Table = reinterpret_cast( + BufferStart + CurrentOffset); Table->Characteristics = CurrentNode->getCharacteristics(); Table->TimeDateStamp = 0; Table->MajorVersion = CurrentNode->getMajorVersion(); @@ -603,13 +627,13 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() { auto &StringChildren = CurrentNode->getStringChildren(); Table->NumberOfNameEntries = StringChildren.size(); Table->NumberOfIDEntries = IDChildren.size(); - Current += sizeof(llvm::object::coff_resource_dir_table); + CurrentOffset += sizeof(llvm::object::coff_resource_dir_table); CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_table); // Write the directory entries immediately following each directory table. for (auto const &Child : StringChildren) { - auto *Entry = - reinterpret_cast(Current); + auto *Entry = reinterpret_cast( + BufferStart + CurrentOffset); Entry->Identifier.NameOffset = StringTableOffsets[Child.second->getStringIndex()]; if (Child.second->checkIsDataNode()) { @@ -624,12 +648,12 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() { sizeof(llvm::object::coff_resource_dir_entry); Queue.push(Child.second.get()); } - Current += sizeof(llvm::object::coff_resource_dir_entry); + CurrentOffset += sizeof(llvm::object::coff_resource_dir_entry); CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry); } for (auto const &Child : IDChildren) { - auto *Entry = - reinterpret_cast(Current); + auto *Entry = reinterpret_cast( + BufferStart + CurrentOffset); Entry->Identifier.ID = Child.first; if (Child.second->checkIsDataNode()) { Entry->Offset.DataEntryOffset = NextLevelOffset; @@ -643,7 +667,7 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() { sizeof(llvm::object::coff_resource_dir_entry); Queue.push(Child.second.get()); } - Current += sizeof(llvm::object::coff_resource_dir_entry); + CurrentOffset += sizeof(llvm::object::coff_resource_dir_entry); CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry); } } @@ -651,14 +675,14 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() { RelocationAddresses.resize(Data.size()); // Now write all the resource data entries. for (auto DataNodes : DataEntriesTreeOrder) { - auto *Entry = - reinterpret_cast(Current); + auto *Entry = reinterpret_cast( + BufferStart + CurrentOffset); RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset; Entry->DataRVA = 0; // Set to zero because it is a relocation. Entry->DataSize = Data[DataNodes->getDataIndex()].size(); Entry->Codepage = 0; Entry->Reserved = 0; - Current += sizeof(llvm::object::coff_resource_data_entry); + CurrentOffset += sizeof(llvm::object::coff_resource_data_entry); CurrentRelativeOffset += sizeof(llvm::object::coff_resource_data_entry); } } @@ -666,17 +690,16 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() { void WindowsResourceCOFFWriter::writeDirectoryStringTable() { // Now write the directory string table for .rsrc$01 uint32_t TotalStringTableSize = 0; - for (auto String : StringTable) { - auto *LengthField = reinterpret_cast(Current); + for (auto &String : StringTable) { uint16_t Length = String.size(); - *LengthField = Length; - Current += sizeof(uint16_t); - auto *Start = reinterpret_cast(Current); + support::endian::write16le(BufferStart + CurrentOffset, Length); + CurrentOffset += sizeof(uint16_t); + auto *Start = reinterpret_cast(BufferStart + CurrentOffset); std::copy(String.begin(), String.end(), Start); - Current += Length * sizeof(UTF16); + CurrentOffset += Length * sizeof(UTF16); TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t); } - Current += + CurrentOffset += alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize; } @@ -687,7 +710,8 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { // .rsrc section. uint32_t NextSymbolIndex = 5; for (unsigned i = 0; i < Data.size(); i++) { - auto *Reloc = reinterpret_cast(Current); + auto *Reloc = reinterpret_cast( + BufferStart + CurrentOffset); Reloc->VirtualAddress = RelocationAddresses[i]; Reloc->SymbolTableIndex = NextSymbolIndex++; switch (MachineType) { @@ -703,7 +727,7 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { default: Reloc->Type = 0; } - Current += sizeof(llvm::object::coff_relocation); + CurrentOffset += sizeof(llvm::object::coff_relocation); } } diff --git a/lib/ObjectYAML/COFFYAML.cpp b/lib/ObjectYAML/COFFYAML.cpp index 7f9f4c1f8c2c..c8cbea1490f6 100644 --- a/lib/ObjectYAML/COFFYAML.cpp +++ b/lib/ObjectYAML/COFFYAML.cpp @@ -488,7 +488,16 @@ void MappingTraits::mapping(IO &IO, COFFYAML::Section &Sec) { IO.mapOptional("VirtualAddress", Sec.Header.VirtualAddress, 0U); IO.mapOptional("VirtualSize", Sec.Header.VirtualSize, 0U); IO.mapOptional("Alignment", Sec.Alignment, 0U); - IO.mapRequired("SectionData", Sec.SectionData); + + // If this is a .debug$S or .debug$T section parse the semantic representation + // of the symbols/types. If it is any other kind of section, just deal in raw + // bytes. + IO.mapOptional("SectionData", Sec.SectionData); + if (Sec.Name == ".debug$S") + IO.mapOptional("Subsections", Sec.DebugS); + else if (Sec.Name == ".debug$T") + IO.mapOptional("Types", Sec.DebugT); + IO.mapOptional("Relocations", Sec.Relocations); } diff --git a/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp b/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp index 08a4bb715fac..d194420d5ef4 100644 --- a/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp +++ b/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp @@ -28,6 +28,7 @@ #include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h" #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/SymbolSerializer.h" #include "llvm/ObjectYAML/CodeViewYAMLSymbols.h" @@ -75,10 +76,9 @@ struct YAMLSubsectionBase { virtual ~YAMLSubsectionBase() {} virtual void map(IO &IO) = 0; - virtual std::unique_ptr + virtual std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *UseStrings, - DebugChecksumsSubsection *UseChecksums) const = 0; + const codeview::StringsAndChecksums &SC) const = 0; }; } } @@ -90,10 +90,9 @@ struct YAMLChecksumsSubsection : public YAMLSubsectionBase { : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &FC); @@ -105,10 +104,9 @@ struct YAMLLinesSubsection : public YAMLSubsectionBase { YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, @@ -122,10 +120,9 @@ struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase { : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, @@ -139,10 +136,9 @@ struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase { : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef &Exports); @@ -154,10 +150,9 @@ struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase { : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings, const DebugCrossModuleImportsSubsectionRef &Imports); @@ -169,10 +164,9 @@ struct YAMLSymbolsSubsection : public YAMLSubsectionBase { YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugSymbolsSubsectionRef &Symbols); @@ -184,10 +178,9 @@ struct YAMLStringTableSubsection : public YAMLSubsectionBase { : YAMLSubsectionBase(DebugSubsectionKind::StringTable) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings); @@ -199,10 +192,9 @@ struct YAMLFrameDataSubsection : public YAMLSubsectionBase { : YAMLSubsectionBase(DebugSubsectionKind::FrameData) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings, const DebugFrameDataSubsectionRef &Frames); @@ -215,10 +207,9 @@ struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase { : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA) {} void map(IO &IO) override; - std::unique_ptr + std::shared_ptr toCodeViewSubsection(BumpPtrAllocator &Allocator, - DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const override; + const codeview::StringsAndChecksums &SC) const override; static Expected> fromCodeViewSubsection(const DebugSymbolRVASubsectionRef &RVAs); @@ -389,34 +380,23 @@ void MappingTraits::mapping( Subsection.Subsection->map(IO); } -static std::shared_ptr -findChecksums(ArrayRef Subsections) { - for (const auto &SS : Subsections) { - if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums) { - return std::static_pointer_cast(SS.Subsection); - } - } - - return nullptr; -} - -std::unique_ptr YAMLChecksumsSubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *UseStrings, - DebugChecksumsSubsection *UseChecksums) const { - assert(UseStrings && !UseChecksums); - auto Result = llvm::make_unique(*UseStrings); +std::shared_ptr YAMLChecksumsSubsection::toCodeViewSubsection( + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + assert(SC.hasStrings()); + auto Result = std::make_shared(*SC.strings()); for (const auto &CS : Checksums) { Result->addChecksum(CS.FileName, CS.Kind, CS.ChecksumBytes.Bytes); } - return std::move(Result); + return Result; } -std::unique_ptr YAMLLinesSubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *UseStrings, - DebugChecksumsSubsection *UseChecksums) const { - assert(UseStrings && UseChecksums); +std::shared_ptr YAMLLinesSubsection::toCodeViewSubsection( + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + assert(SC.hasStrings() && SC.hasChecksums()); auto Result = - llvm::make_unique(*UseChecksums, *UseStrings); + std::make_shared(*SC.checksums(), *SC.strings()); Result->setCodeSize(Lines.CodeSize); Result->setRelocationAddress(Lines.RelocSegment, Lines.RelocOffset); Result->setFlags(Lines.Flags); @@ -438,16 +418,16 @@ std::unique_ptr YAMLLinesSubsection::toCodeViewSubsection( } } } - return llvm::cast(std::move(Result)); + return Result; } -std::unique_ptr +std::shared_ptr YAMLInlineeLinesSubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *UseStrings, - DebugChecksumsSubsection *UseChecksums) const { - assert(UseChecksums); - auto Result = llvm::make_unique( - *UseChecksums, InlineeLines.HasExtraFiles); + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + assert(SC.hasChecksums()); + auto Result = std::make_shared( + *SC.checksums(), InlineeLines.HasExtraFiles); for (const auto &Site : InlineeLines.Sites) { Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName, @@ -459,56 +439,60 @@ YAMLInlineeLinesSubsection::toCodeViewSubsection( Result->addExtraFile(EF); } } - return llvm::cast(std::move(Result)); + return Result; } -std::unique_ptr +std::shared_ptr YAMLCrossModuleExportsSubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const { - auto Result = llvm::make_unique(); + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + auto Result = std::make_shared(); for (const auto &M : Exports) Result->addMapping(M.Local, M.Global); - return llvm::cast(std::move(Result)); + return Result; } -std::unique_ptr +std::shared_ptr YAMLCrossModuleImportsSubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const { - auto Result = llvm::make_unique(*Strings); + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + assert(SC.hasStrings()); + + auto Result = + std::make_shared(*SC.strings()); for (const auto &M : Imports) { for (const auto Id : M.ImportIds) Result->addImport(M.ModuleName, Id); } - return llvm::cast(std::move(Result)); + return Result; } -std::unique_ptr YAMLSymbolsSubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const { - auto Result = llvm::make_unique(); +std::shared_ptr YAMLSymbolsSubsection::toCodeViewSubsection( + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + auto Result = std::make_shared(); for (const auto &Sym : Symbols) Result->addSymbol( Sym.toCodeViewSymbol(Allocator, CodeViewContainer::ObjectFile)); - return std::move(Result); + return Result; } -std::unique_ptr +std::shared_ptr YAMLStringTableSubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const { - auto Result = llvm::make_unique(); + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + auto Result = std::make_shared(); for (const auto &Str : this->Strings) Result->insert(Str); - return std::move(Result); + return Result; } -std::unique_ptr YAMLFrameDataSubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const { - assert(Strings); - auto Result = llvm::make_unique(); +std::shared_ptr YAMLFrameDataSubsection::toCodeViewSubsection( + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + assert(SC.hasStrings()); + + auto Result = std::make_shared(); for (const auto &YF : Frames) { codeview::FrameData F; F.CodeSize = YF.CodeSize; @@ -519,20 +503,20 @@ std::unique_ptr YAMLFrameDataSubsection::toCodeViewSubsection( F.PrologSize = YF.PrologSize; F.RvaStart = YF.RvaStart; F.SavedRegsSize = YF.SavedRegsSize; - F.FrameFunc = Strings->insert(YF.FrameFunc); + F.FrameFunc = SC.strings()->insert(YF.FrameFunc); Result->addFrameData(F); } - return std::move(Result); + return Result; } -std::unique_ptr +std::shared_ptr YAMLCoffSymbolRVASubsection::toCodeViewSubsection( - BumpPtrAllocator &Allocator, DebugStringTableSubsection *Strings, - DebugChecksumsSubsection *Checksums) const { - auto Result = llvm::make_unique(); + BumpPtrAllocator &Allocator, + const codeview::StringsAndChecksums &SC) const { + auto Result = std::make_shared(); for (const auto &RVA : RVAs) Result->addRVA(RVA); - return std::move(Result); + return Result; } static Expected @@ -741,63 +725,17 @@ YAMLCoffSymbolRVASubsection::fromCodeViewSubsection( return Result; } -Expected>> +Expected>> llvm::CodeViewYAML::toCodeViewSubsectionList( BumpPtrAllocator &Allocator, ArrayRef Subsections, - DebugStringTableSubsection &Strings) { - std::vector> Result; + const codeview::StringsAndChecksums &SC) { + std::vector> Result; if (Subsections.empty()) return std::move(Result); - auto Checksums = findChecksums(Subsections); - std::unique_ptr ChecksumsBase; - if (Checksums) - ChecksumsBase = - Checksums->toCodeViewSubsection(Allocator, &Strings, nullptr); - DebugChecksumsSubsection *CS = - static_cast(ChecksumsBase.get()); for (const auto &SS : Subsections) { - // We've already converted the checksums subsection, don't do it - // twice. - std::unique_ptr CVS; - if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums) - CVS = std::move(ChecksumsBase); - else - CVS = SS.Subsection->toCodeViewSubsection(Allocator, &Strings, CS); - assert(CVS != nullptr); - Result.push_back(std::move(CVS)); - } - return std::move(Result); -} - -Expected>> -llvm::CodeViewYAML::toCodeViewSubsectionList( - BumpPtrAllocator &Allocator, ArrayRef Subsections, - std::unique_ptr &TakeStrings, - DebugStringTableSubsection *StringsRef) { - std::vector> Result; - if (Subsections.empty()) - return std::move(Result); - - auto Checksums = findChecksums(Subsections); - - std::unique_ptr ChecksumsBase; - if (Checksums) - ChecksumsBase = - Checksums->toCodeViewSubsection(Allocator, StringsRef, nullptr); - DebugChecksumsSubsection *CS = - static_cast(ChecksumsBase.get()); - for (const auto &SS : Subsections) { - // We've already converted the checksums and string table subsection, don't - // do it twice. - std::unique_ptr CVS; - if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums) - CVS = std::move(ChecksumsBase); - else if (SS.Subsection->Kind == DebugSubsectionKind::StringTable) { - assert(TakeStrings && "No string table!"); - CVS = std::move(TakeStrings); - } else - CVS = SS.Subsection->toCodeViewSubsection(Allocator, StringsRef, CS); + std::shared_ptr CVS; + CVS = SS.Subsection->toCodeViewSubsection(Allocator, SC); assert(CVS != nullptr); Result.push_back(std::move(CVS)); } @@ -810,23 +748,23 @@ struct SubsectionConversionVisitor : public DebugSubsectionVisitor { Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override; Error visitLines(DebugLinesSubsectionRef &Lines, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &Checksums, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &Inlinees, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; Error visitStringTable(DebugStringTableSubsectionRef &ST, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; Error visitSymbols(DebugSymbolsSubsectionRef &Symbols, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; Error visitFrameData(DebugFrameDataSubsectionRef &Symbols, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &Symbols, - const DebugSubsectionState &State) override; + const StringsAndChecksumsRef &State) override; YAMLDebugSubsection Subsection; }; @@ -837,7 +775,7 @@ Error SubsectionConversionVisitor::visitUnknown( } Error SubsectionConversionVisitor::visitLines( - DebugLinesSubsectionRef &Lines, const DebugSubsectionState &State) { + DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) { auto Result = YAMLLinesSubsection::fromCodeViewSubsection( State.strings(), State.checksums(), Lines); if (!Result) @@ -847,7 +785,8 @@ Error SubsectionConversionVisitor::visitLines( } Error SubsectionConversionVisitor::visitFileChecksums( - DebugChecksumsSubsectionRef &Checksums, const DebugSubsectionState &State) { + DebugChecksumsSubsectionRef &Checksums, + const StringsAndChecksumsRef &State) { auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(), Checksums); if (!Result) @@ -858,7 +797,7 @@ Error SubsectionConversionVisitor::visitFileChecksums( Error SubsectionConversionVisitor::visitInlineeLines( DebugInlineeLinesSubsectionRef &Inlinees, - const DebugSubsectionState &State) { + const StringsAndChecksumsRef &State) { auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection( State.strings(), State.checksums(), Inlinees); if (!Result) @@ -869,7 +808,7 @@ Error SubsectionConversionVisitor::visitInlineeLines( Error SubsectionConversionVisitor::visitCrossModuleExports( DebugCrossModuleExportsSubsectionRef &Exports, - const DebugSubsectionState &State) { + const StringsAndChecksumsRef &State) { auto Result = YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports); if (!Result) @@ -880,7 +819,7 @@ Error SubsectionConversionVisitor::visitCrossModuleExports( Error SubsectionConversionVisitor::visitCrossModuleImports( DebugCrossModuleImportsSubsectionRef &Imports, - const DebugSubsectionState &State) { + const StringsAndChecksumsRef &State) { auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection( State.strings(), Imports); if (!Result) @@ -890,7 +829,8 @@ Error SubsectionConversionVisitor::visitCrossModuleImports( } Error SubsectionConversionVisitor::visitStringTable( - DebugStringTableSubsectionRef &Strings, const DebugSubsectionState &State) { + DebugStringTableSubsectionRef &Strings, + const StringsAndChecksumsRef &State) { auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings); if (!Result) return Result.takeError(); @@ -899,7 +839,7 @@ Error SubsectionConversionVisitor::visitStringTable( } Error SubsectionConversionVisitor::visitSymbols( - DebugSymbolsSubsectionRef &Symbols, const DebugSubsectionState &State) { + DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) { auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols); if (!Result) return Result.takeError(); @@ -908,7 +848,7 @@ Error SubsectionConversionVisitor::visitSymbols( } Error SubsectionConversionVisitor::visitFrameData( - DebugFrameDataSubsectionRef &Frames, const DebugSubsectionState &State) { + DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) { auto Result = YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames); if (!Result) @@ -918,7 +858,7 @@ Error SubsectionConversionVisitor::visitFrameData( } Error SubsectionConversionVisitor::visitCOFFSymbolRVAs( - DebugSymbolRVASubsectionRef &RVAs, const DebugSubsectionState &State) { + DebugSymbolRVASubsectionRef &RVAs, const StringsAndChecksumsRef &State) { auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs); if (!Result) return Result.takeError(); @@ -927,29 +867,71 @@ Error SubsectionConversionVisitor::visitCOFFSymbolRVAs( } } -Expected YAMLDebugSubsection::fromCodeViewSubection( - const DebugStringTableSubsectionRef &Strings, - const DebugChecksumsSubsectionRef &Checksums, - const DebugSubsectionRecord &SS) { - DebugSubsectionState State(Strings, Checksums); +Expected +YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef &SC, + const DebugSubsectionRecord &SS) { SubsectionConversionVisitor V; - if (auto EC = visitDebugSubsection(SS, V, State)) + if (auto EC = visitDebugSubsection(SS, V, SC)) return std::move(EC); return V.Subsection; } -std::unique_ptr -llvm::CodeViewYAML::findStringTable(ArrayRef Sections) { - for (const auto &SS : Sections) { - if (SS.Subsection->Kind != DebugSubsectionKind::StringTable) - continue; +std::vector +llvm::CodeViewYAML::fromDebugS(ArrayRef Data, + const StringsAndChecksumsRef &SC) { + BinaryStreamReader Reader(Data, support::little); + uint32_t Magic; - // String Table doesn't use the allocator. - BumpPtrAllocator Allocator; - auto Result = - SS.Subsection->toCodeViewSubsection(Allocator, nullptr, nullptr); - return llvm::cast(std::move(Result)); + ExitOnError Err("Invalid .debug$S section!"); + Err(Reader.readInteger(Magic)); + assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!"); + + DebugSubsectionArray Subsections; + Err(Reader.readArray(Subsections, Reader.bytesRemaining())); + + std::vector Result; + + for (const auto &SS : Subsections) { + auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS)); + Result.push_back(YamlSS); + } + return Result; +} + +void llvm::CodeViewYAML::initializeStringsAndChecksums( + ArrayRef Sections, codeview::StringsAndChecksums &SC) { + // String Table and Checksums subsections don't use the allocator. + BumpPtrAllocator Allocator; + + // It's possible for checksums and strings to even appear in different debug$S + // sections, so we have to make this a stateful function that can build up + // the strings and checksums field over multiple iterations. + + // File Checksums require the string table, but may become before it, so we + // have to scan for strings first, then scan for checksums again from the + // beginning. + if (!SC.hasStrings()) { + for (const auto &SS : Sections) { + if (SS.Subsection->Kind != DebugSubsectionKind::StringTable) + continue; + + auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC); + SC.setStrings( + std::static_pointer_cast(Result)); + break; + } + } + + if (SC.hasStrings() && !SC.hasChecksums()) { + for (const auto &SS : Sections) { + if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums) + continue; + + auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC); + SC.setChecksums( + std::static_pointer_cast(Result)); + break; + } } - return nullptr; } diff --git a/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/lib/ObjectYAML/CodeViewYAMLSymbols.cpp index fa3f1e0b60aa..ba3a2abe2097 100644 --- a/lib/ObjectYAML/CodeViewYAMLSymbols.cpp +++ b/lib/ObjectYAML/CodeViewYAMLSymbols.cpp @@ -35,6 +35,7 @@ LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, false) LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, false) LLVM_YAML_DECLARE_ENUM_TRAITS(SymbolKind) +LLVM_YAML_DECLARE_ENUM_TRAITS(FrameCookieKind) LLVM_YAML_DECLARE_BITSET_TRAITS(CompileSym2Flags) LLVM_YAML_DECLARE_BITSET_TRAITS(CompileSym3Flags) @@ -149,6 +150,15 @@ void ScalarEnumerationTraits::enumeration(IO &io, } } +void ScalarEnumerationTraits::enumeration( + IO &io, FrameCookieKind &FC) { + auto ThunkNames = getFrameCookieKindNames(); + for (const auto &E : ThunkNames) { + io.enumCase(FC, E.Name.str().c_str(), + static_cast(E.Value)); + } +} + namespace llvm { namespace CodeViewYAML { namespace detail { @@ -183,8 +193,47 @@ template struct SymbolRecordImpl : public SymbolRecordBase { mutable T Symbol; }; +struct UnknownSymbolRecord : public SymbolRecordBase { + explicit UnknownSymbolRecord(codeview::SymbolKind K) : SymbolRecordBase(K) {} + + void map(yaml::IO &io) override; + + CVSymbol toCodeViewSymbol(BumpPtrAllocator &Allocator, + CodeViewContainer Container) const override { + RecordPrefix Prefix; + uint32_t TotalLen = sizeof(RecordPrefix) + Data.size(); + Prefix.RecordKind = Kind; + Prefix.RecordLen = TotalLen - 2; + uint8_t *Buffer = Allocator.Allocate(TotalLen); + ::memcpy(Buffer, &Prefix, sizeof(RecordPrefix)); + ::memcpy(Buffer + sizeof(RecordPrefix), Data.data(), Data.size()); + return CVSymbol(Kind, ArrayRef(Buffer, TotalLen)); + } + Error fromCodeViewSymbol(CVSymbol CVS) override { + this->Kind = CVS.kind(); + Data = CVS.RecordData.drop_front(sizeof(RecordPrefix)); + return Error::success(); + } + + std::vector Data; +}; + template <> void SymbolRecordImpl::map(IO &IO) {} +void UnknownSymbolRecord::map(yaml::IO &io) { + yaml::BinaryRef Binary; + if (io.outputting()) + Binary = yaml::BinaryRef(Data); + io.mapRequired("Data", Binary); + if (!io.outputting()) { + std::string Str; + raw_string_ostream OS(Str); + Binary.writeAsBinary(OS); + OS.flush(); + Data.assign(Str.begin(), Str.end()); + } +} + template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Parent", Symbol.Parent); IO.mapRequired("End", Symbol.End); @@ -461,7 +510,7 @@ static inline Expected fromCodeViewSymbolImpl(CVSymbol Symbol) { CodeViewYAML::SymbolRecord Result; - auto Impl = std::make_shared>(Symbol.kind()); + auto Impl = std::make_shared(Symbol.kind()); if (auto EC = Impl->fromCodeViewSymbol(Symbol)) return std::move(EC); Result.Symbol = Impl; @@ -472,12 +521,13 @@ Expected CodeViewYAML::SymbolRecord::fromCodeViewSymbol(CVSymbol Symbol) { #define SYMBOL_RECORD(EnumName, EnumVal, ClassName) \ case EnumName: \ - return fromCodeViewSymbolImpl(Symbol); + return fromCodeViewSymbolImpl>(Symbol); #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName) \ SYMBOL_RECORD(EnumName, EnumVal, ClassName) switch (Symbol.kind()) { #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" - default: { llvm_unreachable("Unknown symbol kind!"); } + default: + return fromCodeViewSymbolImpl(Symbol); } return make_error(cv_error_code::corrupt_record); } @@ -486,7 +536,7 @@ template static void mapSymbolRecordImpl(IO &IO, const char *Class, SymbolKind Kind, CodeViewYAML::SymbolRecord &Obj) { if (!IO.outputting()) - Obj.Symbol = std::make_shared>(Kind); + Obj.Symbol = std::make_shared(Kind); IO.mapRequired(Class, *Obj.Symbol); } @@ -500,12 +550,14 @@ void MappingTraits::mapping( #define SYMBOL_RECORD(EnumName, EnumVal, ClassName) \ case EnumName: \ - mapSymbolRecordImpl(IO, #ClassName, Kind, Obj); \ + mapSymbolRecordImpl>(IO, #ClassName, Kind, \ + Obj); \ break; #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName) \ SYMBOL_RECORD(EnumName, EnumVal, ClassName) switch (Kind) { #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" - default: { llvm_unreachable("Unknown symbol kind!"); } + default: + mapSymbolRecordImpl(IO, "UnknownSym", Kind, Obj); } } diff --git a/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/lib/ObjectYAML/CodeViewYAMLTypes.cpp index 1302b0713d0e..a03b9cd50faa 100644 --- a/lib/ObjectYAML/CodeViewYAMLTypes.cpp +++ b/lib/ObjectYAML/CodeViewYAMLTypes.cpp @@ -714,3 +714,43 @@ void MappingTraits::mapping(IO &IO, MemberRecord &Obj) { default: { llvm_unreachable("Unknown member kind!"); } } } + +std::vector +llvm::CodeViewYAML::fromDebugT(ArrayRef DebugT) { + ExitOnError Err("Invalid .debug$T section!"); + BinaryStreamReader Reader(DebugT, support::little); + CVTypeArray Types; + uint32_t Magic; + + Err(Reader.readInteger(Magic)); + assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$T section!"); + + std::vector Result; + Err(Reader.readArray(Types, Reader.bytesRemaining())); + for (const auto &T : Types) { + auto CVT = Err(LeafRecord::fromCodeViewRecord(T)); + Result.push_back(CVT); + } + return Result; +} + +ArrayRef llvm::CodeViewYAML::toDebugT(ArrayRef Leafs, + BumpPtrAllocator &Alloc) { + TypeTableBuilder TTB(Alloc, false); + uint32_t Size = sizeof(uint32_t); + for (const auto &Leaf : Leafs) { + CVType T = Leaf.toCodeViewRecord(TTB); + Size += T.length(); + assert(T.length() % 4 == 0 && "Improper type record alignment!"); + } + uint8_t *ResultBuffer = Alloc.Allocate(Size); + MutableArrayRef Output(ResultBuffer, Size); + BinaryStreamWriter Writer(Output, support::little); + ExitOnError Err("Error writing type record to .debug$T section"); + Err(Writer.writeInteger(COFF::DEBUG_SECTION_MAGIC)); + for (const auto &R : TTB.records()) { + Err(Writer.writeBytes(R)); + } + assert(Writer.bytesRemaining() == 0 && "Didn't write all type record bytes!"); + return Output; +} diff --git a/lib/ObjectYAML/ELFYAML.cpp b/lib/ObjectYAML/ELFYAML.cpp index 70e25ea504a0..dbd5498e003d 100644 --- a/lib/ObjectYAML/ELFYAML.cpp +++ b/lib/ObjectYAML/ELFYAML.cpp @@ -372,6 +372,7 @@ void ScalarEnumerationTraits::enumeration( ECase(SHT_GROUP); ECase(SHT_SYMTAB_SHNDX); ECase(SHT_LOOS); + ECase(SHT_LLVM_ODRTAB); ECase(SHT_GNU_ATTRIBUTES); ECase(SHT_GNU_HASH); ECase(SHT_GNU_verdef); diff --git a/lib/Option/Arg.cpp b/lib/Option/Arg.cpp index e416df6a38dc..e581fee8bf38 100644 --- a/lib/Option/Arg.cpp +++ b/lib/Option/Arg.cpp @@ -1,4 +1,4 @@ -//===--- Arg.cpp - Argument Implementations -------------------------------===// +//===- Arg.cpp - Argument Implementations ---------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Option/Arg.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" +#include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -67,7 +67,7 @@ LLVM_DUMP_METHOD void Arg::dump() const { print(dbgs()); } std::string Arg::getAsString(const ArgList &Args) const { SmallString<256> Res; - llvm::raw_svector_ostream OS(Res); + raw_svector_ostream OS(Res); ArgStringList ASL; render(Args, ASL); @@ -98,7 +98,7 @@ void Arg::render(const ArgList &Args, ArgStringList &Output) const { case Option::RenderCommaJoinedStyle: { SmallString<256> Res; - llvm::raw_svector_ostream OS(Res); + raw_svector_ostream OS(Res); OS << getSpelling(); for (unsigned i = 0, e = getNumValues(); i != e; ++i) { if (i) OS << ','; diff --git a/lib/Option/ArgList.cpp b/lib/Option/ArgList.cpp index 39dbce87f9ae..cbccc1935d3c 100644 --- a/lib/Option/ArgList.cpp +++ b/lib/Option/ArgList.cpp @@ -1,4 +1,4 @@ -//===--- ArgList.cpp - Argument List Management ---------------------------===// +//===- ArgList.cpp - Argument List Management -----------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,14 +7,25 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Option/ArgList.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Option/OptSpecifier.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include using namespace llvm; using namespace llvm::opt; @@ -197,8 +208,6 @@ void ArgList::print(raw_ostream &O) const { LLVM_DUMP_METHOD void ArgList::dump() const { print(dbgs()); } #endif -// - void InputArgList::releaseMemory() { // An InputArgList always owns its arguments. for (Arg *A : *this) @@ -234,8 +243,6 @@ const char *InputArgList::MakeArgStringRef(StringRef Str) const { return getArgString(MakeIndex(Str)); } -// - DerivedArgList::DerivedArgList(const InputArgList &BaseArgs) : BaseArgs(BaseArgs) {} diff --git a/lib/Option/OptTable.cpp b/lib/Option/OptTable.cpp index b00d21ec8f67..52a81ff0e159 100644 --- a/lib/Option/OptTable.cpp +++ b/lib/Option/OptTable.cpp @@ -1,4 +1,4 @@ -//===--- OptTable.cpp - Option Table Implementation -----------------------===// +//===- OptTable.cpp - Option Table Implementation -------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,16 +7,25 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Option/OptTable.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Option/OptSpecifier.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include +#include #include +#include #include +#include +#include +#include using namespace llvm; using namespace llvm::opt; @@ -80,14 +89,14 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { static inline bool operator<(const OptTable::Info &I, const char *Name) { return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0; } -} -} + +} // end namespace opt +} // end namespace llvm OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {} OptTable::OptTable(ArrayRef OptionInfos, bool IgnoreCase) - : OptionInfos(OptionInfos), IgnoreCase(IgnoreCase), TheInputOptionID(0), - TheUnknownOptionID(0), FirstSearchableIndex(0) { + : OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) { // Explicitly zero initialize the error to work around a bug in array // value-initialization on MinGW with gcc 4.3.5. @@ -138,8 +147,8 @@ OptTable::OptTable(ArrayRef OptionInfos, bool IgnoreCase) } // Build prefix chars. - for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(), - E = PrefixesUnion.end(); I != E; ++I) { + for (StringSet<>::const_iterator I = PrefixesUnion.begin(), + E = PrefixesUnion.end(); I != E; ++I) { StringRef Prefix = I->getKey(); for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end(); C != CE; ++C) @@ -148,8 +157,7 @@ OptTable::OptTable(ArrayRef OptionInfos, bool IgnoreCase) } } -OptTable::~OptTable() { -} +OptTable::~OptTable() = default; const Option OptTable::getOption(OptSpecifier Opt) const { unsigned id = Opt.getID(); @@ -159,11 +167,11 @@ const Option OptTable::getOption(OptSpecifier Opt) const { return Option(&getInfo(id), this); } -static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) { +static bool isInput(const StringSet<> &Prefixes, StringRef Arg) { if (Arg == "-") return true; - for (llvm::StringSet<>::const_iterator I = Prefixes.begin(), - E = Prefixes.end(); I != E; ++I) + for (StringSet<>::const_iterator I = Prefixes.begin(), + E = Prefixes.end(); I != E; ++I) if (Arg.startswith(I->getKey())) return false; return true; @@ -346,7 +354,7 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { static void PrintHelpOptionList(raw_ostream &OS, StringRef Title, std::vector > &OptionHelp) { + const char*>> &OptionHelp) { OS << Title << ":\n"; // Find the maximum option length. @@ -412,8 +420,8 @@ void OptTable::PrintHelp(raw_ostream &OS, const char *Name, const char *Title, // Render help text into a map of group-name to a list of (option, help) // pairs. - typedef std::map > > helpmap_ty; + using helpmap_ty = + std::map>>; helpmap_ty GroupedOptionHelp; for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { diff --git a/lib/Option/Option.cpp b/lib/Option/Option.cpp index 736b939fe80b..4832e659f026 100644 --- a/lib/Option/Option.cpp +++ b/lib/Option/Option.cpp @@ -1,4 +1,4 @@ -//===--- Option.cpp - Abstract Driver Options -----------------------------===// +//===- Option.cpp - Abstract Driver Options -------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,22 +7,24 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Option/Option.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include #include +#include using namespace llvm; using namespace llvm::opt; Option::Option(const OptTable::Info *info, const OptTable *owner) : Info(info), Owner(owner) { - // Multi-level aliases are not supported. This just simplifies option // tracking, it is not an inherent limitation. assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) && diff --git a/lib/Passes/PassBuilder.cpp b/lib/Passes/PassBuilder.cpp index 1f638e768307..afd66f55720a 100644 --- a/lib/Passes/PassBuilder.cpp +++ b/lib/Passes/PassBuilder.cpp @@ -160,6 +160,10 @@ static cl::opt cl::Hidden, cl::ZeroOrMore, cl::desc("Run NewGVN instead of GVN")); +static cl::opt EnableEarlyCSEMemSSA( + "enable-npm-earlycse-memssa", cl::init(false), cl::Hidden, + cl::desc("Enable the EarlyCSE w/ MemorySSA pass for the new PM (default = off)")); + static cl::opt EnableGVNHoist( "enable-npm-gvn-hoist", cl::init(false), cl::Hidden, cl::desc("Enable the GVN hoisting pass for the new PM (default = off)")); @@ -312,7 +316,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, FPM.addPass(SROA()); // Catch trivial redundancies - FPM.addPass(EarlyCSEPass()); + FPM.addPass(EarlyCSEPass(EnableEarlyCSEMemSSA)); // Hoisting of scalars and load expressions. if (EnableGVNHoist) diff --git a/lib/Support/BinaryStreamWriter.cpp b/lib/Support/BinaryStreamWriter.cpp index b22eb1ed12d0..c4276518b191 100644 --- a/lib/Support/BinaryStreamWriter.cpp +++ b/lib/Support/BinaryStreamWriter.cpp @@ -83,6 +83,8 @@ Error BinaryStreamWriter::padToAlignment(uint32_t Align) { uint32_t NewOffset = alignTo(Offset, Align); if (NewOffset > getLength()) return make_error(stream_error_code::stream_too_short); - Offset = NewOffset; + while (Offset < NewOffset) + if (auto EC = writeInteger('\0')) + return EC; return Error::success(); } diff --git a/lib/Support/DebugCounter.cpp b/lib/Support/DebugCounter.cpp index a10ac8e85396..1d46de04ee6a 100644 --- a/lib/Support/DebugCounter.cpp +++ b/lib/Support/DebugCounter.cpp @@ -102,9 +102,13 @@ void DebugCounter::push_back(const std::string &Val) { } } -void DebugCounter::print(raw_ostream &OS) { +void DebugCounter::print(raw_ostream &OS) const { OS << "Counters and values:\n"; for (const auto &KV : Counters) OS << left_justify(RegisteredCounters[KV.first], 32) << ": {" << KV.second.first << "," << KV.second.second << "}\n"; } + +LLVM_DUMP_METHOD void DebugCounter::dump() const { + print(dbgs()); +} diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index c9bca7f4c1ab..4496d06a15f3 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -26,7 +26,7 @@ using namespace llvm; // FoldingSetNodeIDRef Implementation /// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef, -/// used to lookup the node in the FoldingSetImpl. +/// used to lookup the node in the FoldingSetBase. unsigned FoldingSetNodeIDRef::ComputeHash() const { return static_cast(hash_combine_range(Data, Data+Size)); } @@ -142,7 +142,7 @@ void FoldingSetNodeID::AddNodeID(const FoldingSetNodeID &ID) { } /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used to -/// lookup the node in the FoldingSetImpl. +/// lookup the node in the FoldingSetBase. unsigned FoldingSetNodeID::ComputeHash() const { return FoldingSetNodeIDRef(Bits.data(), Bits.size()).ComputeHash(); } @@ -180,7 +180,7 @@ FoldingSetNodeID::Intern(BumpPtrAllocator &Allocator) const { } //===----------------------------------------------------------------------===// -/// Helper functions for FoldingSetImpl. +/// Helper functions for FoldingSetBase. /// GetNextPtr - In order to save space, each bucket is a /// singly-linked-list. In order to make deletion more efficient, we make @@ -188,12 +188,12 @@ FoldingSetNodeID::Intern(BumpPtrAllocator &Allocator) const { /// The problem with this is that the start of the hash buckets are not /// Nodes. If NextInBucketPtr is a bucket pointer, this method returns null: /// use GetBucketPtr when this happens. -static FoldingSetImpl::Node *GetNextPtr(void *NextInBucketPtr) { +static FoldingSetBase::Node *GetNextPtr(void *NextInBucketPtr) { // The low bit is set if this is the pointer back to the bucket. if (reinterpret_cast(NextInBucketPtr) & 1) return nullptr; - return static_cast(NextInBucketPtr); + return static_cast(NextInBucketPtr); } @@ -221,11 +221,11 @@ static void **AllocateBuckets(unsigned NumBuckets) { } //===----------------------------------------------------------------------===// -// FoldingSetImpl Implementation +// FoldingSetBase Implementation -void FoldingSetImpl::anchor() {} +void FoldingSetBase::anchor() {} -FoldingSetImpl::FoldingSetImpl(unsigned Log2InitSize) { +FoldingSetBase::FoldingSetBase(unsigned Log2InitSize) { assert(5 < Log2InitSize && Log2InitSize < 32 && "Initial hash table size out of range"); NumBuckets = 1 << Log2InitSize; @@ -233,14 +233,14 @@ FoldingSetImpl::FoldingSetImpl(unsigned Log2InitSize) { NumNodes = 0; } -FoldingSetImpl::FoldingSetImpl(FoldingSetImpl &&Arg) +FoldingSetBase::FoldingSetBase(FoldingSetBase &&Arg) : Buckets(Arg.Buckets), NumBuckets(Arg.NumBuckets), NumNodes(Arg.NumNodes) { Arg.Buckets = nullptr; Arg.NumBuckets = 0; Arg.NumNodes = 0; } -FoldingSetImpl &FoldingSetImpl::operator=(FoldingSetImpl &&RHS) { +FoldingSetBase &FoldingSetBase::operator=(FoldingSetBase &&RHS) { free(Buckets); // This may be null if the set is in a moved-from state. Buckets = RHS.Buckets; NumBuckets = RHS.NumBuckets; @@ -251,11 +251,11 @@ FoldingSetImpl &FoldingSetImpl::operator=(FoldingSetImpl &&RHS) { return *this; } -FoldingSetImpl::~FoldingSetImpl() { +FoldingSetBase::~FoldingSetBase() { free(Buckets); } -void FoldingSetImpl::clear() { +void FoldingSetBase::clear() { // Set all but the last bucket to null pointers. memset(Buckets, 0, NumBuckets*sizeof(void*)); @@ -266,7 +266,7 @@ void FoldingSetImpl::clear() { NumNodes = 0; } -void FoldingSetImpl::GrowBucketCount(unsigned NewBucketCount) { +void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) { assert((NewBucketCount > NumBuckets) && "Can't shrink a folding set with GrowBucketCount"); assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!"); void **OldBuckets = Buckets; @@ -300,11 +300,11 @@ void FoldingSetImpl::GrowBucketCount(unsigned NewBucketCount) { /// GrowHashTable - Double the size of the hash table and rehash everything. /// -void FoldingSetImpl::GrowHashTable() { +void FoldingSetBase::GrowHashTable() { GrowBucketCount(NumBuckets * 2); } -void FoldingSetImpl::reserve(unsigned EltCount) { +void FoldingSetBase::reserve(unsigned EltCount) { // This will give us somewhere between EltCount / 2 and // EltCount buckets. This puts us in the load factor // range of 1.0 - 2.0. @@ -316,9 +316,9 @@ void FoldingSetImpl::reserve(unsigned EltCount) { /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, /// return it. If not, return the insertion token that will make insertion /// faster. -FoldingSetImpl::Node -*FoldingSetImpl::FindNodeOrInsertPos(const FoldingSetNodeID &ID, - void *&InsertPos) { +FoldingSetBase::Node * +FoldingSetBase::FindNodeOrInsertPos(const FoldingSetNodeID &ID, + void *&InsertPos) { unsigned IDHash = ID.ComputeHash(); void **Bucket = GetBucketFor(IDHash, Buckets, NumBuckets); void *Probe = *Bucket; @@ -342,7 +342,7 @@ FoldingSetImpl::Node /// InsertNode - Insert the specified node into the folding set, knowing that it /// is not already in the map. InsertPos must be obtained from /// FindNodeOrInsertPos. -void FoldingSetImpl::InsertNode(Node *N, void *InsertPos) { +void FoldingSetBase::InsertNode(Node *N, void *InsertPos) { assert(!N->getNextInBucket()); // Do we need to grow the hashtable? if (NumNodes+1 > capacity()) { @@ -371,7 +371,7 @@ void FoldingSetImpl::InsertNode(Node *N, void *InsertPos) { /// RemoveNode - Remove a node from the folding set, returning true if one was /// removed or false if the node was not in the folding set. -bool FoldingSetImpl::RemoveNode(Node *N) { +bool FoldingSetBase::RemoveNode(Node *N) { // Because each bucket is a circular list, we don't need to compute N's hash // to remove it. void *Ptr = N->getNextInBucket(); @@ -412,7 +412,7 @@ bool FoldingSetImpl::RemoveNode(Node *N) { /// GetOrInsertNode - If there is an existing simple Node exactly /// equal to the specified node, return it. Otherwise, insert 'N' and it /// instead. -FoldingSetImpl::Node *FoldingSetImpl::GetOrInsertNode(FoldingSetImpl::Node *N) { +FoldingSetBase::Node *FoldingSetBase::GetOrInsertNode(FoldingSetBase::Node *N) { FoldingSetNodeID ID; GetNodeProfile(N, ID); void *IP; diff --git a/lib/Support/ThreadPool.cpp b/lib/Support/ThreadPool.cpp index db03a4d6240d..22b7550d4971 100644 --- a/lib/Support/ThreadPool.cpp +++ b/lib/Support/ThreadPool.cpp @@ -53,11 +53,7 @@ ThreadPool::ThreadPool(unsigned ThreadCount) Tasks.pop(); } // Run the task we just grabbed -#ifndef _MSC_VER Task(); -#else - Task(/* unused */ false); -#endif { // Adjust `ActiveThreads`, in case someone waits on ThreadPool::wait() @@ -82,7 +78,7 @@ void ThreadPool::wait() { [&] { return !ActiveThreads && Tasks.empty(); }); } -std::shared_future ThreadPool::asyncImpl(TaskTy Task) { +std::shared_future ThreadPool::asyncImpl(TaskTy Task) { /// Wrap the Task in a packaged_task to return a future object. PackagedTaskTy PackagedTask(std::move(Task)); auto Future = PackagedTask.get_future(); @@ -128,25 +124,16 @@ void ThreadPool::wait() { while (!Tasks.empty()) { auto Task = std::move(Tasks.front()); Tasks.pop(); -#ifndef _MSC_VER - Task(); -#else - Task(/* unused */ false); -#endif + Task(); } } -std::shared_future ThreadPool::asyncImpl(TaskTy Task) { -#ifndef _MSC_VER +std::shared_future ThreadPool::asyncImpl(TaskTy Task) { // Get a Future with launch::deferred execution using std::async auto Future = std::async(std::launch::deferred, std::move(Task)).share(); // Wrap the future so that both ThreadPool::wait() can operate and the // returned future can be sync'ed on. PackagedTaskTy PackagedTask([Future]() { Future.get(); }); -#else - auto Future = std::async(std::launch::deferred, std::move(Task), false).share(); - PackagedTaskTy PackagedTask([Future](bool) -> bool { Future.get(); return false; }); -#endif Tasks.push(std::move(PackagedTask)); return Future; } diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index 7d3537e20727..2df0eaff47e5 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -163,16 +163,6 @@ static void SetMemoryLimits (unsigned size) r.rlim_cur = limit; setrlimit (RLIMIT_RSS, &r); #endif -#ifdef RLIMIT_AS // e.g. NetBSD doesn't have it. - // Don't set virtual memory limit if built with any Sanitizer. They need 80Tb - // of virtual memory for shadow memory mapping. -#if !LLVM_MEMORY_SANITIZER_BUILD && !LLVM_ADDRESS_SANITIZER_BUILD - // Virtual memory. - getrlimit (RLIMIT_AS, &r); - r.rlim_cur = limit; - setrlimit (RLIMIT_AS, &r); -#endif -#endif #endif } diff --git a/lib/TableGen/Record.cpp b/lib/TableGen/Record.cpp index 83f7147dc9f6..b2636e1e6cb4 100644 --- a/lib/TableGen/Record.cpp +++ b/lib/TableGen/Record.cpp @@ -11,20 +11,28 @@ // //===----------------------------------------------------------------------===// -#include "llvm/TableGen/Record.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" #include #include -#include +#include +#include +#include +#include using namespace llvm; @@ -162,7 +170,8 @@ RecTy *llvm::resolveTypes(RecTy *T1, RecTy *T2) { // Initializer implementations //===----------------------------------------------------------------------===// -void Init::anchor() { } +void Init::anchor() {} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void Init::dump() const { return print(errs()); } #endif @@ -301,7 +310,6 @@ static Init *fixBitInit(const RecordVal *RV, Init *Before, Init *After) { // resolveReferences - If there are any field references that refer to fields // that have been filled in, we can propagate the values now. -// Init *BitsInit::resolveReferences(Record &R, const RecordVal *RV) const { bool Changed = false; SmallVector NewBits(getNumBits()); @@ -615,7 +623,7 @@ void UnOpInit::Profile(FoldingSetNodeID &ID) const { Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { switch (getOpcode()) { - case CAST: { + case CAST: if (isa(getType())) { if (StringInit *LHSs = dyn_cast(LHS)) return LHSs; @@ -680,15 +688,15 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { } } break; - } - case HEAD: { + + case HEAD: if (ListInit *LHSl = dyn_cast(LHS)) { assert(!LHSl->empty() && "Empty list in head"); return LHSl->getElement(0); } break; - } - case TAIL: { + + case TAIL: if (ListInit *LHSl = dyn_cast(LHS)) { assert(!LHSl->empty() && "Empty list in tail"); // Note the +1. We can't just pass the result of getValues() @@ -696,16 +704,14 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const { return ListInit::get(LHSl->getValues().slice(1), LHSl->getType()); } break; - } - case EMPTY: { + + case EMPTY: if (ListInit *LHSl = dyn_cast(LHS)) return IntInit::get(LHSl->empty()); if (StringInit *LHSs = dyn_cast(LHS)) return IntInit::get(LHSs->getValue().empty()); - break; } - } return const_cast(this); } @@ -948,7 +954,6 @@ static Init *EvaluateOperation(OpInit *RHSo, Init *LHS, Init *Arg, static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type, Record *CurRec, MultiClass *CurMultiClass) { - OpInit *RHSo = dyn_cast(RHS); if (!RHSo) @@ -1245,7 +1250,7 @@ VarInit *VarInit::get(StringRef VN, RecTy *T) { } VarInit *VarInit::get(Init *VN, RecTy *T) { - typedef std::pair Key; + using Key = std::pair; static DenseMap ThePool; Key TheKey(std::make_pair(T, VN)); @@ -1320,7 +1325,7 @@ Init *VarInit::resolveReferences(Record &R, const RecordVal *RV) const { } VarBitInit *VarBitInit::get(TypedInit *T, unsigned B) { - typedef std::pair Key; + using Key = std::pair; static DenseMap ThePool; Key TheKey(std::make_pair(T, B)); @@ -1352,7 +1357,7 @@ Init *VarBitInit::resolveReferences(Record &R, const RecordVal *RV) const { VarListElementInit *VarListElementInit::get(TypedInit *T, unsigned E) { - typedef std::pair Key; + using Key = std::pair; static DenseMap ThePool; Key TheKey(std::make_pair(T, E)); @@ -1422,7 +1427,7 @@ std::string DefInit::getAsString() const { } FieldInit *FieldInit::get(Init *R, StringInit *FN) { - typedef std::pair Key; + using Key = std::pair; static DenseMap ThePool; Key TheKey(std::make_pair(R, FN)); diff --git a/lib/TableGen/SetTheory.cpp b/lib/TableGen/SetTheory.cpp index a4d33051b4f7..733e0aeef623 100644 --- a/lib/TableGen/SetTheory.cpp +++ b/lib/TableGen/SetTheory.cpp @@ -12,18 +12,29 @@ // //===----------------------------------------------------------------------===// -#include "llvm/TableGen/SetTheory.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Format.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" +#include "llvm/TableGen/SetTheory.h" +#include +#include +#include +#include using namespace llvm; // Define the standard operators. namespace { -typedef SetTheory::RecSet RecSet; -typedef SetTheory::RecVec RecVec; +using RecSet = SetTheory::RecSet; +using RecVec = SetTheory::RecVec; // (add a, b, ...) Evaluate and union all arguments. struct AddOp : public SetTheory::Operator { @@ -237,13 +248,13 @@ struct FieldExpander : public SetTheory::Expander { ST.evaluate(Def->getValueInit(FieldName), Elts, Def->getLoc()); } }; + } // end anonymous namespace // Pin the vtables to this file. void SetTheory::Operator::anchor() {} void SetTheory::Expander::anchor() {} - SetTheory::SetTheory() { addOperator("add", llvm::make_unique()); addOperator("sub", llvm::make_unique()); @@ -321,4 +332,3 @@ const RecVec *SetTheory::expand(Record *Set) { // Set is not expandable. return nullptr; } - diff --git a/lib/Target/AArch64/AArch64.td b/lib/Target/AArch64/AArch64.td index abe28460c83a..53eef79c4df3 100644 --- a/lib/Target/AArch64/AArch64.td +++ b/lib/Target/AArch64/AArch64.td @@ -362,6 +362,7 @@ def ProcThunderXT83 : SubtargetFeature<"thunderxt83", "ARMProcFamily", def : ProcessorModel<"generic", NoSchedModel, [ FeatureFPARMv8, + FeatureFuseAES, FeatureNEON, FeaturePerfMon, FeaturePostRAScheduler diff --git a/lib/Target/AArch64/AArch64FastISel.cpp b/lib/Target/AArch64/AArch64FastISel.cpp index e8fcf1a0e9b7..7bf2097c17ce 100644 --- a/lib/Target/AArch64/AArch64FastISel.cpp +++ b/lib/Target/AArch64/AArch64FastISel.cpp @@ -1282,6 +1282,10 @@ unsigned AArch64FastISel::emitAddSub_rr(bool UseAdd, MVT RetVT, unsigned LHSReg, bool WantResult) { assert(LHSReg && RHSReg && "Invalid register number."); + if (LHSReg == AArch64::SP || LHSReg == AArch64::WSP || + RHSReg == AArch64::SP || RHSReg == AArch64::WSP) + return 0; + if (RetVT != MVT::i32 && RetVT != MVT::i64) return 0; @@ -1362,6 +1366,8 @@ unsigned AArch64FastISel::emitAddSub_rs(bool UseAdd, MVT RetVT, unsigned LHSReg, uint64_t ShiftImm, bool SetFlags, bool WantResult) { assert(LHSReg && RHSReg && "Invalid register number."); + assert(LHSReg != AArch64::SP && LHSReg != AArch64::WSP && + RHSReg != AArch64::SP && RHSReg != AArch64::WSP); if (RetVT != MVT::i32 && RetVT != MVT::i64) return 0; @@ -1403,6 +1409,8 @@ unsigned AArch64FastISel::emitAddSub_rx(bool UseAdd, MVT RetVT, unsigned LHSReg, uint64_t ShiftImm, bool SetFlags, bool WantResult) { assert(LHSReg && RHSReg && "Invalid register number."); + assert(LHSReg != AArch64::XZR && LHSReg != AArch64::WZR && + RHSReg != AArch64::XZR && RHSReg != AArch64::WZR); if (RetVT != MVT::i32 && RetVT != MVT::i64) return 0; diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp index 059556a560c0..083ca2156598 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -9366,7 +9366,7 @@ static SDValue splitStores(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, return SDValue(); StoreSDNode *S = cast(N); - if (S->isVolatile()) + if (S->isVolatile() || S->isIndexed()) return SDValue(); SDValue StVal = S->getValue(); diff --git a/lib/Target/AArch64/AArch64SchedFalkorDetails.td b/lib/Target/AArch64/AArch64SchedFalkorDetails.td index 7402bcf1346c..3d737402022d 100644 --- a/lib/Target/AArch64/AArch64SchedFalkorDetails.td +++ b/lib/Target/AArch64/AArch64SchedFalkorDetails.td @@ -160,6 +160,21 @@ def FalkorWr_1VX_1VY_10cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY]> { let NumMicroOps = 2; } +def FalkorWr_1VX_1VY_12cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY]> { + let Latency = 12; + let NumMicroOps = 2; +} + +def FalkorWr_1VX_1VY_14cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY]> { + let Latency = 14; + let NumMicroOps = 2; +} + +def FalkorWr_1VX_1VY_21cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY]> { + let Latency = 21; + let NumMicroOps = 2; +} + def FalkorWr_1GTOV_1VXVY_2cyc : SchedWriteRes<[FalkorUnitGTOV, FalkorUnitVXVY]> { let Latency = 2; let NumMicroOps = 2; @@ -195,10 +210,10 @@ def FalkorWr_1X_1Z_8cyc : SchedWriteRes<[FalkorUnitX, FalkorUnitZ]> { let ResourceCycles = [2, 8]; } -def FalkorWr_1X_1Z_16cyc : SchedWriteRes<[FalkorUnitX, FalkorUnitZ]> { - let Latency = 16; +def FalkorWr_1X_1Z_11cyc : SchedWriteRes<[FalkorUnitX, FalkorUnitZ]> { + let Latency = 11; let NumMicroOps = 2; - let ResourceCycles = [2, 16]; + let ResourceCycles = [2, 11]; } def FalkorWr_1LD_1Z_3cyc : SchedWriteRes<[FalkorUnitLD, FalkorUnitZ]> { @@ -289,9 +304,27 @@ def FalkorWr_1XYZ_1VSD_1ST_0cyc: SchedWriteRes<[FalkorUnitXYZ, FalkorUnitVSD, Fa //===----------------------------------------------------------------------===// // Define 4 micro-op types -def FalkorWr_2VX_2VY_2cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY, - FalkorUnitVX, FalkorUnitVY]> { - let Latency = 2; +def FalkorWr_2VX_2VY_14cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY, + FalkorUnitVX, FalkorUnitVY]> { + let Latency = 14; + let NumMicroOps = 4; +} + +def FalkorWr_2VX_2VY_20cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY, + FalkorUnitVX, FalkorUnitVY]> { + let Latency = 20; + let NumMicroOps = 4; +} + +def FalkorWr_2VX_2VY_21cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY, + FalkorUnitVX, FalkorUnitVY]> { + let Latency = 21; + let NumMicroOps = 4; +} + +def FalkorWr_2VX_2VY_24cyc : SchedWriteRes<[FalkorUnitVX, FalkorUnitVY, + FalkorUnitVX, FalkorUnitVY]> { + let Latency = 24; let NumMicroOps = 4; } @@ -575,7 +608,8 @@ def : InstRW<[FalkorWr_2VXVY_2cyc], (instregex "^FCM(EQ|LE|GE|GT|LT)(v2i64|v4i def : InstRW<[FalkorWr_2VXVY_2cyc], (instrs FCVTLv4i16, FCVTLv2i32)>; def : InstRW<[FalkorWr_2VXVY_2cyc], (instregex "^FRINT(A|I|M|N|P|X|Z)(v2f64|v4f32)$")>; -def : InstRW<[FalkorWr_1VX_1VY_10cyc],(instregex "^(FDIV|FSQRT)v2f32$")>; +def : InstRW<[FalkorWr_1VX_1VY_10cyc],(instrs FDIVv2f32)>; +def : InstRW<[FalkorWr_1VX_1VY_12cyc],(instrs FSQRTv2f32)>; def : InstRW<[FalkorWr_2VXVY_3cyc], (instregex "^(FABD|FADD(P)?|FSUB)(v2f64|v4f32)$")>; @@ -592,7 +626,10 @@ def : InstRW<[FalkorWr_FMUL64_2VXVY_6cyc], def : InstRW<[FalkorWr_3VXVY_4cyc], (instrs FCVTNv4i16, FCVTNv2i32, FCVTXNv2f32)>; def : InstRW<[FalkorWr_3VXVY_5cyc], (instrs FCVTNv8i16, FCVTNv4i32, FCVTXNv4f32)>; -def : InstRW<[FalkorWr_2VX_2VY_2cyc], (instregex "^(FDIV|FSQRT)(v2f64|v4f32)$")>; +def : InstRW<[FalkorWr_2VX_2VY_14cyc],(instrs FDIVv2f64)>; +def : InstRW<[FalkorWr_2VX_2VY_20cyc],(instrs FDIVv4f32)>; +def : InstRW<[FalkorWr_2VX_2VY_21cyc],(instrs FSQRTv2f64)>; +def : InstRW<[FalkorWr_2VX_2VY_24cyc],(instrs FSQRTv4f32)>; def : InstRW<[FalkorWr_VMUL32_1VXVY_4cyc, FalkorReadVMA], (instregex "^ML(A|S)(v8i8|v4i16|v2i32)(_indexed)?$")>; @@ -1039,8 +1076,10 @@ def : InstRW<[FalkorWr_FMUL32_1VXVY_5cyc], def : InstRW<[FalkorWr_FMUL64_1VXVY_6cyc], (instregex "^F(N)?MULDrr$")>; -def : InstRW<[FalkorWr_1VX_1VY_10cyc],(instregex "^FDIV(S|D)rr$")>; -def : InstRW<[FalkorWr_1VX_1VY_2cyc], (instregex "^FSQRT(S|D)r$")>; +def : InstRW<[FalkorWr_1VX_1VY_10cyc],(instrs FDIVSrr)>; +def : InstRW<[FalkorWr_1VX_1VY_14cyc],(instrs FDIVDrr)>; +def : InstRW<[FalkorWr_1VX_1VY_12cyc],(instrs FSQRTSr)>; +def : InstRW<[FalkorWr_1VX_1VY_21cyc],(instrs FSQRTDr)>; def : InstRW<[FalkorWr_FMUL32_1VXVY_5cyc, ReadDefault, ReadDefault, FalkorReadFMA32], (instregex "^F(N)?M(ADD|SUB)Srrr$")>; @@ -1112,7 +1151,7 @@ def : InstRW<[FalkorWr_IMUL64_1X_5cyc, ReadDefault, ReadDefault, FalkorReadIMA64 (instregex "^M(ADD|SUB)Xrrr$")>; def : InstRW<[FalkorWr_1X_1Z_8cyc], (instregex "^(S|U)DIVWr$")>; -def : InstRW<[FalkorWr_1X_1Z_16cyc], (instregex "^(S|U)DIVXr$")>; +def : InstRW<[FalkorWr_1X_1Z_11cyc], (instregex "^(S|U)DIVXr$")>; def : InstRW<[FalkorWr_VMUL32_2VXVY_4cyc], (instregex "^(S|U)MULLv.*$")>; diff --git a/lib/Target/AArch64/AArch64Subtarget.cpp b/lib/Target/AArch64/AArch64Subtarget.cpp index d3cab1ad3397..a9a9d5ce8429 100644 --- a/lib/Target/AArch64/AArch64Subtarget.cpp +++ b/lib/Target/AArch64/AArch64Subtarget.cpp @@ -92,6 +92,10 @@ void AArch64Subtarget::initializeProperties() { MaxInterleaveFactor = 4; // FIXME: remove this to enable 64-bit SLP if performance looks good. MinVectorRegisterBitWidth = 128; + CacheLineSize = 128; + PrefetchDistance = 820; + MinPrefetchStride = 2048; + MaxPrefetchIterationsAhead = 8; break; case Kryo: MaxInterleaveFactor = 4; diff --git a/lib/Target/AArch64/AArch64TargetTransformInfo.h b/lib/Target/AArch64/AArch64TargetTransformInfo.h index d0299149c38c..290a1ca1f24b 100644 --- a/lib/Target/AArch64/AArch64TargetTransformInfo.h +++ b/lib/Target/AArch64/AArch64TargetTransformInfo.h @@ -78,7 +78,7 @@ class AArch64TTIImpl : public BasicTTIImplBase { return 31; } - unsigned getRegisterBitWidth(bool Vector) { + unsigned getRegisterBitWidth(bool Vector) const { if (Vector) { if (ST->hasNEON()) return 128; diff --git a/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp b/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp index 8084d368c80f..6f3742ed039b 100644 --- a/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp +++ b/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp @@ -9,7 +9,7 @@ // /// \file /// This pass marks all internal functions as always_inline and creates -/// duplicates of all other functions a marks the duplicates as always_inline. +/// duplicates of all other functions and marks the duplicates as always_inline. // //===----------------------------------------------------------------------===// diff --git a/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp b/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp index 3c788fa1dcea..6f002860044c 100644 --- a/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp +++ b/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp @@ -107,7 +107,7 @@ bool AMDGPUAnnotateUniformValues::isClobberedInFunction(LoadInst * Load) { DFS(Start, Checklist); for (auto &BB : Checklist) { - BasicBlock::iterator StartIt = (BB == Load->getParent()) ? + BasicBlock::iterator StartIt = (!L && (BB == Load->getParent())) ? BasicBlock::iterator(Load) : BB->end(); if (MDR->getPointerDependencyFrom(MemoryLocation(Ptr), true, StartIt, BB, Load).isClobber()) diff --git a/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp b/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp index 251c2f9bb25a..f235313e4853 100644 --- a/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp +++ b/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp @@ -138,7 +138,10 @@ class AMDGPUDAGToDAGISel : public SelectionDAGISel { bool SelectMUBUFIntrinsicVOffset(SDValue Offset, SDValue &SOffset, SDValue &ImmOffset, SDValue &VOffset) const; - bool SelectFlat(SDValue Addr, SDValue &VAddr, SDValue &SLC) const; + bool SelectFlatAtomic(SDValue Addr, SDValue &VAddr, + SDValue &Offset, SDValue &SLC) const; + bool SelectFlatOffset(SDValue Addr, SDValue &VAddr, + SDValue &Offset, SDValue &SLC) const; bool SelectSMRDOffset(SDValue ByteOffsetNode, SDValue &Offset, bool &Imm) const; @@ -1313,14 +1316,37 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFIntrinsicVOffset(SDValue Offset, return true; } -bool AMDGPUDAGToDAGISel::SelectFlat(SDValue Addr, - SDValue &VAddr, - SDValue &SLC) const { +bool AMDGPUDAGToDAGISel::SelectFlatOffset(SDValue Addr, + SDValue &VAddr, + SDValue &Offset, + SDValue &SLC) const { + int64_t OffsetVal = 0; + + if (Subtarget->hasFlatInstOffsets() && + CurDAG->isBaseWithConstantOffset(Addr)) { + SDValue N0 = Addr.getOperand(0); + SDValue N1 = Addr.getOperand(1); + uint64_t COffsetVal = cast(N1)->getZExtValue(); + if (isUInt<12>(COffsetVal)) { + Addr = N0; + OffsetVal = COffsetVal; + } + } + VAddr = Addr; + Offset = CurDAG->getTargetConstant(OffsetVal, SDLoc(), MVT::i16); SLC = CurDAG->getTargetConstant(0, SDLoc(), MVT::i1); + return true; } +bool AMDGPUDAGToDAGISel::SelectFlatAtomic(SDValue Addr, + SDValue &VAddr, + SDValue &Offset, + SDValue &SLC) const { + return SelectFlatOffset(Addr, VAddr, Offset, SLC); +} + bool AMDGPUDAGToDAGISel::SelectSMRDOffset(SDValue ByteOffsetNode, SDValue &Offset, bool &Imm) const { diff --git a/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp index a7eac080f885..e54c887d6090 100644 --- a/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp +++ b/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp @@ -126,8 +126,9 @@ bool AMDGPUInstructionSelector::selectG_STORE(MachineInstr &I) const { MachineInstr *Flat = BuildMI(*BB, &I, DL, TII.get(AMDGPU::FLAT_STORE_DWORD)) .add(I.getOperand(1)) .add(I.getOperand(0)) - .addImm(0) - .addImm(0); + .addImm(0) // offset + .addImm(0) // glc + .addImm(0); // slc // Now that we selected an opcode, we need to constrain the register @@ -392,8 +393,9 @@ bool AMDGPUInstructionSelector::selectG_LOAD(MachineInstr &I) const { MachineInstr *Flat = BuildMI(*BB, &I, DL, TII.get(Opcode)) .add(I.getOperand(0)) .addReg(PtrReg) - .addImm(0) - .addImm(0); + .addImm(0) // offset + .addImm(0) // glc + .addImm(0); // slc bool Ret = constrainSelectedInstRegOperands(*Flat, TII, TRI, RBI); I.eraseFromParent(); diff --git a/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp index b889788c3426..790a69b84397 100644 --- a/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp +++ b/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp @@ -34,6 +34,8 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo() { const LLT P1 = LLT::pointer(1, 64); const LLT P2 = LLT::pointer(2, 64); + setAction({G_ADD, S32}, Legal); + // FIXME: i1 operands to intrinsics should always be legal, but other i1 // values may not be legal. We need to figure out how to distinguish // between these two scenarios. diff --git a/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp b/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp index dee3d2856701..0d6689bd04c4 100644 --- a/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp +++ b/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp @@ -195,7 +195,7 @@ unsigned AMDGPUTTIImpl::getNumberOfRegisters(bool Vec) { return 4 * 128; // XXX - 4 channels. Should these count as vector instead? } -unsigned AMDGPUTTIImpl::getRegisterBitWidth(bool Vector) { +unsigned AMDGPUTTIImpl::getRegisterBitWidth(bool Vector) const { return Vector ? 0 : 32; } @@ -489,6 +489,19 @@ bool AMDGPUTTIImpl::isSourceOfDivergence(const Value *V) const { return false; } +bool AMDGPUTTIImpl::isAlwaysUniform(const Value *V) const { + if (const IntrinsicInst *Intrinsic = dyn_cast(V)) { + switch (Intrinsic->getIntrinsicID()) { + default: + return false; + case Intrinsic::amdgcn_readfirstlane: + case Intrinsic::amdgcn_readlane: + return true; + } + } + return false; +} + unsigned AMDGPUTTIImpl::getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index, Type *SubTp) { if (ST->hasVOP3PInsts()) { diff --git a/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h b/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h index e0024e21e82b..a60b1bb1b59c 100644 --- a/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h +++ b/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h @@ -76,7 +76,7 @@ class AMDGPUTTIImpl final : public BasicTTIImplBase { } unsigned getNumberOfRegisters(bool Vector); - unsigned getRegisterBitWidth(bool Vector); + unsigned getRegisterBitWidth(bool Vector) const; unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const; bool isLegalToVectorizeMemChain(unsigned ChainSizeInBytes, @@ -103,6 +103,7 @@ class AMDGPUTTIImpl final : public BasicTTIImplBase { int getVectorInstrCost(unsigned Opcode, Type *ValTy, unsigned Index); bool isSourceOfDivergence(const Value *V) const; + bool isAlwaysUniform(const Value *V) const; unsigned getFlatAddressSpace() const { // Don't bother running InferAddressSpaces pass on graphics shaders which diff --git a/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index 16e3b7b4ebee..392e9d89bd9b 100644 --- a/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -285,6 +285,9 @@ class AMDGPUOperand : public MCParsedAsmOperand { bool isOffset() const { return isImmTy(ImmTyOffset) && isUInt<16>(getImm()); } bool isOffset0() const { return isImmTy(ImmTyOffset0) && isUInt<16>(getImm()); } bool isOffset1() const { return isImmTy(ImmTyOffset1) && isUInt<8>(getImm()); } + + bool isOffsetU12() const { return isImmTy(ImmTyOffset) && isUInt<12>(getImm()); } + bool isOffsetS13() const { return isImmTy(ImmTyOffset) && isInt<13>(getImm()); } bool isGDS() const { return isImmTy(ImmTyGDS); } bool isGLC() const { return isImmTy(ImmTyGLC); } bool isSLC() const { return isImmTy(ImmTySLC); } @@ -886,6 +889,10 @@ class AMDGPUAsmParser : public MCTargetAsmParser { return getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm]; } + bool hasFlatOffsets() const { + return getFeatureBits()[AMDGPU::FeatureFlatInstOffsets]; + } + bool hasSGPR102_SGPR103() const { return !isVI(); } @@ -1034,6 +1041,7 @@ class AMDGPUAsmParser : public MCTargetAsmParser { AMDGPUOperand::Ptr defaultSMRDOffset8() const; AMDGPUOperand::Ptr defaultSMRDOffset20() const; AMDGPUOperand::Ptr defaultSMRDLiteralOffset() const; + AMDGPUOperand::Ptr defaultOffsetU12() const; OperandMatchResultTy parseOModOperand(OperandVector &Operands); @@ -1970,6 +1978,15 @@ unsigned AMDGPUAsmParser::checkTargetMatchPredicate(MCInst &Inst) { } } + if ((TSFlags & SIInstrFlags::FLAT) && !hasFlatOffsets()) { + // FIXME: Produces error without correct column reported. + auto OpNum = + AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::offset); + const auto &Op = Inst.getOperand(OpNum); + if (Op.getImm() != 0) + return Match_InvalidOperand; + } + return Match_Success; } @@ -3849,6 +3866,10 @@ AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSMRDLiteralOffset() const { return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyOffset); } +AMDGPUOperand::Ptr AMDGPUAsmParser::defaultOffsetU12() const { + return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyOffset); +} + //===----------------------------------------------------------------------===// // vop3 //===----------------------------------------------------------------------===// diff --git a/lib/Target/AMDGPU/FLATInstructions.td b/lib/Target/AMDGPU/FLATInstructions.td index 8ba9efd42c70..98eda288bcac 100644 --- a/lib/Target/AMDGPU/FLATInstructions.td +++ b/lib/Target/AMDGPU/FLATInstructions.td @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// -def FLATAtomic : ComplexPattern; +def FLATAtomic : ComplexPattern; +def FLATOffset : ComplexPattern; //===----------------------------------------------------------------------===// // FLAT classes @@ -55,6 +56,8 @@ class FLAT_Real op, FLAT_Pseudo ps> : // copy relevant pseudo op flags let SubtargetPredicate = ps.SubtargetPredicate; let AsmMatchConverter = ps.AsmMatchConverter; + let TSFlags = ps.TSFlags; + let UseNamedOperandTable = ps.UseNamedOperandTable; // encoding fields bits<8> vaddr; @@ -63,10 +66,23 @@ class FLAT_Real op, FLAT_Pseudo ps> : bits<1> slc; bits<1> glc; + // Only valid on gfx9 + bits<1> lds = 0; // XXX - What does this actually do? + bits<2> seg; // Segment, 00=flat, 01=scratch, 10=global, 11=reserved + + // Signed offset. Highest bit ignored for flat and treated as 12-bit + // unsigned for flat acceses. + bits<13> offset; + bits<1> nv = 0; // XXX - What does this actually do? + // We don't use tfe right now, and it was removed in gfx9. bits<1> tfe = 0; - // 15-0 is reserved. + // Only valid on GFX9+ + let Inst{12-0} = offset; + let Inst{13} = lds; + let Inst{15-14} = 0; + let Inst{16} = !if(ps.has_glc, glc, ps.glcValue); let Inst{17} = slc; let Inst{24-18} = op; @@ -74,24 +90,30 @@ class FLAT_Real op, FLAT_Pseudo ps> : let Inst{39-32} = vaddr; let Inst{47-40} = !if(ps.has_data, vdata, ?); // 54-48 is reserved. - let Inst{55} = tfe; + let Inst{55} = nv; // nv on GFX9+, TFE before. let Inst{63-56} = !if(ps.has_vdst, vdst, ?); } -class FLAT_Load_Pseudo : FLAT_Pseudo< +class FLAT_Load_Pseudo : FLAT_Pseudo< opName, (outs regClass:$vdst), - (ins VReg_64:$vaddr, GLC:$glc, slc:$slc), - " $vdst, $vaddr$glc$slc"> { + !if(HasSignedOffset, + (ins VReg_64:$vaddr, offset_s13:$offset, GLC:$glc, slc:$slc), + (ins VReg_64:$vaddr, offset_u12:$offset, GLC:$glc, slc:$slc)), + " $vdst, $vaddr$offset$glc$slc"> { let has_data = 0; let mayLoad = 1; } -class FLAT_Store_Pseudo : FLAT_Pseudo< +class FLAT_Store_Pseudo : FLAT_Pseudo< opName, (outs), - (ins VReg_64:$vaddr, vdataClass:$vdata, GLC:$glc, slc:$slc), - " $vaddr, $vdata$glc$slc"> { + !if(HasSignedOffset, + (ins VReg_64:$vaddr, vdataClass:$vdata, offset_s13:$offset, GLC:$glc, slc:$slc), + (ins VReg_64:$vaddr, vdataClass:$vdata, offset_u12:$offset, GLC:$glc, slc:$slc)), + " $vaddr, $vdata$offset$glc$slc"> { let mayLoad = 0; let mayStore = 1; let has_vdst = 0; @@ -103,12 +125,15 @@ multiclass FLAT_Atomic_Pseudo< ValueType vt, SDPatternOperator atomic = null_frag, ValueType data_vt = vt, - RegisterClass data_rc = vdst_rc> { + RegisterClass data_rc = vdst_rc, + bit HasSignedOffset = 0> { def "" : FLAT_Pseudo , AtomicNoRet { let mayLoad = 1; @@ -121,10 +146,12 @@ multiclass FLAT_Atomic_Pseudo< def _RTN : FLAT_Pseudo , + (atomic (FLATAtomic i64:$vaddr, i16:$offset, i1:$slc), data_vt:$vdata))]>, AtomicNoRet { let mayLoad = 1; let mayStore = 1; @@ -312,31 +339,31 @@ def flat_truncstorei16 : flat_st ; // Patterns for global loads with no offset. class FlatLoadPat : Pat < - (vt (node i64:$addr)), - (inst $addr, 0, 0) + (vt (node (FLATAtomic i64:$vaddr, i16:$offset, i1:$slc))), + (inst $vaddr, $offset, 0, $slc) >; class FlatLoadAtomicPat : Pat < - (vt (node i64:$addr)), - (inst $addr, 1, 0) + (vt (node (FLATAtomic i64:$vaddr, i16:$offset, i1:$slc))), + (inst $vaddr, $offset, 1, $slc) >; class FlatStorePat : Pat < - (node vt:$data, i64:$addr), - (inst $addr, $data, 0, 0) + (node vt:$data, (FLATAtomic i64:$vaddr, i16:$offset, i1:$slc)), + (inst $vaddr, $data, $offset, 0, $slc) >; class FlatStoreAtomicPat : Pat < // atomic store follows atomic binop convention so the address comes // first. - (node i64:$addr, vt:$data), - (inst $addr, $data, 1, 0) + (node (FLATAtomic i64:$vaddr, i16:$offset, i1:$slc), vt:$data), + (inst $vaddr, $data, $offset, 1, $slc) >; class FlatAtomicPat : Pat < - (vt (node i64:$addr, data_vt:$data)), - (inst $addr, $data, 0) + (vt (node (FLATAtomic i64:$vaddr, i16:$offset, i1:$slc), data_vt:$data)), + (inst $vaddr, $data, $offset, $slc) >; let Predicates = [isCIVI] in { diff --git a/lib/Target/AMDGPU/SIISelLowering.cpp b/lib/Target/AMDGPU/SIISelLowering.cpp index 599ee942d738..441f1ef4bd04 100644 --- a/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/lib/Target/AMDGPU/SIISelLowering.cpp @@ -567,9 +567,17 @@ bool SITargetLowering::getAddrModeArguments(IntrinsicInst *II, } bool SITargetLowering::isLegalFlatAddressingMode(const AddrMode &AM) const { - // Flat instructions do not have offsets, and only have the register - // address. - return AM.BaseOffs == 0 && (AM.Scale == 0 || AM.Scale == 1); + if (!Subtarget->hasFlatInstOffsets()) { + // Flat instructions do not have offsets, and only have the register + // address. + return AM.BaseOffs == 0 && AM.Scale == 0; + } + + // GFX9 added a 13-bit signed offset. When using regular flat instructions, + // the sign bit is ignored and is treated as a 12-bit unsigned offset. + + // Just r + i + return isUInt<12>(AM.BaseOffs) && AM.Scale == 0; } bool SITargetLowering::isLegalMUBUFAddressingMode(const AddrMode &AM) const { diff --git a/lib/Target/AMDGPU/SIInstrInfo.cpp b/lib/Target/AMDGPU/SIInstrInfo.cpp index 58c05cf16f15..1097814e99ce 100644 --- a/lib/Target/AMDGPU/SIInstrInfo.cpp +++ b/lib/Target/AMDGPU/SIInstrInfo.cpp @@ -468,13 +468,11 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, Builder.addReg(RI.getSubReg(SrcReg, SubIdx)); - if (Idx == SubIndices.size() - 1) - Builder.addReg(SrcReg, getKillRegState(KillSrc) | RegState::Implicit); - if (Idx == 0) Builder.addReg(DestReg, RegState::Define | RegState::Implicit); - Builder.addReg(SrcReg, RegState::Implicit); + bool UseKill = KillSrc && Idx == SubIndices.size() - 1; + Builder.addReg(SrcReg, getKillRegState(UseKill) | RegState::Implicit); } } @@ -2331,11 +2329,12 @@ static bool isSubRegOf(const SIRegisterInfo &TRI, bool SIInstrInfo::verifyInstruction(const MachineInstr &MI, StringRef &ErrInfo) const { uint16_t Opcode = MI.getOpcode(); - if (SIInstrInfo::isGenericOpcode(MI.getOpcode())) return true; - const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); + const MachineFunction *MF = MI.getParent()->getParent(); + const MachineRegisterInfo &MRI = MF->getRegInfo(); + int Src0Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0); int Src1Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1); int Src2Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2); @@ -2565,6 +2564,14 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI, } } + if (isFLAT(MI) && !MF->getSubtarget().hasFlatInstOffsets()) { + const MachineOperand *Offset = getNamedOperand(MI, AMDGPU::OpName::offset); + if (Offset->getImm() != 0) { + ErrInfo = "subtarget does not support offsets in flat instructions"; + return false; + } + } + return true; } diff --git a/lib/Target/AMDGPU/SIInstrInfo.td b/lib/Target/AMDGPU/SIInstrInfo.td index 445bf79a7814..470a47b02443 100644 --- a/lib/Target/AMDGPU/SIInstrInfo.td +++ b/lib/Target/AMDGPU/SIInstrInfo.td @@ -492,11 +492,21 @@ class NamedOperandU8 : Operand { let ParserMatchClass = MatchClass; } +class NamedOperandU12 : Operand { + let PrintMethod = "print"#Name; + let ParserMatchClass = MatchClass; +} + class NamedOperandU16 : Operand { let PrintMethod = "print"#Name; let ParserMatchClass = MatchClass; } +class NamedOperandS13 : Operand { + let PrintMethod = "print"#Name; + let ParserMatchClass = MatchClass; +} + class NamedOperandU32 : Operand { let PrintMethod = "print"#Name; let ParserMatchClass = MatchClass; @@ -514,6 +524,8 @@ def offen : NamedOperandBit<"Offen", NamedMatchClass<"Offen">>; def idxen : NamedOperandBit<"Idxen", NamedMatchClass<"Idxen">>; def addr64 : NamedOperandBit<"Addr64", NamedMatchClass<"Addr64">>; +def offset_u12 : NamedOperandU12<"Offset", NamedMatchClass<"OffsetU12">>; +def offset_s13 : NamedOperandS13<"Offset", NamedMatchClass<"OffsetS13">>; def offset : NamedOperandU16<"Offset", NamedMatchClass<"Offset">>; def offset0 : NamedOperandU8<"Offset0", NamedMatchClass<"Offset0">>; def offset1 : NamedOperandU8<"Offset1", NamedMatchClass<"Offset1">>; diff --git a/lib/Target/ARM/ARMCallLowering.cpp b/lib/Target/ARM/ARMCallLowering.cpp index a7ac9a1dca6e..e498f70b820d 100644 --- a/lib/Target/ARM/ARMCallLowering.cpp +++ b/lib/Target/ARM/ARMCallLowering.cpp @@ -35,9 +35,19 @@ ARMCallLowering::ARMCallLowering(const ARMTargetLowering &TLI) static bool isSupportedType(const DataLayout &DL, const ARMTargetLowering &TLI, Type *T) { - if (T->isArrayTy() || T->isStructTy()) + if (T->isArrayTy()) return true; + if (T->isStructTy()) { + // For now we only allow homogeneous structs that we can manipulate with + // G_MERGE_VALUES and G_UNMERGE_VALUES + auto StructT = cast(T); + for (unsigned i = 1, e = StructT->getNumElements(); i != e; ++i) + if (StructT->getElementType(i) != StructT->getElementType(0)) + return false; + return true; + } + EVT VT = TLI.getValueType(DL, T, true); if (!VT.isSimple() || VT.isVector() || !(VT.isInteger() || VT.isFloatingPoint())) @@ -220,12 +230,16 @@ bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder, return false; SmallVector SplitVTs; + SmallVector Regs; ArgInfo RetInfo(VReg, Val->getType()); setArgFlags(RetInfo, AttributeList::ReturnIndex, DL, F); splitToValueTypes(RetInfo, SplitVTs, MF, [&](unsigned Reg, uint64_t Offset) { - MIRBuilder.buildExtract(Reg, VReg, Offset); + Regs.push_back(Reg); }); + if (Regs.size() > 1) + MIRBuilder.buildUnmerge(Regs, VReg); + CCAssignFn *AssignFn = TLI.CCAssignFnForReturn(F.getCallingConv(), F.isVarArg()); @@ -344,26 +358,6 @@ struct IncomingValueHandler : public CallLowering::ValueHandler { return 1; } - /// Merge the values in \p SrcRegs into \p DstReg at offsets \p SrcOffsets. - /// Note that the source registers are not required to have homogeneous types, - /// so we use G_INSERT rather than G_MERGE_VALUES. - // FIXME: Use G_MERGE_VALUES if the types are homogeneous. - void mergeRegisters(unsigned DstReg, ArrayRef SrcRegs, - ArrayRef SrcOffsets) { - LLT Ty = MRI.getType(DstReg); - - unsigned Dst = MRI.createGenericVirtualRegister(Ty); - MIRBuilder.buildUndef(Dst); - - for (unsigned i = 0; i < SrcRegs.size(); ++i) { - unsigned Tmp = MRI.createGenericVirtualRegister(Ty); - MIRBuilder.buildInsert(Tmp, Dst, SrcRegs[i], SrcOffsets[i]); - Dst = Tmp; - } - - MIRBuilder.buildCopy(DstReg, Dst); - } - /// Marking a physical register as used is different between formal /// parameters, where it's a basic block live-in, and call returns, where it's /// an implicit-def of the call instruction. @@ -413,22 +407,19 @@ bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, SmallVector ArgInfos; SmallVector SplitRegs; - SmallVector RegOffsets; unsigned Idx = 0; for (auto &Arg : F.args()) { ArgInfo AInfo(VRegs[Idx], Arg.getType()); setArgFlags(AInfo, Idx + AttributeList::FirstArgIndex, DL, F); SplitRegs.clear(); - RegOffsets.clear(); splitToValueTypes(AInfo, ArgInfos, MF, [&](unsigned Reg, uint64_t Offset) { SplitRegs.push_back(Reg); - RegOffsets.push_back(Offset); }); if (!SplitRegs.empty()) - ArgHandler.mergeRegisters(VRegs[Idx], SplitRegs, RegOffsets); + MIRBuilder.buildMerge(VRegs[Idx], SplitRegs); Idx++; } @@ -490,9 +481,13 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, if (!Arg.IsFixed) return false; + SmallVector Regs; splitToValueTypes(Arg, ArgInfos, MF, [&](unsigned Reg, uint64_t Offset) { - MIRBuilder.buildExtract(Reg, Arg.Reg, Offset); + Regs.push_back(Reg); }); + + if (Regs.size() > 1) + MIRBuilder.buildUnmerge(Regs, Arg.Reg); } auto ArgAssignFn = TLI.CCAssignFnForCall(CallConv, /*IsVarArg=*/false); @@ -508,11 +503,9 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, return false; ArgInfos.clear(); - SmallVector RegOffsets; SmallVector SplitRegs; splitToValueTypes(OrigRet, ArgInfos, MF, [&](unsigned Reg, uint64_t Offset) { - RegOffsets.push_back(Offset); SplitRegs.push_back(Reg); }); @@ -521,10 +514,10 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, if (!handleAssignments(MIRBuilder, ArgInfos, RetHandler)) return false; - if (!RegOffsets.empty()) { + if (!SplitRegs.empty()) { // We have split the value and allocated each individual piece, now build // it up again. - RetHandler.mergeRegisters(OrigRet.Reg, SplitRegs, RegOffsets); + MIRBuilder.buildMerge(OrigRet.Reg, SplitRegs); } } diff --git a/lib/Target/ARM/ARMInstrVFP.td b/lib/Target/ARM/ARMInstrVFP.td index 817b567db767..5d887c4fcbf2 100644 --- a/lib/Target/ARM/ARMInstrVFP.td +++ b/lib/Target/ARM/ARMInstrVFP.td @@ -2010,7 +2010,8 @@ def VFNMAD : ADbI<0b11101, 0b01, 1, 0, [(set DPR:$Dd,(fsub_mlx (fneg (fmul_su DPR:$Dn,DPR:$Dm)), (f64 DPR:$Ddin)))]>, RegConstraint<"$Ddin = $Dd">, - Requires<[HasVFP4,HasDPVFP,UseFusedMAC]>; + Requires<[HasVFP4,HasDPVFP,UseFusedMAC]>, + Sched<[WriteFPMAC64, ReadFPMAC, ReadFPMUL, ReadFPMUL]>; def VFNMAS : ASbI<0b11101, 0b01, 1, 0, (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm), @@ -2018,7 +2019,8 @@ def VFNMAS : ASbI<0b11101, 0b01, 1, 0, [(set SPR:$Sd, (fsub_mlx (fneg (fmul_su SPR:$Sn, SPR:$Sm)), SPR:$Sdin))]>, RegConstraint<"$Sdin = $Sd">, - Requires<[HasVFP4,DontUseNEONForFP,UseFusedMAC]> { + Requires<[HasVFP4,DontUseNEONForFP,UseFusedMAC]>, + Sched<[WriteFPMAC32, ReadFPMAC, ReadFPMUL, ReadFPMUL]> { // Some single precision VFP instructions may be executed on both NEON and // VFP pipelines. } @@ -2028,7 +2030,8 @@ def VFNMAH : AHbI<0b11101, 0b01, 1, 0, IIC_fpFMAC16, "vfnma", ".f16\t$Sd, $Sn, $Sm", []>, RegConstraint<"$Sdin = $Sd">, - Requires<[HasFullFP16,UseFusedMAC]>; + Requires<[HasFullFP16,UseFusedMAC]>, + Sched<[WriteFPMAC32, ReadFPMAC, ReadFPMUL, ReadFPMUL]>; def : Pat<(fsub_mlx (fneg (fmul_su DPR:$a, (f64 DPR:$b))), DPR:$dstin), (VFNMAD DPR:$dstin, DPR:$a, DPR:$b)>, @@ -2059,14 +2062,16 @@ def VFNMSD : ADbI<0b11101, 0b01, 0, 0, [(set DPR:$Dd, (fsub_mlx (fmul_su DPR:$Dn, DPR:$Dm), (f64 DPR:$Ddin)))]>, RegConstraint<"$Ddin = $Dd">, - Requires<[HasVFP4,HasDPVFP,UseFusedMAC]>; + Requires<[HasVFP4,HasDPVFP,UseFusedMAC]>, + Sched<[WriteFPMAC64, ReadFPMAC, ReadFPMUL, ReadFPMUL]>; def VFNMSS : ASbI<0b11101, 0b01, 0, 0, (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm), IIC_fpFMAC32, "vfnms", ".f32\t$Sd, $Sn, $Sm", [(set SPR:$Sd, (fsub_mlx (fmul_su SPR:$Sn, SPR:$Sm), SPR:$Sdin))]>, RegConstraint<"$Sdin = $Sd">, - Requires<[HasVFP4,DontUseNEONForFP,UseFusedMAC]> { + Requires<[HasVFP4,DontUseNEONForFP,UseFusedMAC]>, + Sched<[WriteFPMAC32, ReadFPMAC, ReadFPMUL, ReadFPMUL]> { // Some single precision VFP instructions may be executed on both NEON and // VFP pipelines. } @@ -2076,7 +2081,8 @@ def VFNMSH : AHbI<0b11101, 0b01, 0, 0, IIC_fpFMAC16, "vfnms", ".f16\t$Sd, $Sn, $Sm", []>, RegConstraint<"$Sdin = $Sd">, - Requires<[HasFullFP16,UseFusedMAC]>; + Requires<[HasFullFP16,UseFusedMAC]>, + Sched<[WriteFPMAC32, ReadFPMAC, ReadFPMUL, ReadFPMUL]>; def : Pat<(fsub_mlx (fmul_su DPR:$a, (f64 DPR:$b)), DPR:$dstin), (VFNMSD DPR:$dstin, DPR:$a, DPR:$b)>, diff --git a/lib/Target/ARM/ARMLegalizerInfo.cpp b/lib/Target/ARM/ARMLegalizerInfo.cpp index 2d490b7c303e..a706079d9866 100644 --- a/lib/Target/ARM/ARMLegalizerInfo.cpp +++ b/lib/Target/ARM/ARMLegalizerInfo.cpp @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #include "ARMLegalizerInfo.h" +#include "ARMCallLowering.h" #include "ARMSubtarget.h" #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" +#include "llvm/CodeGen/LowLevelType.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/DerivedTypes.h" @@ -63,6 +65,16 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) { setAction({Op, s32}, Libcall); } + // FIXME: Support s8 and s16 as well + for (unsigned Op : {G_SREM, G_UREM}) + if (ST.hasDivideInARMMode()) + setAction({Op, s32}, Lower); + else if (ST.isTargetAEABI() || ST.isTargetGNUAEABI() || + ST.isTargetMuslAEABI()) + setAction({Op, s32}, Custom); + else + setAction({Op, s32}, Libcall); + for (unsigned Op : {G_SEXT, G_ZEXT}) { setAction({Op, s32}, Legal); for (auto Ty : {s1, s8, s16}) @@ -134,5 +146,38 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI, } return true; } + case G_SREM: + case G_UREM: { + unsigned OriginalResult = MI.getOperand(0).getReg(); + auto Size = MRI.getType(OriginalResult).getSizeInBits(); + if (Size != 32) + return false; + + auto Libcall = + MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32; + + // Our divmod libcalls return a struct containing the quotient and the + // remainder. We need to create a virtual register for it. + auto &Ctx = MIRBuilder.getMF().getFunction()->getContext(); + Type *ArgTy = Type::getInt32Ty(Ctx); + StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true); + auto RetVal = MRI.createGenericVirtualRegister( + getLLTForType(*RetTy, MIRBuilder.getMF().getDataLayout())); + + auto Status = replaceWithLibcall(MI, MIRBuilder, Libcall, {RetVal, RetTy}, + {{MI.getOperand(1).getReg(), ArgTy}, + {MI.getOperand(2).getReg(), ArgTy}}); + if (Status != LegalizerHelper::Legalized) + return false; + + // The remainder is the second result of divmod. Split the return value into + // a new, unused register for the quotient and the destination of the + // original instruction for the remainder. + MIRBuilder.buildUnmerge( + {MRI.createGenericVirtualRegister(LLT::scalar(32)), OriginalResult}, + RetVal); + + return LegalizerHelper::Legalized; + } } } diff --git a/lib/Target/ARM/ARMTargetTransformInfo.h b/lib/Target/ARM/ARMTargetTransformInfo.h index 7de0543dfa5e..8a1a37863877 100644 --- a/lib/Target/ARM/ARMTargetTransformInfo.h +++ b/lib/Target/ARM/ARMTargetTransformInfo.h @@ -78,7 +78,7 @@ class ARMTTIImpl : public BasicTTIImplBase { return 13; } - unsigned getRegisterBitWidth(bool Vector) { + unsigned getRegisterBitWidth(bool Vector) const { if (Vector) { if (ST->hasNEON()) return 128; diff --git a/lib/Target/BPF/BPFAsmPrinter.cpp b/lib/Target/BPF/BPFAsmPrinter.cpp index fcd903b7a4a8..9397c78f3dff 100644 --- a/lib/Target/BPF/BPFAsmPrinter.cpp +++ b/lib/Target/BPF/BPFAsmPrinter.cpp @@ -35,14 +35,15 @@ using namespace llvm; namespace { class BPFAsmPrinter : public AsmPrinter { public: - explicit BPFAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) + explicit BPFAsmPrinter(TargetMachine &TM, + std::unique_ptr Streamer) : AsmPrinter(TM, std::move(Streamer)) {} StringRef getPassName() const override { return "BPF Assembly Printer"; } void EmitInstruction(const MachineInstr *MI) override; }; -} +} // namespace void BPFAsmPrinter::EmitInstruction(const MachineInstr *MI) { diff --git a/lib/Target/BPF/BPFISelDAGToDAG.cpp b/lib/Target/BPF/BPFISelDAGToDAG.cpp index 279cdb1a89b4..7d5fb6ca17b9 100644 --- a/lib/Target/BPF/BPFISelDAGToDAG.cpp +++ b/lib/Target/BPF/BPFISelDAGToDAG.cpp @@ -22,11 +22,14 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" + using namespace llvm; #define DEBUG_TYPE "bpf-isel" @@ -42,6 +45,8 @@ class BPFDAGToDAGISel : public SelectionDAGISel { return "BPF DAG->DAG Pattern Instruction Selection"; } + void PreprocessISelDAG() override; + private: // Include the pieces autogenerated from the target description. #include "BPFGenDAGISel.inc" @@ -51,15 +56,31 @@ class BPFDAGToDAGISel : public SelectionDAGISel { // Complex Pattern for address selection. bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset); bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset); + + // Find constants from a constant structure + typedef std::vector val_vec_type; + bool fillGenericConstant(const DataLayout &DL, const Constant *CV, + val_vec_type &Vals, uint64_t Offset); + bool fillConstantDataArray(const DataLayout &DL, const ConstantDataArray *CDA, + val_vec_type &Vals, int Offset); + bool fillConstantArray(const DataLayout &DL, const ConstantArray *CA, + val_vec_type &Vals, int Offset); + bool fillConstantStruct(const DataLayout &DL, const ConstantStruct *CS, + val_vec_type &Vals, int Offset); + bool getConstantFieldValue(const GlobalAddressSDNode *Node, uint64_t Offset, + uint64_t Size, unsigned char *ByteSeq); + + // Mapping from ConstantStruct global value to corresponding byte-list values + std::map cs_vals_; }; -} +} // namespace // ComplexPattern used on BPF Load/Store instructions bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { // if Address is FI, get the TargetFrameIndex. SDLoc DL(Addr); if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { - Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); Offset = CurDAG->getTargetConstant(0, DL, MVT::i64); return true; } @@ -85,13 +106,14 @@ bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { } } - Base = Addr; + Base = Addr; Offset = CurDAG->getTargetConstant(0, DL, MVT::i64); return true; } // ComplexPattern used on BPF FI instruction -bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { +bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) { SDLoc DL(Addr); if (!CurDAG->isBaseWithConstantOffset(Addr)) @@ -102,8 +124,7 @@ bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset) if (isInt<16>(CN->getSExtValue())) { // If the first operand is a FI, get the TargetFI Node - if (FrameIndexSDNode *FIN = - dyn_cast(Addr.getOperand(0))) + if (FrameIndexSDNode *FIN = dyn_cast(Addr.getOperand(0))) Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); else return false; @@ -129,7 +150,8 @@ void BPFDAGToDAGISel::Select(SDNode *Node) { // tablegen selection should be handled here. switch (Opcode) { - default: break; + default: + break; case ISD::SDIV: { DebugLoc Empty; const DebugLoc &DL = Node->getDebugLoc(); @@ -181,6 +203,210 @@ void BPFDAGToDAGISel::Select(SDNode *Node) { SelectCode(Node); } +void BPFDAGToDAGISel::PreprocessISelDAG() { + // Iterate through all nodes, only interested in loads from ConstantStruct + // ConstantArray should have converted by IR->DAG processing + for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), + E = CurDAG->allnodes_end(); + I != E;) { + SDNode *Node = &*I++; + unsigned Opcode = Node->getOpcode(); + if (Opcode != ISD::LOAD) + continue; + + unsigned char new_val[8]; // hold up the constant values replacing loads. + bool to_replace = false; + SDLoc DL(Node); + const LoadSDNode *LD = cast(Node); + uint64_t size = LD->getMemOperand()->getSize(); + if (!size || size > 8 || (size & (size - 1))) + continue; + + SDNode *LDAddrNode = LD->getOperand(1).getNode(); + // Match LDAddr against either global_addr or (global_addr + offset) + unsigned opcode = LDAddrNode->getOpcode(); + if (opcode == ISD::ADD) { + SDValue OP1 = LDAddrNode->getOperand(0); + SDValue OP2 = LDAddrNode->getOperand(1); + + // We want to find the pattern global_addr + offset + SDNode *OP1N = OP1.getNode(); + if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END || + OP1N->getNumOperands() == 0) + continue; + + DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n'); + + const GlobalAddressSDNode *GADN = + dyn_cast(OP1N->getOperand(0).getNode()); + const ConstantSDNode *CDN = dyn_cast(OP2.getNode()); + if (GADN && CDN) + to_replace = + getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val); + } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END && + LDAddrNode->getNumOperands() > 0) { + DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n'); + + SDValue OP1 = LDAddrNode->getOperand(0); + if (const GlobalAddressSDNode *GADN = + dyn_cast(OP1.getNode())) + to_replace = getConstantFieldValue(GADN, 0, size, new_val); + } + + if (!to_replace) + continue; + + // replacing the old with a new value + uint64_t val; + if (size == 1) + val = *(uint8_t *)new_val; + else if (size == 2) + val = *(uint16_t *)new_val; + else if (size == 4) + val = *(uint32_t *)new_val; + else { + val = *(uint64_t *)new_val; + } + + DEBUG(dbgs() << "Replacing load of size " << size << " with constant " + << val << '\n'); + SDValue NVal = CurDAG->getConstant(val, DL, MVT::i64); + + // After replacement, the current node is dead, we need to + // go backward one step to make iterator still work + I--; + SDValue From[] = {SDValue(Node, 0), SDValue(Node, 1)}; + SDValue To[] = {NVal, NVal}; + CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2); + I++; + // It is safe to delete node now + CurDAG->DeleteNode(Node); + } +} + +bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node, + uint64_t Offset, uint64_t Size, + unsigned char *ByteSeq) { + const GlobalVariable *V = dyn_cast(Node->getGlobal()); + + if (!V || !V->hasInitializer()) + return false; + + const Constant *Init = V->getInitializer(); + const DataLayout &DL = CurDAG->getDataLayout(); + val_vec_type TmpVal; + + auto it = cs_vals_.find(static_cast(Init)); + if (it != cs_vals_.end()) { + TmpVal = it->second; + } else { + uint64_t total_size = 0; + if (const ConstantStruct *CS = dyn_cast(Init)) + total_size = + DL.getStructLayout(cast(CS->getType()))->getSizeInBytes(); + else if (const ConstantArray *CA = dyn_cast(Init)) + total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) * + CA->getNumOperands(); + else + return false; + + val_vec_type Vals(total_size, 0); + if (fillGenericConstant(DL, Init, Vals, 0) == false) + return false; + cs_vals_[static_cast(Init)] = Vals; + TmpVal = std::move(Vals); + } + + // test whether host endianness matches target + uint8_t test_buf[2]; + uint16_t test_val = 0x2345; + if (DL.isLittleEndian()) + support::endian::write16le(test_buf, test_val); + else + support::endian::write16be(test_buf, test_val); + + bool endian_match = *(uint16_t *)test_buf == test_val; + for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++) + ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j]; + + return true; +} + +bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout &DL, + const Constant *CV, + val_vec_type &Vals, uint64_t Offset) { + uint64_t Size = DL.getTypeAllocSize(CV->getType()); + + if (isa(CV) || isa(CV)) + return true; // already done + + if (const ConstantInt *CI = dyn_cast(CV)) { + uint64_t val = CI->getZExtValue(); + DEBUG(dbgs() << "Byte array at offset " << Offset << " with value " << val + << '\n'); + + if (Size > 8 || (Size & (Size - 1))) + return false; + + // Store based on target endian + for (uint64_t i = 0; i < Size; ++i) { + Vals[Offset + i] = DL.isLittleEndian() + ? ((val >> (i * 8)) & 0xFF) + : ((val >> ((Size - i - 1) * 8)) & 0xFF); + } + return true; + } + + if (const ConstantDataArray *CDA = dyn_cast(CV)) + return fillConstantDataArray(DL, CDA, Vals, Offset); + + if (const ConstantArray *CA = dyn_cast(CV)) + return fillConstantArray(DL, CA, Vals, Offset); + + if (const ConstantStruct *CVS = dyn_cast(CV)) + return fillConstantStruct(DL, CVS, Vals, Offset); + + return false; +} + +bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL, + const ConstantDataArray *CDA, + val_vec_type &Vals, int Offset) { + for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) { + if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) == + false) + return false; + Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType()); + } + + return true; +} + +bool BPFDAGToDAGISel::fillConstantArray(const DataLayout &DL, + const ConstantArray *CA, + val_vec_type &Vals, int Offset) { + for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { + if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false) + return false; + Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType()); + } + + return true; +} + +bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout &DL, + const ConstantStruct *CS, + val_vec_type &Vals, int Offset) { + const StructLayout *Layout = DL.getStructLayout(CS->getType()); + for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { + const Constant *Field = CS->getOperand(i); + uint64_t SizeSoFar = Layout->getElementOffset(i); + if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false) + return false; + } + return true; +} + FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) { return new BPFDAGToDAGISel(TM); } diff --git a/lib/Target/BPF/BPFInstrInfo.td b/lib/Target/BPF/BPFInstrInfo.td index c6c0ff587c6b..5ad777268208 100644 --- a/lib/Target/BPF/BPFInstrInfo.td +++ b/lib/Target/BPF/BPFInstrInfo.td @@ -51,7 +51,7 @@ def u64imm : Operand { let PrintMethod = "printImm64Operand"; } -def i64immSExt32 : PatLeaf<(imm), +def i64immSExt32 : PatLeaf<(i64 imm), [{return isInt<32>(N->getSExtValue()); }]>; // Addressing modes. @@ -67,17 +67,17 @@ def MEMri : Operand { } // Conditional code predicates - used for pattern matching for jump instructions -def BPF_CC_EQ : PatLeaf<(imm), +def BPF_CC_EQ : PatLeaf<(i64 imm), [{return (N->getZExtValue() == ISD::SETEQ);}]>; -def BPF_CC_NE : PatLeaf<(imm), +def BPF_CC_NE : PatLeaf<(i64 imm), [{return (N->getZExtValue() == ISD::SETNE);}]>; -def BPF_CC_GE : PatLeaf<(imm), +def BPF_CC_GE : PatLeaf<(i64 imm), [{return (N->getZExtValue() == ISD::SETGE);}]>; -def BPF_CC_GT : PatLeaf<(imm), +def BPF_CC_GT : PatLeaf<(i64 imm), [{return (N->getZExtValue() == ISD::SETGT);}]>; -def BPF_CC_GTU : PatLeaf<(imm), +def BPF_CC_GTU : PatLeaf<(i64 imm), [{return (N->getZExtValue() == ISD::SETUGT);}]>; -def BPF_CC_GEU : PatLeaf<(imm), +def BPF_CC_GEU : PatLeaf<(i64 imm), [{return (N->getZExtValue() == ISD::SETUGE);}]>; // jump instructions diff --git a/lib/Target/Hexagon/HexagonGenMux.cpp b/lib/Target/Hexagon/HexagonGenMux.cpp index 3c37d9ebb0eb..11ac5454f604 100644 --- a/lib/Target/Hexagon/HexagonGenMux.cpp +++ b/lib/Target/Hexagon/HexagonGenMux.cpp @@ -59,9 +59,7 @@ namespace { public: static char ID; - HexagonGenMux() : MachineFunctionPass(ID), HII(nullptr), HRI(nullptr) { - initializeHexagonGenMuxPass(*PassRegistry::getPassRegistry()); - } + HexagonGenMux() : MachineFunctionPass(ID) {} StringRef getPassName() const override { return "Hexagon generate mux instructions"; @@ -79,8 +77,8 @@ namespace { } private: - const HexagonInstrInfo *HII; - const HexagonRegisterInfo *HRI; + const HexagonInstrInfo *HII = nullptr; + const HexagonRegisterInfo *HRI = nullptr; struct CondsetInfo { unsigned PredR = 0; @@ -134,7 +132,7 @@ namespace { } // end anonymous namespace -INITIALIZE_PASS(HexagonGenMux, "hexagon-mux", +INITIALIZE_PASS(HexagonGenMux, "hexagon-gen-mux", "Hexagon generate mux instructions", false, false) void HexagonGenMux::getSubRegs(unsigned Reg, BitVector &SRs) const { @@ -297,12 +295,15 @@ bool HexagonGenMux::genMuxInBlock(MachineBasicBlock &B) { unsigned SR1 = Src1->isReg() ? Src1->getReg() : 0; unsigned SR2 = Src2->isReg() ? Src2->getReg() : 0; bool Failure = false, CanUp = true, CanDown = true; + bool Used1 = false, Used2 = false; for (unsigned X = MinX+1; X < MaxX; X++) { const DefUseInfo &DU = DUM.lookup(X); if (DU.Defs[PR] || DU.Defs[DR] || DU.Uses[DR]) { Failure = true; break; } + Used1 |= DU.Uses[SR1]; + Used2 |= DU.Uses[SR2]; if (CanDown && DU.Defs[SR1]) CanDown = false; if (CanUp && DU.Defs[SR2]) @@ -316,6 +317,45 @@ bool HexagonGenMux::genMuxInBlock(MachineBasicBlock &B) { // Prefer "down", since this will move the MUX farther away from the // predicate definition. MachineBasicBlock::iterator At = CanDown ? Def2 : Def1; + if (CanDown) { + // If the MUX is placed "down", we need to make sure that there aren't + // any kills of the source registers between the two defs. + if (Used1 || Used2) { + auto ResetKill = [this] (unsigned Reg, MachineInstr &MI) -> bool { + if (MachineOperand *Op = MI.findRegisterUseOperand(Reg, true, HRI)) { + Op->setIsKill(false); + return true; + } + return false; + }; + bool KilledSR1 = false, KilledSR2 = false; + for (MachineInstr &MJ : make_range(std::next(It1), It2)) { + if (SR1) + KilledSR1 |= ResetKill(SR1, MJ); + if (SR2) + KilledSR2 |= ResetKill(SR1, MJ); + } + // If any of the source registers were killed in this range, transfer + // the kills to the source operands: they will me "moved" to the + // resulting MUX and their parent instructions will be deleted. + if (KilledSR1) { + assert(Src1->isReg()); + Src1->setIsKill(true); + } + if (KilledSR2) { + assert(Src2->isReg()); + Src2->setIsKill(true); + } + } + } else { + // If the MUX is placed "up", it shouldn't kill any source registers + // that are still used afterwards. We can reset the kill flags directly + // on the operands, because the source instructions will be erased. + if (Used1 && Src1->isReg()) + Src1->setIsKill(false); + if (Used2 && Src2->isReg()) + Src2->setIsKill(false); + } ML.push_back(MuxInfo(At, DR, PR, SrcT, SrcF, Def1, Def2)); } diff --git a/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp b/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp index e4434136bf86..e5f49ca77a91 100644 --- a/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp +++ b/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp @@ -124,6 +124,7 @@ class HexagonDAGToDAGISel : public SelectionDAGISel { bool keepsLowBits(const SDValue &Val, unsigned NumBits, SDValue &Src); bool isOrEquivalentToAdd(const SDNode *N) const; bool isAlignedMemNode(const MemSDNode *N) const; + bool isSmallStackStore(const StoreSDNode *N) const; bool isPositiveHalfWord(const SDNode *N) const; // DAG preprocessing functions. @@ -1462,6 +1463,20 @@ bool HexagonDAGToDAGISel::isAlignedMemNode(const MemSDNode *N) const { return N->getAlignment() >= N->getMemoryVT().getStoreSize(); } +bool HexagonDAGToDAGISel::isSmallStackStore(const StoreSDNode *N) const { + unsigned StackSize = MF->getFrameInfo().estimateStackSize(*MF); + switch (N->getMemoryVT().getStoreSize()) { + case 1: + return StackSize <= 56; // 1*2^6 - 8 + case 2: + return StackSize <= 120; // 2*2^6 - 8 + case 4: + return StackSize <= 248; // 4*2^6 - 8 + default: + return false; + } +} + // Return true when the given node fits in a positive half word. bool HexagonDAGToDAGISel::isPositiveHalfWord(const SDNode *N) const { if (const ConstantSDNode *CN = dyn_cast(N)) { diff --git a/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp b/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp index b748b58bc0ae..f82ad6cb3da6 100644 --- a/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp +++ b/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp @@ -1744,7 +1744,8 @@ bool PolynomialMultiplyRecognize::recognize() { // wide as the target's pmpy instruction. if (!promoteTypes(LoopB, ExitB)) return false; - convertShiftsToLeft(LoopB, ExitB, IterCount); + if (!convertShiftsToLeft(LoopB, ExitB, IterCount)) + return false; cleanupLoopBody(LoopB); } diff --git a/lib/Target/Hexagon/HexagonPatterns.td b/lib/Target/Hexagon/HexagonPatterns.td index f269b74fc447..689419638f54 100644 --- a/lib/Target/Hexagon/HexagonPatterns.td +++ b/lib/Target/Hexagon/HexagonPatterns.td @@ -401,6 +401,11 @@ def Aext64: PatFrag<(ops node:$Rs), (i64 (anyext node:$Rs))>; def Zext64: PatFrag<(ops node:$Rs), (i64 (zext node:$Rs))>; def Sext64: PatLeaf<(i64 Usxtw:$Rs)>; +def: Pat<(i32 (trunc (sra (mul Sext64:$Rs, Sext64:$Rt), (i32 32)))), + (M2_mpy_up (LoReg Sext64:$Rs), (LoReg Sext64:$Rt))>; +def: Pat<(i32 (trunc (srl (mul Sext64:$Rs, Sext64:$Rt), (i32 32)))), + (M2_mpy_up (LoReg Sext64:$Rs), (LoReg Sext64:$Rt))>; + def: Pat<(mul (Aext64 I32:$Rs), (Aext64 I32:$Rt)), (M2_dpmpyuu_s0 I32:$Rs, I32:$Rt)>; @@ -1470,16 +1475,22 @@ def i32in8ImmPred: PatLeaf<(i32 imm), [{ return v == (int64_t)(int8_t)v; }]>; +class SmallStackStore + : PatFrag<(ops node:$Val, node:$Addr), (Store node:$Val, node:$Addr), [{ + return isSmallStackStore(cast(N)); +}]>; let AddedComplexity = 40 in { // Even though the offset is not extendable in the store-immediate, we // can still generate the fi# in the base address. If the final offset // is not valid for the instruction, we will replace it with a scratch // register. -// def: Storexm_fi_pat ; -// def: Storexm_fi_pat ; -// def: Storexm_fi_pat ; + def: Storexm_fi_pat , s32_0ImmPred, + ToImmByte, S4_storeirb_io>; + def: Storexm_fi_pat , i16in8ImmPred, + ToImmHalf, S4_storeirh_io>; + def: Storexm_fi_pat , i32in8ImmPred, + ToImmWord, S4_storeiri_io>; // defm: Storexm_fi_add_pat ; diff --git a/lib/Target/Hexagon/HexagonTargetMachine.cpp b/lib/Target/Hexagon/HexagonTargetMachine.cpp index c757b6ecdd00..e507a797871f 100644 --- a/lib/Target/Hexagon/HexagonTargetMachine.cpp +++ b/lib/Target/Hexagon/HexagonTargetMachine.cpp @@ -111,6 +111,7 @@ namespace llvm { extern char &HexagonExpandCondsetsID; void initializeHexagonExpandCondsetsPass(PassRegistry&); void initializeHexagonLoopIdiomRecognizePass(PassRegistry&); + void initializeHexagonGenMuxPass(PassRegistry&); void initializeHexagonOptAddrModePass(PassRegistry&); Pass *createHexagonLoopIdiomPass(); @@ -152,8 +153,11 @@ static Reloc::Model getEffectiveRelocModel(Optional RM) { extern "C" void LLVMInitializeHexagonTarget() { // Register the target. RegisterTargetMachine X(getTheHexagonTarget()); - initializeHexagonLoopIdiomRecognizePass(*PassRegistry::getPassRegistry()); - initializeHexagonOptAddrModePass(*PassRegistry::getPassRegistry()); + + PassRegistry &PR = *PassRegistry::getPassRegistry(); + initializeHexagonLoopIdiomRecognizePass(PR); + initializeHexagonGenMuxPass(PR); + initializeHexagonOptAddrModePass(PR); } HexagonTargetMachine::HexagonTargetMachine(const Target &T, const Triple &TT, diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index f2193013b7aa..68708dc4f50f 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -364,6 +364,18 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM, setOperationAction(ISD::UDIV, MVT::i64, Expand); setOperationAction(ISD::UREM, MVT::i64, Expand); + if (!(Subtarget.hasDSP() && Subtarget.hasMips32r2())) { + setOperationAction(ISD::ADDC, MVT::i32, Expand); + setOperationAction(ISD::ADDE, MVT::i32, Expand); + } + + setOperationAction(ISD::ADDC, MVT::i64, Expand); + setOperationAction(ISD::ADDE, MVT::i64, Expand); + setOperationAction(ISD::SUBC, MVT::i32, Expand); + setOperationAction(ISD::SUBE, MVT::i32, Expand); + setOperationAction(ISD::SUBC, MVT::i64, Expand); + setOperationAction(ISD::SUBE, MVT::i64, Expand); + // Operations not directly supported by Mips. setOperationAction(ISD::BR_CC, MVT::f32, Expand); setOperationAction(ISD::BR_CC, MVT::f64, Expand); @@ -469,6 +481,7 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM, setTargetDAGCombine(ISD::AND); setTargetDAGCombine(ISD::OR); setTargetDAGCombine(ISD::ADD); + setTargetDAGCombine(ISD::SUB); setTargetDAGCombine(ISD::AssertZext); setTargetDAGCombine(ISD::SHL); @@ -918,14 +931,130 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, } } +static SDValue performMADD_MSUBCombine(SDNode *ROOTNode, SelectionDAG &CurDAG, + const MipsSubtarget &Subtarget) { + // ROOTNode must have a multiplication as an operand for the match to be + // successful. + if (ROOTNode->getOperand(0).getOpcode() != ISD::MUL && + ROOTNode->getOperand(1).getOpcode() != ISD::MUL) + return SDValue(); + + // We don't handle vector types here. + if (ROOTNode->getValueType(0).isVector()) + return SDValue(); + + // For MIPS64, madd / msub instructions are inefficent to use with 64 bit + // arithmetic. E.g. + // (add (mul a b) c) => + // let res = (madd (mthi (drotr c 32))x(mtlo c) a b) in + // MIPS64: (or (dsll (mfhi res) 32) (dsrl (dsll (mflo res) 32) 32) + // or + // MIPS64R2: (dins (mflo res) (mfhi res) 32 32) + // + // The overhead of setting up the Hi/Lo registers and reassembling the + // result makes this a dubious optimzation for MIPS64. The core of the + // problem is that Hi/Lo contain the upper and lower 32 bits of the + // operand and result. + // + // It requires a chain of 4 add/mul for MIPS64R2 to get better code + // density than doing it naively, 5 for MIPS64. Additionally, using + // madd/msub on MIPS64 requires the operands actually be 32 bit sign + // extended operands, not true 64 bit values. + // + // FIXME: For the moment, disable this completely for MIPS64. + if (Subtarget.hasMips64()) + return SDValue(); + + SDValue Mult = ROOTNode->getOperand(0).getOpcode() == ISD::MUL + ? ROOTNode->getOperand(0) + : ROOTNode->getOperand(1); + + SDValue AddOperand = ROOTNode->getOperand(0).getOpcode() == ISD::MUL + ? ROOTNode->getOperand(1) + : ROOTNode->getOperand(0); + + // Transform this to a MADD only if the user of this node is the add. + // If there are other users of the mul, this function returns here. + if (!Mult.hasOneUse()) + return SDValue(); + + // maddu and madd are unusual instructions in that on MIPS64 bits 63..31 + // must be in canonical form, i.e. sign extended. For MIPS32, the operands + // of the multiply must have 32 or more sign bits, otherwise we cannot + // perform this optimization. We have to check this here as we're performing + // this optimization pre-legalization. + SDValue MultLHS = Mult->getOperand(0); + SDValue MultRHS = Mult->getOperand(1); + unsigned LHSSB = CurDAG.ComputeNumSignBits(MultLHS); + unsigned RHSSB = CurDAG.ComputeNumSignBits(MultRHS); + + if (LHSSB < 32 || RHSSB < 32) + return SDValue(); + + APInt HighMask = + APInt::getHighBitsSet(Mult->getValueType(0).getScalarSizeInBits(), 32); + bool IsUnsigned = CurDAG.MaskedValueIsZero(Mult->getOperand(0), HighMask) && + CurDAG.MaskedValueIsZero(Mult->getOperand(1), HighMask) && + CurDAG.MaskedValueIsZero(AddOperand, HighMask); + + // Initialize accumulator. + SDLoc DL(ROOTNode); + SDValue TopHalf; + SDValue BottomHalf; + BottomHalf = CurDAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, AddOperand, + CurDAG.getIntPtrConstant(0, DL)); + + TopHalf = CurDAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, AddOperand, + CurDAG.getIntPtrConstant(1, DL)); + SDValue ACCIn = CurDAG.getNode(MipsISD::MTLOHI, DL, MVT::Untyped, + BottomHalf, + TopHalf); + + // Create MipsMAdd(u) / MipsMSub(u) node. + bool IsAdd = ROOTNode->getOpcode() == ISD::ADD; + unsigned Opcode = IsAdd ? (IsUnsigned ? MipsISD::MAddu : MipsISD::MAdd) + : (IsUnsigned ? MipsISD::MSubu : MipsISD::MSub); + SDValue MAddOps[3] = { + CurDAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Mult->getOperand(0)), + CurDAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Mult->getOperand(1)), ACCIn}; + EVT VTs[2] = {MVT::i32, MVT::i32}; + SDValue MAdd = CurDAG.getNode(Opcode, DL, VTs, MAddOps); + + SDValue ResLo = CurDAG.getNode(MipsISD::MFLO, DL, MVT::i32, MAdd); + SDValue ResHi = CurDAG.getNode(MipsISD::MFHI, DL, MVT::i32, MAdd); + SDValue Combined = + CurDAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, ResLo, ResHi); + return Combined; +} + +static SDValue performSUBCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget &Subtarget) { + // (sub v0 (mul v1, v2)) => (msub v1, v2, v0) + if (DCI.isBeforeLegalizeOps()) { + if (Subtarget.hasMips32() && !Subtarget.hasMips32r6() && + !Subtarget.inMips16Mode() && N->getValueType(0) == MVT::i64) + return performMADD_MSUBCombine(N, DAG, Subtarget); + + return SDValue(); + } + + return SDValue(); +} + static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const MipsSubtarget &Subtarget) { - // (add v0, (add v1, abs_lo(tjt))) => (add (add v0, v1), abs_lo(tjt)) + // (add v0 (mul v1, v2)) => (madd v1, v2, v0) + if (DCI.isBeforeLegalizeOps()) { + if (Subtarget.hasMips32() && !Subtarget.hasMips32r6() && + !Subtarget.inMips16Mode() && N->getValueType(0) == MVT::i64) + return performMADD_MSUBCombine(N, DAG, Subtarget); - if (DCI.isBeforeLegalizeOps()) return SDValue(); + } + // (add v0, (add v1, abs_lo(tjt))) => (add (add v0, v1), abs_lo(tjt)) SDValue Add = N->getOperand(1); if (Add.getOpcode() != ISD::ADD) @@ -1053,6 +1182,8 @@ SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) return performAssertZextCombine(N, DAG, DCI, Subtarget); case ISD::SHL: return performSHLCombine(N, DAG, DCI, Subtarget); + case ISD::SUB: + return performSUBCombine(N, DAG, DCI, Subtarget); } return SDValue(); diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp index df62c66b75a3..4adf77f8d9a9 100644 --- a/lib/Target/Mips/MipsInstrInfo.cpp +++ b/lib/Target/Mips/MipsInstrInfo.cpp @@ -103,12 +103,9 @@ void MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineInstrBuilder MIB = BuildMI(&MBB, DL, MCID); for (unsigned i = 1; i < Cond.size(); ++i) { - if (Cond[i].isReg()) - MIB.addReg(Cond[i].getReg()); - else if (Cond[i].isImm()) - MIB.addImm(Cond[i].getImm()); - else - assert(false && "Cannot copy operand"); + assert((Cond[i].isImm() || Cond[i].isReg()) && + "Cannot copy operand for conditional branch!"); + MIB.add(Cond[i]); } MIB.addMBB(TBB); } diff --git a/lib/Target/Mips/MipsLongBranch.cpp b/lib/Target/Mips/MipsLongBranch.cpp index b95f1158fa56..272595af5f6f 100644 --- a/lib/Target/Mips/MipsLongBranch.cpp +++ b/lib/Target/Mips/MipsLongBranch.cpp @@ -274,8 +274,8 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { if (IsPIC) { MachineBasicBlock *BalTgtMBB = MF->CreateMachineBasicBlock(BB); MF->insert(FallThroughMBB, BalTgtMBB); - LongBrMBB->addSuccessor(BalTgtMBB); - BalTgtMBB->addSuccessor(TgtMBB); + LongBrMBB->addSuccessor(BalTgtMBB, BranchProbability::getOne()); + BalTgtMBB->addSuccessor(&*FallThroughMBB, BranchProbability::getOne()); // We must select between the MIPS32r6/MIPS64r6 BAL (which is a normal // instruction) and the pre-MIPS32r6/MIPS64r6 definition (which is an @@ -342,8 +342,8 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { .addReg(Mips::SP).addImm(8); if (Subtarget.hasMips32r6()) - BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JALR)) - .addReg(Mips::ZERO).addReg(Mips::AT); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JALR), Mips::ZERO) + .addReg(Mips::AT); else BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JR)).addReg(Mips::AT); @@ -415,8 +415,8 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { .addReg(Mips::SP_64).addImm(0); if (Subtarget.hasMips64r6()) - BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JALR64)) - .addReg(Mips::ZERO_64).addReg(Mips::AT_64); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JALR64), Mips::ZERO_64) + .addReg(Mips::AT_64); else BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JR64)).addReg(Mips::AT_64); diff --git a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp index 49ae6dd4cd39..4be26dd25dc0 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -245,46 +245,64 @@ void MipsSEDAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) { } } -void MipsSEDAGToDAGISel::selectAddESubE(unsigned MOp, SDValue InFlag, - SDValue CmpLHS, const SDLoc &DL, - SDNode *Node) const { - unsigned Opc = InFlag.getOpcode(); (void)Opc; - - assert(((Opc == ISD::ADDC || Opc == ISD::ADDE) || - (Opc == ISD::SUBC || Opc == ISD::SUBE)) && - "(ADD|SUB)E flag operand must come from (ADD|SUB)C/E insn"); - - unsigned SLTuOp = Mips::SLTu, ADDuOp = Mips::ADDu; - if (Subtarget->isGP64bit()) { - SLTuOp = Mips::SLTu64; - ADDuOp = Mips::DADDu; - } - - SDValue Ops[] = { CmpLHS, InFlag.getOperand(1) }; +void MipsSEDAGToDAGISel::selectAddE(SDNode *Node, const SDLoc &DL) const { + SDValue InFlag = Node->getOperand(2); + unsigned Opc = InFlag.getOpcode(); SDValue LHS = Node->getOperand(0), RHS = Node->getOperand(1); EVT VT = LHS.getValueType(); - SDNode *Carry = CurDAG->getMachineNode(SLTuOp, DL, VT, Ops); - - if (Subtarget->isGP64bit()) { - // On 64-bit targets, sltu produces an i64 but our backend currently says - // that SLTu64 produces an i32. We need to fix this in the long run but for - // now, just make the DAG type-correct by asserting the upper bits are zero. - Carry = CurDAG->getMachineNode(Mips::SUBREG_TO_REG, DL, VT, - CurDAG->getTargetConstant(0, DL, VT), - SDValue(Carry, 0), - CurDAG->getTargetConstant(Mips::sub_32, DL, - VT)); + // In the base case, we can rely on the carry bit from the addsc + // instruction. + if (Opc == ISD::ADDC) { + SDValue Ops[3] = {LHS, RHS, InFlag}; + CurDAG->SelectNodeTo(Node, Mips::ADDWC, VT, MVT::Glue, Ops); + return; } - // Generate a second addition only if we know that RHS is not a - // constant-zero node. - SDNode *AddCarry = Carry; - ConstantSDNode *C = dyn_cast(RHS); - if (!C || C->getZExtValue()) - AddCarry = CurDAG->getMachineNode(ADDuOp, DL, VT, SDValue(Carry, 0), RHS); + assert(Opc == ISD::ADDE && "ISD::ADDE not in a chain of ADDE nodes!"); - CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Glue, LHS, SDValue(AddCarry, 0)); + // The more complex case is when there is a chain of ISD::ADDE nodes like: + // (adde (adde (adde (addc a b) c) d) e). + // + // The addwc instruction does not write to the carry bit, instead it writes + // to bit 20 of the dsp control register. To match this series of nodes, each + // intermediate adde node must be expanded to write the carry bit before the + // addition. + + // Start by reading the overflow field for addsc and moving the value to the + // carry field. The usage of 1 here with MipsISD::RDDSP / Mips::WRDSP + // corresponds to reading/writing the entire control register to/from a GPR. + + SDValue CstOne = CurDAG->getTargetConstant(1, DL, MVT::i32); + + SDValue OuFlag = CurDAG->getTargetConstant(20, DL, MVT::i32); + + SDNode *DSPCtrlField = + CurDAG->getMachineNode(Mips::RDDSP, DL, MVT::i32, MVT::Glue, CstOne, InFlag); + + SDNode *Carry = CurDAG->getMachineNode( + Mips::EXT, DL, MVT::i32, SDValue(DSPCtrlField, 0), OuFlag, CstOne); + + SDValue Ops[4] = {SDValue(DSPCtrlField, 0), + CurDAG->getTargetConstant(6, DL, MVT::i32), CstOne, + SDValue(Carry, 0)}; + SDNode *DSPCFWithCarry = CurDAG->getMachineNode(Mips::INS, DL, MVT::i32, Ops); + + // My reading of the the MIPS DSP 3.01 specification isn't as clear as I + // would like about whether bit 20 always gets overwritten by addwc. + // Hence take an extremely conservative view and presume it's sticky. We + // therefore need to clear it. + + SDValue Zero = CurDAG->getRegister(Mips::ZERO, MVT::i32); + + SDValue InsOps[4] = {Zero, OuFlag, CstOne, SDValue(DSPCFWithCarry, 0)}; + SDNode *DSPCtrlFinal = CurDAG->getMachineNode(Mips::INS, DL, MVT::i32, InsOps); + + SDNode *WrDSP = CurDAG->getMachineNode(Mips::WRDSP, DL, MVT::Glue, + SDValue(DSPCtrlFinal, 0), CstOne); + + SDValue Operands[3] = {LHS, RHS, SDValue(WrDSP, 0)}; + CurDAG->SelectNodeTo(Node, Mips::ADDWC, VT, MVT::Glue, Operands); } /// Match frameindex @@ -765,19 +783,8 @@ bool MipsSEDAGToDAGISel::trySelect(SDNode *Node) { switch(Opcode) { default: break; - case ISD::SUBE: { - SDValue InFlag = Node->getOperand(2); - unsigned Opc = Subtarget->isGP64bit() ? Mips::DSUBu : Mips::SUBu; - selectAddESubE(Opc, InFlag, InFlag.getOperand(0), DL, Node); - return true; - } - case ISD::ADDE: { - if (Subtarget->hasDSP()) // Select DSP instructions, ADDSC and ADDWC. - break; - SDValue InFlag = Node->getOperand(2); - unsigned Opc = Subtarget->isGP64bit() ? Mips::DADDu : Mips::ADDu; - selectAddESubE(Opc, InFlag, InFlag.getValue(0), DL, Node); + selectAddE(Node, DL); return true; } diff --git a/lib/Target/Mips/MipsSEISelDAGToDAG.h b/lib/Target/Mips/MipsSEISelDAGToDAG.h index f89a350cab04..6f38289c5a45 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.h +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.h @@ -41,8 +41,7 @@ class MipsSEDAGToDAGISel : public MipsDAGToDAGISel { const SDLoc &dl, EVT Ty, bool HasLo, bool HasHi); - void selectAddESubE(unsigned MOp, SDValue InFlag, SDValue CmpLHS, - const SDLoc &DL, SDNode *Node) const; + void selectAddE(SDNode *Node, const SDLoc &DL) const; bool selectAddrFrameIndex(SDValue Addr, SDValue &Base, SDValue &Offset) const; bool selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, SDValue &Offset, diff --git a/lib/Target/Mips/MipsSEISelLowering.cpp b/lib/Target/Mips/MipsSEISelLowering.cpp index bf7f079e3105..2382ea271661 100644 --- a/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/lib/Target/Mips/MipsSEISelLowering.cpp @@ -179,8 +179,6 @@ MipsSETargetLowering::MipsSETargetLowering(const MipsTargetMachine &TM, setOperationAction(ISD::LOAD, MVT::i32, Custom); setOperationAction(ISD::STORE, MVT::i32, Custom); - setTargetDAGCombine(ISD::ADDE); - setTargetDAGCombine(ISD::SUBE); setTargetDAGCombine(ISD::MUL); setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); @@ -421,163 +419,6 @@ SDValue MipsSETargetLowering::LowerOperation(SDValue Op, return MipsTargetLowering::LowerOperation(Op, DAG); } -// selectMADD - -// Transforms a subgraph in CurDAG if the following pattern is found: -// (addc multLo, Lo0), (adde multHi, Hi0), -// where, -// multHi/Lo: product of multiplication -// Lo0: initial value of Lo register -// Hi0: initial value of Hi register -// Return true if pattern matching was successful. -static bool selectMADD(SDNode *ADDENode, SelectionDAG *CurDAG) { - // ADDENode's second operand must be a flag output of an ADDC node in order - // for the matching to be successful. - SDNode *ADDCNode = ADDENode->getOperand(2).getNode(); - - if (ADDCNode->getOpcode() != ISD::ADDC) - return false; - - SDValue MultHi = ADDENode->getOperand(0); - SDValue MultLo = ADDCNode->getOperand(0); - SDNode *MultNode = MultHi.getNode(); - unsigned MultOpc = MultHi.getOpcode(); - - // MultHi and MultLo must be generated by the same node, - if (MultLo.getNode() != MultNode) - return false; - - // and it must be a multiplication. - if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) - return false; - - // MultLo amd MultHi must be the first and second output of MultNode - // respectively. - if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) - return false; - - // Transform this to a MADD only if ADDENode and ADDCNode are the only users - // of the values of MultNode, in which case MultNode will be removed in later - // phases. - // If there exist users other than ADDENode or ADDCNode, this function returns - // here, which will result in MultNode being mapped to a single MULT - // instruction node rather than a pair of MULT and MADD instructions being - // produced. - if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) - return false; - - SDLoc DL(ADDENode); - - // Initialize accumulator. - SDValue ACCIn = CurDAG->getNode(MipsISD::MTLOHI, DL, MVT::Untyped, - ADDCNode->getOperand(1), - ADDENode->getOperand(1)); - - // create MipsMAdd(u) node - MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MAddu : MipsISD::MAdd; - - SDValue MAdd = CurDAG->getNode(MultOpc, DL, MVT::Untyped, - MultNode->getOperand(0),// Factor 0 - MultNode->getOperand(1),// Factor 1 - ACCIn); - - // replace uses of adde and addc here - if (!SDValue(ADDCNode, 0).use_empty()) { - SDValue LoOut = CurDAG->getNode(MipsISD::MFLO, DL, MVT::i32, MAdd); - CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDCNode, 0), LoOut); - } - if (!SDValue(ADDENode, 0).use_empty()) { - SDValue HiOut = CurDAG->getNode(MipsISD::MFHI, DL, MVT::i32, MAdd); - CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDENode, 0), HiOut); - } - - return true; -} - -// selectMSUB - -// Transforms a subgraph in CurDAG if the following pattern is found: -// (addc Lo0, multLo), (sube Hi0, multHi), -// where, -// multHi/Lo: product of multiplication -// Lo0: initial value of Lo register -// Hi0: initial value of Hi register -// Return true if pattern matching was successful. -static bool selectMSUB(SDNode *SUBENode, SelectionDAG *CurDAG) { - // SUBENode's second operand must be a flag output of an SUBC node in order - // for the matching to be successful. - SDNode *SUBCNode = SUBENode->getOperand(2).getNode(); - - if (SUBCNode->getOpcode() != ISD::SUBC) - return false; - - SDValue MultHi = SUBENode->getOperand(1); - SDValue MultLo = SUBCNode->getOperand(1); - SDNode *MultNode = MultHi.getNode(); - unsigned MultOpc = MultHi.getOpcode(); - - // MultHi and MultLo must be generated by the same node, - if (MultLo.getNode() != MultNode) - return false; - - // and it must be a multiplication. - if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) - return false; - - // MultLo amd MultHi must be the first and second output of MultNode - // respectively. - if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) - return false; - - // Transform this to a MSUB only if SUBENode and SUBCNode are the only users - // of the values of MultNode, in which case MultNode will be removed in later - // phases. - // If there exist users other than SUBENode or SUBCNode, this function returns - // here, which will result in MultNode being mapped to a single MULT - // instruction node rather than a pair of MULT and MSUB instructions being - // produced. - if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) - return false; - - SDLoc DL(SUBENode); - - // Initialize accumulator. - SDValue ACCIn = CurDAG->getNode(MipsISD::MTLOHI, DL, MVT::Untyped, - SUBCNode->getOperand(0), - SUBENode->getOperand(0)); - - // create MipsSub(u) node - MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MSubu : MipsISD::MSub; - - SDValue MSub = CurDAG->getNode(MultOpc, DL, MVT::Glue, - MultNode->getOperand(0),// Factor 0 - MultNode->getOperand(1),// Factor 1 - ACCIn); - - // replace uses of sube and subc here - if (!SDValue(SUBCNode, 0).use_empty()) { - SDValue LoOut = CurDAG->getNode(MipsISD::MFLO, DL, MVT::i32, MSub); - CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBCNode, 0), LoOut); - } - if (!SDValue(SUBENode, 0).use_empty()) { - SDValue HiOut = CurDAG->getNode(MipsISD::MFHI, DL, MVT::i32, MSub); - CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBENode, 0), HiOut); - } - - return true; -} - -static SDValue performADDECombine(SDNode *N, SelectionDAG &DAG, - TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget &Subtarget) { - if (DCI.isBeforeLegalize()) - return SDValue(); - - if (Subtarget.hasMips32() && !Subtarget.hasMips32r6() && - N->getValueType(0) == MVT::i32 && selectMADD(N, &DAG)) - return SDValue(N, 0); - - return SDValue(); -} - // Fold zero extensions into MipsISD::VEXTRACT_[SZ]EXT_ELT // // Performs the following transformations: @@ -820,19 +661,6 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, return SDValue(); } -static SDValue performSUBECombine(SDNode *N, SelectionDAG &DAG, - TargetLowering::DAGCombinerInfo &DCI, - const MipsSubtarget &Subtarget) { - if (DCI.isBeforeLegalize()) - return SDValue(); - - if (Subtarget.hasMips32() && N->getValueType(0) == MVT::i32 && - selectMSUB(N, &DAG)) - return SDValue(N, 0); - - return SDValue(); -} - static SDValue genConstMult(SDValue X, uint64_t C, const SDLoc &DL, EVT VT, EVT ShiftTy, SelectionDAG &DAG) { // Clear the upper (64 - VT.sizeInBits) bits. @@ -1110,16 +938,12 @@ MipsSETargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { SDValue Val; switch (N->getOpcode()) { - case ISD::ADDE: - return performADDECombine(N, DAG, DCI, Subtarget); case ISD::AND: Val = performANDCombine(N, DAG, DCI, Subtarget); break; case ISD::OR: Val = performORCombine(N, DAG, DCI, Subtarget); break; - case ISD::SUBE: - return performSUBECombine(N, DAG, DCI, Subtarget); case ISD::MUL: return performMULCombine(N, DAG, DCI, this); case ISD::SHL: diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h index 625a652a0ca0..ccd47f00c0d3 100644 --- a/lib/Target/Mips/MipsSubtarget.h +++ b/lib/Target/Mips/MipsSubtarget.h @@ -78,7 +78,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo { // IsNan2008 - IEEE 754-2008 NaN encoding. bool IsNaN2008bit; - // IsFP64bit - General-purpose registers are 64 bits wide + // IsGP64bit - General-purpose registers are 64 bits wide bool IsGP64bit; // IsPTR64bit - Pointers are 64 bit wide diff --git a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index 28d496ee9ca1..afd2e87078a9 100644 --- a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -2907,19 +2907,6 @@ SDValue PPCDAGToDAGISel::get64BitZExtCompare(SDValue LHS, SDValue RHS, getI64Imm(58, dl), getI64Imm(63, dl)), 0); } - case ISD::SETNE: { - // {addc.reg, addc.CA} = (addcarry (xor %a, %b), -1) - // (zext (setcc %a, %b, setne)) -> (sube addc.reg, addc.reg, addc.CA) - // {addcz.reg, addcz.CA} = (addcarry %a, -1) - // (zext (setcc %a, 0, setne)) -> (sube addcz.reg, addcz.reg, addcz.CA) - SDValue Xor = IsRHSZero ? LHS : - SDValue(CurDAG->getMachineNode(PPC::XOR8, dl, MVT::i64, LHS, RHS), 0); - SDValue AC = - SDValue(CurDAG->getMachineNode(PPC::ADDIC8, dl, MVT::i64, MVT::Glue, - Xor, getI32Imm(~0U, dl)), 0); - return SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64, AC, - Xor, AC.getValue(1)), 0); - } } } @@ -2944,19 +2931,6 @@ SDValue PPCDAGToDAGISel::get64BitSExtCompare(SDValue LHS, SDValue RHS, return SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64, Addic, Addic, Addic.getValue(1)), 0); } - case ISD::SETNE: { - // {subfc.reg, subfc.CA} = (subcarry 0, (xor %a, %b)) - // (sext (setcc %a, %b, setne)) -> (sube subfc.reg, subfc.reg, subfc.CA) - // {subfcz.reg, subfcz.CA} = (subcarry 0, %a) - // (sext (setcc %a, 0, setne)) -> (sube subfcz.reg, subfcz.reg, subfcz.CA) - SDValue Xor = IsRHSZero ? LHS : - SDValue(CurDAG->getMachineNode(PPC::XOR8, dl, MVT::i64, LHS, RHS), 0); - SDValue SC = - SDValue(CurDAG->getMachineNode(PPC::SUBFIC8, dl, MVT::i64, MVT::Glue, - Xor, getI32Imm(0, dl)), 0); - return SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64, SC, - SC, SC.getValue(1)), 0); - } } } diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index bda4e5e81734..662550f7a396 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -136,7 +136,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM, addRegisterClass(MVT::f64, &PPC::F8RCRegClass); } - // PowerPC has an i16 but no i8 (or i1) SEXTLOAD + // PowerPC has an i16 but no i8 (or i1) SEXTLOAD. for (MVT VT : MVT::integer_valuetypes()) { setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i8, Expand); @@ -175,7 +175,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM, setOperationAction(ISD::UINT_TO_FP, MVT::i1, Custom); } - // PowerPC does not support direct load / store of condition registers + // PowerPC does not support direct load/store of condition registers. setOperationAction(ISD::LOAD, MVT::i1, Custom); setOperationAction(ISD::STORE, MVT::i1, Custom); @@ -204,11 +204,23 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM, setOperationAction(ISD::FNEARBYINT, MVT::ppcf128, Expand); setOperationAction(ISD::FREM, MVT::ppcf128, Expand); - // PowerPC has no SREM/UREM instructions - setOperationAction(ISD::SREM, MVT::i32, Expand); - setOperationAction(ISD::UREM, MVT::i32, Expand); - setOperationAction(ISD::SREM, MVT::i64, Expand); - setOperationAction(ISD::UREM, MVT::i64, Expand); + // PowerPC has no SREM/UREM instructions unless we are on P9 + // On P9 we may use a hardware instruction to compute the remainder. + // The instructions are not legalized directly because in the cases where the + // result of both the remainder and the division is required it is more + // efficient to compute the remainder from the result of the division rather + // than use the remainder instruction. + if (Subtarget.isISA3_0()) { + setOperationAction(ISD::SREM, MVT::i32, Custom); + setOperationAction(ISD::UREM, MVT::i32, Custom); + setOperationAction(ISD::SREM, MVT::i64, Custom); + setOperationAction(ISD::UREM, MVT::i64, Custom); + } else { + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i64, Expand); + setOperationAction(ISD::UREM, MVT::i64, Expand); + } // Don't use SMUL_LOHI/UMUL_LOHI or SDIVREM/UDIVREM to lower SREM/UREM. setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); @@ -1116,6 +1128,7 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const { case PPCISD::VPERM: return "PPCISD::VPERM"; case PPCISD::XXSPLT: return "PPCISD::XXSPLT"; case PPCISD::XXINSERT: return "PPCISD::XXINSERT"; + case PPCISD::XXREVERSE: return "PPCISD::XXREVERSE"; case PPCISD::XXPERMDI: return "PPCISD::XXPERMDI"; case PPCISD::VECSHL: return "PPCISD::VECSHL"; case PPCISD::CMPB: return "PPCISD::CMPB"; @@ -1598,22 +1611,34 @@ bool PPC::isSplatShuffleMask(ShuffleVectorSDNode *N, unsigned EltSize) { return true; } -// Check that the mask is shuffling N byte elements. -static bool isNByteElemShuffleMask(ShuffleVectorSDNode *N, unsigned Width) { +/// Check that the mask is shuffling N byte elements. Within each N byte +/// element of the mask, the indices could be either in increasing or +/// decreasing order as long as they are consecutive. +/// \param[in] N the shuffle vector SD Node to analyze +/// \param[in] Width the element width in bytes, could be 2/4/8/16 (HalfWord/ +/// Word/DoubleWord/QuadWord). +/// \param[in] StepLen the delta indices number among the N byte element, if +/// the mask is in increasing/decreasing order then it is 1/-1. +/// \return true iff the mask is shuffling N byte elements. +static bool isNByteElemShuffleMask(ShuffleVectorSDNode *N, unsigned Width, + int StepLen) { assert((Width == 2 || Width == 4 || Width == 8 || Width == 16) && "Unexpected element width."); + assert((StepLen == 1 || StepLen == -1) && "Unexpected element width."); unsigned NumOfElem = 16 / Width; unsigned MaskVal[16]; // Width is never greater than 16 for (unsigned i = 0; i < NumOfElem; ++i) { MaskVal[0] = N->getMaskElt(i * Width); - if (MaskVal[0] % Width) { + if ((StepLen == 1) && (MaskVal[0] % Width)) { + return false; + } else if ((StepLen == -1) && ((MaskVal[0] + 1) % Width)) { return false; } for (unsigned int j = 1; j < Width; ++j) { MaskVal[j] = N->getMaskElt(i * Width + j); - if (MaskVal[j] != MaskVal[j-1] + 1) { + if (MaskVal[j] != MaskVal[j-1] + StepLen) { return false; } } @@ -1624,7 +1649,7 @@ static bool isNByteElemShuffleMask(ShuffleVectorSDNode *N, unsigned Width) { bool PPC::isXXINSERTWMask(ShuffleVectorSDNode *N, unsigned &ShiftElts, unsigned &InsertAtByte, bool &Swap, bool IsLE) { - if (!isNByteElemShuffleMask(N, 4)) + if (!isNByteElemShuffleMask(N, 4, 1)) return false; // Now we look at mask elements 0,4,8,12 @@ -1701,7 +1726,7 @@ bool PPC::isXXSLDWIShuffleMask(ShuffleVectorSDNode *N, unsigned &ShiftElts, bool &Swap, bool IsLE) { assert(N->getValueType(0) == MVT::v16i8 && "Shuffle vector expects v16i8"); // Ensure each byte index of the word is consecutive. - if (!isNByteElemShuffleMask(N, 4)) + if (!isNByteElemShuffleMask(N, 4, 1)) return false; // Now we look at mask elements 0,4,8,12, which are the beginning of words. @@ -1759,6 +1784,35 @@ bool PPC::isXXSLDWIShuffleMask(ShuffleVectorSDNode *N, unsigned &ShiftElts, } } +bool static isXXBRShuffleMaskHelper(ShuffleVectorSDNode *N, int Width) { + assert(N->getValueType(0) == MVT::v16i8 && "Shuffle vector expects v16i8"); + + if (!isNByteElemShuffleMask(N, Width, -1)) + return false; + + for (int i = 0; i < 16; i += Width) + if (N->getMaskElt(i) != i + Width - 1) + return false; + + return true; +} + +bool PPC::isXXBRHShuffleMask(ShuffleVectorSDNode *N) { + return isXXBRShuffleMaskHelper(N, 2); +} + +bool PPC::isXXBRWShuffleMask(ShuffleVectorSDNode *N) { + return isXXBRShuffleMaskHelper(N, 4); +} + +bool PPC::isXXBRDShuffleMask(ShuffleVectorSDNode *N) { + return isXXBRShuffleMaskHelper(N, 8); +} + +bool PPC::isXXBRQShuffleMask(ShuffleVectorSDNode *N) { + return isXXBRShuffleMaskHelper(N, 16); +} + /// Can node \p N be lowered to an XXPERMDI instruction? If so, set \p Swap /// if the inputs to the instruction should be swapped and set \p DM to the /// value for the immediate. @@ -1772,7 +1826,7 @@ bool PPC::isXXPERMDIShuffleMask(ShuffleVectorSDNode *N, unsigned &DM, assert(N->getValueType(0) == MVT::v16i8 && "Shuffle vector expects v16i8"); // Ensure each byte index of the double word is consecutive. - if (!isNByteElemShuffleMask(N, 8)) + if (!isNByteElemShuffleMask(N, 8, 1)) return false; unsigned M0 = N->getMaskElt(0) / 8; @@ -6819,6 +6873,7 @@ bool PPCTargetLowering::canReuseLoadAddress(SDValue Op, EVT MemVT, // Given the head of the old chain, ResChain, insert a token factor containing // it and NewResChain, and make users of ResChain now be users of that token // factor. +// TODO: Remove and use DAG::makeEquivalentMemoryOrdering() instead. void PPCTargetLowering::spliceIntoChain(SDValue ResChain, SDValue NewResChain, SelectionDAG &DAG) const { @@ -7846,6 +7901,26 @@ SDValue PPCTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, return DAG.getNode(ISD::BITCAST, dl, MVT::v16i8, PermDI); } + if (Subtarget.hasP9Vector()) { + if (PPC::isXXBRHShuffleMask(SVOp)) { + SDValue Conv = DAG.getNode(ISD::BITCAST, dl, MVT::v8i16, V1); + SDValue ReveHWord = DAG.getNode(PPCISD::XXREVERSE, dl, MVT::v8i16, Conv); + return DAG.getNode(ISD::BITCAST, dl, MVT::v16i8, ReveHWord); + } else if (PPC::isXXBRWShuffleMask(SVOp)) { + SDValue Conv = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, V1); + SDValue ReveWord = DAG.getNode(PPCISD::XXREVERSE, dl, MVT::v4i32, Conv); + return DAG.getNode(ISD::BITCAST, dl, MVT::v16i8, ReveWord); + } else if (PPC::isXXBRDShuffleMask(SVOp)) { + SDValue Conv = DAG.getNode(ISD::BITCAST, dl, MVT::v2i64, V1); + SDValue ReveDWord = DAG.getNode(PPCISD::XXREVERSE, dl, MVT::v2i64, Conv); + return DAG.getNode(ISD::BITCAST, dl, MVT::v16i8, ReveDWord); + } else if (PPC::isXXBRQShuffleMask(SVOp)) { + SDValue Conv = DAG.getNode(ISD::BITCAST, dl, MVT::v1i128, V1); + SDValue ReveQWord = DAG.getNode(PPCISD::XXREVERSE, dl, MVT::v1i128, Conv); + return DAG.getNode(ISD::BITCAST, dl, MVT::v16i8, ReveQWord); + } + } + if (Subtarget.hasVSX()) { if (V2.isUndef() && PPC::isSplatShuffleMask(SVOp, 4)) { int SplatIdx = PPC::getVSPLTImmediate(SVOp, 4, DAG); @@ -8393,6 +8468,18 @@ SDValue PPCTargetLowering::LowerINTRINSIC_VOID(SDValue Op, return SDValue(); } +SDValue PPCTargetLowering::LowerREM(SDValue Op, SelectionDAG &DAG) const { + // Check for a DIV with the same operands as this REM. + for (auto UI : Op.getOperand(1)->uses()) { + if ((Op.getOpcode() == ISD::SREM && UI->getOpcode() == ISD::SDIV) || + (Op.getOpcode() == ISD::UREM && UI->getOpcode() == ISD::UDIV)) + if (UI->getOperand(0) == Op.getOperand(0) && + UI->getOperand(1) == Op.getOperand(1)) + return SDValue(); + } + return Op; +} + SDValue PPCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op, SelectionDAG &DAG) const { SDLoc dl(Op); @@ -8861,6 +8948,9 @@ SDValue PPCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::INTRINSIC_VOID: return LowerINTRINSIC_VOID(Op, DAG); + case ISD::SREM: + case ISD::UREM: + return LowerREM(Op, DAG); } } diff --git a/lib/Target/PowerPC/PPCISelLowering.h b/lib/Target/PowerPC/PPCISelLowering.h index 7982a4a9e9fb..a5108727bb4b 100644 --- a/lib/Target/PowerPC/PPCISelLowering.h +++ b/lib/Target/PowerPC/PPCISelLowering.h @@ -86,6 +86,10 @@ namespace llvm { /// XXINSERT, + /// XXREVERSE - The PPC VSX reverse instruction + /// + XXREVERSE, + /// VECSHL - The PPC VSX shift left instruction /// VECSHL, @@ -458,6 +462,23 @@ namespace llvm { /// for a XXSLDWI instruction. bool isXXSLDWIShuffleMask(ShuffleVectorSDNode *N, unsigned &ShiftElts, bool &Swap, bool IsLE); + + /// isXXBRHShuffleMask - Return true if this is a shuffle mask suitable + /// for a XXBRH instruction. + bool isXXBRHShuffleMask(ShuffleVectorSDNode *N); + + /// isXXBRWShuffleMask - Return true if this is a shuffle mask suitable + /// for a XXBRW instruction. + bool isXXBRWShuffleMask(ShuffleVectorSDNode *N); + + /// isXXBRDShuffleMask - Return true if this is a shuffle mask suitable + /// for a XXBRD instruction. + bool isXXBRDShuffleMask(ShuffleVectorSDNode *N); + + /// isXXBRQShuffleMask - Return true if this is a shuffle mask suitable + /// for a XXBRQ instruction. + bool isXXBRQShuffleMask(ShuffleVectorSDNode *N); + /// isXXPERMDIShuffleMask - Return true if this is a shuffle mask suitable /// for a XXPERMDI instruction. bool isXXPERMDIShuffleMask(ShuffleVectorSDNode *N, unsigned &ShiftElts, @@ -918,6 +939,7 @@ namespace llvm { SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerREM(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSIGN_EXTEND_INREG(SDValue Op, SelectionDAG &DAG) const; SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const; diff --git a/lib/Target/PowerPC/PPCInstr64Bit.td b/lib/Target/PowerPC/PPCInstr64Bit.td index 295590b2acf6..70536a6039b8 100644 --- a/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/lib/Target/PowerPC/PPCInstr64Bit.td @@ -683,6 +683,16 @@ def DIVDE : XOForm_1<31, 425, 0, (outs g8rc:$rT), (ins g8rc:$rA, g8rc:$rB), "divde $rT, $rA, $rB", IIC_IntDivD, [(set i64:$rT, (int_ppc_divde g8rc:$rA, g8rc:$rB))]>, isPPC64, Requires<[HasExtDiv]>; + +let Predicates = [IsISA3_0] in { +def MODSD : XForm_8<31, 777, (outs g8rc:$rT), (ins g8rc:$rA, g8rc:$rB), + "modsd $rT, $rA, $rB", IIC_IntDivW, + [(set i64:$rT, (srem i64:$rA, i64:$rB))]>; +def MODUD : XForm_8<31, 265, (outs g8rc:$rT), (ins g8rc:$rA, g8rc:$rB), + "modud $rT, $rA, $rB", IIC_IntDivW, + [(set i64:$rT, (urem i64:$rA, i64:$rB))]>; +} + let Defs = [CR0] in def DIVDEo : XOForm_1<31, 425, 0, (outs g8rc:$rT), (ins g8rc:$rA, g8rc:$rB), "divde. $rT, $rA, $rB", IIC_IntDivD, diff --git a/lib/Target/PowerPC/PPCInstrInfo.cpp b/lib/Target/PowerPC/PPCInstrInfo.cpp index f3c68c443b1b..236e513bec23 100644 --- a/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -1964,7 +1964,7 @@ bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { } case PPC::CFENCE8: { auto Val = MI.getOperand(0).getReg(); - BuildMI(MBB, MI, DL, get(PPC::CMPW), PPC::CR7).addReg(Val).addReg(Val); + BuildMI(MBB, MI, DL, get(PPC::CMPD), PPC::CR7).addReg(Val).addReg(Val); BuildMI(MBB, MI, DL, get(PPC::CTRL_DEP)) .addImm(PPC::PRED_NE_MINUS) .addReg(PPC::CR7) diff --git a/lib/Target/PowerPC/PPCInstrInfo.td b/lib/Target/PowerPC/PPCInstrInfo.td index 8223aa655e38..47d59c25392a 100644 --- a/lib/Target/PowerPC/PPCInstrInfo.td +++ b/lib/Target/PowerPC/PPCInstrInfo.td @@ -53,6 +53,10 @@ def SDT_PPCVecInsert : SDTypeProfile<1, 3, [ SDTCisVec<0>, SDTCisVec<1>, SDTCisVec<2>, SDTCisInt<3> ]>; +def SDT_PPCVecReverse: SDTypeProfile<1, 1, [ SDTCisVec<0>, + SDTCisVec<1> +]>; + def SDT_PPCxxpermdi: SDTypeProfile<1, 3, [ SDTCisVec<0>, SDTCisVec<1>, SDTCisVec<2>, SDTCisInt<3> ]>; @@ -174,6 +178,7 @@ def PPCaddiDtprelL : SDNode<"PPCISD::ADDI_DTPREL_L", SDTIntBinOp>; def PPCvperm : SDNode<"PPCISD::VPERM", SDT_PPCvperm, []>; def PPCxxsplt : SDNode<"PPCISD::XXSPLT", SDT_PPCVecSplat, []>; def PPCxxinsert : SDNode<"PPCISD::XXINSERT", SDT_PPCVecInsert, []>; +def PPCxxreverse : SDNode<"PPCISD::XXREVERSE", SDT_PPCVecReverse, []>; def PPCxxpermdi : SDNode<"PPCISD::XXPERMDI", SDT_PPCxxpermdi, []>; def PPCvecshl : SDNode<"PPCISD::VECSHL", SDT_PPCVecShift, []>; @@ -2544,6 +2549,14 @@ let Uses = [RM] in { "mffs. $rT", IIC_IntMFFS, []>, isDOT; } +let Predicates = [IsISA3_0] in { +def MODSW : XForm_8<31, 779, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), + "modsw $rT, $rA, $rB", IIC_IntDivW, + [(set i32:$rT, (srem i32:$rA, i32:$rB))]>; +def MODUW : XForm_8<31, 267, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), + "moduw $rT, $rA, $rB", IIC_IntDivW, + [(set i32:$rT, (urem i32:$rA, i32:$rB))]>; +} let PPC970_Unit = 1, hasSideEffects = 0 in { // FXU Operations. // XO-Form instructions. Arithmetic instructions that can set overflow bit diff --git a/lib/Target/PowerPC/PPCInstrVSX.td b/lib/Target/PowerPC/PPCInstrVSX.td index e214d26c063b..9cfc897cdb3f 100644 --- a/lib/Target/PowerPC/PPCInstrVSX.td +++ b/lib/Target/PowerPC/PPCInstrVSX.td @@ -2340,6 +2340,16 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in { def XXBRD : XX2_XT6_XO5_XB6<60, 23, 475, "xxbrd", vsrc, []>; def XXBRQ : XX2_XT6_XO5_XB6<60, 31, 475, "xxbrq", vsrc, []>; + // Vector Reverse + def : Pat<(v8i16 (PPCxxreverse v8i16 :$A)), + (v8i16 (COPY_TO_REGCLASS (XXBRH (COPY_TO_REGCLASS $A, VSRC)), VRRC))>; + def : Pat<(v4i32 (PPCxxreverse v4i32 :$A)), + (v4i32 (XXBRW $A))>; + def : Pat<(v2i64 (PPCxxreverse v2i64 :$A)), + (v2i64 (XXBRD $A))>; + def : Pat<(v1i128 (PPCxxreverse v1i128 :$A)), + (v1i128 (COPY_TO_REGCLASS (XXBRQ (COPY_TO_REGCLASS $A, VSRC)), VRRC))>; + // Vector Permute def XXPERM : XX3_XT5_XA5_XB5<60, 26, "xxperm" , vsrc, vsrc, vsrc, IIC_VecPerm, []>; diff --git a/lib/Target/PowerPC/PPCRegisterInfo.cpp b/lib/Target/PowerPC/PPCRegisterInfo.cpp index aad913924692..637e52bbdbee 100644 --- a/lib/Target/PowerPC/PPCRegisterInfo.cpp +++ b/lib/Target/PowerPC/PPCRegisterInfo.cpp @@ -273,6 +273,20 @@ BitVector PPCRegisterInfo::getReservedRegs(const MachineFunction &MF) const { return Reserved; } +bool PPCRegisterInfo::isCallerPreservedPhysReg(unsigned PhysReg, + const MachineFunction &MF) const { + assert(TargetRegisterInfo::isPhysicalRegister(PhysReg)); + if (TM.isELFv2ABI() && PhysReg == PPC::X2) { + // X2 is guaranteed to be preserved within a function if it is reserved. + // The reason it's reserved is that it's the TOC pointer (and the function + // uses the TOC). In functions where it isn't reserved (i.e. leaf functions + // with no TOC access), we can't claim that it is preserved. + return (getReservedRegs(MF).test(PPC::X2)); + } else { + return false; + } +} + unsigned PPCRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC, MachineFunction &MF) const { const PPCFrameLowering *TFI = getFrameLowering(MF); diff --git a/lib/Target/PowerPC/PPCRegisterInfo.h b/lib/Target/PowerPC/PPCRegisterInfo.h index 4a96327fe552..0bbb71fdf9fb 100644 --- a/lib/Target/PowerPC/PPCRegisterInfo.h +++ b/lib/Target/PowerPC/PPCRegisterInfo.h @@ -83,6 +83,7 @@ class PPCRegisterInfo : public PPCGenRegisterInfo { void adjustStackMapLiveOutMask(uint32_t *Mask) const override; BitVector getReservedRegs(const MachineFunction &MF) const override; + bool isCallerPreservedPhysReg(unsigned PhysReg, const MachineFunction &MF) const override; /// We require the register scavenger. bool requiresRegisterScavenging(const MachineFunction &MF) const override { diff --git a/lib/Target/PowerPC/PPCTargetTransformInfo.cpp b/lib/Target/PowerPC/PPCTargetTransformInfo.cpp index 5559cdc5fe46..3dbd5f5b9a92 100644 --- a/lib/Target/PowerPC/PPCTargetTransformInfo.cpp +++ b/lib/Target/PowerPC/PPCTargetTransformInfo.cpp @@ -230,7 +230,7 @@ unsigned PPCTTIImpl::getNumberOfRegisters(bool Vector) { return ST->hasVSX() ? 64 : 32; } -unsigned PPCTTIImpl::getRegisterBitWidth(bool Vector) { +unsigned PPCTTIImpl::getRegisterBitWidth(bool Vector) const { if (Vector) { if (ST->hasQPX()) return 256; if (ST->hasAltivec()) return 128; diff --git a/lib/Target/PowerPC/PPCTargetTransformInfo.h b/lib/Target/PowerPC/PPCTargetTransformInfo.h index 2e0116fee04c..758c335def08 100644 --- a/lib/Target/PowerPC/PPCTargetTransformInfo.h +++ b/lib/Target/PowerPC/PPCTargetTransformInfo.h @@ -63,7 +63,7 @@ class PPCTTIImpl : public BasicTTIImplBase { bool expandMemCmp(Instruction *I, unsigned &MaxLoadSize); bool enableInterleavedAccessVectorization(); unsigned getNumberOfRegisters(bool Vector); - unsigned getRegisterBitWidth(bool Vector); + unsigned getRegisterBitWidth(bool Vector) const; unsigned getCacheLineSize(); unsigned getPrefetchDistance(); unsigned getMaxInterleaveFactor(unsigned VF); diff --git a/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp b/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp index 6a3dc6799c43..422c16b8eb62 100644 --- a/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp +++ b/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp @@ -302,7 +302,7 @@ unsigned SystemZTTIImpl::getNumberOfRegisters(bool Vector) { return 0; } -unsigned SystemZTTIImpl::getRegisterBitWidth(bool Vector) { +unsigned SystemZTTIImpl::getRegisterBitWidth(bool Vector) const { if (!Vector) return 64; if (ST->hasVector()) diff --git a/lib/Target/SystemZ/SystemZTargetTransformInfo.h b/lib/Target/SystemZ/SystemZTargetTransformInfo.h index ad597f5c65f0..bdba7601eb78 100644 --- a/lib/Target/SystemZ/SystemZTargetTransformInfo.h +++ b/lib/Target/SystemZ/SystemZTargetTransformInfo.h @@ -53,7 +53,7 @@ class SystemZTTIImpl : public BasicTTIImplBase { /// @{ unsigned getNumberOfRegisters(bool Vector); - unsigned getRegisterBitWidth(bool Vector); + unsigned getRegisterBitWidth(bool Vector) const; bool prefersVectorizedAddressing() { return false; } bool supportsEfficientVectorElementLoadStore() { return true; } diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h index ddf964e7dbb7..5ad147e5e596 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -46,9 +46,7 @@ class WebAssemblyTargetStreamer : public MCTargetStreamer { /// .functype virtual void emitIndirectFunctionType(StringRef name, SmallVectorImpl &Params, - SmallVectorImpl &Results) { - llvm_unreachable("emitIndirectFunctionType not implemented"); - } + SmallVectorImpl &Results) = 0; /// .indidx virtual void emitIndIdx(const MCExpr *Value) = 0; /// .import_global diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp index 27c01cb8acf7..19e14f3261aa 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -16,11 +16,15 @@ #include "MCTargetDesc/WebAssemblyFixupKinds.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "llvm/BinaryFormat/Wasm.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCSymbolWasm.h" #include "llvm/MC/MCWasmObjectWriter.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" + using namespace llvm; namespace { @@ -29,8 +33,8 @@ class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter { explicit WebAssemblyWasmObjectWriter(bool Is64Bit); private: - unsigned getRelocType(MCContext &Ctx, const MCValue &Target, - const MCFixup &Fixup, bool IsPCRel) const override; + unsigned getRelocType(const MCValue &Target, + const MCFixup &Fixup) const override; }; } // end anonymous namespace @@ -39,16 +43,13 @@ WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit) // Test whether the given expression computes a function address. static bool IsFunctionExpr(const MCExpr *Expr) { - if (const MCSymbolRefExpr *SyExp = - dyn_cast(Expr)) + if (auto SyExp = dyn_cast(Expr)) return cast(SyExp->getSymbol()).isFunction(); - if (const MCBinaryExpr *BinOp = - dyn_cast(Expr)) + if (auto BinOp = dyn_cast(Expr)) return IsFunctionExpr(BinOp->getLHS()) != IsFunctionExpr(BinOp->getRHS()); - if (const MCUnaryExpr *UnOp = - dyn_cast(Expr)) + if (auto UnOp = dyn_cast(Expr)) return IsFunctionExpr(UnOp->getSubExpr()); return false; @@ -59,15 +60,13 @@ static bool IsFunctionType(const MCValue &Target) { return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX; } -unsigned WebAssemblyWasmObjectWriter::getRelocType(MCContext &Ctx, - const MCValue &Target, - const MCFixup &Fixup, - bool IsPCRel) const { +unsigned +WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, + const MCFixup &Fixup) const { // WebAssembly functions are not allocated in the data address space. To // resolve a pointer to a function, we must use a special relocation type. bool IsFunction = IsFunctionExpr(Fixup.getValue()); - assert(!IsPCRel); switch (unsigned(Fixup.getKind())) { case WebAssembly::fixup_code_sleb128_i32: if (IsFunction) diff --git a/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 4178ec0b28f0..b999091e2d29 100644 --- a/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -33,6 +33,8 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" @@ -218,9 +220,13 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { const MCExpr *WebAssemblyAsmPrinter::lowerConstant(const Constant *CV) { if (const GlobalValue *GV = dyn_cast(CV)) - if (GV->getValueType()->isFunctionTy()) + if (GV->getValueType()->isFunctionTy()) { + MCSymbol* Sym = getSymbol(GV); + if (!isa(Sym)) + cast(Sym)->setIsFunction(true); return MCSymbolRefExpr::create( - getSymbol(GV), MCSymbolRefExpr::VK_WebAssembly_FUNCTION, OutContext); + Sym, MCSymbolRefExpr::VK_WebAssembly_FUNCTION, OutContext); + } return AsmPrinter::lowerConstant(CV); } diff --git a/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp b/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp index 47aadf99e860..b3ce4bd27460 100644 --- a/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp +++ b/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp @@ -36,7 +36,7 @@ unsigned WebAssemblyTTIImpl::getNumberOfRegisters(bool Vector) { return Result; } -unsigned WebAssemblyTTIImpl::getRegisterBitWidth(bool Vector) { +unsigned WebAssemblyTTIImpl::getRegisterBitWidth(bool Vector) const { if (Vector && getST()->hasSIMD128()) return 128; diff --git a/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h b/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h index f658609f8930..7b35fc916133 100644 --- a/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h +++ b/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h @@ -55,7 +55,7 @@ class WebAssemblyTTIImpl final : public BasicTTIImplBase { /// @{ unsigned getNumberOfRegisters(bool Vector); - unsigned getRegisterBitWidth(bool Vector); + unsigned getRegisterBitWidth(bool Vector) const; unsigned getArithmeticInstrCost( unsigned Opcode, Type *Ty, TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue, diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 831e9bdab0e1..172eba0002d4 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1,4 +1,3 @@ - //===-- X86ISelLowering.cpp - X86 DAG Lowering Implementation -------------===// // // The LLVM Compiler Infrastructure @@ -5314,20 +5313,37 @@ static bool getTargetConstantBitsFromNode(SDValue Op, unsigned EltSizeInBits, assert((SizeInBits % EltSizeInBits) == 0 && "Can't split constant!"); unsigned NumElts = SizeInBits / EltSizeInBits; - unsigned SrcEltSizeInBits = VT.getScalarSizeInBits(); - unsigned NumSrcElts = SizeInBits / SrcEltSizeInBits; + // Bitcast a source array of element bits to the target size. + auto CastBitData = [&](APInt &UndefSrcElts, ArrayRef SrcEltBits) { + unsigned NumSrcElts = UndefSrcElts.getBitWidth(); + unsigned SrcEltSizeInBits = SrcEltBits[0].getBitWidth(); + assert((NumSrcElts * SrcEltSizeInBits) == SizeInBits && + "Constant bit sizes don't match"); - // Extract all the undef/constant element data and pack into single bitsets. - APInt UndefBits(SizeInBits, 0); - APInt MaskBits(SizeInBits, 0); - - // Split the undef/constant single bitset data into the target elements. - auto SplitBitData = [&]() { // Don't split if we don't allow undef bits. bool AllowUndefs = AllowWholeUndefs || AllowPartialUndefs; - if (UndefBits.getBoolValue() && !AllowUndefs) + if (UndefSrcElts.getBoolValue() && !AllowUndefs) return false; + // If we're already the right size, don't bother bitcasting. + if (NumSrcElts == NumElts) { + UndefElts = UndefSrcElts; + EltBits.assign(SrcEltBits.begin(), SrcEltBits.end()); + return true; + } + + // Extract all the undef/constant element data and pack into single bitsets. + APInt UndefBits(SizeInBits, 0); + APInt MaskBits(SizeInBits, 0); + + for (unsigned i = 0; i != NumSrcElts; ++i) { + unsigned BitOffset = i * SrcEltSizeInBits; + if (UndefSrcElts[i]) + UndefBits.setBits(BitOffset, BitOffset + SrcEltSizeInBits); + MaskBits.insertBits(SrcEltBits[i], BitOffset); + } + + // Split the undef/constant single bitset data into the target elements. UndefElts = APInt(NumElts, 0); EltBits.resize(NumElts, APInt(EltSizeInBits, 0)); @@ -5356,20 +5372,19 @@ static bool getTargetConstantBitsFromNode(SDValue Op, unsigned EltSizeInBits, // Collect constant bits and insert into mask/undef bit masks. auto CollectConstantBits = [](const Constant *Cst, APInt &Mask, APInt &Undefs, - unsigned BitOffset) { + unsigned UndefBitIndex) { if (!Cst) return false; if (isa(Cst)) { - unsigned CstSizeInBits = Cst->getType()->getPrimitiveSizeInBits(); - Undefs.setBits(BitOffset, BitOffset + CstSizeInBits); + Undefs.setBit(UndefBitIndex); return true; } if (auto *CInt = dyn_cast(Cst)) { - Mask.insertBits(CInt->getValue(), BitOffset); + Mask = CInt->getValue(); return true; } if (auto *CFP = dyn_cast(Cst)) { - Mask.insertBits(CFP->getValueAPF().bitcastToAPInt(), BitOffset); + Mask = CFP->getValueAPF().bitcastToAPInt(); return true; } return false; @@ -5377,18 +5392,21 @@ static bool getTargetConstantBitsFromNode(SDValue Op, unsigned EltSizeInBits, // Extract constant bits from build vector. if (ISD::isBuildVectorOfConstantSDNodes(Op.getNode())) { + unsigned SrcEltSizeInBits = VT.getScalarSizeInBits(); + unsigned NumSrcElts = SizeInBits / SrcEltSizeInBits; + + APInt UndefSrcElts(NumSrcElts, 0); + SmallVector SrcEltBits(NumSrcElts, APInt(SrcEltSizeInBits, 0)); for (unsigned i = 0, e = Op.getNumOperands(); i != e; ++i) { const SDValue &Src = Op.getOperand(i); - unsigned BitOffset = i * SrcEltSizeInBits; if (Src.isUndef()) { - UndefBits.setBits(BitOffset, BitOffset + SrcEltSizeInBits); + UndefSrcElts.setBit(i); continue; } auto *Cst = cast(Src); - APInt Bits = Cst->getAPIntValue().zextOrTrunc(SrcEltSizeInBits); - MaskBits.insertBits(Bits, BitOffset); + SrcEltBits[i] = Cst->getAPIntValue().zextOrTrunc(SrcEltSizeInBits); } - return SplitBitData(); + return CastBitData(UndefSrcElts, SrcEltBits); } // Extract constant bits from constant pool vector. @@ -5397,27 +5415,33 @@ static bool getTargetConstantBitsFromNode(SDValue Op, unsigned EltSizeInBits, if (!CstTy->isVectorTy() || (SizeInBits != CstTy->getPrimitiveSizeInBits())) return false; - unsigned CstEltSizeInBits = CstTy->getScalarSizeInBits(); - for (unsigned i = 0, e = CstTy->getVectorNumElements(); i != e; ++i) - if (!CollectConstantBits(Cst->getAggregateElement(i), MaskBits, UndefBits, - i * CstEltSizeInBits)) + unsigned SrcEltSizeInBits = CstTy->getScalarSizeInBits(); + unsigned NumSrcElts = CstTy->getVectorNumElements(); + + APInt UndefSrcElts(NumSrcElts, 0); + SmallVector SrcEltBits(NumSrcElts, APInt(SrcEltSizeInBits, 0)); + for (unsigned i = 0; i != NumSrcElts; ++i) + if (!CollectConstantBits(Cst->getAggregateElement(i), SrcEltBits[i], + UndefSrcElts, i)) return false; - return SplitBitData(); + return CastBitData(UndefSrcElts, SrcEltBits); } // Extract constant bits from a broadcasted constant pool scalar. if (Op.getOpcode() == X86ISD::VBROADCAST && - EltSizeInBits <= SrcEltSizeInBits) { + EltSizeInBits <= VT.getScalarSizeInBits()) { if (auto *Broadcast = getTargetConstantFromNode(Op.getOperand(0))) { - APInt Bits(SizeInBits, 0); - APInt Undefs(SizeInBits, 0); - if (CollectConstantBits(Broadcast, Bits, Undefs, 0)) { - for (unsigned i = 0; i != NumSrcElts; ++i) { - MaskBits |= Bits.shl(i * SrcEltSizeInBits); - UndefBits |= Undefs.shl(i * SrcEltSizeInBits); - } - return SplitBitData(); + unsigned SrcEltSizeInBits = Broadcast->getType()->getScalarSizeInBits(); + unsigned NumSrcElts = SizeInBits / SrcEltSizeInBits; + + APInt UndefSrcElts(NumSrcElts, 0); + SmallVector SrcEltBits(1, APInt(SrcEltSizeInBits, 0)); + if (CollectConstantBits(Broadcast, SrcEltBits[0], UndefSrcElts, 0)) { + if (UndefSrcElts[0]) + UndefSrcElts.setBits(0, NumSrcElts); + SrcEltBits.append(NumSrcElts - 1, SrcEltBits[0]); + return CastBitData(UndefSrcElts, SrcEltBits); } } } @@ -5426,10 +5450,15 @@ static bool getTargetConstantBitsFromNode(SDValue Op, unsigned EltSizeInBits, if (Op.getOpcode() == X86ISD::VZEXT_MOVL && Op.getOperand(0).getOpcode() == ISD::SCALAR_TO_VECTOR && isa(Op.getOperand(0).getOperand(0))) { + unsigned SrcEltSizeInBits = VT.getScalarSizeInBits(); + unsigned NumSrcElts = SizeInBits / SrcEltSizeInBits; + + APInt UndefSrcElts(NumSrcElts, 0); + SmallVector SrcEltBits; auto *CN = cast(Op.getOperand(0).getOperand(0)); - MaskBits = CN->getAPIntValue().zextOrTrunc(SrcEltSizeInBits); - MaskBits = MaskBits.zext(SizeInBits); - return SplitBitData(); + SrcEltBits.push_back(CN->getAPIntValue().zextOrTrunc(SrcEltSizeInBits)); + SrcEltBits.append(NumSrcElts - 1, APInt(SrcEltSizeInBits, 0)); + return CastBitData(UndefSrcElts, SrcEltBits); } return false; @@ -6491,16 +6520,7 @@ static SDValue EltsFromConsecutiveLoads(EVT VT, ArrayRef Elts, SDValue NewLd = DAG.getLoad(VT, DL, LDBase->getChain(), LDBase->getBasePtr(), LDBase->getPointerInfo(), LDBase->getAlignment(), MMOFlags); - - if (LDBase->hasAnyUseOfValue(1)) { - SDValue NewChain = - DAG.getNode(ISD::TokenFactor, DL, MVT::Other, SDValue(LDBase, 1), - SDValue(NewLd.getNode(), 1)); - DAG.ReplaceAllUsesOfValueWith(SDValue(LDBase, 1), NewChain); - DAG.UpdateNodeOperands(NewChain.getNode(), SDValue(LDBase, 1), - SDValue(NewLd.getNode(), 1)); - } - + DAG.makeEquivalentMemoryOrdering(LDBase, NewLd); return NewLd; }; @@ -6565,19 +6585,7 @@ static SDValue EltsFromConsecutiveLoads(EVT VT, ArrayRef Elts, LDBase->getAlignment(), false/*isVolatile*/, true/*ReadMem*/, false/*WriteMem*/); - - // Make sure the newly-created LOAD is in the same position as LDBase in - // terms of dependency. We create a TokenFactor for LDBase and ResNode, - // and update uses of LDBase's output chain to use the TokenFactor. - if (LDBase->hasAnyUseOfValue(1)) { - SDValue NewChain = - DAG.getNode(ISD::TokenFactor, DL, MVT::Other, SDValue(LDBase, 1), - SDValue(ResNode.getNode(), 1)); - DAG.ReplaceAllUsesOfValueWith(SDValue(LDBase, 1), NewChain); - DAG.UpdateNodeOperands(NewChain.getNode(), SDValue(LDBase, 1), - SDValue(ResNode.getNode(), 1)); - } - + DAG.makeEquivalentMemoryOrdering(LDBase, ResNode); return DAG.getBitcast(VT, ResNode); } } @@ -9930,17 +9938,7 @@ static SDValue lowerVectorShuffleAsBroadcast(const SDLoc &DL, MVT VT, V = DAG.getLoad(SVT, DL, Ld->getChain(), NewAddr, DAG.getMachineFunction().getMachineMemOperand( Ld->getMemOperand(), Offset, SVT.getStoreSize())); - - // Make sure the newly-created LOAD is in the same position as Ld in - // terms of dependency. We create a TokenFactor for Ld and V, - // and update uses of Ld's output chain to use the TokenFactor. - if (Ld->hasAnyUseOfValue(1)) { - SDValue NewChain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, - SDValue(Ld, 1), SDValue(V.getNode(), 1)); - DAG.ReplaceAllUsesOfValueWith(SDValue(Ld, 1), NewChain); - DAG.UpdateNodeOperands(NewChain.getNode(), SDValue(Ld, 1), - SDValue(V.getNode(), 1)); - } + DAG.makeEquivalentMemoryOrdering(Ld, V); } else if (!BroadcastFromReg) { // We can't broadcast from a vector register. return SDValue(); @@ -10891,9 +10889,10 @@ static SDValue lowerV8I16GeneralSingleInputVectorShuffle( "We need to be changing the number of flipped inputs!"); int PSHUFHalfMask[] = {0, 1, 2, 3}; std::swap(PSHUFHalfMask[FixFreeIdx % 4], PSHUFHalfMask[FixIdx % 4]); - V = DAG.getNode(FixIdx < 4 ? X86ISD::PSHUFLW : X86ISD::PSHUFHW, DL, - MVT::v8i16, V, - getV4X86ShuffleImm8ForMask(PSHUFHalfMask, DL, DAG)); + V = DAG.getNode( + FixIdx < 4 ? X86ISD::PSHUFLW : X86ISD::PSHUFHW, DL, + MVT::getVectorVT(MVT::i16, V.getValueSizeInBits() / 16), V, + getV4X86ShuffleImm8ForMask(PSHUFHalfMask, DL, DAG)); for (int &M : Mask) if (M >= 0 && M == FixIdx) @@ -12007,18 +12006,22 @@ static SDValue lowerV2X128VectorShuffle(const SDLoc &DL, MVT VT, SDValue V1, // subvector. bool OnlyUsesV1 = isShuffleEquivalent(V1, V2, Mask, {0, 1, 0, 1}); if (OnlyUsesV1 || isShuffleEquivalent(V1, V2, Mask, {0, 1, 4, 5})) { - // With AVX2 we should use VPERMQ/VPERMPD to allow memory folding. + // With AVX2, use VPERMQ/VPERMPD to allow memory folding. if (Subtarget.hasAVX2() && V2.isUndef()) return SDValue(); - MVT SubVT = MVT::getVectorVT(VT.getVectorElementType(), - VT.getVectorNumElements() / 2); - SDValue LoV = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SubVT, V1, - DAG.getIntPtrConstant(0, DL)); - SDValue HiV = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SubVT, - OnlyUsesV1 ? V1 : V2, - DAG.getIntPtrConstant(0, DL)); - return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, LoV, HiV); + // With AVX1, use vperm2f128 (below) to allow load folding. Otherwise, + // this will likely become vinsertf128 which can't fold a 256-bit memop. + if (!isa(peekThroughBitcasts(V1))) { + MVT SubVT = MVT::getVectorVT(VT.getVectorElementType(), + VT.getVectorNumElements() / 2); + SDValue LoV = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SubVT, V1, + DAG.getIntPtrConstant(0, DL)); + SDValue HiV = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SubVT, + OnlyUsesV1 ? V1 : V2, + DAG.getIntPtrConstant(0, DL)); + return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, LoV, HiV); + } } } @@ -19117,7 +19120,7 @@ static SDValue getScalarMaskingNode(SDValue Op, SDValue Mask, SDValue IMask = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v1i1, Mask); if (Op.getOpcode() == X86ISD::FSETCCM || - Op.getOpcode() == X86ISD::FSETCCM_RND) + Op.getOpcode() == X86ISD::FSETCCM_RND) return DAG.getNode(ISD::AND, dl, VT, Op, IMask); if (Op.getOpcode() == X86ISD::VFPCLASSS) return DAG.getNode(ISD::OR, dl, VT, Op, IMask); @@ -27968,28 +27971,45 @@ static bool combineX86ShufflesRecursively(ArrayRef SrcOps, OpMask.size() % RootMask.size() == 0) || OpMask.size() == RootMask.size()) && "The smaller number of elements must divide the larger."); - int MaskWidth = std::max(OpMask.size(), RootMask.size()); - int RootRatio = std::max(1, OpMask.size() / RootMask.size()); - int OpRatio = std::max(1, RootMask.size() / OpMask.size()); - assert(((RootRatio == 1 && OpRatio == 1) || - (RootRatio == 1) != (OpRatio == 1)) && + + // This function can be performance-critical, so we rely on the power-of-2 + // knowledge that we have about the mask sizes to replace div/rem ops with + // bit-masks and shifts. + assert(isPowerOf2_32(RootMask.size()) && "Non-power-of-2 shuffle mask sizes"); + assert(isPowerOf2_32(OpMask.size()) && "Non-power-of-2 shuffle mask sizes"); + unsigned RootMaskSizeLog2 = countTrailingZeros(RootMask.size()); + unsigned OpMaskSizeLog2 = countTrailingZeros(OpMask.size()); + + unsigned MaskWidth = std::max(OpMask.size(), RootMask.size()); + unsigned RootRatio = std::max(1, OpMask.size() >> RootMaskSizeLog2); + unsigned OpRatio = std::max(1, RootMask.size() >> OpMaskSizeLog2); + assert((RootRatio == 1 || OpRatio == 1) && "Must not have a ratio for both incoming and op masks!"); - SmallVector Mask((unsigned)MaskWidth, SM_SentinelUndef); + assert(isPowerOf2_32(MaskWidth) && "Non-power-of-2 shuffle mask sizes"); + assert(isPowerOf2_32(RootRatio) && "Non-power-of-2 shuffle mask sizes"); + assert(isPowerOf2_32(OpRatio) && "Non-power-of-2 shuffle mask sizes"); + unsigned RootRatioLog2 = countTrailingZeros(RootRatio); + unsigned OpRatioLog2 = countTrailingZeros(OpRatio); + + SmallVector Mask(MaskWidth, SM_SentinelUndef); // Merge this shuffle operation's mask into our accumulated mask. Note that // this shuffle's mask will be the first applied to the input, followed by the // root mask to get us all the way to the root value arrangement. The reason // for this order is that we are recursing up the operation chain. - for (int i = 0; i < MaskWidth; ++i) { - int RootIdx = i / RootRatio; + for (unsigned i = 0; i < MaskWidth; ++i) { + unsigned RootIdx = i >> RootRatioLog2; if (RootMask[RootIdx] < 0) { // This is a zero or undef lane, we're done. Mask[i] = RootMask[RootIdx]; continue; } - int RootMaskedIdx = RootMask[RootIdx] * RootRatio + i % RootRatio; + unsigned RootMaskedIdx = + RootRatio == 1 + ? RootMask[RootIdx] + : (RootMask[RootIdx] << RootRatioLog2) + (i & (RootRatio - 1)); // Just insert the scaled root mask value if it references an input other // than the SrcOp we're currently inserting. @@ -27999,9 +28019,8 @@ static bool combineX86ShufflesRecursively(ArrayRef SrcOps, continue; } - RootMaskedIdx %= MaskWidth; - - int OpIdx = RootMaskedIdx / OpRatio; + RootMaskedIdx = RootMaskedIdx & (MaskWidth - 1); + unsigned OpIdx = RootMaskedIdx >> OpRatioLog2; if (OpMask[OpIdx] < 0) { // The incoming lanes are zero or undef, it doesn't matter which ones we // are using. @@ -28010,9 +28029,12 @@ static bool combineX86ShufflesRecursively(ArrayRef SrcOps, } // Ok, we have non-zero lanes, map them through to one of the Op's inputs. - int OpMaskedIdx = OpMask[OpIdx] * OpRatio + RootMaskedIdx % OpRatio; - OpMaskedIdx %= MaskWidth; + unsigned OpMaskedIdx = + OpRatio == 1 + ? OpMask[OpIdx] + : (OpMask[OpIdx] << OpRatioLog2) + (RootMaskedIdx & (OpRatio - 1)); + OpMaskedIdx = OpMaskedIdx & (MaskWidth - 1); if (OpMask[OpIdx] < (int)OpMask.size()) { assert(0 <= InputIdx0 && "Unknown target shuffle input"); OpMaskedIdx += InputIdx0 * MaskWidth; diff --git a/lib/Target/X86/X86InstrAVX512.td b/lib/Target/X86/X86InstrAVX512.td index d8702693884d..2620679df251 100644 --- a/lib/Target/X86/X86InstrAVX512.td +++ b/lib/Target/X86/X86InstrAVX512.td @@ -1631,6 +1631,7 @@ multiclass avx512_icmp_packed opc, string OpcodeStr, SDNode OpNode, [(set _.KRC:$dst, (OpNode (_.VT _.RC:$src1), (_.VT (bitconvert (_.LdFrag addr:$src2)))))], IIC_SSE_ALU_F32P_RM>, EVEX_4V; + let isCommutable = IsCommutable in def rrk : AVX512BI opc, string Suffix, SDNode OpNode, (_.VT (bitconvert (_.LdFrag addr:$src2))), imm:$cc))], IIC_SSE_ALU_F32P_RM>, EVEX_4V; + let isCommutable = 1 in def rrik : AVX512AIi8; -// Like 'load', but uses special alignment checks suitable for use in +// Like 'vec128load', but uses special alignment checks suitable for use in // memory operands in most SSE instructions, which are required to // be naturally aligned on some targets but not on others. If the subtarget // allows unaligned accesses, match any load, though this may require // setting a feature bit in the processor (on startup, for example). // Opteron 10h and later implement such a feature. -// Avoid non-temporal aligned loads on supported targets. -def memop : PatFrag<(ops node:$ptr), (load node:$ptr), [{ - return (Subtarget->hasSSEUnalignedMem() || - cast(N)->getAlignment() >= 16) && - (!Subtarget->hasSSE41() || - !(cast(N)->getAlignment() >= 16 && - cast(N)->isNonTemporal())); +def memop : PatFrag<(ops node:$ptr), (vec128load node:$ptr), [{ + return Subtarget->hasSSEUnalignedMem() || + cast(N)->getAlignment() >= 16; }]>; // 128-bit memop pattern fragments diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp index ff5d90c4e78b..f3094b781c49 100644 --- a/lib/Target/X86/X86InstrInfo.cpp +++ b/lib/Target/X86/X86InstrInfo.cpp @@ -898,10 +898,14 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZrr, X86::VPABSDZrm, 0 }, { X86::VPABSQZrr, X86::VPABSQZrm, 0 }, { X86::VPABSWZrr, X86::VPABSWZrm, 0 }, + { X86::VPCONFLICTDZrr, X86::VPCONFLICTDZrm, 0 }, + { X86::VPCONFLICTQZrr, X86::VPCONFLICTQZrm, 0 }, { X86::VPERMILPDZri, X86::VPERMILPDZmi, 0 }, { X86::VPERMILPSZri, X86::VPERMILPSZmi, 0 }, { X86::VPERMPDZri, X86::VPERMPDZmi, 0 }, { X86::VPERMQZri, X86::VPERMQZmi, 0 }, + { X86::VPLZCNTDZrr, X86::VPLZCNTDZrm, 0 }, + { X86::VPLZCNTQZrr, X86::VPLZCNTQZrm, 0 }, { X86::VPMOVSXBDZrr, X86::VPMOVSXBDZrm, 0 }, { X86::VPMOVSXBQZrr, X86::VPMOVSXBQZrm, TB_NO_REVERSE }, { X86::VPMOVSXBWZrr, X86::VPMOVSXBWZrm, 0 }, @@ -948,10 +952,14 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZ256rr, X86::VPABSDZ256rm, 0 }, { X86::VPABSQZ256rr, X86::VPABSQZ256rm, 0 }, { X86::VPABSWZ256rr, X86::VPABSWZ256rm, 0 }, + { X86::VPCONFLICTDZ256rr, X86::VPCONFLICTDZ256rm, 0 }, + { X86::VPCONFLICTQZ256rr, X86::VPCONFLICTQZ256rm, 0 }, { X86::VPERMILPDZ256ri, X86::VPERMILPDZ256mi, 0 }, { X86::VPERMILPSZ256ri, X86::VPERMILPSZ256mi, 0 }, { X86::VPERMPDZ256ri, X86::VPERMPDZ256mi, 0 }, { X86::VPERMQZ256ri, X86::VPERMQZ256mi, 0 }, + { X86::VPLZCNTDZ256rr, X86::VPLZCNTDZ256rm, 0 }, + { X86::VPLZCNTQZ256rr, X86::VPLZCNTQZ256rm, 0 }, { X86::VPMOVSXBDZ256rr, X86::VPMOVSXBDZ256rm, TB_NO_REVERSE }, { X86::VPMOVSXBQZ256rr, X86::VPMOVSXBQZ256rm, TB_NO_REVERSE }, { X86::VPMOVSXBWZ256rr, X86::VPMOVSXBWZ256rm, 0 }, @@ -995,8 +1003,12 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZ128rr, X86::VPABSDZ128rm, 0 }, { X86::VPABSQZ128rr, X86::VPABSQZ128rm, 0 }, { X86::VPABSWZ128rr, X86::VPABSWZ128rm, 0 }, + { X86::VPCONFLICTDZ128rr, X86::VPCONFLICTDZ128rm, 0 }, + { X86::VPCONFLICTQZ128rr, X86::VPCONFLICTQZ128rm, 0 }, { X86::VPERMILPDZ128ri, X86::VPERMILPDZ128mi, 0 }, { X86::VPERMILPSZ128ri, X86::VPERMILPSZ128mi, 0 }, + { X86::VPLZCNTDZ128rr, X86::VPLZCNTDZ128rm, 0 }, + { X86::VPLZCNTQZ128rr, X86::VPLZCNTQZ128rm, 0 }, { X86::VPMOVSXBDZ128rr, X86::VPMOVSXBDZ128rm, TB_NO_REVERSE }, { X86::VPMOVSXBQZ128rr, X86::VPMOVSXBQZ128rm, TB_NO_REVERSE }, { X86::VPMOVSXBWZ128rr, X86::VPMOVSXBWZ128rm, TB_NO_REVERSE }, @@ -2312,10 +2324,14 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZrrkz, X86::VPABSDZrmkz, 0 }, { X86::VPABSQZrrkz, X86::VPABSQZrmkz, 0 }, { X86::VPABSWZrrkz, X86::VPABSWZrmkz, 0 }, + { X86::VPCONFLICTDZrrkz, X86::VPCONFLICTDZrmkz, 0 }, + { X86::VPCONFLICTQZrrkz, X86::VPCONFLICTQZrmkz, 0 }, { X86::VPERMILPDZrikz, X86::VPERMILPDZmikz, 0 }, { X86::VPERMILPSZrikz, X86::VPERMILPSZmikz, 0 }, { X86::VPERMPDZrikz, X86::VPERMPDZmikz, 0 }, { X86::VPERMQZrikz, X86::VPERMQZmikz, 0 }, + { X86::VPLZCNTDZrrkz, X86::VPLZCNTDZrmkz, 0 }, + { X86::VPLZCNTQZrrkz, X86::VPLZCNTQZrmkz, 0 }, { X86::VPMOVSXBDZrrkz, X86::VPMOVSXBDZrmkz, 0 }, { X86::VPMOVSXBQZrrkz, X86::VPMOVSXBQZrmkz, TB_NO_REVERSE }, { X86::VPMOVSXBWZrrkz, X86::VPMOVSXBWZrmkz, 0 }, @@ -2350,10 +2366,14 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZ256rrkz, X86::VPABSDZ256rmkz, 0 }, { X86::VPABSQZ256rrkz, X86::VPABSQZ256rmkz, 0 }, { X86::VPABSWZ256rrkz, X86::VPABSWZ256rmkz, 0 }, + { X86::VPCONFLICTDZ256rrkz, X86::VPCONFLICTDZ256rmkz, 0 }, + { X86::VPCONFLICTQZ256rrkz, X86::VPCONFLICTQZ256rmkz, 0 }, { X86::VPERMILPDZ256rikz, X86::VPERMILPDZ256mikz, 0 }, { X86::VPERMILPSZ256rikz, X86::VPERMILPSZ256mikz, 0 }, { X86::VPERMPDZ256rikz, X86::VPERMPDZ256mikz, 0 }, { X86::VPERMQZ256rikz, X86::VPERMQZ256mikz, 0 }, + { X86::VPLZCNTDZ256rrkz, X86::VPLZCNTDZ256rmkz, 0 }, + { X86::VPLZCNTQZ256rrkz, X86::VPLZCNTQZ256rmkz, 0 }, { X86::VPMOVSXBDZ256rrkz, X86::VPMOVSXBDZ256rmkz, TB_NO_REVERSE }, { X86::VPMOVSXBQZ256rrkz, X86::VPMOVSXBQZ256rmkz, TB_NO_REVERSE }, { X86::VPMOVSXBWZ256rrkz, X86::VPMOVSXBWZ256rmkz, 0 }, @@ -2385,8 +2405,12 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZ128rrkz, X86::VPABSDZ128rmkz, 0 }, { X86::VPABSQZ128rrkz, X86::VPABSQZ128rmkz, 0 }, { X86::VPABSWZ128rrkz, X86::VPABSWZ128rmkz, 0 }, + { X86::VPCONFLICTDZ128rrkz, X86::VPCONFLICTDZ128rmkz, 0 }, + { X86::VPCONFLICTQZ128rrkz, X86::VPCONFLICTQZ128rmkz, 0 }, { X86::VPERMILPDZ128rikz, X86::VPERMILPDZ128mikz, 0 }, { X86::VPERMILPSZ128rikz, X86::VPERMILPSZ128mikz, 0 }, + { X86::VPLZCNTDZ128rrkz, X86::VPLZCNTDZ128rmkz, 0 }, + { X86::VPLZCNTQZ128rrkz, X86::VPLZCNTQZ128rmkz, 0 }, { X86::VPMOVSXBDZ128rrkz, X86::VPMOVSXBDZ128rmkz, TB_NO_REVERSE }, { X86::VPMOVSXBQZ128rrkz, X86::VPMOVSXBQZ128rmkz, TB_NO_REVERSE }, { X86::VPMOVSXBWZ128rrkz, X86::VPMOVSXBWZ128rmkz, TB_NO_REVERSE }, @@ -2935,10 +2959,14 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZrrk, X86::VPABSDZrmk, 0 }, { X86::VPABSQZrrk, X86::VPABSQZrmk, 0 }, { X86::VPABSWZrrk, X86::VPABSWZrmk, 0 }, + { X86::VPCONFLICTDZrrk, X86::VPCONFLICTDZrmk, 0 }, + { X86::VPCONFLICTQZrrk, X86::VPCONFLICTQZrmk, 0 }, { X86::VPERMILPDZrik, X86::VPERMILPDZmik, 0 }, { X86::VPERMILPSZrik, X86::VPERMILPSZmik, 0 }, { X86::VPERMPDZrik, X86::VPERMPDZmik, 0 }, { X86::VPERMQZrik, X86::VPERMQZmik, 0 }, + { X86::VPLZCNTDZrrk, X86::VPLZCNTDZrmk, 0 }, + { X86::VPLZCNTQZrrk, X86::VPLZCNTQZrmk, 0 }, { X86::VPMOVSXBDZrrk, X86::VPMOVSXBDZrmk, 0 }, { X86::VPMOVSXBQZrrk, X86::VPMOVSXBQZrmk, TB_NO_REVERSE }, { X86::VPMOVSXBWZrrk, X86::VPMOVSXBWZrmk, 0 }, @@ -2973,10 +3001,14 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZ256rrk, X86::VPABSDZ256rmk, 0 }, { X86::VPABSQZ256rrk, X86::VPABSQZ256rmk, 0 }, { X86::VPABSWZ256rrk, X86::VPABSWZ256rmk, 0 }, + { X86::VPCONFLICTDZ256rrk, X86::VPCONFLICTDZ256rmk, 0 }, + { X86::VPCONFLICTQZ256rrk, X86::VPCONFLICTQZ256rmk, 0 }, { X86::VPERMILPDZ256rik, X86::VPERMILPDZ256mik, 0 }, { X86::VPERMILPSZ256rik, X86::VPERMILPSZ256mik, 0 }, { X86::VPERMPDZ256rik, X86::VPERMPDZ256mik, 0 }, { X86::VPERMQZ256rik, X86::VPERMQZ256mik, 0 }, + { X86::VPLZCNTDZ256rrk, X86::VPLZCNTDZ256rmk, 0 }, + { X86::VPLZCNTQZ256rrk, X86::VPLZCNTQZ256rmk, 0 }, { X86::VPMOVSXBDZ256rrk, X86::VPMOVSXBDZ256rmk, TB_NO_REVERSE }, { X86::VPMOVSXBQZ256rrk, X86::VPMOVSXBQZ256rmk, TB_NO_REVERSE }, { X86::VPMOVSXBWZ256rrk, X86::VPMOVSXBWZ256rmk, 0 }, @@ -3008,8 +3040,12 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPABSDZ128rrk, X86::VPABSDZ128rmk, 0 }, { X86::VPABSQZ128rrk, X86::VPABSQZ128rmk, 0 }, { X86::VPABSWZ128rrk, X86::VPABSWZ128rmk, 0 }, + { X86::VPCONFLICTDZ128rrk, X86::VPCONFLICTDZ128rmk, 0 }, + { X86::VPCONFLICTQZ128rrk, X86::VPCONFLICTQZ128rmk, 0 }, { X86::VPERMILPDZ128rik, X86::VPERMILPDZ128mik, 0 }, { X86::VPERMILPSZ128rik, X86::VPERMILPSZ128mik, 0 }, + { X86::VPLZCNTDZ128rrk, X86::VPLZCNTDZ128rmk, 0 }, + { X86::VPLZCNTQZ128rrk, X86::VPLZCNTQZ128rmk, 0 }, { X86::VPMOVSXBDZ128rrk, X86::VPMOVSXBDZ128rmk, TB_NO_REVERSE }, { X86::VPMOVSXBQZ128rrk, X86::VPMOVSXBQZ128rmk, TB_NO_REVERSE }, { X86::VPMOVSXBWZ128rrk, X86::VPMOVSXBWZ128rmk, TB_NO_REVERSE }, @@ -3034,6 +3070,64 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI) { X86::VPSRLDZ128rik, X86::VPSRLDZ128mik, 0 }, { X86::VPSRLQZ128rik, X86::VPSRLQZ128mik, 0 }, { X86::VPSRLWZ128rik, X86::VPSRLWZ128mik, 0 }, + + // AVX-512 masked compare instructions + { X86::VCMPPDZ128rrik, X86::VCMPPDZ128rmik, 0 }, + { X86::VCMPPSZ128rrik, X86::VCMPPSZ128rmik, 0 }, + { X86::VCMPPDZ256rrik, X86::VCMPPDZ256rmik, 0 }, + { X86::VCMPPSZ256rrik, X86::VCMPPSZ256rmik, 0 }, + { X86::VCMPPDZrrik, X86::VCMPPDZrmik, 0 }, + { X86::VCMPPSZrrik, X86::VCMPPSZrmik, 0 }, + { X86::VCMPSDZrr_Intk, X86::VCMPSDZrm_Intk, TB_NO_REVERSE }, + { X86::VCMPSSZrr_Intk, X86::VCMPSSZrm_Intk, TB_NO_REVERSE }, + { X86::VPCMPBZ128rrik, X86::VPCMPBZ128rmik, 0 }, + { X86::VPCMPBZ256rrik, X86::VPCMPBZ256rmik, 0 }, + { X86::VPCMPBZrrik, X86::VPCMPBZrmik, 0 }, + { X86::VPCMPDZ128rrik, X86::VPCMPDZ128rmik, 0 }, + { X86::VPCMPDZ256rrik, X86::VPCMPDZ256rmik, 0 }, + { X86::VPCMPDZrrik, X86::VPCMPDZrmik, 0 }, + { X86::VPCMPEQBZ128rrk, X86::VPCMPEQBZ128rmk, 0 }, + { X86::VPCMPEQBZ256rrk, X86::VPCMPEQBZ256rmk, 0 }, + { X86::VPCMPEQBZrrk, X86::VPCMPEQBZrmk, 0 }, + { X86::VPCMPEQDZ128rrk, X86::VPCMPEQDZ128rmk, 0 }, + { X86::VPCMPEQDZ256rrk, X86::VPCMPEQDZ256rmk, 0 }, + { X86::VPCMPEQDZrrk, X86::VPCMPEQDZrmk, 0 }, + { X86::VPCMPEQQZ128rrk, X86::VPCMPEQQZ128rmk, 0 }, + { X86::VPCMPEQQZ256rrk, X86::VPCMPEQQZ256rmk, 0 }, + { X86::VPCMPEQQZrrk, X86::VPCMPEQQZrmk, 0 }, + { X86::VPCMPEQWZ128rrk, X86::VPCMPEQWZ128rmk, 0 }, + { X86::VPCMPEQWZ256rrk, X86::VPCMPEQWZ256rmk, 0 }, + { X86::VPCMPEQWZrrk, X86::VPCMPEQWZrmk, 0 }, + { X86::VPCMPGTBZ128rrk, X86::VPCMPGTBZ128rmk, 0 }, + { X86::VPCMPGTBZ256rrk, X86::VPCMPGTBZ256rmk, 0 }, + { X86::VPCMPGTBZrrk, X86::VPCMPGTBZrmk, 0 }, + { X86::VPCMPGTDZ128rrk, X86::VPCMPGTDZ128rmk, 0 }, + { X86::VPCMPGTDZ256rrk, X86::VPCMPGTDZ256rmk, 0 }, + { X86::VPCMPGTDZrrk, X86::VPCMPGTDZrmk, 0 }, + { X86::VPCMPGTQZ128rrk, X86::VPCMPGTQZ128rmk, 0 }, + { X86::VPCMPGTQZ256rrk, X86::VPCMPGTQZ256rmk, 0 }, + { X86::VPCMPGTQZrrk, X86::VPCMPGTQZrmk, 0 }, + { X86::VPCMPGTWZ128rrk, X86::VPCMPGTWZ128rmk, 0 }, + { X86::VPCMPGTWZ256rrk, X86::VPCMPGTWZ256rmk, 0 }, + { X86::VPCMPGTWZrrk, X86::VPCMPGTWZrmk, 0 }, + { X86::VPCMPQZ128rrik, X86::VPCMPQZ128rmik, 0 }, + { X86::VPCMPQZ256rrik, X86::VPCMPQZ256rmik, 0 }, + { X86::VPCMPQZrrik, X86::VPCMPQZrmik, 0 }, + { X86::VPCMPUBZ128rrik, X86::VPCMPUBZ128rmik, 0 }, + { X86::VPCMPUBZ256rrik, X86::VPCMPUBZ256rmik, 0 }, + { X86::VPCMPUBZrrik, X86::VPCMPUBZrmik, 0 }, + { X86::VPCMPUDZ128rrik, X86::VPCMPUDZ128rmik, 0 }, + { X86::VPCMPUDZ256rrik, X86::VPCMPUDZ256rmik, 0 }, + { X86::VPCMPUDZrrik, X86::VPCMPUDZrmik, 0 }, + { X86::VPCMPUQZ128rrik, X86::VPCMPUQZ128rmik, 0 }, + { X86::VPCMPUQZ256rrik, X86::VPCMPUQZ256rmik, 0 }, + { X86::VPCMPUQZrrik, X86::VPCMPUQZrmik, 0 }, + { X86::VPCMPUWZ128rrik, X86::VPCMPUWZ128rmik, 0 }, + { X86::VPCMPUWZ256rrik, X86::VPCMPUWZ256rmik, 0 }, + { X86::VPCMPUWZrrik, X86::VPCMPUWZrmik, 0 }, + { X86::VPCMPWZ128rrik, X86::VPCMPWZ128rmik, 0 }, + { X86::VPCMPWZ256rrik, X86::VPCMPWZ256rmik, 0 }, + { X86::VPCMPWZrrik, X86::VPCMPWZrmik, 0 }, }; for (X86MemoryFoldTableEntry Entry : MemoryFoldTable3) { @@ -5136,20 +5230,32 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI, return nullptr; } } - case X86::VPCMPBZ128rri: case X86::VPCMPUBZ128rri: - case X86::VPCMPBZ256rri: case X86::VPCMPUBZ256rri: - case X86::VPCMPBZrri: case X86::VPCMPUBZrri: - case X86::VPCMPDZ128rri: case X86::VPCMPUDZ128rri: - case X86::VPCMPDZ256rri: case X86::VPCMPUDZ256rri: - case X86::VPCMPDZrri: case X86::VPCMPUDZrri: - case X86::VPCMPQZ128rri: case X86::VPCMPUQZ128rri: - case X86::VPCMPQZ256rri: case X86::VPCMPUQZ256rri: - case X86::VPCMPQZrri: case X86::VPCMPUQZrri: - case X86::VPCMPWZ128rri: case X86::VPCMPUWZ128rri: - case X86::VPCMPWZ256rri: case X86::VPCMPUWZ256rri: - case X86::VPCMPWZrri: case X86::VPCMPUWZrri: { + case X86::VPCMPBZ128rri: case X86::VPCMPUBZ128rri: + case X86::VPCMPBZ256rri: case X86::VPCMPUBZ256rri: + case X86::VPCMPBZrri: case X86::VPCMPUBZrri: + case X86::VPCMPDZ128rri: case X86::VPCMPUDZ128rri: + case X86::VPCMPDZ256rri: case X86::VPCMPUDZ256rri: + case X86::VPCMPDZrri: case X86::VPCMPUDZrri: + case X86::VPCMPQZ128rri: case X86::VPCMPUQZ128rri: + case X86::VPCMPQZ256rri: case X86::VPCMPUQZ256rri: + case X86::VPCMPQZrri: case X86::VPCMPUQZrri: + case X86::VPCMPWZ128rri: case X86::VPCMPUWZ128rri: + case X86::VPCMPWZ256rri: case X86::VPCMPUWZ256rri: + case X86::VPCMPWZrri: case X86::VPCMPUWZrri: + case X86::VPCMPBZ128rrik: case X86::VPCMPUBZ128rrik: + case X86::VPCMPBZ256rrik: case X86::VPCMPUBZ256rrik: + case X86::VPCMPBZrrik: case X86::VPCMPUBZrrik: + case X86::VPCMPDZ128rrik: case X86::VPCMPUDZ128rrik: + case X86::VPCMPDZ256rrik: case X86::VPCMPUDZ256rrik: + case X86::VPCMPDZrrik: case X86::VPCMPUDZrrik: + case X86::VPCMPQZ128rrik: case X86::VPCMPUQZ128rrik: + case X86::VPCMPQZ256rrik: case X86::VPCMPUQZ256rrik: + case X86::VPCMPQZrrik: case X86::VPCMPUQZrrik: + case X86::VPCMPWZ128rrik: case X86::VPCMPUWZ128rrik: + case X86::VPCMPWZ256rrik: case X86::VPCMPUWZ256rrik: + case X86::VPCMPWZrrik: case X86::VPCMPUWZrrik: { // Flip comparison mode immediate (if necessary). - unsigned Imm = MI.getOperand(3).getImm() & 0x7; + unsigned Imm = MI.getOperand(MI.getNumOperands() - 1).getImm() & 0x7; switch (Imm) { default: llvm_unreachable("Unreachable!"); case 0x01: Imm = 0x06; break; // LT -> NLE @@ -5163,7 +5269,7 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI, break; } auto &WorkingMI = cloneIfNew(MI); - WorkingMI.getOperand(3).setImm(Imm); + WorkingMI.getOperand(MI.getNumOperands() - 1).setImm(Imm); return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false, OpIdx1, OpIdx2); } diff --git a/lib/Testing/CMakeLists.txt b/lib/Testing/CMakeLists.txt new file mode 100644 index 000000000000..fc23e64eeb7a --- /dev/null +++ b/lib/Testing/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Support) diff --git a/lib/Testing/LLVMBuild.txt b/lib/Testing/LLVMBuild.txt new file mode 100644 index 000000000000..cdf83736298e --- /dev/null +++ b/lib/Testing/LLVMBuild.txt @@ -0,0 +1,19 @@ +;===- ./lib/Testing/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 +; +;===------------------------------------------------------------------------===; + +[common] +subdirectories = Support diff --git a/lib/Testing/Support/CMakeLists.txt b/lib/Testing/Support/CMakeLists.txt new file mode 100644 index 000000000000..fa8dfe59c8bd --- /dev/null +++ b/lib/Testing/Support/CMakeLists.txt @@ -0,0 +1,12 @@ +add_llvm_library(LLVMTestingSupport + Error.cpp + + BUILDTREE_ONLY + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Testing/Support + ) + +include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include) +include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googlemock/include) +target_link_libraries(LLVMTestingSupport PRIVATE gtest) \ No newline at end of file diff --git a/lib/Testing/Support/Error.cpp b/lib/Testing/Support/Error.cpp new file mode 100644 index 000000000000..ce0da44da408 --- /dev/null +++ b/lib/Testing/Support/Error.cpp @@ -0,0 +1,22 @@ +//===- llvm/Testing/Support/Error.cpp -------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Testing/Support/Error.h" + +#include "llvm/ADT/StringRef.h" + +using namespace llvm; + +llvm::detail::ErrorHolder llvm::detail::TakeError(llvm::Error Err) { + bool Succeeded = !static_cast(Err); + std::string Message; + if (!Succeeded) + Message = toString(std::move(Err)); + return {Succeeded, Message}; +} diff --git a/lib/Testing/Support/LLVMBuild.txt b/lib/Testing/Support/LLVMBuild.txt new file mode 100644 index 000000000000..40853e8172d5 --- /dev/null +++ b/lib/Testing/Support/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./Testing/Support/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 = Library +name = TestingSupport +parent = Libraries +required_libraries = Support diff --git a/lib/Transforms/IPO/CrossDSOCFI.cpp b/lib/Transforms/IPO/CrossDSOCFI.cpp index 1b111de06157..d94aa5da8560 100644 --- a/lib/Transforms/IPO/CrossDSOCFI.cpp +++ b/lib/Transforms/IPO/CrossDSOCFI.cpp @@ -95,6 +95,17 @@ void CrossDSOCFI::buildCFICheck(Module &M) { } } + NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions"); + if (CfiFunctionsMD) { + for (auto Func : CfiFunctionsMD->operands()) { + assert(Func->getNumOperands() >= 2); + for (unsigned I = 2; I < Func->getNumOperands(); ++I) + if (ConstantInt *TypeId = + extractNumericTypeId(cast(Func->getOperand(I).get()))) + TypeIds.insert(TypeId->getZExtValue()); + } + } + LLVMContext &Ctx = M.getContext(); Constant *C = M.getOrInsertFunction( "__cfi_check", Type::getVoidTy(Ctx), Type::getInt64Ty(Ctx), diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index c0dfeede05c5..ad89e40661c6 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -523,40 +523,47 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG, if (!Callee || Callee->isDeclaration()) continue; - // If this call site is dead and it is to a readonly function, we should - // just delete the call instead of trying to inline it, regardless of - // size. This happens because IPSCCP propagates the result out of the - // call and then we're left with the dead call. - if (isInstructionTriviallyDead(CS.getInstruction(), &TLI)) { - DEBUG(dbgs() << " -> Deleting dead call: " << *CS.getInstruction() - << "\n"); - // Update the call graph by deleting the edge from Callee to Caller. - CG[Caller]->removeCallEdgeFor(CS); - CS.getInstruction()->eraseFromParent(); - ++NumCallsDeleted; - } else { + Instruction *Instr = CS.getInstruction(); + + bool IsTriviallyDead = isInstructionTriviallyDead(Instr, &TLI); + + int InlineHistoryID; + if (!IsTriviallyDead) { // If this call site was obtained by inlining another function, verify // that the include path for the function did not include the callee // itself. If so, we'd be recursively inlining the same function, // which would provide the same callsites, which would cause us to // infinitely inline. - int InlineHistoryID = CallSites[CSi].second; + InlineHistoryID = CallSites[CSi].second; if (InlineHistoryID != -1 && InlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory)) continue; + } + // FIXME for new PM: because of the old PM we currently generate ORE and + // in turn BFI on demand. With the new PM, the ORE dependency should + // just become a regular analysis dependency. + OptimizationRemarkEmitter ORE(Caller); + + // If the policy determines that we should inline this function, + // delete the call instead. + if (!shouldInline(CS, GetInlineCost, ORE)) + continue; + + // If this call site is dead and it is to a readonly function, we should + // just delete the call instead of trying to inline it, regardless of + // size. This happens because IPSCCP propagates the result out of the + // call and then we're left with the dead call. + if (IsTriviallyDead) { + DEBUG(dbgs() << " -> Deleting dead call: " << *Instr << "\n"); + // Update the call graph by deleting the edge from Callee to Caller. + CG[Caller]->removeCallEdgeFor(CS); + Instr->eraseFromParent(); + ++NumCallsDeleted; + } else { // Get DebugLoc to report. CS will be invalid after Inliner. - DebugLoc DLoc = CS.getInstruction()->getDebugLoc(); + DebugLoc DLoc = Instr->getDebugLoc(); BasicBlock *Block = CS.getParent(); - // FIXME for new PM: because of the old PM we currently generate ORE and - // in turn BFI on demand. With the new PM, the ORE dependency should - // just become a regular analysis dependency. - OptimizationRemarkEmitter ORE(Caller); - - // If the policy determines that we should inline this function, - // try to do so. - if (!shouldInline(CS, GetInlineCost, ORE)) - continue; // Attempt to inline the function. using namespace ore; diff --git a/lib/Transforms/IPO/LowerTypeTests.cpp b/lib/Transforms/IPO/LowerTypeTests.cpp index 90896d285f5a..b406c22c69d7 100644 --- a/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/lib/Transforms/IPO/LowerTypeTests.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" +#include "llvm/Analysis/TypeMetadataUtils.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" @@ -206,17 +207,26 @@ struct ByteArrayInfo { class GlobalTypeMember final : TrailingObjects { GlobalObject *GO; size_t NTypes; + // For functions: true if this is a definition (either in the merged module or + // in one of the thinlto modules). + bool IsDefinition; + // For functions: true if this function is either defined or used in a thinlto + // module and its jumptable entry needs to be exported to thinlto backends. + bool IsExported; friend TrailingObjects; size_t numTrailingObjects(OverloadToken) const { return NTypes; } public: static GlobalTypeMember *create(BumpPtrAllocator &Alloc, GlobalObject *GO, + bool IsDefinition, bool IsExported, ArrayRef Types) { auto *GTM = static_cast(Alloc.Allocate( totalSizeToAlloc(Types.size()), alignof(GlobalTypeMember))); GTM->GO = GO; GTM->NTypes = Types.size(); + GTM->IsDefinition = IsDefinition; + GTM->IsExported = IsExported; std::uninitialized_copy(Types.begin(), Types.end(), GTM->getTrailingObjects()); return GTM; @@ -224,6 +234,12 @@ class GlobalTypeMember final : TrailingObjects { GlobalObject *getGlobal() const { return GO; } + bool isDefinition() const { + return IsDefinition; + } + bool isExported() const { + return IsExported; + } ArrayRef types() const { return makeArrayRef(getTrailingObjects(), NTypes); } @@ -294,6 +310,7 @@ class LowerTypeTestsModule { void exportTypeId(StringRef TypeId, const TypeIdLowering &TIL); TypeIdLowering importTypeId(StringRef TypeId); void importTypeTest(CallInst *CI); + void importFunction(Function *F, bool isDefinition); BitSetInfo buildBitSet(Metadata *TypeId, @@ -820,6 +837,41 @@ void LowerTypeTestsModule::importTypeTest(CallInst *CI) { CI->eraseFromParent(); } +// ThinLTO backend: the function F has a jump table entry; update this module +// accordingly. isDefinition describes the type of the jump table entry. +void LowerTypeTestsModule::importFunction(Function *F, bool isDefinition) { + assert(F->getType()->getAddressSpace() == 0); + + // Declaration of a local function - nothing to do. + if (F->isDeclarationForLinker() && isDefinition) + return; + + GlobalValue::VisibilityTypes Visibility = F->getVisibility(); + std::string Name = F->getName(); + Function *FDecl; + + if (F->isDeclarationForLinker() && !isDefinition) { + // Declaration of an external function. + FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, + Name + ".cfi_jt", &M); + FDecl->setVisibility(GlobalValue::HiddenVisibility); + } else { + // Definition. + assert(isDefinition); + F->setName(Name + ".cfi"); + F->setLinkage(GlobalValue::ExternalLinkage); + F->setVisibility(GlobalValue::HiddenVisibility); + FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, + Name, &M); + FDecl->setVisibility(Visibility); + } + + if (F->isWeakForLinker()) + replaceWeakDeclarationWithJumpTablePtr(F, FDecl); + else + F->replaceAllUsesWith(FDecl); +} + void LowerTypeTestsModule::lowerTypeTestCalls( ArrayRef TypeIds, Constant *CombinedGlobalAddr, const DenseMap &GlobalLayout) { @@ -1143,7 +1195,6 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative( // arithmetic that we normally use for globals. // FIXME: find a better way to represent the jumptable in the IR. - assert(!Functions.empty()); // Build a simple layout based on the regular layout of jump tables. @@ -1167,6 +1218,7 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative( // references to the original functions with references to the aliases. for (unsigned I = 0; I != Functions.size(); ++I) { Function *F = cast(Functions[I]->getGlobal()); + bool IsDefinition = Functions[I]->isDefinition(); Constant *CombinedGlobalElemPtr = ConstantExpr::getBitCast( ConstantExpr::getInBoundsGetElementPtr( @@ -1174,7 +1226,18 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative( ArrayRef{ConstantInt::get(IntPtrTy, 0), ConstantInt::get(IntPtrTy, I)}), F->getType()); - if (F->isDeclarationForLinker()) { + if (Functions[I]->isExported()) { + if (IsDefinition) { + ExportSummary->cfiFunctionDefs().insert(F->getName()); + } else { + GlobalAlias *JtAlias = GlobalAlias::create( + F->getValueType(), 0, GlobalValue::ExternalLinkage, + F->getName() + ".cfi_jt", CombinedGlobalElemPtr, &M); + JtAlias->setVisibility(GlobalValue::HiddenVisibility); + ExportSummary->cfiFunctionDecls().insert(F->getName()); + } + } + if (!IsDefinition) { if (F->isWeakForLinker()) replaceWeakDeclarationWithJumpTablePtr(F, CombinedGlobalElemPtr); else @@ -1182,9 +1245,8 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative( } else { assert(F->getType()->getAddressSpace() == 0); - GlobalAlias *FAlias = GlobalAlias::create(F->getValueType(), 0, - F->getLinkage(), "", - CombinedGlobalElemPtr, &M); + GlobalAlias *FAlias = GlobalAlias::create( + F->getValueType(), 0, F->getLinkage(), "", CombinedGlobalElemPtr, &M); FAlias->setVisibility(F->getVisibility()); FAlias->takeName(F); if (FAlias->hasName()) @@ -1353,15 +1415,37 @@ bool LowerTypeTestsModule::runForTesting(Module &M) { bool LowerTypeTestsModule::lower() { Function *TypeTestFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_test)); - if ((!TypeTestFunc || TypeTestFunc->use_empty()) && !ExportSummary) + if ((!TypeTestFunc || TypeTestFunc->use_empty()) && !ExportSummary && + !ImportSummary) return false; if (ImportSummary) { - for (auto UI = TypeTestFunc->use_begin(), UE = TypeTestFunc->use_end(); - UI != UE;) { - auto *CI = cast((*UI++).getUser()); - importTypeTest(CI); + if (TypeTestFunc) { + for (auto UI = TypeTestFunc->use_begin(), UE = TypeTestFunc->use_end(); + UI != UE;) { + auto *CI = cast((*UI++).getUser()); + importTypeTest(CI); + } } + + SmallVector Defs; + SmallVector Decls; + for (auto &F : M) { + // CFI functions are either external, or promoted. A local function may + // have the same name, but it's not the one we are looking for. + if (F.hasLocalLinkage()) + continue; + if (ImportSummary->cfiFunctionDefs().count(F.getName())) + Defs.push_back(&F); + else if (ImportSummary->cfiFunctionDecls().count(F.getName())) + Decls.push_back(&F); + } + + for (auto F : Defs) + importFunction(F, /*isDefinition*/ true); + for (auto F : Decls) + importFunction(F, /*isDefinition*/ false); + return true; } @@ -1387,6 +1471,58 @@ bool LowerTypeTestsModule::lower() { llvm::DenseMap TypeIdInfo; unsigned I = 0; SmallVector Types; + + struct ExportedFunctionInfo { + CfiFunctionLinkage Linkage; + MDNode *FuncMD; // {name, linkage, type[, type...]} + }; + DenseMap ExportedFunctions; + if (ExportSummary) { + NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions"); + if (CfiFunctionsMD) { + for (auto FuncMD : CfiFunctionsMD->operands()) { + assert(FuncMD->getNumOperands() >= 2); + StringRef FunctionName = + cast(FuncMD->getOperand(0))->getString(); + if (!ExportSummary->isGUIDLive(GlobalValue::getGUID( + GlobalValue::dropLLVMManglingEscape(FunctionName)))) + continue; + CfiFunctionLinkage Linkage = static_cast( + cast(FuncMD->getOperand(1)) + ->getValue() + ->getUniqueInteger() + .getZExtValue()); + auto P = ExportedFunctions.insert({FunctionName, {Linkage, FuncMD}}); + if (!P.second && P.first->second.Linkage != CFL_Definition) + P.first->second = {Linkage, FuncMD}; + } + + for (const auto &P : ExportedFunctions) { + StringRef FunctionName = P.first; + CfiFunctionLinkage Linkage = P.second.Linkage; + MDNode *FuncMD = P.second.FuncMD; + Function *F = M.getFunction(FunctionName); + if (!F) + F = Function::Create( + FunctionType::get(Type::getVoidTy(M.getContext()), false), + GlobalVariable::ExternalLinkage, FunctionName, &M); + + if (Linkage == CFL_Definition) + F->eraseMetadata(LLVMContext::MD_type); + + if (F->isDeclaration()) { + if (Linkage == CFL_WeakDeclaration) + F->setLinkage(GlobalValue::ExternalWeakLinkage); + + SmallVector Types; + for (unsigned I = 2; I < FuncMD->getNumOperands(); ++I) + F->addMetadata(LLVMContext::MD_type, + *cast(FuncMD->getOperand(I).get())); + } + } + } + } + for (GlobalObject &GO : M.global_objects()) { if (isa(GO) && GO.isDeclarationForLinker()) continue; @@ -1396,7 +1532,15 @@ bool LowerTypeTestsModule::lower() { if (Types.empty()) continue; - auto *GTM = GlobalTypeMember::create(Alloc, &GO, Types); + bool IsDefinition = !GO.isDeclarationForLinker(); + bool IsExported = false; + if (isa(GO) && ExportedFunctions.count(GO.getName())) { + IsDefinition |= ExportedFunctions[GO.getName()].Linkage == CFL_Definition; + IsExported = true; + } + + auto *GTM = + GlobalTypeMember::create(Alloc, &GO, IsDefinition, IsExported, Types); for (MDNode *Type : Types) { verifyTypeMDNode(&GO, Type); auto &Info = TypeIdInfo[cast(Type)->getOperand(1)]; diff --git a/lib/Transforms/IPO/PartialInlining.cpp b/lib/Transforms/IPO/PartialInlining.cpp index ea805efc66b7..8840435af642 100644 --- a/lib/Transforms/IPO/PartialInlining.cpp +++ b/lib/Transforms/IPO/PartialInlining.cpp @@ -103,6 +103,35 @@ struct PartialInlinerImpl { bool run(Module &M); Function *unswitchFunction(Function *F); + // This class speculatively clones the the function to be partial inlined. + // At the end of partial inlining, the remaining callsites to the cloned + // function that are not partially inlined will be fixed up to reference + // the original function, and the cloned function will be erased. + struct FunctionCloner { + FunctionCloner(Function *F, FunctionOutliningInfo *OI); + ~FunctionCloner(); + + // Prepare for function outlining: making sure there is only + // one incoming edge from the extracted/outlined region to + // the return block. + void NormalizeReturnBlock(); + + // Do function outlining: + Function *doFunctionOutlining(); + + Function *OrigFunc = nullptr; + Function *ClonedFunc = nullptr; + Function *OutlinedFunc = nullptr; + BasicBlock *OutliningCallBB = nullptr; + // ClonedFunc is inlined in one of its callers after function + // outlining. + bool IsFunctionInlined = false; + // The cost of the region to be outlined. + int OutlinedRegionCost = 0; + std::unique_ptr ClonedOI = nullptr; + std::unique_ptr ClonedFuncBFI = nullptr; + }; + private: int NumPartialInlining = 0; std::function *GetAssumptionCache; @@ -114,27 +143,18 @@ struct PartialInlinerImpl { // The result is no larger than 1 and is represented using BP. // (Note that the outlined region's 'head' block can only have incoming // edges from the guarding entry blocks). - BranchProbability getOutliningCallBBRelativeFreq(Function *F, - FunctionOutliningInfo *OI, - Function *DuplicateFunction, - BlockFrequencyInfo *BFI, - BasicBlock *OutliningCallBB); + BranchProbability getOutliningCallBBRelativeFreq(FunctionCloner &Cloner); // Return true if the callee of CS should be partially inlined with // profit. - bool shouldPartialInline(CallSite CS, Function *F, FunctionOutliningInfo *OI, - BlockFrequencyInfo *CalleeBFI, - BasicBlock *OutliningCallBB, - int OutliningCallOverhead, + bool shouldPartialInline(CallSite CS, FunctionCloner &Cloner, + BlockFrequency WeightedOutliningRcost, OptimizationRemarkEmitter &ORE); // Try to inline DuplicateFunction (cloned from F with call to // the OutlinedFunction into its callers. Return true // if there is any successful inlining. - bool tryPartialInline(Function *DuplicateFunction, - Function *F, /*orignal function */ - FunctionOutliningInfo *OI, Function *OutlinedFunction, - BlockFrequencyInfo *CalleeBFI); + bool tryPartialInline(FunctionCloner &Cloner); // Compute the mapping from use site of DuplicationFunction to the enclosing // BB's profile count. @@ -146,7 +166,7 @@ struct PartialInlinerImpl { NumPartialInlining >= MaxNumPartialInlining); } - CallSite getCallSite(User *U) { + static CallSite getCallSite(User *U) { CallSite CS; if (CallInst *CI = dyn_cast(U)) CS = CallSite(CI); @@ -157,7 +177,7 @@ struct PartialInlinerImpl { return CS; } - CallSite getOneCallSiteTo(Function *F) { + static CallSite getOneCallSiteTo(Function *F) { User *User = *F->user_begin(); return getCallSite(User); } @@ -171,20 +191,15 @@ struct PartialInlinerImpl { // Returns the costs associated with function outlining: // - The first value is the non-weighted runtime cost for making the call - // to the outlined function 'OutlinedFunction', including the addtional - // setup cost in the outlined function itself; + // to the outlined function, including the addtional setup cost in the + // outlined function itself; // - The second value is the estimated size of the new call sequence in - // basic block 'OutliningCallBB'; - // - The third value is the estimated size of the original code from - // function 'F' that is extracted into the outlined function. - std::tuple - computeOutliningCosts(Function *F, const FunctionOutliningInfo *OutliningInfo, - Function *OutlinedFunction, - BasicBlock *OutliningCallBB); + // basic block Cloner.OutliningCallBB; + std::tuple computeOutliningCosts(FunctionCloner &Cloner); // Compute the 'InlineCost' of block BB. InlineCost is a proxy used to // approximate both the size and runtime cost (Note that in the current // inline cost analysis, there is no clear distinction there either). - int computeBBInlineCost(BasicBlock *BB); + static int computeBBInlineCost(BasicBlock *BB); std::unique_ptr computeOutliningInfo(Function *F); @@ -396,19 +411,19 @@ static bool hasProfileData(Function *F, FunctionOutliningInfo *OI) { return false; } -BranchProbability PartialInlinerImpl::getOutliningCallBBRelativeFreq( - Function *F, FunctionOutliningInfo *OI, Function *DuplicateFunction, - BlockFrequencyInfo *BFI, BasicBlock *OutliningCallBB) { +BranchProbability +PartialInlinerImpl::getOutliningCallBBRelativeFreq(FunctionCloner &Cloner) { auto EntryFreq = - BFI->getBlockFreq(&DuplicateFunction->getEntryBlock()); - auto OutliningCallFreq = BFI->getBlockFreq(OutliningCallBB); + Cloner.ClonedFuncBFI->getBlockFreq(&Cloner.ClonedFunc->getEntryBlock()); + auto OutliningCallFreq = + Cloner.ClonedFuncBFI->getBlockFreq(Cloner.OutliningCallBB); auto OutlineRegionRelFreq = BranchProbability::getBranchProbability(OutliningCallFreq.getFrequency(), EntryFreq.getFrequency()); - if (hasProfileData(F, OI)) + if (hasProfileData(Cloner.OrigFunc, Cloner.ClonedOI.get())) return OutlineRegionRelFreq; // When profile data is not available, we need to be conservative in @@ -433,15 +448,17 @@ BranchProbability PartialInlinerImpl::getOutliningCallBBRelativeFreq( } bool PartialInlinerImpl::shouldPartialInline( - CallSite CS, Function *F /* Original Callee */, FunctionOutliningInfo *OI, - BlockFrequencyInfo *CalleeBFI, BasicBlock *OutliningCallBB, - int NonWeightedOutliningRcost, OptimizationRemarkEmitter &ORE) { + CallSite CS, FunctionCloner &Cloner, BlockFrequency WeightedOutliningRcost, + OptimizationRemarkEmitter &ORE) { + using namespace ore; if (SkipCostAnalysis) return true; Instruction *Call = CS.getInstruction(); Function *Callee = CS.getCalledFunction(); + assert(Callee == Cloner.ClonedFunc); + Function *Caller = CS.getCaller(); auto &CalleeTTI = (*GetTTI)(*Callee); InlineCost IC = getInlineCost(CS, getInlineParams(), CalleeTTI, @@ -449,14 +466,14 @@ bool PartialInlinerImpl::shouldPartialInline( if (IC.isAlways()) { ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AlwaysInline", Call) - << NV("Callee", F) + << NV("Callee", Cloner.OrigFunc) << " should always be fully inlined, not partially"); return false; } if (IC.isNever()) { ORE.emit(OptimizationRemarkMissed(DEBUG_TYPE, "NeverInline", Call) - << NV("Callee", F) << " not partially inlined into " + << NV("Callee", Cloner.OrigFunc) << " not partially inlined into " << NV("Caller", Caller) << " because it should never be inlined (cost=never)"); return false; @@ -464,29 +481,25 @@ bool PartialInlinerImpl::shouldPartialInline( if (!IC) { ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "TooCostly", Call) - << NV("Callee", F) << " not partially inlined into " + << NV("Callee", Cloner.OrigFunc) << " not partially inlined into " << NV("Caller", Caller) << " because too costly to inline (cost=" << NV("Cost", IC.getCost()) << ", threshold=" << NV("Threshold", IC.getCostDelta() + IC.getCost()) << ")"); return false; } const DataLayout &DL = Caller->getParent()->getDataLayout(); + // The savings of eliminating the call: int NonWeightedSavings = getCallsiteCost(CS, DL); BlockFrequency NormWeightedSavings(NonWeightedSavings); - auto RelativeFreq = - getOutliningCallBBRelativeFreq(F, OI, Callee, CalleeBFI, OutliningCallBB); - auto NormWeightedRcost = - BlockFrequency(NonWeightedOutliningRcost) * RelativeFreq; - // Weighted saving is smaller than weighted cost, return false - if (NormWeightedSavings < NormWeightedRcost) { + if (NormWeightedSavings < WeightedOutliningRcost) { ORE.emit( OptimizationRemarkAnalysis(DEBUG_TYPE, "OutliningCallcostTooHigh", Call) - << NV("Callee", F) << " not partially inlined into " + << NV("Callee", Cloner.OrigFunc) << " not partially inlined into " << NV("Caller", Caller) << " runtime overhead (overhead=" - << NV("Overhead", (unsigned)NormWeightedRcost.getFrequency()) + << NV("Overhead", (unsigned)WeightedOutliningRcost.getFrequency()) << ", savings=" << NV("Savings", (unsigned)NormWeightedSavings.getFrequency()) << ")" << " of making the outlined call is too high"); @@ -495,7 +508,7 @@ bool PartialInlinerImpl::shouldPartialInline( } ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "CanBePartiallyInlined", Call) - << NV("Callee", F) << " can be partially inlined into " + << NV("Callee", Cloner.OrigFunc) << " can be partially inlined into " << NV("Caller", Caller) << " with cost=" << NV("Cost", IC.getCost()) << " (threshold=" << NV("Threshold", IC.getCostDelta() + IC.getCost()) << ")"); @@ -551,50 +564,32 @@ int PartialInlinerImpl::computeBBInlineCost(BasicBlock *BB) { return InlineCost; } -std::tuple PartialInlinerImpl::computeOutliningCosts( - Function *F, const FunctionOutliningInfo *OI, Function *OutlinedFunction, - BasicBlock *OutliningCallBB) { - // First compute the cost of the outlined region 'OI' in the original - // function 'F'. - // FIXME: The code extractor (outliner) can now do code sinking/hoisting - // to reduce outlining cost. The hoisted/sunk code currently do not - // incur any runtime cost so it is still OK to compare the outlined - // function cost with the outlined region in the original function. - // If this ever changes, we will need to introduce new extractor api - // to pass the information. - int OutlinedRegionCost = 0; - for (BasicBlock &BB : *F) { - if (&BB != OI->ReturnBlock && - // Assuming Entry set is small -- do a linear search here: - std::find(OI->Entries.begin(), OI->Entries.end(), &BB) == - OI->Entries.end()) { - OutlinedRegionCost += computeBBInlineCost(&BB); - } - } +std::tuple +PartialInlinerImpl::computeOutliningCosts(FunctionCloner &Cloner) { // Now compute the cost of the call sequence to the outlined function // 'OutlinedFunction' in BB 'OutliningCallBB': - int OutliningFuncCallCost = computeBBInlineCost(OutliningCallBB); + int OutliningFuncCallCost = computeBBInlineCost(Cloner.OutliningCallBB); // Now compute the cost of the extracted/outlined function itself: int OutlinedFunctionCost = 0; - for (BasicBlock &BB : *OutlinedFunction) { + for (BasicBlock &BB : *Cloner.OutlinedFunc) { OutlinedFunctionCost += computeBBInlineCost(&BB); } - assert(OutlinedFunctionCost >= OutlinedRegionCost && + assert(OutlinedFunctionCost >= Cloner.OutlinedRegionCost && "Outlined function cost should be no less than the outlined region"); // The code extractor introduces a new root and exit stub blocks with // additional unconditional branches. Those branches will be eliminated // later with bb layout. The cost should be adjusted accordingly: OutlinedFunctionCost -= 2 * InlineConstants::InstrCost; - int OutliningRuntimeOverhead = OutliningFuncCallCost + - (OutlinedFunctionCost - OutlinedRegionCost) + - ExtraOutliningPenalty; + int OutliningRuntimeOverhead = + OutliningFuncCallCost + + (OutlinedFunctionCost - Cloner.OutlinedRegionCost) + + ExtraOutliningPenalty; - return std::make_tuple(OutliningFuncCallCost, OutliningRuntimeOverhead, - OutlinedRegionCost); + return std::make_tuple(OutliningFuncCallCost, OutliningRuntimeOverhead); } // Create the callsite to profile count map which is @@ -641,6 +636,166 @@ void PartialInlinerImpl::computeCallsiteToProfCountMap( } } +PartialInlinerImpl::FunctionCloner::FunctionCloner(Function *F, + FunctionOutliningInfo *OI) + : OrigFunc(F) { + ClonedOI = llvm::make_unique(); + + // Clone the function, so that we can hack away on it. + ValueToValueMapTy VMap; + ClonedFunc = CloneFunction(F, VMap); + + ClonedOI->ReturnBlock = cast(VMap[OI->ReturnBlock]); + ClonedOI->NonReturnBlock = cast(VMap[OI->NonReturnBlock]); + for (BasicBlock *BB : OI->Entries) { + ClonedOI->Entries.push_back(cast(VMap[BB])); + } + for (BasicBlock *E : OI->ReturnBlockPreds) { + BasicBlock *NewE = cast(VMap[E]); + ClonedOI->ReturnBlockPreds.push_back(NewE); + } + // Go ahead and update all uses to the duplicate, so that we can just + // use the inliner functionality when we're done hacking. + F->replaceAllUsesWith(ClonedFunc); +} + +void PartialInlinerImpl::FunctionCloner::NormalizeReturnBlock() { + + auto getFirstPHI = [](BasicBlock *BB) { + BasicBlock::iterator I = BB->begin(); + PHINode *FirstPhi = nullptr; + while (I != BB->end()) { + PHINode *Phi = dyn_cast(I); + if (!Phi) + break; + if (!FirstPhi) { + FirstPhi = Phi; + break; + } + } + return FirstPhi; + }; + + // Special hackery is needed with PHI nodes that have inputs from more than + // one extracted block. For simplicity, just split the PHIs into a two-level + // sequence of PHIs, some of which will go in the extracted region, and some + // of which will go outside. + BasicBlock *PreReturn = ClonedOI->ReturnBlock; + // only split block when necessary: + PHINode *FirstPhi = getFirstPHI(PreReturn); + unsigned NumPredsFromEntries = ClonedOI->ReturnBlockPreds.size(); + + if (!FirstPhi || FirstPhi->getNumIncomingValues() <= NumPredsFromEntries + 1) + return; + + auto IsTrivialPhi = [](PHINode *PN) -> Value * { + Value *CommonValue = PN->getIncomingValue(0); + if (all_of(PN->incoming_values(), + [&](Value *V) { return V == CommonValue; })) + return CommonValue; + return nullptr; + }; + + ClonedOI->ReturnBlock = ClonedOI->ReturnBlock->splitBasicBlock( + ClonedOI->ReturnBlock->getFirstNonPHI()->getIterator()); + BasicBlock::iterator I = PreReturn->begin(); + Instruction *Ins = &ClonedOI->ReturnBlock->front(); + SmallVector DeadPhis; + while (I != PreReturn->end()) { + PHINode *OldPhi = dyn_cast(I); + if (!OldPhi) + break; + + PHINode *RetPhi = + PHINode::Create(OldPhi->getType(), NumPredsFromEntries + 1, "", Ins); + OldPhi->replaceAllUsesWith(RetPhi); + Ins = ClonedOI->ReturnBlock->getFirstNonPHI(); + + RetPhi->addIncoming(&*I, PreReturn); + for (BasicBlock *E : ClonedOI->ReturnBlockPreds) { + RetPhi->addIncoming(OldPhi->getIncomingValueForBlock(E), E); + OldPhi->removeIncomingValue(E); + } + + // After incoming values splitting, the old phi may become trivial. + // Keeping the trivial phi can introduce definition inside the outline + // region which is live-out, causing necessary overhead (load, store + // arg passing etc). + if (auto *OldPhiVal = IsTrivialPhi(OldPhi)) { + OldPhi->replaceAllUsesWith(OldPhiVal); + DeadPhis.push_back(OldPhi); + } + ++I; + } + for (auto *DP : DeadPhis) + DP->eraseFromParent(); + + for (auto E : ClonedOI->ReturnBlockPreds) { + E->getTerminator()->replaceUsesOfWith(PreReturn, ClonedOI->ReturnBlock); + } +} + +Function *PartialInlinerImpl::FunctionCloner::doFunctionOutlining() { + // Returns true if the block is to be partial inlined into the caller + // (i.e. not to be extracted to the out of line function) + auto ToBeInlined = [&, this](BasicBlock *BB) { + return BB == ClonedOI->ReturnBlock || + (std::find(ClonedOI->Entries.begin(), ClonedOI->Entries.end(), BB) != + ClonedOI->Entries.end()); + }; + + // Gather up the blocks that we're going to extract. + std::vector ToExtract; + ToExtract.push_back(ClonedOI->NonReturnBlock); + OutlinedRegionCost += + PartialInlinerImpl::computeBBInlineCost(ClonedOI->NonReturnBlock); + for (BasicBlock &BB : *ClonedFunc) + if (!ToBeInlined(&BB) && &BB != ClonedOI->NonReturnBlock) { + ToExtract.push_back(&BB); + // FIXME: the code extractor may hoist/sink more code + // into the outlined function which may make the outlining + // overhead (the difference of the outlined function cost + // and OutliningRegionCost) look larger. + OutlinedRegionCost += computeBBInlineCost(&BB); + } + + // The CodeExtractor needs a dominator tree. + DominatorTree DT; + DT.recalculate(*ClonedFunc); + + // Manually calculate a BlockFrequencyInfo and BranchProbabilityInfo. + LoopInfo LI(DT); + BranchProbabilityInfo BPI(*ClonedFunc, LI); + ClonedFuncBFI.reset(new BlockFrequencyInfo(*ClonedFunc, BPI, LI)); + + // Extract the body of the if. + OutlinedFunc = CodeExtractor(ToExtract, &DT, /*AggregateArgs*/ false, + ClonedFuncBFI.get(), &BPI) + .extractCodeRegion(); + + if (OutlinedFunc) { + OutliningCallBB = PartialInlinerImpl::getOneCallSiteTo(OutlinedFunc) + .getInstruction() + ->getParent(); + assert(OutliningCallBB->getParent() == ClonedFunc); + } + + return OutlinedFunc; +} + +PartialInlinerImpl::FunctionCloner::~FunctionCloner() { + // Ditch the duplicate, since we're done with it, and rewrite all remaining + // users (function pointers, etc.) back to the original function. + ClonedFunc->replaceAllUsesWith(OrigFunc); + ClonedFunc->eraseFromParent(); + if (!IsFunctionInlined) { + // Remove the function that is speculatively created if there is no + // reference. + if (OutlinedFunc) + OutlinedFunc->eraseFromParent(); + } +} + Function *PartialInlinerImpl::unswitchFunction(Function *F) { if (F->hasAddressTaken()) @@ -664,187 +819,62 @@ Function *PartialInlinerImpl::unswitchFunction(Function *F) { if (!OI) return nullptr; - // Clone the function, so that we can hack away on it. - ValueToValueMapTy VMap; - Function *DuplicateFunction = CloneFunction(F, VMap); - BasicBlock *NewReturnBlock = cast(VMap[OI->ReturnBlock]); - BasicBlock *NewNonReturnBlock = cast(VMap[OI->NonReturnBlock]); - DenseSet NewEntries; - for (BasicBlock *BB : OI->Entries) { - NewEntries.insert(cast(VMap[BB])); - } + FunctionCloner Cloner(F, OI.get()); + Cloner.NormalizeReturnBlock(); + Function *OutlinedFunction = Cloner.doFunctionOutlining(); - // Go ahead and update all uses to the duplicate, so that we can just - // use the inliner functionality when we're done hacking. - F->replaceAllUsesWith(DuplicateFunction); - - auto getFirstPHI = [](BasicBlock *BB) { - BasicBlock::iterator I = BB->begin(); - PHINode *FirstPhi = nullptr; - while (I != BB->end()) { - PHINode *Phi = dyn_cast(I); - if (!Phi) - break; - if (!FirstPhi) { - FirstPhi = Phi; - break; - } - } - return FirstPhi; - }; - // Special hackery is needed with PHI nodes that have inputs from more than - // one extracted block. For simplicity, just split the PHIs into a two-level - // sequence of PHIs, some of which will go in the extracted region, and some - // of which will go outside. - BasicBlock *PreReturn = NewReturnBlock; - // only split block when necessary: - PHINode *FirstPhi = getFirstPHI(PreReturn); - unsigned NumPredsFromEntries = OI->ReturnBlockPreds.size(); - auto IsTrivialPhi = [](PHINode *PN) -> Value * { - Value *CommonValue = PN->getIncomingValue(0); - if (all_of(PN->incoming_values(), - [&](Value *V) { return V == CommonValue; })) - return CommonValue; - return nullptr; - }; - - if (FirstPhi && FirstPhi->getNumIncomingValues() > NumPredsFromEntries + 1) { - - NewReturnBlock = NewReturnBlock->splitBasicBlock( - NewReturnBlock->getFirstNonPHI()->getIterator()); - BasicBlock::iterator I = PreReturn->begin(); - Instruction *Ins = &NewReturnBlock->front(); - SmallVector DeadPhis; - while (I != PreReturn->end()) { - PHINode *OldPhi = dyn_cast(I); - if (!OldPhi) - break; - - PHINode *RetPhi = - PHINode::Create(OldPhi->getType(), NumPredsFromEntries + 1, "", Ins); - OldPhi->replaceAllUsesWith(RetPhi); - Ins = NewReturnBlock->getFirstNonPHI(); - - RetPhi->addIncoming(&*I, PreReturn); - for (BasicBlock *E : OI->ReturnBlockPreds) { - BasicBlock *NewE = cast(VMap[E]); - RetPhi->addIncoming(OldPhi->getIncomingValueForBlock(NewE), NewE); - OldPhi->removeIncomingValue(NewE); - } - - // After incoming values splitting, the old phi may become trivial. - // Keeping the trivial phi can introduce definition inside the outline - // region which is live-out, causing necessary overhead (load, store - // arg passing etc). - if (auto *OldPhiVal = IsTrivialPhi(OldPhi)) { - OldPhi->replaceAllUsesWith(OldPhiVal); - DeadPhis.push_back(OldPhi); - } - - ++I; - } - - for (auto *DP : DeadPhis) - DP->eraseFromParent(); - - for (auto E : OI->ReturnBlockPreds) { - BasicBlock *NewE = cast(VMap[E]); - NewE->getTerminator()->replaceUsesOfWith(PreReturn, NewReturnBlock); - } - } - - // Returns true if the block is to be partial inlined into the caller - // (i.e. not to be extracted to the out of line function) - auto ToBeInlined = [&](BasicBlock *BB) { - return BB == NewReturnBlock || NewEntries.count(BB); - }; - // Gather up the blocks that we're going to extract. - std::vector ToExtract; - ToExtract.push_back(NewNonReturnBlock); - for (BasicBlock &BB : *DuplicateFunction) - if (!ToBeInlined(&BB) && &BB != NewNonReturnBlock) - ToExtract.push_back(&BB); - - // The CodeExtractor needs a dominator tree. - DominatorTree DT; - DT.recalculate(*DuplicateFunction); - - // Manually calculate a BlockFrequencyInfo and BranchProbabilityInfo. - LoopInfo LI(DT); - BranchProbabilityInfo BPI(*DuplicateFunction, LI); - BlockFrequencyInfo BFI(*DuplicateFunction, BPI, LI); - - // Extract the body of the if. - Function *OutlinedFunction = - CodeExtractor(ToExtract, &DT, /*AggregateArgs*/ false, &BFI, &BPI) - .extractCodeRegion(); - - bool AnyInline = - tryPartialInline(DuplicateFunction, F, OI.get(), OutlinedFunction, &BFI); - - // Ditch the duplicate, since we're done with it, and rewrite all remaining - // users (function pointers, etc.) back to the original function. - DuplicateFunction->replaceAllUsesWith(F); - DuplicateFunction->eraseFromParent(); + bool AnyInline = tryPartialInline(Cloner); if (AnyInline) return OutlinedFunction; - // Remove the function that is speculatively created: - if (OutlinedFunction) - OutlinedFunction->eraseFromParent(); - return nullptr; } -bool PartialInlinerImpl::tryPartialInline(Function *DuplicateFunction, - Function *F, - FunctionOutliningInfo *OI, - Function *OutlinedFunction, - BlockFrequencyInfo *CalleeBFI) { - if (OutlinedFunction == nullptr) - return false; - +bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) { int NonWeightedRcost; int SizeCost; - int OutlinedRegionSizeCost; - auto OutliningCallBB = - getOneCallSiteTo(OutlinedFunction).getInstruction()->getParent(); + if (Cloner.OutlinedFunc == nullptr) + return false; - std::tie(SizeCost, NonWeightedRcost, OutlinedRegionSizeCost) = - computeOutliningCosts(F, OI, OutlinedFunction, OutliningCallBB); + std::tie(SizeCost, NonWeightedRcost) = computeOutliningCosts(Cloner); + + auto RelativeToEntryFreq = getOutliningCallBBRelativeFreq(Cloner); + auto WeightedRcost = BlockFrequency(NonWeightedRcost) * RelativeToEntryFreq; // The call sequence to the outlined function is larger than the original // outlined region size, it does not increase the chances of inlining - // 'F' with outlining (The inliner usies the size increase to model the - // the cost of inlining a callee). - if (!SkipCostAnalysis && OutlinedRegionSizeCost < SizeCost) { - OptimizationRemarkEmitter ORE(F); + // the function with outlining (The inliner usies the size increase to + // model the cost of inlining a callee). + if (!SkipCostAnalysis && Cloner.OutlinedRegionCost < SizeCost) { + OptimizationRemarkEmitter ORE(Cloner.OrigFunc); DebugLoc DLoc; BasicBlock *Block; - std::tie(DLoc, Block) = getOneDebugLoc(DuplicateFunction); + std::tie(DLoc, Block) = getOneDebugLoc(Cloner.ClonedFunc); ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "OutlineRegionTooSmall", DLoc, Block) - << ore::NV("Function", F) + << ore::NV("Function", Cloner.OrigFunc) << " not partially inlined into callers (Original Size = " - << ore::NV("OutlinedRegionOriginalSize", OutlinedRegionSizeCost) + << ore::NV("OutlinedRegionOriginalSize", Cloner.OutlinedRegionCost) << ", Size of call sequence to outlined function = " << ore::NV("NewSize", SizeCost) << ")"); return false; } - assert(F->user_begin() == F->user_end() && + assert(Cloner.OrigFunc->user_begin() == Cloner.OrigFunc->user_end() && "F's users should all be replaced!"); - std::vector Users(DuplicateFunction->user_begin(), - DuplicateFunction->user_end()); + + std::vector Users(Cloner.ClonedFunc->user_begin(), + Cloner.ClonedFunc->user_end()); DenseMap CallSiteToProfCountMap; - if (F->getEntryCount()) - computeCallsiteToProfCountMap(DuplicateFunction, CallSiteToProfCountMap); + if (Cloner.OrigFunc->getEntryCount()) + computeCallsiteToProfCountMap(Cloner.ClonedFunc, CallSiteToProfCountMap); - auto CalleeEntryCount = F->getEntryCount(); + auto CalleeEntryCount = Cloner.OrigFunc->getEntryCount(); uint64_t CalleeEntryCountV = (CalleeEntryCount ? *CalleeEntryCount : 0); + bool AnyInline = false; for (User *User : Users) { CallSite CS = getCallSite(User); @@ -854,13 +884,12 @@ bool PartialInlinerImpl::tryPartialInline(Function *DuplicateFunction, OptimizationRemarkEmitter ORE(CS.getCaller()); - if (!shouldPartialInline(CS, F, OI, CalleeBFI, OutliningCallBB, - NonWeightedRcost, ORE)) + if (!shouldPartialInline(CS, Cloner, WeightedRcost, ORE)) continue; ORE.emit( OptimizationRemark(DEBUG_TYPE, "PartiallyInlined", CS.getInstruction()) - << ore::NV("Callee", F) << " partially inlined into " + << ore::NV("Callee", Cloner.OrigFunc) << " partially inlined into " << ore::NV("Caller", CS.getCaller())); InlineFunctionInfo IFI(nullptr, GetAssumptionCache, PSI); @@ -878,8 +907,11 @@ bool PartialInlinerImpl::tryPartialInline(Function *DuplicateFunction, NumPartialInlined++; } - if (AnyInline && CalleeEntryCount) - F->setEntryCount(CalleeEntryCountV); + if (AnyInline) { + Cloner.IsFunctionInlined = true; + if (CalleeEntryCount) + Cloner.OrigFunc->setEntryCount(CalleeEntryCountV); + } return AnyInline; } diff --git a/lib/Transforms/IPO/PassManagerBuilder.cpp b/lib/Transforms/IPO/PassManagerBuilder.cpp index 16fba32e9805..4bc64ab698ff 100644 --- a/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -141,6 +141,10 @@ static cl::opt PreInlineThreshold( cl::desc("Control the amount of inlining in pre-instrumentation inliner " "(default = 75)")); +static cl::opt EnableEarlyCSEMemSSA( + "enable-earlycse-memssa", cl::init(false), cl::Hidden, + cl::desc("Enable the EarlyCSE w/ MemorySSA pass (default = off)")); + static cl::opt EnableGVNHoist( "enable-gvn-hoist", cl::init(false), cl::Hidden, cl::desc("Enable the GVN hoisting pass (default = off)")); @@ -308,7 +312,7 @@ void PassManagerBuilder::addFunctionSimplificationPasses( // Start of function pass. // Break up aggregate allocas, using SSAUpdater. MPM.add(createSROAPass()); - MPM.add(createEarlyCSEPass()); // Catch trivial redundancies + MPM.add(createEarlyCSEPass(EnableEarlyCSEMemSSA)); // Catch trivial redundancies if (EnableGVNHoist) MPM.add(createGVNHoistPass()); if (EnableGVNSink) { diff --git a/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp index a7bcc7cc5532..802f470ffe1f 100644 --- a/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ b/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -32,7 +32,8 @@ namespace { // Promote each local-linkage entity defined by ExportM and used by ImportM by // changing visibility and appending the given ModuleId. -void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId) { +void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId, + SetVector &PromoteExtra) { DenseMap RenamedComdats; for (auto &ExportGV : ExportM.global_values()) { if (!ExportGV.hasLocalLinkage()) @@ -40,7 +41,7 @@ void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId) { auto Name = ExportGV.getName(); GlobalValue *ImportGV = ImportM.getNamedValue(Name); - if (!ImportGV || ImportGV->use_empty()) + if ((!ImportGV || ImportGV->use_empty()) && !PromoteExtra.count(&ExportGV)) continue; std::string NewName = (Name + ModuleId).str(); @@ -53,8 +54,10 @@ void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId) { ExportGV.setLinkage(GlobalValue::ExternalLinkage); ExportGV.setVisibility(GlobalValue::HiddenVisibility); - ImportGV->setName(NewName); - ImportGV->setVisibility(GlobalValue::HiddenVisibility); + if (ImportGV) { + ImportGV->setName(NewName); + ImportGV->setVisibility(GlobalValue::HiddenVisibility); + } } if (!RenamedComdats.empty()) @@ -296,6 +299,11 @@ void splitAndWriteThinLTOBitcode( F.setComdat(nullptr); } + SetVector CfiFunctions; + for (auto &F : M) + if ((!F.hasLocalLinkage() || F.hasAddressTaken()) && HasTypeMetadata(&F)) + CfiFunctions.insert(&F); + // Remove all globals with type metadata, globals with comdats that live in // MergedM, and aliases pointing to such globals from the thin LTO module. filterModule(&M, [&](const GlobalValue *GV) { @@ -308,12 +316,40 @@ void splitAndWriteThinLTOBitcode( return true; }); - promoteInternals(*MergedM, M, ModuleId); - promoteInternals(M, *MergedM, ModuleId); + promoteInternals(*MergedM, M, ModuleId, CfiFunctions); + promoteInternals(M, *MergedM, ModuleId, CfiFunctions); + + SmallVector CfiFunctionMDs; + for (auto V : CfiFunctions) { + Function &F = *cast(V); + SmallVector Types; + F.getMetadata(LLVMContext::MD_type, Types); + + auto &Ctx = MergedM->getContext(); + SmallVector Elts; + Elts.push_back(MDString::get(Ctx, F.getName())); + CfiFunctionLinkage Linkage; + if (!F.isDeclarationForLinker()) + Linkage = CFL_Definition; + else if (F.isWeakForLinker()) + Linkage = CFL_WeakDeclaration; + else + Linkage = CFL_Declaration; + Elts.push_back(ConstantAsMetadata::get( + llvm::ConstantInt::get(Type::getInt8Ty(Ctx), Linkage))); + for (auto Type : Types) + Elts.push_back(Type); + CfiFunctionMDs.push_back(MDTuple::get(Ctx, Elts)); + } + + if(!CfiFunctionMDs.empty()) { + NamedMDNode *NMD = MergedM->getOrInsertNamedMetadata("cfi.functions"); + for (auto MD : CfiFunctionMDs) + NMD->addOperand(MD); + } simplifyExternals(*MergedM); - // FIXME: Try to re-use BSI and PFI from the original module here. ProfileSummaryInfo PSI(M); ModuleSummaryIndex Index = buildModuleSummaryIndex(M, nullptr, &PSI); diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 4fe3225a2172..a881bda5ba98 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -763,8 +763,54 @@ foldAndOrOfEqualityCmpsWithConstants(ICmpInst *LHS, ICmpInst *RHS, return nullptr; } +// Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2) +// Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2) +Value *InstCombiner::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS, ICmpInst *RHS, + bool JoinedByAnd, + Instruction &CxtI) { + ICmpInst::Predicate Pred = LHS->getPredicate(); + if (Pred != RHS->getPredicate()) + return nullptr; + if (JoinedByAnd && Pred != ICmpInst::ICMP_NE) + return nullptr; + if (!JoinedByAnd && Pred != ICmpInst::ICMP_EQ) + return nullptr; + + // TODO support vector splats + ConstantInt *LHSC = dyn_cast(LHS->getOperand(1)); + ConstantInt *RHSC = dyn_cast(RHS->getOperand(1)); + if (!LHSC || !RHSC || !LHSC->isZero() || !RHSC->isZero()) + return nullptr; + + Value *A, *B, *C, *D; + if (match(LHS->getOperand(0), m_And(m_Value(A), m_Value(B))) && + match(RHS->getOperand(0), m_And(m_Value(C), m_Value(D)))) { + if (A == D || B == D) + std::swap(C, D); + if (B == C) + std::swap(A, B); + + if (A == C && + isKnownToBeAPowerOfTwo(B, false, 0, &CxtI) && + isKnownToBeAPowerOfTwo(D, false, 0, &CxtI)) { + Value *Mask = Builder->CreateOr(B, D); + Value *Masked = Builder->CreateAnd(A, Mask); + auto NewPred = JoinedByAnd ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE; + return Builder->CreateICmp(NewPred, Masked, Mask); + } + } + + return nullptr; +} + /// Fold (icmp)&(icmp) if possible. -Value *InstCombiner::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS) { +Value *InstCombiner::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS, + Instruction &CxtI) { + // Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2) + // if K1 and K2 are a one-bit mask. + if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, true, CxtI)) + return V; + ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); // (icmp1 A, B) & (icmp2 A, B) --> (icmp3 A, B) @@ -1127,8 +1173,8 @@ Instruction *InstCombiner::foldCastedBitwiseLogic(BinaryOperator &I) { ICmpInst *ICmp0 = dyn_cast(Cast0Src); ICmpInst *ICmp1 = dyn_cast(Cast1Src); if (ICmp0 && ICmp1) { - Value *Res = LogicOpc == Instruction::And ? foldAndOfICmps(ICmp0, ICmp1) - : foldOrOfICmps(ICmp0, ICmp1, &I); + Value *Res = LogicOpc == Instruction::And ? foldAndOfICmps(ICmp0, ICmp1, I) + : foldOrOfICmps(ICmp0, ICmp1, I); if (Res) return CastInst::Create(CastOpcode, Res, DestTy); return nullptr; @@ -1426,7 +1472,7 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { ICmpInst *LHS = dyn_cast(Op0); ICmpInst *RHS = dyn_cast(Op1); if (LHS && RHS) - if (Value *Res = foldAndOfICmps(LHS, RHS)) + if (Value *Res = foldAndOfICmps(LHS, RHS, I)) return replaceInstUsesWith(I, Res); // TODO: Make this recursive; it's a little tricky because an arbitrary @@ -1434,18 +1480,18 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { Value *X, *Y; if (LHS && match(Op1, m_OneUse(m_And(m_Value(X), m_Value(Y))))) { if (auto *Cmp = dyn_cast(X)) - if (Value *Res = foldAndOfICmps(LHS, Cmp)) + if (Value *Res = foldAndOfICmps(LHS, Cmp, I)) return replaceInstUsesWith(I, Builder->CreateAnd(Res, Y)); if (auto *Cmp = dyn_cast(Y)) - if (Value *Res = foldAndOfICmps(LHS, Cmp)) + if (Value *Res = foldAndOfICmps(LHS, Cmp, I)) return replaceInstUsesWith(I, Builder->CreateAnd(Res, X)); } if (RHS && match(Op0, m_OneUse(m_And(m_Value(X), m_Value(Y))))) { if (auto *Cmp = dyn_cast(X)) - if (Value *Res = foldAndOfICmps(Cmp, RHS)) + if (Value *Res = foldAndOfICmps(Cmp, RHS, I)) return replaceInstUsesWith(I, Builder->CreateAnd(Res, Y)); if (auto *Cmp = dyn_cast(Y)) - if (Value *Res = foldAndOfICmps(Cmp, RHS)) + if (Value *Res = foldAndOfICmps(Cmp, RHS, I)) return replaceInstUsesWith(I, Builder->CreateAnd(Res, X)); } } @@ -1591,42 +1637,17 @@ static Value *matchSelectFromAndOr(Value *A, Value *C, Value *B, Value *D, /// Fold (icmp)|(icmp) if possible. Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, - Instruction *CxtI) { - ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); - + Instruction &CxtI) { // Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2) // if K1 and K2 are a one-bit mask. + if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, false, CxtI)) + return V; + + ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); + ConstantInt *LHSC = dyn_cast(LHS->getOperand(1)); ConstantInt *RHSC = dyn_cast(RHS->getOperand(1)); - if (LHS->getPredicate() == ICmpInst::ICMP_EQ && LHSC && LHSC->isZero() && - RHS->getPredicate() == ICmpInst::ICMP_EQ && RHSC && RHSC->isZero()) { - - BinaryOperator *LAnd = dyn_cast(LHS->getOperand(0)); - BinaryOperator *RAnd = dyn_cast(RHS->getOperand(0)); - if (LAnd && RAnd && LAnd->hasOneUse() && RHS->hasOneUse() && - LAnd->getOpcode() == Instruction::And && - RAnd->getOpcode() == Instruction::And) { - - Value *Mask = nullptr; - Value *Masked = nullptr; - if (LAnd->getOperand(0) == RAnd->getOperand(0) && - isKnownToBeAPowerOfTwo(LAnd->getOperand(1), false, 0, CxtI) && - isKnownToBeAPowerOfTwo(RAnd->getOperand(1), false, 0, CxtI)) { - Mask = Builder->CreateOr(LAnd->getOperand(1), RAnd->getOperand(1)); - Masked = Builder->CreateAnd(LAnd->getOperand(0), Mask); - } else if (LAnd->getOperand(1) == RAnd->getOperand(1) && - isKnownToBeAPowerOfTwo(LAnd->getOperand(0), false, 0, CxtI) && - isKnownToBeAPowerOfTwo(RAnd->getOperand(0), false, 0, CxtI)) { - Mask = Builder->CreateOr(LAnd->getOperand(0), RAnd->getOperand(0)); - Masked = Builder->CreateAnd(LAnd->getOperand(1), Mask); - } - - if (Masked) - return Builder->CreateICmp(ICmpInst::ICMP_NE, Masked, Mask); - } - } - // Fold (icmp ult/ule (A + C1), C3) | (icmp ult/ule (A + C2), C3) // --> (icmp ult/ule ((A & ~(C1 ^ C2)) + max(C1, C2)), C3) // The original condition actually refers to the following two ranges: @@ -2117,12 +2138,16 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { } // (A ^ B) | ((B ^ C) ^ A) -> (A ^ B) | C + // FIXME: The two hasOneUse calls here are the same call, maybe we were + // supposed to check Op1->operand(0)? if (match(Op0, m_Xor(m_Value(A), m_Value(B)))) if (match(Op1, m_Xor(m_Xor(m_Specific(B), m_Value(C)), m_Specific(A)))) if (Op1->hasOneUse() || cast(Op1)->hasOneUse()) return BinaryOperator::CreateOr(Op0, C); // ((A ^ C) ^ B) | (B ^ A) -> (B ^ A) | C + // FIXME: The two hasOneUse calls here are the same call, maybe we were + // supposed to check Op0->operand(0)? if (match(Op0, m_Xor(m_Xor(m_Value(A), m_Value(C)), m_Value(B)))) if (match(Op1, m_Xor(m_Specific(B), m_Specific(A)))) if (Op0->hasOneUse() || cast(Op0)->hasOneUse()) @@ -2194,7 +2219,7 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { ICmpInst *LHS = dyn_cast(Op0); ICmpInst *RHS = dyn_cast(Op1); if (LHS && RHS) - if (Value *Res = foldOrOfICmps(LHS, RHS, &I)) + if (Value *Res = foldOrOfICmps(LHS, RHS, I)) return replaceInstUsesWith(I, Res); // TODO: Make this recursive; it's a little tricky because an arbitrary @@ -2202,18 +2227,18 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { Value *X, *Y; if (LHS && match(Op1, m_OneUse(m_Or(m_Value(X), m_Value(Y))))) { if (auto *Cmp = dyn_cast(X)) - if (Value *Res = foldOrOfICmps(LHS, Cmp, &I)) + if (Value *Res = foldOrOfICmps(LHS, Cmp, I)) return replaceInstUsesWith(I, Builder->CreateOr(Res, Y)); if (auto *Cmp = dyn_cast(Y)) - if (Value *Res = foldOrOfICmps(LHS, Cmp, &I)) + if (Value *Res = foldOrOfICmps(LHS, Cmp, I)) return replaceInstUsesWith(I, Builder->CreateOr(Res, X)); } if (RHS && match(Op0, m_OneUse(m_Or(m_Value(X), m_Value(Y))))) { if (auto *Cmp = dyn_cast(X)) - if (Value *Res = foldOrOfICmps(Cmp, RHS, &I)) + if (Value *Res = foldOrOfICmps(Cmp, RHS, I)) return replaceInstUsesWith(I, Builder->CreateOr(Res, Y)); if (auto *Cmp = dyn_cast(Y)) - if (Value *Res = foldOrOfICmps(Cmp, RHS, &I)) + if (Value *Res = foldOrOfICmps(Cmp, RHS, I)) return replaceInstUsesWith(I, Builder->CreateOr(Res, X)); } } diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index d29ed49eca0b..c0830a5d2112 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -94,75 +94,80 @@ static Constant *getNegativeIsTrueBoolVec(ConstantDataVector *V) { return ConstantVector::get(BoolVec); } -Instruction * -InstCombiner::SimplifyElementAtomicMemCpy(ElementAtomicMemCpyInst *AMI) { +Instruction *InstCombiner::SimplifyElementUnorderedAtomicMemCpy( + ElementUnorderedAtomicMemCpyInst *AMI) { // Try to unfold this intrinsic into sequence of explicit atomic loads and // stores. // First check that number of elements is compile time constant. - auto *NumElementsCI = dyn_cast(AMI->getNumElements()); - if (!NumElementsCI) + auto *LengthCI = dyn_cast(AMI->getLength()); + if (!LengthCI) return nullptr; // Check that there are not too many elements. - uint64_t NumElements = NumElementsCI->getZExtValue(); + uint64_t LengthInBytes = LengthCI->getZExtValue(); + uint32_t ElementSizeInBytes = AMI->getElementSizeInBytes(); + uint64_t NumElements = LengthInBytes / ElementSizeInBytes; if (NumElements >= UnfoldElementAtomicMemcpyMaxElements) return nullptr; - // Don't unfold into illegal integers - uint64_t ElementSizeInBytes = AMI->getElementSizeInBytes() * 8; - if (!getDataLayout().isLegalInteger(ElementSizeInBytes)) - return nullptr; + // Only expand if there are elements to copy. + if (NumElements > 0) { + // Don't unfold into illegal integers + uint64_t ElementSizeInBits = ElementSizeInBytes * 8; + if (!getDataLayout().isLegalInteger(ElementSizeInBits)) + return nullptr; - // Cast source and destination to the correct type. Intrinsic input arguments - // are usually represented as i8*. - // Often operands will be explicitly casted to i8* and we can just strip - // those casts instead of inserting new ones. However it's easier to rely on - // other InstCombine rules which will cover trivial cases anyway. - Value *Src = AMI->getRawSource(); - Value *Dst = AMI->getRawDest(); - Type *ElementPointerType = Type::getIntNPtrTy( - AMI->getContext(), ElementSizeInBytes, Src->getType()->getPointerAddressSpace()); + // Cast source and destination to the correct type. Intrinsic input + // arguments are usually represented as i8*. Often operands will be + // explicitly casted to i8* and we can just strip those casts instead of + // inserting new ones. However it's easier to rely on other InstCombine + // rules which will cover trivial cases anyway. + Value *Src = AMI->getRawSource(); + Value *Dst = AMI->getRawDest(); + Type *ElementPointerType = + Type::getIntNPtrTy(AMI->getContext(), ElementSizeInBits, + Src->getType()->getPointerAddressSpace()); - Value *SrcCasted = Builder->CreatePointerCast(Src, ElementPointerType, - "memcpy_unfold.src_casted"); - Value *DstCasted = Builder->CreatePointerCast(Dst, ElementPointerType, - "memcpy_unfold.dst_casted"); + Value *SrcCasted = Builder->CreatePointerCast(Src, ElementPointerType, + "memcpy_unfold.src_casted"); + Value *DstCasted = Builder->CreatePointerCast(Dst, ElementPointerType, + "memcpy_unfold.dst_casted"); - for (uint64_t i = 0; i < NumElements; ++i) { - // Get current element addresses - ConstantInt *ElementIdxCI = - ConstantInt::get(AMI->getContext(), APInt(64, i)); - Value *SrcElementAddr = - Builder->CreateGEP(SrcCasted, ElementIdxCI, "memcpy_unfold.src_addr"); - Value *DstElementAddr = - Builder->CreateGEP(DstCasted, ElementIdxCI, "memcpy_unfold.dst_addr"); + for (uint64_t i = 0; i < NumElements; ++i) { + // Get current element addresses + ConstantInt *ElementIdxCI = + ConstantInt::get(AMI->getContext(), APInt(64, i)); + Value *SrcElementAddr = + Builder->CreateGEP(SrcCasted, ElementIdxCI, "memcpy_unfold.src_addr"); + Value *DstElementAddr = + Builder->CreateGEP(DstCasted, ElementIdxCI, "memcpy_unfold.dst_addr"); - // Load from the source. Transfer alignment information and mark load as - // unordered atomic. - LoadInst *Load = Builder->CreateLoad(SrcElementAddr, "memcpy_unfold.val"); - Load->setOrdering(AtomicOrdering::Unordered); - // We know alignment of the first element. It is also guaranteed by the - // verifier that element size is less or equal than first element alignment - // and both of this values are powers of two. - // This means that all subsequent accesses are at least element size - // aligned. - // TODO: We can infer better alignment but there is no evidence that this - // will matter. - Load->setAlignment(i == 0 ? AMI->getSrcAlignment() - : AMI->getElementSizeInBytes()); - Load->setDebugLoc(AMI->getDebugLoc()); + // Load from the source. Transfer alignment information and mark load as + // unordered atomic. + LoadInst *Load = Builder->CreateLoad(SrcElementAddr, "memcpy_unfold.val"); + Load->setOrdering(AtomicOrdering::Unordered); + // We know alignment of the first element. It is also guaranteed by the + // verifier that element size is less or equal than first element + // alignment and both of this values are powers of two. This means that + // all subsequent accesses are at least element size aligned. + // TODO: We can infer better alignment but there is no evidence that this + // will matter. + Load->setAlignment(i == 0 ? AMI->getParamAlignment(1) + : ElementSizeInBytes); + Load->setDebugLoc(AMI->getDebugLoc()); - // Store loaded value via unordered atomic store. - StoreInst *Store = Builder->CreateStore(Load, DstElementAddr); - Store->setOrdering(AtomicOrdering::Unordered); - Store->setAlignment(i == 0 ? AMI->getDstAlignment() - : AMI->getElementSizeInBytes()); - Store->setDebugLoc(AMI->getDebugLoc()); + // Store loaded value via unordered atomic store. + StoreInst *Store = Builder->CreateStore(Load, DstElementAddr); + Store->setOrdering(AtomicOrdering::Unordered); + Store->setAlignment(i == 0 ? AMI->getParamAlignment(0) + : ElementSizeInBytes); + Store->setDebugLoc(AMI->getDebugLoc()); + } } // Set the number of elements of the copy to 0, it will be deleted on the // next iteration. - AMI->setNumElements(Constant::getNullValue(NumElementsCI->getType())); + AMI->setLength(Constant::getNullValue(LengthCI->getType())); return AMI; } @@ -1888,12 +1893,12 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { if (Changed) return II; } - if (auto *AMI = dyn_cast(II)) { - if (Constant *C = dyn_cast(AMI->getNumElements())) + if (auto *AMI = dyn_cast(II)) { + if (Constant *C = dyn_cast(AMI->getLength())) if (C->isNullValue()) return eraseInstFromFunction(*AMI); - if (Instruction *I = SimplifyElementAtomicMemCpy(AMI)) + if (Instruction *I = SimplifyElementUnorderedAtomicMemCpy(AMI)) return I; } diff --git a/lib/Transforms/InstCombine/InstCombineInternal.h b/lib/Transforms/InstCombine/InstCombineInternal.h index fd0a64a5bbb5..1a7db146df42 100644 --- a/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/lib/Transforms/InstCombine/InstCombineInternal.h @@ -447,12 +447,14 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner Instruction::CastOps isEliminableCastPair(const CastInst *CI1, const CastInst *CI2); - Value *foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS); + Value *foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS, Instruction &CxtI); Value *foldAndOfFCmps(FCmpInst *LHS, FCmpInst *RHS); - Value *foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, Instruction *CxtI); + Value *foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, Instruction &CxtI); Value *foldOrOfFCmps(FCmpInst *LHS, FCmpInst *RHS); Value *foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS); + Value *foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS, ICmpInst *RHS, + bool JoinedByAnd, Instruction &CxtI); public: /// \brief Inserts an instruction \p New before instruction \p Old /// @@ -724,7 +726,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner Instruction *MatchBSwap(BinaryOperator &I); bool SimplifyStoreAtEndOfBlock(StoreInst &SI); - Instruction *SimplifyElementAtomicMemCpy(ElementAtomicMemCpyInst *AMI); + Instruction * + SimplifyElementUnorderedAtomicMemCpy(ElementUnorderedAtomicMemCpyInst *AMI); Instruction *SimplifyMemTransfer(MemIntrinsic *MI); Instruction *SimplifyMemSet(MemSetInst *MI); diff --git a/lib/Transforms/InstCombine/InstCombineShifts.cpp b/lib/Transforms/InstCombine/InstCombineShifts.cpp index 3f2ddcacce2b..8cec865c6422 100644 --- a/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -682,11 +682,11 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, Mask)); } - if (match(Op0, m_SExt(m_Value(X)))) { + if (match(Op0, m_SExt(m_Value(X))) && + (!Ty->isIntegerTy() || shouldChangeType(Ty, X->getType()))) { // Are we moving the sign bit to the low bit and widening with high zeros? unsigned SrcTyBitWidth = X->getType()->getScalarSizeInBits(); - if (ShAmt == BitWidth - 1 && - (!Ty->isIntegerTy() || shouldChangeType(Ty, X->getType()))) { + if (ShAmt == BitWidth - 1) { // lshr (sext i1 X to iN), N-1 --> zext X to iN if (SrcTyBitWidth == 1) return new ZExtInst(X, Ty); @@ -698,7 +698,13 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { } } - // TODO: Convert to ashr+zext if the shift equals the extension amount. + // lshr (sext iM X to iN), N-M --> zext (ashr X, min(N-M, M-1)) to iN + if (ShAmt == BitWidth - SrcTyBitWidth && Op0->hasOneUse()) { + // The new shift amount can't be more than the narrow source type. + unsigned NewShAmt = std::min(ShAmt, SrcTyBitWidth - 1); + Value *AShr = Builder->CreateAShr(X, NewShAmt); + return new ZExtInst(AShr, Ty); + } } if (match(Op0, m_LShr(m_Value(X), m_APInt(ShOp1)))) { diff --git a/lib/Transforms/Instrumentation/CMakeLists.txt b/lib/Transforms/Instrumentation/CMakeLists.txt index 7ff69b9eb7f4..f2806e278e6e 100644 --- a/lib/Transforms/Instrumentation/CMakeLists.txt +++ b/lib/Transforms/Instrumentation/CMakeLists.txt @@ -8,6 +8,7 @@ add_llvm_library(LLVMInstrumentation Instrumentation.cpp InstrProfiling.cpp PGOInstrumentation.cpp + PGOMemOPSizeOpt.cpp SanitizerCoverage.cpp ThreadSanitizer.cpp EfficiencySanitizer.cpp diff --git a/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp b/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp index 96027bc3d0a9..0d308810009d 100644 --- a/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp +++ b/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp @@ -56,8 +56,6 @@ using namespace llvm; STATISTIC(NumOfPGOICallPromotion, "Number of indirect call promotions."); STATISTIC(NumOfPGOICallsites, "Number of indirect call candidate sites."); -STATISTIC(NumOfPGOMemOPOpt, "Number of memop intrinsics optimized."); -STATISTIC(NumOfPGOMemOPAnnotate, "Number of memop intrinsics annotated."); // Command line option to disable indirect-call promotion with the default as // false. This is for debug purpose. @@ -111,44 +109,6 @@ static cl::opt ICPDUMPAFTER("icp-dumpafter", cl::init(false), cl::Hidden, cl::desc("Dump IR after transformation happens")); -// The minimum call count to optimize memory intrinsic calls. -static cl::opt - MemOPCountThreshold("pgo-memop-count-threshold", cl::Hidden, cl::ZeroOrMore, - cl::init(1000), - cl::desc("The minimum count to optimize memory " - "intrinsic calls")); - -// Command line option to disable memory intrinsic optimization. The default is -// false. This is for debug purpose. -static cl::opt DisableMemOPOPT("disable-memop-opt", cl::init(false), - cl::Hidden, cl::desc("Disable optimize")); - -// The percent threshold to optimize memory intrinsic calls. -static cl::opt - MemOPPercentThreshold("pgo-memop-percent-threshold", cl::init(40), - cl::Hidden, cl::ZeroOrMore, - cl::desc("The percentage threshold for the " - "memory intrinsic calls optimization")); - -// Maximum number of versions for optimizing memory intrinsic call. -static cl::opt - MemOPMaxVersion("pgo-memop-max-version", cl::init(3), cl::Hidden, - cl::ZeroOrMore, - cl::desc("The max version for the optimized memory " - " intrinsic calls")); - -// Scale the counts from the annotation using the BB count value. -static cl::opt - MemOPScaleCount("pgo-memop-scale-count", cl::init(true), cl::Hidden, - cl::desc("Scale the memop size counts using the basic " - " block count value")); - -// This option sets the rangge of precise profile memop sizes. -extern cl::opt MemOPSizeRange; - -// This option sets the value that groups large memop sizes -extern cl::opt MemOPSizeLarge; - namespace { class PGOIndirectCallPromotionLegacyPass : public ModulePass { public: @@ -173,24 +133,6 @@ class PGOIndirectCallPromotionLegacyPass : public ModulePass { // the promoted direct call. bool SamplePGO; }; - -class PGOMemOPSizeOptLegacyPass : public FunctionPass { -public: - static char ID; - - PGOMemOPSizeOptLegacyPass() : FunctionPass(ID) { - initializePGOMemOPSizeOptLegacyPassPass(*PassRegistry::getPassRegistry()); - } - - StringRef getPassName() const override { return "PGOMemOPSize"; } - -private: - bool runOnFunction(Function &F) override; - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - AU.addPreserved(); - } -}; } // end anonymous namespace char PGOIndirectCallPromotionLegacyPass::ID = 0; @@ -204,19 +146,6 @@ ModulePass *llvm::createPGOIndirectCallPromotionLegacyPass(bool InLTO, return new PGOIndirectCallPromotionLegacyPass(InLTO, SamplePGO); } -char PGOMemOPSizeOptLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(PGOMemOPSizeOptLegacyPass, "pgo-memop-opt", - "Optimize memory intrinsic using its size value profile", - false, false) -INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) -INITIALIZE_PASS_END(PGOMemOPSizeOptLegacyPass, "pgo-memop-opt", - "Optimize memory intrinsic using its size value profile", - false, false) - -FunctionPass *llvm::createPGOMemOPSizeOptLegacyPass() { - return new PGOMemOPSizeOptLegacyPass(); -} - namespace { // The class for main data structure to promote indirect calls to conditional // direct calls. @@ -749,285 +678,3 @@ PreservedAnalyses PGOIndirectCallPromotion::run(Module &M, return PreservedAnalyses::none(); } - -namespace { -class MemOPSizeOpt : public InstVisitor { -public: - MemOPSizeOpt(Function &Func, BlockFrequencyInfo &BFI) - : Func(Func), BFI(BFI), Changed(false) { - ValueDataArray = - llvm::make_unique(MemOPMaxVersion + 2); - // Get the MemOPSize range information from option MemOPSizeRange, - getMemOPSizeRangeFromOption(MemOPSizeRange, PreciseRangeStart, - PreciseRangeLast); - } - bool isChanged() const { return Changed; } - void perform() { - WorkList.clear(); - visit(Func); - - for (auto &MI : WorkList) { - ++NumOfPGOMemOPAnnotate; - if (perform(MI)) { - Changed = true; - ++NumOfPGOMemOPOpt; - DEBUG(dbgs() << "MemOP call: " << MI->getCalledFunction()->getName() - << "is Transformed.\n"); - } - } - } - - void visitMemIntrinsic(MemIntrinsic &MI) { - Value *Length = MI.getLength(); - // Not perform on constant length calls. - if (dyn_cast(Length)) - return; - WorkList.push_back(&MI); - } - -private: - Function &Func; - BlockFrequencyInfo &BFI; - bool Changed; - std::vector WorkList; - // Start of the previse range. - int64_t PreciseRangeStart; - // Last value of the previse range. - int64_t PreciseRangeLast; - // The space to read the profile annotation. - std::unique_ptr ValueDataArray; - bool perform(MemIntrinsic *MI); - - // This kind shows which group the value falls in. For PreciseValue, we have - // the profile count for that value. LargeGroup groups the values that are in - // range [LargeValue, +inf). NonLargeGroup groups the rest of values. - enum MemOPSizeKind { PreciseValue, NonLargeGroup, LargeGroup }; - - MemOPSizeKind getMemOPSizeKind(int64_t Value) const { - if (Value == MemOPSizeLarge && MemOPSizeLarge != 0) - return LargeGroup; - if (Value == PreciseRangeLast + 1) - return NonLargeGroup; - return PreciseValue; - } -}; - -static const char *getMIName(const MemIntrinsic *MI) { - switch (MI->getIntrinsicID()) { - case Intrinsic::memcpy: - return "memcpy"; - case Intrinsic::memmove: - return "memmove"; - case Intrinsic::memset: - return "memset"; - default: - return "unknown"; - } -} - -static bool isProfitable(uint64_t Count, uint64_t TotalCount) { - assert(Count <= TotalCount); - if (Count < MemOPCountThreshold) - return false; - if (Count < TotalCount * MemOPPercentThreshold / 100) - return false; - return true; -} - -static inline uint64_t getScaledCount(uint64_t Count, uint64_t Num, - uint64_t Denom) { - if (!MemOPScaleCount) - return Count; - bool Overflowed; - uint64_t ScaleCount = SaturatingMultiply(Count, Num, &Overflowed); - return ScaleCount / Denom; -} - -bool MemOPSizeOpt::perform(MemIntrinsic *MI) { - assert(MI); - if (MI->getIntrinsicID() == Intrinsic::memmove) - return false; - - uint32_t NumVals, MaxNumPromotions = MemOPMaxVersion + 2; - uint64_t TotalCount; - if (!getValueProfDataFromInst(*MI, IPVK_MemOPSize, MaxNumPromotions, - ValueDataArray.get(), NumVals, TotalCount)) - return false; - - uint64_t ActualCount = TotalCount; - uint64_t SavedTotalCount = TotalCount; - if (MemOPScaleCount) { - auto BBEdgeCount = BFI.getBlockProfileCount(MI->getParent()); - if (!BBEdgeCount) - return false; - ActualCount = *BBEdgeCount; - } - - ArrayRef VDs(ValueDataArray.get(), NumVals); - DEBUG(dbgs() << "Read one memory intrinsic profile with count " << ActualCount - << "\n"); - DEBUG( - for (auto &VD - : VDs) { dbgs() << " (" << VD.Value << "," << VD.Count << ")\n"; }); - - if (ActualCount < MemOPCountThreshold) - return false; - // Skip if the total value profiled count is 0, in which case we can't - // scale up the counts properly (and there is no profitable transformation). - if (TotalCount == 0) - return false; - - TotalCount = ActualCount; - if (MemOPScaleCount) - DEBUG(dbgs() << "Scale counts: numerator = " << ActualCount - << " denominator = " << SavedTotalCount << "\n"); - - // Keeping track of the count of the default case: - uint64_t RemainCount = TotalCount; - SmallVector SizeIds; - SmallVector CaseCounts; - uint64_t MaxCount = 0; - unsigned Version = 0; - // Default case is in the front -- save the slot here. - CaseCounts.push_back(0); - for (auto &VD : VDs) { - int64_t V = VD.Value; - uint64_t C = VD.Count; - if (MemOPScaleCount) - C = getScaledCount(C, ActualCount, SavedTotalCount); - - // Only care precise value here. - if (getMemOPSizeKind(V) != PreciseValue) - continue; - - // ValueCounts are sorted on the count. Break at the first un-profitable - // value. - if (!isProfitable(C, RemainCount)) - break; - - SizeIds.push_back(V); - CaseCounts.push_back(C); - if (C > MaxCount) - MaxCount = C; - - assert(RemainCount >= C); - RemainCount -= C; - - if (++Version > MemOPMaxVersion && MemOPMaxVersion != 0) - break; - } - - if (Version == 0) - return false; - - CaseCounts[0] = RemainCount; - if (RemainCount > MaxCount) - MaxCount = RemainCount; - - uint64_t SumForOpt = TotalCount - RemainCount; - - DEBUG(dbgs() << "Optimize one memory intrinsic call to " << Version - << " Versions (covering " << SumForOpt << " out of " - << TotalCount << ")\n"); - - // mem_op(..., size) - // ==> - // switch (size) { - // case s1: - // mem_op(..., s1); - // goto merge_bb; - // case s2: - // mem_op(..., s2); - // goto merge_bb; - // ... - // default: - // mem_op(..., size); - // goto merge_bb; - // } - // merge_bb: - - BasicBlock *BB = MI->getParent(); - DEBUG(dbgs() << "\n\n== Basic Block Before ==\n"); - DEBUG(dbgs() << *BB << "\n"); - auto OrigBBFreq = BFI.getBlockFreq(BB); - - BasicBlock *DefaultBB = SplitBlock(BB, MI); - BasicBlock::iterator It(*MI); - ++It; - assert(It != DefaultBB->end()); - BasicBlock *MergeBB = SplitBlock(DefaultBB, &(*It)); - MergeBB->setName("MemOP.Merge"); - BFI.setBlockFreq(MergeBB, OrigBBFreq.getFrequency()); - DefaultBB->setName("MemOP.Default"); - - auto &Ctx = Func.getContext(); - IRBuilder<> IRB(BB); - BB->getTerminator()->eraseFromParent(); - Value *SizeVar = MI->getLength(); - SwitchInst *SI = IRB.CreateSwitch(SizeVar, DefaultBB, SizeIds.size()); - - // Clear the value profile data. - MI->setMetadata(LLVMContext::MD_prof, nullptr); - - DEBUG(dbgs() << "\n\n== Basic Block After==\n"); - - for (uint64_t SizeId : SizeIds) { - ConstantInt *CaseSizeId = ConstantInt::get(Type::getInt64Ty(Ctx), SizeId); - BasicBlock *CaseBB = BasicBlock::Create( - Ctx, Twine("MemOP.Case.") + Twine(SizeId), &Func, DefaultBB); - Instruction *NewInst = MI->clone(); - // Fix the argument. - dyn_cast(NewInst)->setLength(CaseSizeId); - CaseBB->getInstList().push_back(NewInst); - IRBuilder<> IRBCase(CaseBB); - IRBCase.CreateBr(MergeBB); - SI->addCase(CaseSizeId, CaseBB); - DEBUG(dbgs() << *CaseBB << "\n"); - } - setProfMetadata(Func.getParent(), SI, CaseCounts, MaxCount); - - DEBUG(dbgs() << *BB << "\n"); - DEBUG(dbgs() << *DefaultBB << "\n"); - DEBUG(dbgs() << *MergeBB << "\n"); - - emitOptimizationRemark(Func.getContext(), "memop-opt", Func, - MI->getDebugLoc(), - Twine("optimize ") + getMIName(MI) + " with count " + - Twine(SumForOpt) + " out of " + Twine(TotalCount) + - " for " + Twine(Version) + " versions"); - - return true; -} -} // namespace - -static bool PGOMemOPSizeOptImpl(Function &F, BlockFrequencyInfo &BFI) { - if (DisableMemOPOPT) - return false; - - if (F.hasFnAttribute(Attribute::OptimizeForSize)) - return false; - MemOPSizeOpt MemOPSizeOpt(F, BFI); - MemOPSizeOpt.perform(); - return MemOPSizeOpt.isChanged(); -} - -bool PGOMemOPSizeOptLegacyPass::runOnFunction(Function &F) { - BlockFrequencyInfo &BFI = - getAnalysis().getBFI(); - return PGOMemOPSizeOptImpl(F, BFI); -} - -namespace llvm { -char &PGOMemOPSizeOptID = PGOMemOPSizeOptLegacyPass::ID; - -PreservedAnalyses PGOMemOPSizeOpt::run(Function &F, - FunctionAnalysisManager &FAM) { - auto &BFI = FAM.getResult(F); - bool Changed = PGOMemOPSizeOptImpl(F, BFI); - if (!Changed) - return PreservedAnalyses::all(); - auto PA = PreservedAnalyses(); - PA.preserve(); - return PA; -} -} // namespace llvm diff --git a/lib/Transforms/Instrumentation/InstrProfiling.cpp b/lib/Transforms/Instrumentation/InstrProfiling.cpp index f83c930ca61b..37f88d5f95f1 100644 --- a/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -343,14 +343,24 @@ static std::string getVarName(InstrProfIncrementInst *Inc, StringRef Prefix) { static inline bool shouldRecordFunctionAddr(Function *F) { // Check the linkage + bool HasAvailableExternallyLinkage = F->hasAvailableExternallyLinkage(); if (!F->hasLinkOnceLinkage() && !F->hasLocalLinkage() && - !F->hasAvailableExternallyLinkage()) + !HasAvailableExternallyLinkage) return true; + + // A function marked 'alwaysinline' with available_externally linkage can't + // have its address taken. Doing so would create an undefined external ref to + // the function, which would fail to link. + if (HasAvailableExternallyLinkage && + F->hasFnAttribute(Attribute::AlwaysInline)) + return false; + // Prohibit function address recording if the function is both internal and // COMDAT. This avoids the profile data variable referencing internal symbols // in COMDAT. if (F->hasLocalLinkage() && F->hasComdat()) return false; + // Check uses of this function for other than direct calls or invokes to it. // Inline virtual functions have linkeOnceODR linkage. When a key method // exists, the vtable will only be emitted in the TU where the key method diff --git a/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp b/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp new file mode 100644 index 000000000000..0bc9ddfbe4d3 --- /dev/null +++ b/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp @@ -0,0 +1,419 @@ +//===-- PGOMemOPSizeOpt.cpp - Optimizations based on value profiling ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the transformation that optimizes memory intrinsics +// such as memcpy using the size value profile. When memory intrinsic size +// value profile metadata is available, a single memory intrinsic is expanded +// to a sequence of guarded specialized versions that are called with the +// hottest size(s), for later expansion into more optimal inline sequences. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Type.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" +#include "llvm/PassSupport.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/PGOInstrumentation.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "pgo-memop-opt" + +STATISTIC(NumOfPGOMemOPOpt, "Number of memop intrinsics optimized."); +STATISTIC(NumOfPGOMemOPAnnotate, "Number of memop intrinsics annotated."); + +// The minimum call count to optimize memory intrinsic calls. +static cl::opt + MemOPCountThreshold("pgo-memop-count-threshold", cl::Hidden, cl::ZeroOrMore, + cl::init(1000), + cl::desc("The minimum count to optimize memory " + "intrinsic calls")); + +// Command line option to disable memory intrinsic optimization. The default is +// false. This is for debug purpose. +static cl::opt DisableMemOPOPT("disable-memop-opt", cl::init(false), + cl::Hidden, cl::desc("Disable optimize")); + +// The percent threshold to optimize memory intrinsic calls. +static cl::opt + MemOPPercentThreshold("pgo-memop-percent-threshold", cl::init(40), + cl::Hidden, cl::ZeroOrMore, + cl::desc("The percentage threshold for the " + "memory intrinsic calls optimization")); + +// Maximum number of versions for optimizing memory intrinsic call. +static cl::opt + MemOPMaxVersion("pgo-memop-max-version", cl::init(3), cl::Hidden, + cl::ZeroOrMore, + cl::desc("The max version for the optimized memory " + " intrinsic calls")); + +// Scale the counts from the annotation using the BB count value. +static cl::opt + MemOPScaleCount("pgo-memop-scale-count", cl::init(true), cl::Hidden, + cl::desc("Scale the memop size counts using the basic " + " block count value")); + +// This option sets the rangge of precise profile memop sizes. +extern cl::opt MemOPSizeRange; + +// This option sets the value that groups large memop sizes +extern cl::opt MemOPSizeLarge; + +namespace { +class PGOMemOPSizeOptLegacyPass : public FunctionPass { +public: + static char ID; + + PGOMemOPSizeOptLegacyPass() : FunctionPass(ID) { + initializePGOMemOPSizeOptLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "PGOMemOPSize"; } + +private: + bool runOnFunction(Function &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + } +}; +} // end anonymous namespace + +char PGOMemOPSizeOptLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(PGOMemOPSizeOptLegacyPass, "pgo-memop-opt", + "Optimize memory intrinsic using its size value profile", + false, false) +INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) +INITIALIZE_PASS_END(PGOMemOPSizeOptLegacyPass, "pgo-memop-opt", + "Optimize memory intrinsic using its size value profile", + false, false) + +FunctionPass *llvm::createPGOMemOPSizeOptLegacyPass() { + return new PGOMemOPSizeOptLegacyPass(); +} + +namespace { +class MemOPSizeOpt : public InstVisitor { +public: + MemOPSizeOpt(Function &Func, BlockFrequencyInfo &BFI) + : Func(Func), BFI(BFI), Changed(false) { + ValueDataArray = + llvm::make_unique(MemOPMaxVersion + 2); + // Get the MemOPSize range information from option MemOPSizeRange, + getMemOPSizeRangeFromOption(MemOPSizeRange, PreciseRangeStart, + PreciseRangeLast); + } + bool isChanged() const { return Changed; } + void perform() { + WorkList.clear(); + visit(Func); + + for (auto &MI : WorkList) { + ++NumOfPGOMemOPAnnotate; + if (perform(MI)) { + Changed = true; + ++NumOfPGOMemOPOpt; + DEBUG(dbgs() << "MemOP call: " << MI->getCalledFunction()->getName() + << "is Transformed.\n"); + } + } + } + + void visitMemIntrinsic(MemIntrinsic &MI) { + Value *Length = MI.getLength(); + // Not perform on constant length calls. + if (dyn_cast(Length)) + return; + WorkList.push_back(&MI); + } + +private: + Function &Func; + BlockFrequencyInfo &BFI; + bool Changed; + std::vector WorkList; + // Start of the previse range. + int64_t PreciseRangeStart; + // Last value of the previse range. + int64_t PreciseRangeLast; + // The space to read the profile annotation. + std::unique_ptr ValueDataArray; + bool perform(MemIntrinsic *MI); + + // This kind shows which group the value falls in. For PreciseValue, we have + // the profile count for that value. LargeGroup groups the values that are in + // range [LargeValue, +inf). NonLargeGroup groups the rest of values. + enum MemOPSizeKind { PreciseValue, NonLargeGroup, LargeGroup }; + + MemOPSizeKind getMemOPSizeKind(int64_t Value) const { + if (Value == MemOPSizeLarge && MemOPSizeLarge != 0) + return LargeGroup; + if (Value == PreciseRangeLast + 1) + return NonLargeGroup; + return PreciseValue; + } +}; + +static const char *getMIName(const MemIntrinsic *MI) { + switch (MI->getIntrinsicID()) { + case Intrinsic::memcpy: + return "memcpy"; + case Intrinsic::memmove: + return "memmove"; + case Intrinsic::memset: + return "memset"; + default: + return "unknown"; + } +} + +static bool isProfitable(uint64_t Count, uint64_t TotalCount) { + assert(Count <= TotalCount); + if (Count < MemOPCountThreshold) + return false; + if (Count < TotalCount * MemOPPercentThreshold / 100) + return false; + return true; +} + +static inline uint64_t getScaledCount(uint64_t Count, uint64_t Num, + uint64_t Denom) { + if (!MemOPScaleCount) + return Count; + bool Overflowed; + uint64_t ScaleCount = SaturatingMultiply(Count, Num, &Overflowed); + return ScaleCount / Denom; +} + +bool MemOPSizeOpt::perform(MemIntrinsic *MI) { + assert(MI); + if (MI->getIntrinsicID() == Intrinsic::memmove) + return false; + + uint32_t NumVals, MaxNumPromotions = MemOPMaxVersion + 2; + uint64_t TotalCount; + if (!getValueProfDataFromInst(*MI, IPVK_MemOPSize, MaxNumPromotions, + ValueDataArray.get(), NumVals, TotalCount)) + return false; + + uint64_t ActualCount = TotalCount; + uint64_t SavedTotalCount = TotalCount; + if (MemOPScaleCount) { + auto BBEdgeCount = BFI.getBlockProfileCount(MI->getParent()); + if (!BBEdgeCount) + return false; + ActualCount = *BBEdgeCount; + } + + ArrayRef VDs(ValueDataArray.get(), NumVals); + DEBUG(dbgs() << "Read one memory intrinsic profile with count " << ActualCount + << "\n"); + DEBUG( + for (auto &VD + : VDs) { dbgs() << " (" << VD.Value << "," << VD.Count << ")\n"; }); + + if (ActualCount < MemOPCountThreshold) + return false; + // Skip if the total value profiled count is 0, in which case we can't + // scale up the counts properly (and there is no profitable transformation). + if (TotalCount == 0) + return false; + + TotalCount = ActualCount; + if (MemOPScaleCount) + DEBUG(dbgs() << "Scale counts: numerator = " << ActualCount + << " denominator = " << SavedTotalCount << "\n"); + + // Keeping track of the count of the default case: + uint64_t RemainCount = TotalCount; + uint64_t SavedRemainCount = SavedTotalCount; + SmallVector SizeIds; + SmallVector CaseCounts; + uint64_t MaxCount = 0; + unsigned Version = 0; + // Default case is in the front -- save the slot here. + CaseCounts.push_back(0); + for (auto &VD : VDs) { + int64_t V = VD.Value; + uint64_t C = VD.Count; + if (MemOPScaleCount) + C = getScaledCount(C, ActualCount, SavedTotalCount); + + // Only care precise value here. + if (getMemOPSizeKind(V) != PreciseValue) + continue; + + // ValueCounts are sorted on the count. Break at the first un-profitable + // value. + if (!isProfitable(C, RemainCount)) + break; + + SizeIds.push_back(V); + CaseCounts.push_back(C); + if (C > MaxCount) + MaxCount = C; + + assert(RemainCount >= C); + RemainCount -= C; + assert(SavedRemainCount >= VD.Count); + SavedRemainCount -= VD.Count; + + if (++Version > MemOPMaxVersion && MemOPMaxVersion != 0) + break; + } + + if (Version == 0) + return false; + + CaseCounts[0] = RemainCount; + if (RemainCount > MaxCount) + MaxCount = RemainCount; + + uint64_t SumForOpt = TotalCount - RemainCount; + + DEBUG(dbgs() << "Optimize one memory intrinsic call to " << Version + << " Versions (covering " << SumForOpt << " out of " + << TotalCount << ")\n"); + + // mem_op(..., size) + // ==> + // switch (size) { + // case s1: + // mem_op(..., s1); + // goto merge_bb; + // case s2: + // mem_op(..., s2); + // goto merge_bb; + // ... + // default: + // mem_op(..., size); + // goto merge_bb; + // } + // merge_bb: + + BasicBlock *BB = MI->getParent(); + DEBUG(dbgs() << "\n\n== Basic Block Before ==\n"); + DEBUG(dbgs() << *BB << "\n"); + auto OrigBBFreq = BFI.getBlockFreq(BB); + + BasicBlock *DefaultBB = SplitBlock(BB, MI); + BasicBlock::iterator It(*MI); + ++It; + assert(It != DefaultBB->end()); + BasicBlock *MergeBB = SplitBlock(DefaultBB, &(*It)); + MergeBB->setName("MemOP.Merge"); + BFI.setBlockFreq(MergeBB, OrigBBFreq.getFrequency()); + DefaultBB->setName("MemOP.Default"); + + auto &Ctx = Func.getContext(); + IRBuilder<> IRB(BB); + BB->getTerminator()->eraseFromParent(); + Value *SizeVar = MI->getLength(); + SwitchInst *SI = IRB.CreateSwitch(SizeVar, DefaultBB, SizeIds.size()); + + // Clear the value profile data. + MI->setMetadata(LLVMContext::MD_prof, nullptr); + // If all promoted, we don't need the MD.prof metadata. + if (SavedRemainCount > 0 || Version != NumVals) + // Otherwise we need update with the un-promoted records back. + annotateValueSite(*Func.getParent(), *MI, VDs.slice(Version), + SavedRemainCount, IPVK_MemOPSize, NumVals); + + DEBUG(dbgs() << "\n\n== Basic Block After==\n"); + + for (uint64_t SizeId : SizeIds) { + ConstantInt *CaseSizeId = ConstantInt::get(Type::getInt64Ty(Ctx), SizeId); + BasicBlock *CaseBB = BasicBlock::Create( + Ctx, Twine("MemOP.Case.") + Twine(SizeId), &Func, DefaultBB); + Instruction *NewInst = MI->clone(); + // Fix the argument. + dyn_cast(NewInst)->setLength(CaseSizeId); + CaseBB->getInstList().push_back(NewInst); + IRBuilder<> IRBCase(CaseBB); + IRBCase.CreateBr(MergeBB); + SI->addCase(CaseSizeId, CaseBB); + DEBUG(dbgs() << *CaseBB << "\n"); + } + setProfMetadata(Func.getParent(), SI, CaseCounts, MaxCount); + + DEBUG(dbgs() << *BB << "\n"); + DEBUG(dbgs() << *DefaultBB << "\n"); + DEBUG(dbgs() << *MergeBB << "\n"); + + emitOptimizationRemark(Func.getContext(), "memop-opt", Func, + MI->getDebugLoc(), + Twine("optimize ") + getMIName(MI) + " with count " + + Twine(SumForOpt) + " out of " + Twine(TotalCount) + + " for " + Twine(Version) + " versions"); + + return true; +} +} // namespace + +static bool PGOMemOPSizeOptImpl(Function &F, BlockFrequencyInfo &BFI) { + if (DisableMemOPOPT) + return false; + + if (F.hasFnAttribute(Attribute::OptimizeForSize)) + return false; + MemOPSizeOpt MemOPSizeOpt(F, BFI); + MemOPSizeOpt.perform(); + return MemOPSizeOpt.isChanged(); +} + +bool PGOMemOPSizeOptLegacyPass::runOnFunction(Function &F) { + BlockFrequencyInfo &BFI = + getAnalysis().getBFI(); + return PGOMemOPSizeOptImpl(F, BFI); +} + +namespace llvm { +char &PGOMemOPSizeOptID = PGOMemOPSizeOptLegacyPass::ID; + +PreservedAnalyses PGOMemOPSizeOpt::run(Function &F, + FunctionAnalysisManager &FAM) { + auto &BFI = FAM.getResult(F); + bool Changed = PGOMemOPSizeOptImpl(F, BFI); + if (!Changed) + return PreservedAnalyses::all(); + auto PA = PreservedAnalyses(); + PA.preserve(); + return PA; +} +} // namespace llvm diff --git a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index 8aa40d1759de..e3c36c98ab0d 100644 --- a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -61,7 +61,7 @@ static const char *const SanCov8bitCountersInitName = "__sanitizer_cov_8bit_counters_init"; static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_counters"; +static const char *const SanCovCountersSectionName = "sancov_cntrs"; static cl::opt ClCoverageLevel( "sanitizer-coverage-level", diff --git a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 7b625b9b136e..2a4c9526dfcd 100644 --- a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -551,7 +551,7 @@ static bool runImpl(Function &F, LazyValueInfo *LVI, const SimplifyQuery &SQ) { BBChanged = true; } } - }; + } FnChanged |= BBChanged; } diff --git a/lib/Transforms/Scalar/EarlyCSE.cpp b/lib/Transforms/Scalar/EarlyCSE.cpp index c4f450949e6d..0f92760a874b 100644 --- a/lib/Transforms/Scalar/EarlyCSE.cpp +++ b/lib/Transforms/Scalar/EarlyCSE.cpp @@ -15,6 +15,7 @@ #include "llvm/Transforms/Scalar/EarlyCSE.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/ScopedHashTable.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/GlobalsModRef.h" @@ -506,7 +507,7 @@ class EarlyCSE { if (MemoryAccess *MA = MSSA->getMemoryAccess(Inst)) { // Optimize MemoryPhi nodes that may become redundant by having all the // same input values once MA is removed. - SmallVector PhisToCheck; + SmallSetVector PhisToCheck; SmallVector WorkQueue; WorkQueue.push_back(MA); // Process MemoryPhi nodes in FIFO order using a ever-growing vector since @@ -517,7 +518,7 @@ class EarlyCSE { for (auto *U : WI->users()) if (MemoryPhi *MP = dyn_cast(U)) - PhisToCheck.push_back(MP); + PhisToCheck.insert(MP); MSSAUpdater->removeMemoryAccess(WI); diff --git a/lib/Transforms/Scalar/GVNSink.cpp b/lib/Transforms/Scalar/GVNSink.cpp index 8634816e702f..5fd2dfc118b4 100644 --- a/lib/Transforms/Scalar/GVNSink.cpp +++ b/lib/Transforms/Scalar/GVNSink.cpp @@ -64,6 +64,17 @@ using namespace llvm; STATISTIC(NumRemoved, "Number of instructions removed"); +namespace llvm { +namespace GVNExpression { + +LLVM_DUMP_METHOD void Expression::dump() const { + print(dbgs()); + dbgs() << "\n"; +} + +} +} + namespace { static bool isMemoryInst(const Instruction *I) { diff --git a/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/lib/Transforms/Scalar/LoopIdiomRecognize.cpp index b706152f30c8..8b435050ac76 100644 --- a/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ b/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -983,21 +983,21 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, const SCEV *NumBytesS = SE->getAddExpr(BECount, SE->getOne(IntPtrTy), SCEV::FlagNUW); + if (StoreSize != 1) + NumBytesS = SE->getMulExpr(NumBytesS, SE->getConstant(IntPtrTy, StoreSize), + SCEV::FlagNUW); + + Value *NumBytes = + Expander.expandCodeFor(NumBytesS, IntPtrTy, Preheader->getTerminator()); + unsigned Align = std::min(SI->getAlignment(), LI->getAlignment()); CallInst *NewCall = nullptr; // Check whether to generate an unordered atomic memcpy: // If the load or store are atomic, then they must neccessarily be unordered // by previous checks. - if (!SI->isAtomic() && !LI->isAtomic()) { - if (StoreSize != 1) - NumBytesS = SE->getMulExpr( - NumBytesS, SE->getConstant(IntPtrTy, StoreSize), SCEV::FlagNUW); - - Value *NumBytes = - Expander.expandCodeFor(NumBytesS, IntPtrTy, Preheader->getTerminator()); - + if (!SI->isAtomic() && !LI->isAtomic()) NewCall = Builder.CreateMemCpy(StoreBasePtr, LoadBasePtr, NumBytes, Align); - } else { + else { // We cannot allow unaligned ops for unordered load/store, so reject // anything where the alignment isn't at least the element size. if (Align < StoreSize) @@ -1010,11 +1010,9 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, if (StoreSize > TTI->getAtomicMemIntrinsicMaxElementSize()) return false; - Value *NumElements = - Expander.expandCodeFor(NumBytesS, IntPtrTy, Preheader->getTerminator()); + NewCall = Builder.CreateElementUnorderedAtomicMemCpy( + StoreBasePtr, LoadBasePtr, NumBytes, StoreSize); - NewCall = Builder.CreateElementAtomicMemCpy(StoreBasePtr, LoadBasePtr, - NumElements, StoreSize); // Propagate alignment info onto the pointer args. Note that unordered // atomic loads/stores are *required* by the spec to have an alignment // but non-atomic loads/stores may not. diff --git a/lib/Transforms/Scalar/NewGVN.cpp b/lib/Transforms/Scalar/NewGVN.cpp index 6926aae37963..cbbd55512c9f 100644 --- a/lib/Transforms/Scalar/NewGVN.cpp +++ b/lib/Transforms/Scalar/NewGVN.cpp @@ -2195,7 +2195,7 @@ void NewGVN::moveValueToNewCongruenceClass(Instruction *I, const Expression *E, // For a given expression, mark the phi of ops instructions that could have // changed as a result. void NewGVN::markPhiOfOpsChanged(const Expression *E) { - touchAndErase(ExpressionToPhiOfOps, E); + touchAndErase(ExpressionToPhiOfOps, ExactEqualsExpression(*E)); } // Perform congruence finding on a given value numbering expression. @@ -3561,7 +3561,7 @@ bool NewGVN::eliminateInstructions(Function &F) { // TODO: It would be faster to use getNumIncomingBlocks() on a phi node in // the block and subtract the pred count, but it's more complicated. if (ReachablePredCount.lookup(BB) != - std::distance(pred_begin(BB), pred_end(BB))) { + unsigned(std::distance(pred_begin(BB), pred_end(BB)))) { for (auto II = BB->begin(); isa(II); ++II) { auto &PHI = cast(*II); ReplaceUnreachablePHIArgs(PHI, BB); diff --git a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index bae7911d222c..a52739bb76f7 100644 --- a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -89,10 +89,10 @@ struct RewriteStatepointsForGC : public ModulePass { Changed |= runOnFunction(F); if (Changed) { - // stripNonValidAttributes asserts that shouldRewriteStatepointsIn + // stripNonValidAttributesAndMetadata asserts that shouldRewriteStatepointsIn // returns true for at least one function in the module. Since at least // one function changed, we know that the precondition is satisfied. - stripNonValidAttributes(M); + stripNonValidAttributesAndMetadata(M); } return Changed; @@ -105,20 +105,24 @@ struct RewriteStatepointsForGC : public ModulePass { AU.addRequired(); } - /// The IR fed into RewriteStatepointsForGC may have had attributes implying - /// dereferenceability that are no longer valid/correct after - /// RewriteStatepointsForGC has run. This is because semantically, after + /// The IR fed into RewriteStatepointsForGC may have had attributes and + /// metadata implying dereferenceability that are no longer valid/correct after + /// RewriteStatepointsForGC has run. This is because semantically, after /// RewriteStatepointsForGC runs, all calls to gc.statepoint "free" the entire - /// heap. stripNonValidAttributes (conservatively) restores correctness - /// by erasing all attributes in the module that externally imply - /// dereferenceability. - /// Similar reasoning also applies to the noalias attributes. gc.statepoint - /// can touch the entire heap including noalias objects. - void stripNonValidAttributes(Module &M); + /// heap. stripNonValidAttributesAndMetadata (conservatively) restores + /// correctness by erasing all attributes in the module that externally imply + /// dereferenceability. Similar reasoning also applies to the noalias + /// attributes and metadata. gc.statepoint can touch the entire heap including + /// noalias objects. + void stripNonValidAttributesAndMetadata(Module &M); - // Helpers for stripNonValidAttributes - void stripNonValidAttributesFromBody(Function &F); + // Helpers for stripNonValidAttributesAndMetadata + void stripNonValidAttributesAndMetadataFromBody(Function &F); void stripNonValidAttributesFromPrototype(Function &F); + // Certain metadata on instructions are invalid after running RS4GC. + // Optimizations that run after RS4GC can incorrectly use this metadata to + // optimize functions. We drop such metadata on the instruction. + void stripInvalidMetadataFromInstruction(Instruction &I); }; } // namespace @@ -2306,13 +2310,44 @@ RewriteStatepointsForGC::stripNonValidAttributesFromPrototype(Function &F) { RemoveNonValidAttrAtIndex(Ctx, F, AttributeList::ReturnIndex); } -void RewriteStatepointsForGC::stripNonValidAttributesFromBody(Function &F) { +void RewriteStatepointsForGC::stripInvalidMetadataFromInstruction(Instruction &I) { + + if (!isa(I) && !isa(I)) + return; + // These are the attributes that are still valid on loads and stores after + // RS4GC. + // The metadata implying dereferenceability and noalias are (conservatively) + // dropped. This is because semantically, after RewriteStatepointsForGC runs, + // all calls to gc.statepoint "free" the entire heap. Also, gc.statepoint can + // touch the entire heap including noalias objects. Note: The reasoning is + // same as stripping the dereferenceability and noalias attributes that are + // analogous to the metadata counterparts. + // We also drop the invariant.load metadata on the load because that metadata + // implies the address operand to the load points to memory that is never + // changed once it became dereferenceable. This is no longer true after RS4GC. + // Similar reasoning applies to invariant.group metadata, which applies to + // loads within a group. + unsigned ValidMetadataAfterRS4GC[] = {LLVMContext::MD_tbaa, + LLVMContext::MD_range, + LLVMContext::MD_alias_scope, + LLVMContext::MD_nontemporal, + LLVMContext::MD_nonnull, + LLVMContext::MD_align, + LLVMContext::MD_type}; + + // Drops all metadata on the instruction other than ValidMetadataAfterRS4GC. + I.dropUnknownNonDebugMetadata(ValidMetadataAfterRS4GC); + +} + +void RewriteStatepointsForGC::stripNonValidAttributesAndMetadataFromBody(Function &F) { if (F.empty()) return; LLVMContext &Ctx = F.getContext(); MDBuilder Builder(Ctx); + for (Instruction &I : instructions(F)) { if (const MDNode *MD = I.getMetadata(LLVMContext::MD_tbaa)) { assert(MD->getNumOperands() < 5 && "unrecognized metadata shape!"); @@ -2333,6 +2368,8 @@ void RewriteStatepointsForGC::stripNonValidAttributesFromBody(Function &F) { I.setMetadata(LLVMContext::MD_tbaa, MutableTBAA); } + stripInvalidMetadataFromInstruction(I); + if (CallSite CS = CallSite(&I)) { for (int i = 0, e = CS.arg_size(); i != e; i++) if (isa(CS.getArgument(i)->getType())) @@ -2357,7 +2394,7 @@ static bool shouldRewriteStatepointsIn(Function &F) { return false; } -void RewriteStatepointsForGC::stripNonValidAttributes(Module &M) { +void RewriteStatepointsForGC::stripNonValidAttributesAndMetadata(Module &M) { #ifndef NDEBUG assert(any_of(M, shouldRewriteStatepointsIn) && "precondition!"); #endif @@ -2366,7 +2403,7 @@ void RewriteStatepointsForGC::stripNonValidAttributes(Module &M) { stripNonValidAttributesFromPrototype(F); for (Function &F : M) - stripNonValidAttributesFromBody(F); + stripNonValidAttributesAndMetadataFromBody(F); } bool RewriteStatepointsForGC::runOnFunction(Function &F) { diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index 815492ac354c..c6929c33b3e9 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -515,10 +515,6 @@ class SCCPSolver : public InstVisitor { void visitCmpInst(CmpInst &I); void visitExtractValueInst(ExtractValueInst &EVI); void visitInsertValueInst(InsertValueInst &IVI); - void visitLandingPadInst(LandingPadInst &I) { markOverdefined(&I); } - void visitFuncletPadInst(FuncletPadInst &FPI) { - markOverdefined(&FPI); - } void visitCatchSwitchInst(CatchSwitchInst &CPI) { markOverdefined(&CPI); visitTerminatorInst(CPI); @@ -539,13 +535,6 @@ class SCCPSolver : public InstVisitor { void visitResumeInst (TerminatorInst &I) { /*returns void*/ } void visitUnreachableInst(TerminatorInst &I) { /*returns void*/ } void visitFenceInst (FenceInst &I) { /*returns void*/ } - void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { - markOverdefined(&I); - } - void visitAtomicRMWInst (AtomicRMWInst &I) { markOverdefined(&I); } - void visitAllocaInst (Instruction &I) { markOverdefined(&I); } - void visitVAArgInst (Instruction &I) { markOverdefined(&I); } - void visitInstruction(Instruction &I) { // If a new instruction is added to LLVM that we don't handle. DEBUG(dbgs() << "SCCP: Don't know how to handle: " << I << '\n'); diff --git a/lib/Transforms/Utils/CodeExtractor.cpp b/lib/Transforms/Utils/CodeExtractor.cpp index 24d28a6c2831..5d57ed9718fb 100644 --- a/lib/Transforms/Utils/CodeExtractor.cpp +++ b/lib/Transforms/Utils/CodeExtractor.cpp @@ -142,8 +142,139 @@ static bool definedInCaller(const SetVector &Blocks, Value *V) { return false; } -void CodeExtractor::findAllocas(ValueSet &SinkCands) const { +static BasicBlock *getCommonExitBlock(const SetVector &Blocks) { + BasicBlock *CommonExitBlock = nullptr; + auto hasNonCommonExitSucc = [&](BasicBlock *Block) { + for (auto *Succ : successors(Block)) { + // Internal edges, ok. + if (Blocks.count(Succ)) + continue; + if (!CommonExitBlock) { + CommonExitBlock = Succ; + continue; + } + if (CommonExitBlock == Succ) + continue; + + return true; + } + return false; + }; + + if (any_of(Blocks, hasNonCommonExitSucc)) + return nullptr; + + return CommonExitBlock; +} + +bool CodeExtractor::isLegalToShrinkwrapLifetimeMarkers( + Instruction *Addr) const { + AllocaInst *AI = cast(Addr->stripInBoundsConstantOffsets()); Function *Func = (*Blocks.begin())->getParent(); + for (BasicBlock &BB : *Func) { + if (Blocks.count(&BB)) + continue; + for (Instruction &II : BB) { + + if (isa(II)) + continue; + + unsigned Opcode = II.getOpcode(); + Value *MemAddr = nullptr; + switch (Opcode) { + case Instruction::Store: + case Instruction::Load: { + if (Opcode == Instruction::Store) { + StoreInst *SI = cast(&II); + MemAddr = SI->getPointerOperand(); + } else { + LoadInst *LI = cast(&II); + MemAddr = LI->getPointerOperand(); + } + // Global variable can not be aliased with locals. + if (dyn_cast(MemAddr)) + break; + Value *Base = MemAddr->stripInBoundsConstantOffsets(); + if (!dyn_cast(Base) || Base == AI) + return false; + break; + } + default: { + IntrinsicInst *IntrInst = dyn_cast(&II); + if (IntrInst) { + if (IntrInst->getIntrinsicID() == Intrinsic::lifetime_start || + IntrInst->getIntrinsicID() == Intrinsic::lifetime_end) + break; + return false; + } + // Treat all the other cases conservatively if it has side effects. + if (II.mayHaveSideEffects()) + return false; + } + } + } + } + + return true; +} + +BasicBlock * +CodeExtractor::findOrCreateBlockForHoisting(BasicBlock *CommonExitBlock) { + BasicBlock *SinglePredFromOutlineRegion = nullptr; + assert(!Blocks.count(CommonExitBlock) && + "Expect a block outside the region!"); + for (auto *Pred : predecessors(CommonExitBlock)) { + if (!Blocks.count(Pred)) + continue; + if (!SinglePredFromOutlineRegion) { + SinglePredFromOutlineRegion = Pred; + } else if (SinglePredFromOutlineRegion != Pred) { + SinglePredFromOutlineRegion = nullptr; + break; + } + } + + if (SinglePredFromOutlineRegion) + return SinglePredFromOutlineRegion; + +#ifndef NDEBUG + auto getFirstPHI = [](BasicBlock *BB) { + BasicBlock::iterator I = BB->begin(); + PHINode *FirstPhi = nullptr; + while (I != BB->end()) { + PHINode *Phi = dyn_cast(I); + if (!Phi) + break; + if (!FirstPhi) { + FirstPhi = Phi; + break; + } + } + return FirstPhi; + }; + // If there are any phi nodes, the single pred either exists or has already + // be created before code extraction. + assert(!getFirstPHI(CommonExitBlock) && "Phi not expected"); +#endif + + BasicBlock *NewExitBlock = CommonExitBlock->splitBasicBlock( + CommonExitBlock->getFirstNonPHI()->getIterator()); + + for (auto *Pred : predecessors(CommonExitBlock)) { + if (Blocks.count(Pred)) + continue; + Pred->getTerminator()->replaceUsesOfWith(CommonExitBlock, NewExitBlock); + } + // Now add the old exit block to the outline region. + Blocks.insert(CommonExitBlock); + return CommonExitBlock; +} + +void CodeExtractor::findAllocas(ValueSet &SinkCands, ValueSet &HoistCands, + BasicBlock *&ExitBlock) const { + Function *Func = (*Blocks.begin())->getParent(); + ExitBlock = getCommonExitBlock(Blocks); + for (BasicBlock &BB : *Func) { if (Blocks.count(&BB)) continue; @@ -152,49 +283,96 @@ void CodeExtractor::findAllocas(ValueSet &SinkCands) const { if (!AI) continue; - // Returns true if matching life time markers are found within - // the outlined region. - auto GetLifeTimeMarkers = [&](Instruction *Addr) { + // Find the pair of life time markers for address 'Addr' that are either + // defined inside the outline region or can legally be shrinkwrapped into + // the outline region. If there are not other untracked uses of the + // address, return the pair of markers if found; otherwise return a pair + // of nullptr. + auto GetLifeTimeMarkers = + [&](Instruction *Addr, bool &SinkLifeStart, + bool &HoistLifeEnd) -> std::pair { Instruction *LifeStart = nullptr, *LifeEnd = nullptr; - for (User *U : Addr->users()) { - if (!definedInRegion(Blocks, U)) - return false; + for (User *U : Addr->users()) { IntrinsicInst *IntrInst = dyn_cast(U); if (IntrInst) { - if (IntrInst->getIntrinsicID() == Intrinsic::lifetime_start) + if (IntrInst->getIntrinsicID() == Intrinsic::lifetime_start) { + // Do not handle the case where AI has multiple start markers. + if (LifeStart) + return std::make_pair(nullptr, nullptr); LifeStart = IntrInst; - if (IntrInst->getIntrinsicID() == Intrinsic::lifetime_end) + } + if (IntrInst->getIntrinsicID() == Intrinsic::lifetime_end) { + if (LifeEnd) + return std::make_pair(nullptr, nullptr); LifeEnd = IntrInst; + } + continue; } + // Find untracked uses of the address, bail. + if (!definedInRegion(Blocks, U)) + return std::make_pair(nullptr, nullptr); } - return LifeStart && LifeEnd; + + if (!LifeStart || !LifeEnd) + return std::make_pair(nullptr, nullptr); + + SinkLifeStart = !definedInRegion(Blocks, LifeStart); + HoistLifeEnd = !definedInRegion(Blocks, LifeEnd); + // Do legality Check. + if ((SinkLifeStart || HoistLifeEnd) && + !isLegalToShrinkwrapLifetimeMarkers(Addr)) + return std::make_pair(nullptr, nullptr); + + // Check to see if we have a place to do hoisting, if not, bail. + if (HoistLifeEnd && !ExitBlock) + return std::make_pair(nullptr, nullptr); + + return std::make_pair(LifeStart, LifeEnd); }; - if (GetLifeTimeMarkers(AI)) { + bool SinkLifeStart = false, HoistLifeEnd = false; + auto Markers = GetLifeTimeMarkers(AI, SinkLifeStart, HoistLifeEnd); + + if (Markers.first) { + if (SinkLifeStart) + SinkCands.insert(Markers.first); SinkCands.insert(AI); + if (HoistLifeEnd) + HoistCands.insert(Markers.second); continue; } - // Follow the bitcast: + // Follow the bitcast. Instruction *MarkerAddr = nullptr; for (User *U : AI->users()) { - if (U->stripPointerCasts() == AI) { + + if (U->stripInBoundsConstantOffsets() == AI) { + SinkLifeStart = false; + HoistLifeEnd = false; Instruction *Bitcast = cast(U); - if (GetLifeTimeMarkers(Bitcast)) { + Markers = GetLifeTimeMarkers(Bitcast, SinkLifeStart, HoistLifeEnd); + if (Markers.first) { MarkerAddr = Bitcast; continue; } } + + // Found unknown use of AI. if (!definedInRegion(Blocks, U)) { MarkerAddr = nullptr; break; } } + if (MarkerAddr) { + if (SinkLifeStart) + SinkCands.insert(Markers.first); if (!definedInRegion(Blocks, MarkerAddr)) SinkCands.insert(MarkerAddr); SinkCands.insert(AI); + if (HoistLifeEnd) + HoistCands.insert(Markers.second); } } } @@ -780,7 +958,8 @@ Function *CodeExtractor::extractCodeRegion() { if (!isEligible()) return nullptr; - ValueSet inputs, outputs, SinkingCands; + ValueSet inputs, outputs, SinkingCands, HoistingCands; + BasicBlock *CommonExit = nullptr; // Assumption: this is a single-entry code region, and the header is the first // block in the region. @@ -819,7 +998,8 @@ Function *CodeExtractor::extractCodeRegion() { "newFuncRoot"); newFuncRoot->getInstList().push_back(BranchInst::Create(header)); - findAllocas(SinkingCands); + findAllocas(SinkingCands, HoistingCands, CommonExit); + assert(HoistingCands.empty() || CommonExit); // Find inputs to, outputs from the code region. findInputsOutputs(inputs, outputs, SinkingCands); @@ -829,6 +1009,13 @@ Function *CodeExtractor::extractCodeRegion() { cast(II)->moveBefore(*newFuncRoot, newFuncRoot->getFirstInsertionPt()); + if (!HoistingCands.empty()) { + auto *HoistToBlock = findOrCreateBlockForHoisting(CommonExit); + Instruction *TI = HoistToBlock->getTerminator(); + for (auto *II : HoistingCands) + cast(II)->moveBefore(TI); + } + // Calculate the exit blocks for the extracted region and the total exit // weights for each of those blocks. DenseMap ExitWeights; diff --git a/lib/Transforms/Utils/PredicateInfo.cpp b/lib/Transforms/Utils/PredicateInfo.cpp index 9e71cba4f1b7..1260e35e934d 100644 --- a/lib/Transforms/Utils/PredicateInfo.cpp +++ b/lib/Transforms/Utils/PredicateInfo.cpp @@ -460,6 +460,9 @@ void PredicateInfo::buildPredicateInfo() { if (auto *BI = dyn_cast(BranchBB->getTerminator())) { if (!BI->isConditional()) continue; + // Can't insert conditional information if they all go to the same place. + if (BI->getSuccessor(0) == BI->getSuccessor(1)) + continue; processBranch(BI, BranchBB, OpsToRename); } else if (auto *SI = dyn_cast(BranchBB->getTerminator())) { processSwitch(SI, BranchBB, OpsToRename); diff --git a/lib/Transforms/Utils/SimplifyIndVar.cpp b/lib/Transforms/Utils/SimplifyIndVar.cpp index 02a5d3dbeadf..faa14046b1e3 100644 --- a/lib/Transforms/Utils/SimplifyIndVar.cpp +++ b/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -352,7 +352,7 @@ bool SimplifyIndvar::eliminateOverflowIntrinsic(CallInst *CI) { return false; typedef const SCEV *(ScalarEvolution::*OperationFunctionTy)( - const SCEV *, const SCEV *, SCEV::NoWrapFlags); + const SCEV *, const SCEV *, SCEV::NoWrapFlags, unsigned); typedef const SCEV *(ScalarEvolution::*ExtensionFunctionTy)( const SCEV *, Type *); @@ -406,10 +406,11 @@ bool SimplifyIndvar::eliminateOverflowIntrinsic(CallInst *CI) { IntegerType::get(NarrowTy->getContext(), NarrowTy->getBitWidth() * 2); const SCEV *A = - (SE->*Extension)((SE->*Operation)(LHS, RHS, SCEV::FlagAnyWrap), WideTy); + (SE->*Extension)((SE->*Operation)(LHS, RHS, SCEV::FlagAnyWrap, 0u), + WideTy); const SCEV *B = (SE->*Operation)((SE->*Extension)(LHS, WideTy), - (SE->*Extension)(RHS, WideTy), SCEV::FlagAnyWrap); + (SE->*Extension)(RHS, WideTy), SCEV::FlagAnyWrap, 0u); if (A != B) return false; @@ -530,8 +531,7 @@ bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO, return false; const SCEV *(ScalarEvolution::*GetExprForBO)(const SCEV *, const SCEV *, - SCEV::NoWrapFlags); - + SCEV::NoWrapFlags, unsigned); switch (BO->getOpcode()) { default: return false; @@ -560,7 +560,7 @@ bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO, const SCEV *ExtendAfterOp = SE->getZeroExtendExpr(SE->getSCEV(BO), WideTy); const SCEV *OpAfterExtend = (SE->*GetExprForBO)( SE->getZeroExtendExpr(LHS, WideTy), SE->getZeroExtendExpr(RHS, WideTy), - SCEV::FlagAnyWrap); + SCEV::FlagAnyWrap, 0u); if (ExtendAfterOp == OpAfterExtend) { BO->setHasNoUnsignedWrap(); SE->forgetValue(BO); @@ -572,7 +572,7 @@ bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO, const SCEV *ExtendAfterOp = SE->getSignExtendExpr(SE->getSCEV(BO), WideTy); const SCEV *OpAfterExtend = (SE->*GetExprForBO)( SE->getSignExtendExpr(LHS, WideTy), SE->getSignExtendExpr(RHS, WideTy), - SCEV::FlagAnyWrap); + SCEV::FlagAnyWrap, 0u); if (ExtendAfterOp == OpAfterExtend) { BO->setHasNoSignedWrap(); SE->forgetValue(BO); diff --git a/test/Analysis/ScalarEvolution/limit-depth.ll b/test/Analysis/ScalarEvolution/limit-depth.ll new file mode 100644 index 000000000000..5a35bfefd20a --- /dev/null +++ b/test/Analysis/ScalarEvolution/limit-depth.ll @@ -0,0 +1,44 @@ +; RUN: opt -scalar-evolution-max-arith-depth=0 -analyze -scalar-evolution < %s | FileCheck %s + +; Check that depth set to 0 prevents getAddExpr and getMulExpr from making +; transformations in SCEV. We expect the result to be very straightforward. + +define void @test_add(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) { +; CHECK-LABEL: @test_add +; CHECK: %s2 = add i32 %s1, %p3 +; CHECK-NEXT: --> (%a + %a + %b + %b + %c + %c + %d + %d + %e + %e + %f + %f) + %tmp0 = add i32 %a, %b + %tmp1 = add i32 %b, %c + %tmp2 = add i32 %c, %d + %tmp3 = add i32 %d, %e + %tmp4 = add i32 %e, %f + %tmp5 = add i32 %f, %a + + %p1 = add i32 %tmp0, %tmp3 + %p2 = add i32 %tmp1, %tmp4 + %p3 = add i32 %tmp2, %tmp5 + + %s1 = add i32 %p1, %p2 + %s2 = add i32 %s1, %p3 + ret void +} + +define void @test_mul(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) { +; CHECK-LABEL: @test_mul +; CHECK: %s2 = mul i32 %s1, %p3 +; CHECK-NEXT: --> (2 * 3 * 4 * 5 * 6 * 7 * %a * %b * %c * %d * %e * %f) + %tmp0 = mul i32 %a, 2 + %tmp1 = mul i32 %b, 3 + %tmp2 = mul i32 %c, 4 + %tmp3 = mul i32 %d, 5 + %tmp4 = mul i32 %e, 6 + %tmp5 = mul i32 %f, 7 + + %p1 = mul i32 %tmp0, %tmp3 + %p2 = mul i32 %tmp1, %tmp4 + %p3 = mul i32 %tmp2, %tmp5 + + %s1 = mul i32 %p1, %p2 + %s2 = mul i32 %s1, %p3 + ret void +} diff --git a/test/Assembler/diexpression.ll b/test/Assembler/diexpression.ll index c2fa3ee14c23..39f4be70145a 100644 --- a/test/Assembler/diexpression.ll +++ b/test/Assembler/diexpression.ll @@ -1,18 +1,20 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: !named = !{!0, !1, !2, !3, !4, !5} -!named = !{!0, !1, !2, !3, !4, !5} +; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6} +!named = !{!0, !1, !2, !3, !4, !5, !6} ; CHECK: !0 = !DIExpression() ; CHECK-NEXT: !1 = !DIExpression(DW_OP_deref) -; CHECK-NEXT: !2 = !DIExpression(DW_OP_plus, 3) +; CHECK-NEXT: !2 = !DIExpression(DW_OP_constu, 3, DW_OP_plus) ; CHECK-NEXT: !3 = !DIExpression(DW_OP_LLVM_fragment, 3, 7) -; CHECK-NEXT: !4 = !DIExpression(DW_OP_deref, DW_OP_plus, 3, DW_OP_LLVM_fragment, 3, 7) +; CHECK-NEXT: !4 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 3, DW_OP_LLVM_fragment, 3, 7) ; CHECK-NEXT: !5 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef) +; CHECK-NEXT: !6 = !DIExpression(DW_OP_plus_uconst, 3) !0 = !DIExpression() !1 = !DIExpression(DW_OP_deref) -!2 = !DIExpression(DW_OP_plus, 3) +!2 = !DIExpression(DW_OP_constu, 3, DW_OP_plus) !3 = !DIExpression(DW_OP_LLVM_fragment, 3, 7) -!4 = !DIExpression(DW_OP_deref, DW_OP_plus, 3, DW_OP_LLVM_fragment, 3, 7) +!4 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 3, DW_OP_LLVM_fragment, 3, 7) !5 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef) +!6 = !DIExpression(DW_OP_plus_uconst, 3) diff --git a/test/Bitcode/DIExpression-deref.ll b/test/Bitcode/DIExpression-deref.ll index 3a161b8ee4d2..a03d6016523e 100644 --- a/test/Bitcode/DIExpression-deref.ll +++ b/test/Bitcode/DIExpression-deref.ll @@ -11,11 +11,11 @@ !5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) ; DW_OP_deref should be moved to the back of the expression. ; -; CHECK: !DIExpression(DW_OP_plus, 0, DW_OP_deref, DW_OP_LLVM_fragment, 8, 32) +; CHECK: !DIExpression(DW_OP_plus_uconst, 0, DW_OP_deref, DW_OP_LLVM_fragment, 8, 32) !6 = !DIExpression(DW_OP_deref, DW_OP_plus, 0, DW_OP_LLVM_fragment, 8, 32) -; CHECK: !DIExpression(DW_OP_plus, 0, DW_OP_deref) +; CHECK: !DIExpression(DW_OP_plus_uconst, 0, DW_OP_deref) !7 = !DIExpression(DW_OP_deref, DW_OP_plus, 0) -; CHECK: !DIExpression(DW_OP_plus, 1, DW_OP_deref) +; CHECK: !DIExpression(DW_OP_plus_uconst, 1, DW_OP_deref) !8 = !DIExpression(DW_OP_plus, 1, DW_OP_deref) ; CHECK: !DIExpression(DW_OP_deref) !9 = !DIExpression(DW_OP_deref) diff --git a/test/Bitcode/DIExpression-minus-upgrade.ll b/test/Bitcode/DIExpression-minus-upgrade.ll new file mode 100644 index 000000000000..1f26eba6f98c --- /dev/null +++ b/test/Bitcode/DIExpression-minus-upgrade.ll @@ -0,0 +1,16 @@ +; RUN: llvm-dis -o - %s.bc | FileCheck %s + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!8, !9} + +!0 = distinct !DIGlobalVariable(name: "g", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true) +!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang (llvm/trunk 304286)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !4) +!2 = !DIFile(filename: "a.c", directory: "/") +!3 = !{} +!4 = !{!7} +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +; CHECK: !DIExpression(DW_OP_constu, 42, DW_OP_minus) +!6 = !DIExpression(DW_OP_minus, 42) +!7 = !DIGlobalVariableExpression(var: !0, expr: !6) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} diff --git a/test/Bitcode/DIExpression-minus-upgrade.ll.bc b/test/Bitcode/DIExpression-minus-upgrade.ll.bc new file mode 100644 index 0000000000000000000000000000000000000000..354ba6454c3febe5a5fe01e25ffe9769d85ff978 GIT binary patch literal 988 zcmXw2acCQ56#uSw$z7ZCa>*hj_U^cAt3;UgOr|ELktSEW4#P-s%7ltZwxz9hS(;{P z+My&(#$_|&Z3M|5Ll&5SY=3p&AEHB=q}H>~nXX3wJy0Hj8&3~j z^QhPfEp2mNN3!J88p6V1AB9rHYdzlUI`0^5GdT$J>wUI?+=OD{rSaV7z+&^ZCMd-q ztouEa>3lQu+f~dkuD!wo&qlazk z@B#JL8g(F|A+^M`N=&VbJ3(esVAj*@W>EX9A~{vbS?uDMRYyT`POnErr@0)i-(S09L_U*_|?1@o+y0 z%ubrydBC)q>^{PU&6AE*>6IH9SIs~4Um*c`F^MOOlfFlazQX|b9=91}9tv!u%zlV) zorDFp9n_w>oN?5uu2snm33*%@X-TdeRIB-K`(UN=BFu-tm#uiL)4L@e00)#IZi1I` zq{V3&Qm&0|sOrpspD@`zGh2k?sxmo3p8`NqG}0gfK=Ao9!)NA#k!jvKHZW2&rZ)q;$w@!SeSq7Tx?#1$GFB+_EPUBtFA zBMpF9Fo{3FL}&+~5kLd<$x$Axk!x|Ze7jsIgQGu^$gxil#e--^U#O)#{b4y>Y{>UT_=Es1AnL^~J2P_xSSZXi;** w7OqOp?dr-Nvr&5Dp{FyNdjk6}r(hm()A^4!iXOnA?5ua-#CL2)w9wW60T9Sa1^@s6 literal 0 HcmV?d00001 diff --git a/test/Bitcode/DIGlobalVariableExpression.ll b/test/Bitcode/DIGlobalVariableExpression.ll index f6796bbdb7a0..31c3fda1b00a 100644 --- a/test/Bitcode/DIGlobalVariableExpression.ll +++ b/test/Bitcode/DIGlobalVariableExpression.ll @@ -14,7 +14,7 @@ ; CHECK: ![[HVAR:[0-9]+]] = distinct !DIGlobalVariable(name: "h", ; CHECK: ![[IMPORTS]] = !{![[CIMPORT:[0-9]+]]} ; CHECK: ![[CIMPORT]] = !DIImportedEntity({{.*}}entity: ![[HVAR]] -; CHECK: ![[GEXPR]] = !DIExpression(DW_OP_plus, 1) +; CHECK: ![[GEXPR]] = !DIExpression(DW_OP_plus_uconst, 1) ; CHECK: ![[H]] = {{.*}}!DIGlobalVariableExpression(var: ![[HVAR]]) @g = common global i32 0, align 4, !dbg !0 diff --git a/test/Bitcode/upgrade-linker-options.ll b/test/Bitcode/upgrade-linker-options.ll new file mode 100644 index 000000000000..6c874fa81e64 --- /dev/null +++ b/test/Bitcode/upgrade-linker-options.ll @@ -0,0 +1,15 @@ +; RUN: llvm-as -disable-verify < %s | llvm-dis | FileCheck %s +; RUN: not llvm-as < %s 2>&1 | FileCheck --check-prefix=ERROR %s + +; CHECK: !llvm.linker.options = !{!2, !3} +; CHECK: !2 = !{!"/DEFAULTLIB:libcmtd.lib"} +; CHECK: !3 = !{!"/DEFAULTLIB:oldnames.lib"} + +; ERROR: 'Linker Options' named metadata no longer supported + +!0 = !{i32 6, !"Linker Options", !1} +!1 = !{!2, !3} +!2 = !{!"/DEFAULTLIB:libcmtd.lib"} +!3 = !{!"/DEFAULTLIB:oldnames.lib"} + +!llvm.module.flags = !{!0} diff --git a/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir b/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir index c806b4a7060d..ce913d211ae2 100644 --- a/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir +++ b/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir @@ -53,9 +53,7 @@ body: | ; CHECK: %7(<2 x s32>) = G_LOAD %0(p0) :: (load 8 from %ir.addr) %7(<2 x s32>) = G_LOAD %0(p0) :: (load 8 from %ir.addr) - ; CHECK: [[OFFSET0:%[0-9]+]](s64) = G_CONSTANT i64 0 - ; CHECK: [[GEP0:%[0-9]+]](p0) = G_GEP %0, [[OFFSET0]](s64) - ; CHECK: [[LOAD0:%[0-9]+]](s64) = G_LOAD [[GEP0]](p0) :: (load 16 from %ir.addr) + ; CHECK: [[LOAD0:%[0-9]+]](s64) = G_LOAD %0(p0) :: (load 16 from %ir.addr) ; CHECK: [[OFFSET1:%[0-9]+]](s64) = G_CONSTANT i64 8 ; CHECK: [[GEP1:%[0-9]+]](p0) = G_GEP %0, [[OFFSET1]](s64) ; CHECK: [[LOAD1:%[0-9]+]](s64) = G_LOAD [[GEP1]](p0) :: (load 16 from %ir.addr) @@ -105,9 +103,7 @@ body: | ; CHECK: G_STORE %0(p0), %0(p0) :: (store 8 into %ir.addr) G_STORE %0(p0), %0(p0) :: (store 8 into %ir.addr) - ; CHECK: [[OFFSET0:%[0-9]+]](s64) = G_CONSTANT i64 0 - ; CHECK: [[GEP0:%[0-9]+]](p0) = G_GEP %0, [[OFFSET0]](s64) - ; CHECK: G_STORE %5(s64), [[GEP0]](p0) :: (store 16 into %ir.addr) + ; CHECK: G_STORE %5(s64), %0(p0) :: (store 16 into %ir.addr) ; CHECK: [[OFFSET1:%[0-9]+]](s64) = G_CONSTANT i64 8 ; CHECK: [[GEP1:%[0-9]+]](p0) = G_GEP %0, [[OFFSET1]](s64) ; CHECK: G_STORE %6(s64), [[GEP1]](p0) :: (store 16 into %ir.addr) diff --git a/test/CodeGen/AArch64/arm64-sincos.ll b/test/CodeGen/AArch64/arm64-sincos.ll index 06157b2580c4..98876dbe87b0 100644 --- a/test/CodeGen/AArch64/arm64-sincos.ll +++ b/test/CodeGen/AArch64/arm64-sincos.ll @@ -1,7 +1,9 @@ ; RUN: llc < %s -mtriple=arm64-apple-ios7 | FileCheck %s --check-prefix CHECK-IOS ; RUN: llc < %s -mtriple=arm64-linux-gnu | FileCheck %s --check-prefix CHECK-LINUX -; Combine sin / cos into a single call. +; Combine sin / cos into a single call unless they may write errno (as +; captured by readnone attrbiute, controlled by clang -fmath-errno +; setting). ; rdar://12856873 define float @test1(float %x) nounwind { @@ -11,11 +13,26 @@ entry: ; CHECK-IOS: fadd s0, s0, s1 ; CHECK-LINUX-LABEL: test1: +; CHECK-LINUX: bl sincosf + + %call = tail call float @sinf(float %x) readnone + %call1 = tail call float @cosf(float %x) readnone + %add = fadd float %call, %call1 + ret float %add +} + +define float @test1_errno(float %x) nounwind { +entry: +; CHECK-IOS-LABEL: test1_errno: +; CHECK-IOS: bl _sinf +; CHECK-IOS: bl _cosf + +; CHECK-LINUX-LABEL: test1_errno: ; CHECK-LINUX: bl sinf ; CHECK-LINUX: bl cosf - %call = tail call float @sinf(float %x) nounwind readnone - %call1 = tail call float @cosf(float %x) nounwind readnone + %call = tail call float @sinf(float %x) + %call1 = tail call float @cosf(float %x) %add = fadd float %call, %call1 ret float %add } @@ -27,16 +44,31 @@ entry: ; CHECK-IOS: fadd d0, d0, d1 ; CHECK-LINUX-LABEL: test2: -; CHECK-LINUX: bl sin -; CHECK-LINUX: bl cos +; CHECK-LINUX: bl sincos - %call = tail call double @sin(double %x) nounwind readnone - %call1 = tail call double @cos(double %x) nounwind readnone + %call = tail call double @sin(double %x) readnone + %call1 = tail call double @cos(double %x) readnone %add = fadd double %call, %call1 ret double %add } -declare float @sinf(float) readonly -declare double @sin(double) readonly -declare float @cosf(float) readonly -declare double @cos(double) readonly +define double @test2_errno(double %x) nounwind { +entry: +; CHECK-IOS-LABEL: test2_errno: +; CHECK-IOS: bl _sin +; CHECK-IOS: bl _cos + +; CHECK-LINUX-LABEL: test2_errno: +; CHECK-LINUX: bl sin +; CHECK-LINUX: bl cos + + %call = tail call double @sin(double %x) + %call1 = tail call double @cos(double %x) + %add = fadd double %call, %call1 + ret double %add +} + +declare float @sinf(float) +declare double @sin(double) +declare float @cosf(float) +declare double @cos(double) diff --git a/test/CodeGen/AArch64/fast-isel-sp-adjust.ll b/test/CodeGen/AArch64/fast-isel-sp-adjust.ll new file mode 100644 index 000000000000..9201d1be6a9c --- /dev/null +++ b/test/CodeGen/AArch64/fast-isel-sp-adjust.ll @@ -0,0 +1,288 @@ +; RUN: llc -O0 -mtriple=aarch64-apple-ios -o - %s | FileCheck %s +; RUN: not llc -O0 -mtriple=aarch64-apple-ios -o /dev/null -fast-isel-abort=3 %s 2> %t +; RUN: FileCheck %s --check-prefix=CHECK-ERRORS < %t + +; The issue here is that FastISel cannot emit an ADDrr where one of the inputs +; is SP. This only ever crops up with function calls, and then only if the +; argument is at an offset > 2^12 * size from SP. + +; If FastISel ever starts coping with this and emits an "add xD, sp, xM" it's +; critical to check the encoding as well as the textual assembly. An ADDXrs with +; SP as an operand will still print with SP, but will actually mean XZR. + +; CHECK-ERRORS: LLVM ERROR: FastISel missed call + +; CHECK-LABEL: foo: +; CHECK-DAG: mov x[[SP:[0-9]+]], sp +; CHECK-DAG: mov [[TMP:w[0-9]+]], #4104 +; CHECK: mov w[[OFFSET:[0-9]+]], [[TMP]] +; CHECK: strb w0, [x[[SP]], x[[OFFSET]]] + +define void @foo(i8 %in) { + call void @bar(i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, ; All regs gone. + i64 undef, i64 undef, i64 undef, i64 undef, ; sp + 32 + i64 undef, i64 undef, i64 undef, i64 undef, ; sp + 64 + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, ; sp + 128 + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, ; sp + 256 + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, ; sp + 512 + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, ; sp + 1024 + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, ; sp + 2048 + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, + i64 undef, i64 undef, i64 undef, i64 undef, ; sp + 4096 + i64 undef, ; sp + 4104 (i.e. not uimm12 or uimm12 << 12). + i8 %in) + ret void +} + +declare void @bar(i64, i64, i64, i64, + i64, i64, i64, i64, ; All regs gone. + i64, i64, i64, i64, ; sp + 32 + i64, i64, i64, i64, ; sp + 64 + i64, i64, i64, i64, + i64, i64, i64, i64, ; sp + 128 + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, ; sp + 256 + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, ; sp + 512 + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, ; sp + 1024 + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, ; sp + 2048 + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, + i64, i64, i64, i64, ; sp + 4096 + i64, + i8) diff --git a/test/CodeGen/AArch64/misched-fusion-aes.ll b/test/CodeGen/AArch64/misched-fusion-aes.ll index bd7c69c910c0..8ee4dbcee52b 100644 --- a/test/CodeGen/AArch64/misched-fusion-aes.ll +++ b/test/CodeGen/AArch64/misched-fusion-aes.ll @@ -1,7 +1,9 @@ -; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=cortex-a53 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKCORTEX -; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=cortex-a57 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKCORTEX -; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=cortex-a72 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKCORTEX -; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=cortex-a73 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKCORTEX +; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=+fuse-aes,+crypto | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKFUSEALLPAIRS +; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=generic -mattr=+crypto | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKFUSEALLPAIRS +; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=cortex-a53 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKFUSEALLPAIRS +; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=cortex-a57 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKFUSEALLPAIRS +; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=cortex-a72 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKFUSEALLPAIRS +; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=cortex-a73 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKFUSEALLPAIRS ; RUN: llc %s -o - -mtriple=aarch64-unknown -mcpu=exynos-m1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKM1 declare <16 x i8> @llvm.aarch64.crypto.aese(<16 x i8> %d, <16 x i8> %k) @@ -74,22 +76,23 @@ define void @aesea(<16 x i8>* %a0, <16 x i8>* %b0, <16 x i8>* %c0, <16 x i8> %d, ret void ; CHECK-LABEL: aesea: -; CHECKCORTEX: aese [[VA:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesmc {{v[0-7].16b}}, [[VA]] -; CHECKCORTEX: aese [[VB:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesmc {{v[0-7].16b}}, [[VB]] -; CHECKCORTEX: aese [[VC:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesmc {{v[0-7].16b}}, [[VC]] -; CHECKCORTEX: aese [[VD:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesmc {{v[0-7].16b}}, [[VD]] -; CHECKCORTEX: aese [[VE:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesmc {{v[0-7].16b}}, [[VE]] -; CHECKCORTEX: aese [[VF:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesmc {{v[0-7].16b}}, [[VF]] -; CHECKCORTEX: aese [[VG:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesmc {{v[0-7].16b}}, [[VG]] -; CHECKCORTEX: aese [[VH:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesmc {{v[0-7].16b}}, [[VH]] +; CHECKFUSEALLPAIRS: aese [[VA:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesmc {{v[0-7].16b}}, [[VA]] +; CHECKFUSEALLPAIRS: aese [[VB:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesmc {{v[0-7].16b}}, [[VB]] +; CHECKFUSEALLPAIRS: aese [[VC:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesmc {{v[0-7].16b}}, [[VC]] +; CHECKFUSEALLPAIRS: aese [[VD:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesmc {{v[0-7].16b}}, [[VD]] +; CHECKFUSEALLPAIRS: aese [[VE:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesmc {{v[0-7].16b}}, [[VE]] +; CHECKFUSEALLPAIRS: aese [[VF:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesmc {{v[0-7].16b}}, [[VF]] +; CHECKFUSEALLPAIRS: aese [[VG:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesmc {{v[0-7].16b}}, [[VG]] +; CHECKFUSEALLPAIRS: aese [[VH:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesmc {{v[0-7].16b}}, [[VH]] +; CHECKFUSEALLPAIRS-NOT: aesmc ; CHECKM1: aese [[VA:v[0-7].16b]], {{v[0-7].16b}} ; CHECKM1-NEXT: aesmc {{v[0-7].16b}}, [[VA]] @@ -175,22 +178,23 @@ define void @aesda(<16 x i8>* %a0, <16 x i8>* %b0, <16 x i8>* %c0, <16 x i8> %d, ret void ; CHECK-LABEL: aesda: -; CHECKCORTEX: aesd [[VA:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesimc {{v[0-7].16b}}, [[VA]] -; CHECKCORTEX: aesd [[VB:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesimc {{v[0-7].16b}}, [[VB]] -; CHECKCORTEX: aesd [[VC:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesimc {{v[0-7].16b}}, [[VC]] -; CHECKCORTEX: aesd [[VD:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesimc {{v[0-7].16b}}, [[VD]] -; CHECKCORTEX: aesd [[VE:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesimc {{v[0-7].16b}}, [[VE]] -; CHECKCORTEX: aesd [[VF:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesimc {{v[0-7].16b}}, [[VF]] -; CHECKCORTEX: aesd [[VG:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesimc {{v[0-7].16b}}, [[VG]] -; CHECKCORTEX: aesd [[VH:v[0-7].16b]], {{v[0-7].16b}} -; CHECKCORTEX-NEXT: aesimc {{v[0-7].16b}}, [[VH]] +; CHECKFUSEALLPAIRS: aesd [[VA:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesimc {{v[0-7].16b}}, [[VA]] +; CHECKFUSEALLPAIRS: aesd [[VB:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesimc {{v[0-7].16b}}, [[VB]] +; CHECKFUSEALLPAIRS: aesd [[VC:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesimc {{v[0-7].16b}}, [[VC]] +; CHECKFUSEALLPAIRS: aesd [[VD:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesimc {{v[0-7].16b}}, [[VD]] +; CHECKFUSEALLPAIRS: aesd [[VE:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesimc {{v[0-7].16b}}, [[VE]] +; CHECKFUSEALLPAIRS: aesd [[VF:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesimc {{v[0-7].16b}}, [[VF]] +; CHECKFUSEALLPAIRS: aesd [[VG:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesimc {{v[0-7].16b}}, [[VG]] +; CHECKFUSEALLPAIRS: aesd [[VH:v[0-7].16b]], {{v[0-7].16b}} +; CHECKFUSEALLPAIRS-NEXT: aesimc {{v[0-7].16b}}, [[VH]] +; CHECKFUSEALLPAIRS-NOT: aesimc ; CHECKM1: aesd [[VA:v[0-7].16b]], {{v[0-7].16b}} ; CHECKM1-NEXT: aesimc {{v[0-7].16b}}, [[VA]] @@ -236,4 +240,5 @@ entry: ; CHECK-NEXT: aesmc {{v[0-7].16b}}, [[VA]] ; CHECK: aese [[VB:v[0-7].16b]], {{v[0-7].16b}} ; CHECK-NEXT: aesmc {{v[0-7].16b}}, [[VB]] +; CHECK-NOT: aesmc } diff --git a/test/CodeGen/AArch64/sincos-expansion.ll b/test/CodeGen/AArch64/sincos-expansion.ll index c3a172dfb427..41ee40378b4f 100644 --- a/test/CodeGen/AArch64/sincos-expansion.ll +++ b/test/CodeGen/AArch64/sincos-expansion.ll @@ -1,8 +1,18 @@ ; RUN: llc -mtriple=aarch64-linux-gnu -verify-machineinstrs -o - %s | FileCheck %s define float @test_sincos_f32(float %f) { +; CHECK-LABEL: test_sincos_f32: %sin = call float @sinf(float %f) readnone %cos = call float @cosf(float %f) readnone +; CHECK: bl sincosf + %val = fadd float %sin, %cos + ret float %val +} + +define float @test_sincos_f32_errno(float %f) { +; CHECK-LABEL: test_sincos_f32_errno: + %sin = call float @sinf(float %f) + %cos = call float @cosf(float %f) ; CHECK: bl sinf ; CHECK: bl cosf %val = fadd float %sin, %cos @@ -10,26 +20,46 @@ define float @test_sincos_f32(float %f) { } define double @test_sincos_f64(double %f) { +; CHECK-LABEL: test_sincos_f64: %sin = call double @sin(double %f) readnone %cos = call double @cos(double %f) readnone %val = fadd double %sin, %cos +; CHECK: bl sincos + ret double %val +} + +define double @test_sincos_f64_errno(double %f) { +; CHECK-LABEL: test_sincos_f64_errno: + %sin = call double @sin(double %f) + %cos = call double @cos(double %f) + %val = fadd double %sin, %cos ; CHECK: bl sin ; CHECK: bl cos ret double %val } define fp128 @test_sincos_f128(fp128 %f) { +; CHECK-LABEL: test_sincos_f128: %sin = call fp128 @sinl(fp128 %f) readnone %cos = call fp128 @cosl(fp128 %f) readnone %val = fadd fp128 %sin, %cos +; CHECK: bl sincosl + ret fp128 %val +} + +define fp128 @test_sincos_f128_errno(fp128 %f) { +; CHECK-LABEL: test_sincos_f128_errno: + %sin = call fp128 @sinl(fp128 %f) + %cos = call fp128 @cosl(fp128 %f) + %val = fadd fp128 %sin, %cos ; CHECK: bl sinl ; CHECK: bl cosl ret fp128 %val } -declare float @sinf(float) readonly -declare double @sin(double) readonly -declare fp128 @sinl(fp128) readonly -declare float @cosf(float) readonly -declare double @cos(double) readonly -declare fp128 @cosl(fp128) readonly +declare float @sinf(float) +declare double @sin(double) +declare fp128 @sinl(fp128) +declare float @cosf(float) +declare double @cos(double) +declare fp128 @cosl(fp128) diff --git a/test/CodeGen/AArch64/swifterror.ll b/test/CodeGen/AArch64/swifterror.ll index 69bf3510cc5a..bc28f477c810 100644 --- a/test/CodeGen/AArch64/swifterror.ll +++ b/test/CodeGen/AArch64/swifterror.ll @@ -597,3 +597,30 @@ entry: tail call void @acallee(i8* null) ret void } + +declare swiftcc void @foo2(%swift_error** swifterror) + +; Make sure we properly assign registers during fast-isel. +; CHECK-O0-LABEL: testAssign +; CHECK-O0: mov [[TMP:x.*]], xzr +; CHECK-O0: mov x21, [[TMP]] +; CHECK-O0: bl _foo2 +; CHECK-O0: str x21, [s[[STK:.*]]] +; CHECK-O0: ldr x0, [s[[STK]]] + +; CHECK-APPLE-LABEL: testAssign +; CHECK-APPLE: mov x21, xzr +; CHECK-APPLE: bl _foo2 +; CHECK-APPLE: mov x0, x21 + +define swiftcc %swift_error* @testAssign(i8* %error_ref) { +entry: + %error_ptr = alloca swifterror %swift_error* + store %swift_error* null, %swift_error** %error_ptr + call swiftcc void @foo2(%swift_error** swifterror %error_ptr) + br label %a + +a: + %error = load %swift_error*, %swift_error** %error_ptr + ret %swift_error* %error +} diff --git a/test/CodeGen/AMDGPU/GlobalISel/inst-select-load-flat.mir b/test/CodeGen/AMDGPU/GlobalISel/inst-select-load-flat.mir index 2a3d3887ed69..56a9e7022db9 100644 --- a/test/CodeGen/AMDGPU/GlobalISel/inst-select-load-flat.mir +++ b/test/CodeGen/AMDGPU/GlobalISel/inst-select-load-flat.mir @@ -14,7 +14,7 @@ regBankSelected: true # GCN: global_addrspace # GCN: [[PTR:%[0-9]+]] = COPY %vgpr0_vgpr1 -# GCN: FLAT_LOAD_DWORD [[PTR]], 0, 0 +# GCN: FLAT_LOAD_DWORD [[PTR]], 0, 0, 0 body: | bb.0: diff --git a/test/CodeGen/AMDGPU/GlobalISel/inst-select-store-flat.mir b/test/CodeGen/AMDGPU/GlobalISel/inst-select-store-flat.mir index 89be3bde94a8..ea435725bf25 100644 --- a/test/CodeGen/AMDGPU/GlobalISel/inst-select-store-flat.mir +++ b/test/CodeGen/AMDGPU/GlobalISel/inst-select-store-flat.mir @@ -15,7 +15,7 @@ regBankSelected: true # GCN: global_addrspace # GCN: [[PTR:%[0-9]+]] = COPY %vgpr0_vgpr1 # GCN: [[VAL:%[0-9]+]] = COPY %vgpr2 -# GCN: FLAT_STORE_DWORD [[PTR]], [[VAL]], 0, 0 +# GCN: FLAT_STORE_DWORD [[PTR]], [[VAL]], 0, 0, 0 body: | bb.0: diff --git a/test/CodeGen/AMDGPU/GlobalISel/legalize-add.mir b/test/CodeGen/AMDGPU/GlobalISel/legalize-add.mir new file mode 100644 index 000000000000..f10c896a7af6 --- /dev/null +++ b/test/CodeGen/AMDGPU/GlobalISel/legalize-add.mir @@ -0,0 +1,22 @@ +# RUN: llc -mtriple=amdgcn-mesa-mesa3d -mcpu=fiji -O0 -run-pass=legalizer -global-isel %s -o - | FileCheck %s + +--- | + define void @test_add() { ret void } +... + +--- +name: test_add +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0: + liveins: %vgpr0, %vgpr1 + ; CHECK-LABEL: name: test_add + ; CHECK: %2(s32) = G_ADD %0, %1 + + %0(s32) = COPY %vgpr0 + %1(s32) = COPY %vgpr1 + %2(s32) = G_ADD %0, %1 +... diff --git a/test/CodeGen/AMDGPU/always-uniform.ll b/test/CodeGen/AMDGPU/always-uniform.ll new file mode 100644 index 000000000000..4ba57fba81bc --- /dev/null +++ b/test/CodeGen/AMDGPU/always-uniform.ll @@ -0,0 +1,21 @@ +; RUN: llc -mtriple amdgcn-amdhsa -mcpu=fiji -amdgpu-scalarize-global-loads -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s + +declare i32 @llvm.amdgcn.workitem.id.x() +declare i32 @llvm.amdgcn.readfirstlane(i32) + +; GCN-LABEL: readfirstlane_uniform +; GCN: s_load_dwordx2 s{{\[}}[[IN_ADDR:[0-9]+]]:1{{\]}}, s[4:5], 0x0 +; GCN: v_readfirstlane_b32 s[[SCALAR:[0-9]+]], v0 +; GCN: s_add_u32 s[[LOAD_ADDR:[0-9]+]], s[[IN_ADDR]], s[[SCALAR]] +; GCN: s_load_dword s{{[0-9]+}}, s{{\[}}[[LOAD_ADDR]] + +define amdgpu_kernel void @readfirstlane_uniform(float addrspace(1)* noalias nocapture readonly, float addrspace(1)* noalias nocapture readonly) { + %tid = tail call i32 @llvm.amdgcn.workitem.id.x() + %scalar = tail call i32 @llvm.amdgcn.readfirstlane(i32 %tid) + %idx = zext i32 %scalar to i64 + %gep0 = getelementptr inbounds float, float addrspace(1)* %0, i64 %idx + %val = load float, float addrspace(1)* %gep0, align 4 + %gep1 = getelementptr inbounds float, float addrspace(1)* %1, i64 10 + store float %val, float addrspace(1)* %gep1, align 4 + ret void +} diff --git a/test/CodeGen/AMDGPU/cgp-addressing-modes-flat.ll b/test/CodeGen/AMDGPU/cgp-addressing-modes-flat.ll index cbdcf6aeaf42..5dec3e35ab3d 100644 --- a/test/CodeGen/AMDGPU/cgp-addressing-modes-flat.ll +++ b/test/CodeGen/AMDGPU/cgp-addressing-modes-flat.ll @@ -1,12 +1,19 @@ -; RUN: opt -S -codegenprepare -mtriple=amdgcn-unknown-unknown -mcpu=bonaire < %s | FileCheck -check-prefix=OPT -check-prefix=OPT-CI %s -; RUN: opt -S -codegenprepare -mtriple=amdgcn-unknown-unknown -mcpu=tonga -mattr=-flat-for-global < %s | FileCheck -check-prefix=OPT -check-prefix=OPT-VI %s -; RUN: llc -march=amdgcn -mcpu=bonaire -mattr=-promote-alloca < %s | FileCheck -check-prefix=GCN -check-prefix=CI %s -; RUN: llc -march=amdgcn -mcpu=tonga -mattr=-flat-for-global -mattr=-promote-alloca < %s | FileCheck -check-prefix=GCN -check-prefix=VI %s +; RUN: opt -S -codegenprepare -mtriple=amdgcn-unknown-unknown -mcpu=bonaire < %s | FileCheck -check-prefix=OPT -check-prefix=OPT-CI -check-prefix=OPT-CIVI %s +; RUN: opt -S -codegenprepare -mtriple=amdgcn-unknown-unknown -mcpu=tonga -mattr=-flat-for-global < %s | FileCheck -check-prefix=OPT -check-prefix=OPT-VI -check-prefix=OPT-CIVI %s +; RUN: opt -S -codegenprepare -mtriple=amdgcn-unknown-unknown -mcpu=gfx900 -mattr=-flat-for-global < %s | FileCheck -check-prefix=OPT -check-prefix=OPT-GFX9 %s +; RUN: llc -march=amdgcn -mcpu=bonaire -mattr=-promote-alloca < %s | FileCheck -check-prefix=GCN -check-prefix=CI -check-prefix=CIVI %s +; RUN: llc -march=amdgcn -mcpu=tonga -mattr=-flat-for-global -mattr=-promote-alloca < %s | FileCheck -check-prefix=GCN -check-prefix=VI -check-prefix=CIVI %s +; RUN: llc -march=amdgcn -mcpu=gfx900 -mattr=-flat-for-global -mattr=-promote-alloca < %s | FileCheck -check-prefix=GCN -check-prefix=GFX9 %s ; OPT-LABEL: @test_no_sink_flat_small_offset_i32( -; OPT: getelementptr i32, i32 addrspace(4)* %in -; OPT: br i1 -; OPT-NOT: ptrtoint +; OPT-CIVI: getelementptr i32, i32 addrspace(4)* %in +; OPT-CIVI: br i1 +; OPT-CIVI-NOT: ptrtoint + +; OPT-GFX9: br +; OPT-GFX9: %sunkaddr = getelementptr i8, i8 addrspace(4)* %0, i64 28 +; OPT-GFX9: %1 = bitcast i8 addrspace(4)* %sunkaddr to i32 addrspace(4)* +; OPT-GFX9: load i32, i32 addrspace(4)* %1 ; GCN-LABEL: {{^}}test_no_sink_flat_small_offset_i32: ; GCN: flat_load_dword @@ -96,3 +103,105 @@ endif: done: ret void } + +; OPT-LABEL: @test_sink_flat_small_max_flat_offset( +; OPT-CIVI: %in.gep = getelementptr i8, i8 addrspace(4)* %in, i64 4095 +; OPT-CIVI: br +; OPT-CIVI-NOT: getelementptr +; OPT-CIVI: load i8, i8 addrspace(4)* %in.gep + +; OPT-GFX9: br +; OPT-GFX9: %sunkaddr = getelementptr i8, i8 addrspace(4)* %in, i64 4095 +; OPT-GFX9: load i8, i8 addrspace(4)* %sunkaddr + +; GCN-LABEL: {{^}}test_sink_flat_small_max_flat_offset: +; GFX9: flat_load_sbyte v{{[0-9]+}}, v{{\[[0-9]+:[0-9]+\]}} offset:4095{{$}} +; CIVI: flat_load_sbyte v{{[0-9]+}}, v{{\[[0-9]+:[0-9]+\]$}} +define amdgpu_kernel void @test_sink_flat_small_max_flat_offset(i32 addrspace(4)* %out, i8 addrspace(4)* %in) #1 { +entry: + %out.gep = getelementptr i32, i32 addrspace(4)* %out, i32 1024 + %in.gep = getelementptr i8, i8 addrspace(4)* %in, i64 4095 + %tid = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0) #0 + %tmp0 = icmp eq i32 %tid, 0 + br i1 %tmp0, label %endif, label %if + +if: + %tmp1 = load i8, i8 addrspace(4)* %in.gep + %tmp2 = sext i8 %tmp1 to i32 + br label %endif + +endif: + %x = phi i32 [ %tmp2, %if ], [ 0, %entry ] + store i32 %x, i32 addrspace(4)* %out.gep + br label %done + +done: + ret void +} + +; OPT-LABEL: @test_sink_flat_small_max_plus_1_flat_offset( +; OPT: %in.gep = getelementptr i8, i8 addrspace(4)* %in, i64 4096 +; OPT: br +; OPT-NOT: getelementptr +; OPT: load i8, i8 addrspace(4)* %in.gep + +; GCN-LABEL: {{^}}test_sink_flat_small_max_plus_1_flat_offset: +; GCN: flat_load_sbyte v{{[0-9]+}}, v{{\[[0-9]+:[0-9]+\]$}} +define amdgpu_kernel void @test_sink_flat_small_max_plus_1_flat_offset(i32 addrspace(4)* %out, i8 addrspace(4)* %in) #1 { +entry: + %out.gep = getelementptr i32, i32 addrspace(4)* %out, i64 99999 + %in.gep = getelementptr i8, i8 addrspace(4)* %in, i64 4096 + %tid = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0) #0 + %tmp0 = icmp eq i32 %tid, 0 + br i1 %tmp0, label %endif, label %if + +if: + %tmp1 = load i8, i8 addrspace(4)* %in.gep + %tmp2 = sext i8 %tmp1 to i32 + br label %endif + +endif: + %x = phi i32 [ %tmp2, %if ], [ 0, %entry ] + store i32 %x, i32 addrspace(4)* %out.gep + br label %done + +done: + ret void +} + +; OPT-LABEL: @test_no_sink_flat_reg_offset( +; OPT: %in.gep = getelementptr i8, i8 addrspace(4)* %in, i64 %reg +; OPT: br + +; OPT-NOT: getelementptr +; OPT: load i8, i8 addrspace(4)* %in.gep + +; GCN-LABEL: {{^}}test_no_sink_flat_reg_offset: +; GCN: flat_load_sbyte v{{[0-9]+}}, v{{\[[0-9]+:[0-9]+\]$}} +define amdgpu_kernel void @test_no_sink_flat_reg_offset(i32 addrspace(4)* %out, i8 addrspace(4)* %in, i64 %reg) #1 { +entry: + %out.gep = getelementptr i32, i32 addrspace(4)* %out, i32 1024 + %in.gep = getelementptr i8, i8 addrspace(4)* %in, i64 %reg + %tid = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0) #0 + %tmp0 = icmp eq i32 %tid, 0 + br i1 %tmp0, label %endif, label %if + +if: + %tmp1 = load i8, i8 addrspace(4)* %in.gep + %tmp2 = sext i8 %tmp1 to i32 + br label %endif + +endif: + %x = phi i32 [ %tmp2, %if ], [ 0, %entry ] + store i32 %x, i32 addrspace(4)* %out.gep + br label %done + +done: + ret void +} + +declare i32 @llvm.amdgcn.mbcnt.lo(i32, i32) #0 + +attributes #0 = { nounwind readnone } +attributes #1 = { nounwind } +attributes #2 = { nounwind argmemonly } diff --git a/test/CodeGen/AMDGPU/code-object-metadata-kernel-debug-props.ll b/test/CodeGen/AMDGPU/code-object-metadata-kernel-debug-props.ll index 801029be8cb9..0796c24b3317 100644 --- a/test/CodeGen/AMDGPU/code-object-metadata-kernel-debug-props.ll +++ b/test/CodeGen/AMDGPU/code-object-metadata-kernel-debug-props.ll @@ -12,7 +12,9 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK: DebugProps: ; CHECK: DebuggerABIVersion: [ 1, 0 ] ; CHECK: ReservedNumVGPRs: 4 -; CHECK: ReservedFirstVGPR: 11 +; GFX700: ReservedFirstVGPR: 11 +; GFX800: ReservedFirstVGPR: 11 +; GFX9: ReservedFirstVGPR: 14 ; CHECK: PrivateSegmentBufferSGPR: 0 ; CHECK: WavefrontPrivateSegmentOffsetSGPR: 11 define amdgpu_kernel void @test(i32 addrspace(1)* %A) #0 !dbg !7 !kernel_arg_addr_space !12 !kernel_arg_access_qual !13 !kernel_arg_type !14 !kernel_arg_base_type !14 !kernel_arg_type_qual !15 { diff --git a/test/CodeGen/AMDGPU/constant-fold-imm-immreg.mir b/test/CodeGen/AMDGPU/constant-fold-imm-immreg.mir index bc992ed77ffd..62b47beb1251 100644 --- a/test/CodeGen/AMDGPU/constant-fold-imm-immreg.mir +++ b/test/CodeGen/AMDGPU/constant-fold-imm-immreg.mir @@ -219,19 +219,19 @@ body: | %34 = V_MOV_B32_e32 63, implicit %exec %27 = V_AND_B32_e64 %26, %24, implicit %exec - FLAT_STORE_DWORD %37, %27, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %37, %27, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %28 = V_AND_B32_e64 %24, %26, implicit %exec - FLAT_STORE_DWORD %37, %28, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %37, %28, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %29 = V_AND_B32_e32 %26, %24, implicit %exec - FLAT_STORE_DWORD %37, %29, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %37, %29, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %30 = V_AND_B32_e64 %26, %26, implicit %exec - FLAT_STORE_DWORD %37, %30, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %37, %30, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %31 = V_AND_B32_e64 %34, %34, implicit %exec - FLAT_STORE_DWORD %37, %31, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %37, %31, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) S_ENDPGM @@ -407,34 +407,34 @@ body: | %27 = S_MOV_B32 -4 %11 = V_LSHLREV_B32_e64 12, %10, implicit %exec - FLAT_STORE_DWORD %20, %11, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %11, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %12 = V_LSHLREV_B32_e64 %7, 12, implicit %exec - FLAT_STORE_DWORD %20, %12, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %12, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %13 = V_LSHL_B32_e64 %7, 12, implicit %exec - FLAT_STORE_DWORD %20, %13, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %13, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %14 = V_LSHL_B32_e64 12, %7, implicit %exec - FLAT_STORE_DWORD %20, %14, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %14, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %15 = V_LSHL_B32_e64 12, %24, implicit %exec - FLAT_STORE_DWORD %20, %15, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %15, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %22 = V_LSHL_B32_e64 %6, 12, implicit %exec - FLAT_STORE_DWORD %20, %22, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %22, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %23 = V_LSHL_B32_e64 %6, 32, implicit %exec - FLAT_STORE_DWORD %20, %23, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %23, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %25 = V_LSHL_B32_e32 %6, %6, implicit %exec - FLAT_STORE_DWORD %20, %25, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %25, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %26 = V_LSHLREV_B32_e32 11, %24, implicit %exec - FLAT_STORE_DWORD %20, %26, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %26, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %28 = V_LSHL_B32_e32 %27, %6, implicit %exec - FLAT_STORE_DWORD %20, %28, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %28, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) S_ENDPGM @@ -615,34 +615,34 @@ body: | %35 = V_MOV_B32_e32 2, implicit %exec %11 = V_ASHRREV_I32_e64 8, %10, implicit %exec - FLAT_STORE_DWORD %20, %11, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %11, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %12 = V_ASHRREV_I32_e64 %8, %10, implicit %exec - FLAT_STORE_DWORD %20, %12, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %12, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %13 = V_ASHR_I32_e64 %7, 3, implicit %exec - FLAT_STORE_DWORD %20, %13, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %13, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %14 = V_ASHR_I32_e64 7, %32, implicit %exec - FLAT_STORE_DWORD %20, %14, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %14, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %15 = V_ASHR_I32_e64 %27, %24, implicit %exec - FLAT_STORE_DWORD %20, %15, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %15, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %22 = V_ASHR_I32_e64 %6, 4, implicit %exec - FLAT_STORE_DWORD %20, %22, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %22, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %23 = V_ASHR_I32_e64 %6, %33, implicit %exec - FLAT_STORE_DWORD %20, %23, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %23, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %25 = V_ASHR_I32_e32 %34, %34, implicit %exec - FLAT_STORE_DWORD %20, %25, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %25, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %26 = V_ASHRREV_I32_e32 11, %10, implicit %exec - FLAT_STORE_DWORD %20, %26, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %26, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %28 = V_ASHR_I32_e32 %27, %35, implicit %exec - FLAT_STORE_DWORD %20, %28, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %28, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) S_ENDPGM @@ -824,34 +824,34 @@ body: | %35 = V_MOV_B32_e32 2, implicit %exec %11 = V_LSHRREV_B32_e64 8, %10, implicit %exec - FLAT_STORE_DWORD %20, %11, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %11, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %12 = V_LSHRREV_B32_e64 %8, %10, implicit %exec - FLAT_STORE_DWORD %20, %12, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %12, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %13 = V_LSHR_B32_e64 %7, 3, implicit %exec - FLAT_STORE_DWORD %20, %13, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %13, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %14 = V_LSHR_B32_e64 7, %32, implicit %exec - FLAT_STORE_DWORD %20, %14, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %14, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %15 = V_LSHR_B32_e64 %27, %24, implicit %exec - FLAT_STORE_DWORD %20, %15, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %15, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %22 = V_LSHR_B32_e64 %6, 4, implicit %exec - FLAT_STORE_DWORD %20, %22, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %22, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %23 = V_LSHR_B32_e64 %6, %33, implicit %exec - FLAT_STORE_DWORD %20, %23, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %23, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %25 = V_LSHR_B32_e32 %34, %34, implicit %exec - FLAT_STORE_DWORD %20, %25, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %25, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %26 = V_LSHRREV_B32_e32 11, %10, implicit %exec - FLAT_STORE_DWORD %20, %26, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %26, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) %28 = V_LSHR_B32_e32 %27, %35, implicit %exec - FLAT_STORE_DWORD %20, %28, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) + FLAT_STORE_DWORD %20, %28, 0, 0, 0, implicit %exec, implicit %flat_scr :: (volatile store 4 into %ir.gep.out) S_ENDPGM diff --git a/test/CodeGen/AMDGPU/flat-address-space.ll b/test/CodeGen/AMDGPU/flat-address-space.ll index c867e4fca229..e486b9c71a54 100644 --- a/test/CodeGen/AMDGPU/flat-address-space.ll +++ b/test/CodeGen/AMDGPU/flat-address-space.ll @@ -1,6 +1,7 @@ -; RUN: llc -O0 -mtriple=amdgcn-mesa-mesa3d -mcpu=bonaire < %s | FileCheck %s -; RUN: llc -O0 -mtriple=amdgcn-mesa-mesa3d -mcpu=tonga -mattr=-flat-for-global < %s | FileCheck %s +; RUN: llc -O0 -mtriple=amdgcn-mesa-mesa3d -mcpu=bonaire < %s | FileCheck -check-prefixes=CHECK,CIVI %s +; RUN: llc -O0 -mtriple=amdgcn-mesa-mesa3d -mcpu=tonga -mattr=-flat-for-global < %s | FileCheck -check-prefixes=CHECK,CIVI %s ; RUN: llc -O0 -mtriple=amdgcn-amd-amdhsa -mcpu=fiji -mattr=-flat-for-global < %s | FileCheck -check-prefixes=CHECK,HSA %s +; RUN: llc -O0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -mattr=-flat-for-global < %s | FileCheck -check-prefixes=CHECK,HSA,GFX9 %s ; Disable optimizations in case there are optimizations added that ; specialize away generic pointer accesses. @@ -172,6 +173,55 @@ define amdgpu_kernel void @flat_scratch_multidword_store() { ret void } +; CHECK-LABEL: {{^}}store_flat_i8_max_offset: +; CIVI: flat_store_byte v{{\[[0-9]+:[0-9]+\]}}, v{{[0-9]+}}{{$}} +; GFX9: flat_store_byte v{{\[[0-9]+:[0-9]+\]}}, v{{[0-9]+}} offset:4095{{$}} +define amdgpu_kernel void @store_flat_i8_max_offset(i8 addrspace(4)* %fptr, i8 %x) #0 { + %fptr.offset = getelementptr inbounds i8, i8 addrspace(4)* %fptr, i64 4095 + store volatile i8 %x, i8 addrspace(4)* %fptr.offset + ret void +} + +; CHECK-LABEL: {{^}}store_flat_i8_max_offset_p1: +; CHECK: flat_store_byte v{{\[[0-9]+:[0-9]+\]}}, v{{[0-9]+}}{{$}} +define amdgpu_kernel void @store_flat_i8_max_offset_p1(i8 addrspace(4)* %fptr, i8 %x) #0 { + %fptr.offset = getelementptr inbounds i8, i8 addrspace(4)* %fptr, i64 4096 + store volatile i8 %x, i8 addrspace(4)* %fptr.offset + ret void +} + +; CHECK-LABEL: {{^}}store_flat_i8_neg_offset: +; CHECK: flat_store_byte v{{\[[0-9]+:[0-9]+\]}}, v{{[0-9]+}}{{$}} +define amdgpu_kernel void @store_flat_i8_neg_offset(i8 addrspace(4)* %fptr, i8 %x) #0 { + %fptr.offset = getelementptr inbounds i8, i8 addrspace(4)* %fptr, i64 -2 + store volatile i8 %x, i8 addrspace(4)* %fptr.offset + ret void +} + +; CHECK-LABEL: {{^}}load_flat_i8_max_offset: +; CIVI: flat_load_ubyte v{{[0-9]+}}, v{{\[[0-9]+:[0-9]+\]}}{{$}} +; GFX9: flat_load_ubyte v{{[0-9]+}}, v{{\[[0-9]+:[0-9]+\]}} offset:4095{{$}} +define amdgpu_kernel void @load_flat_i8_max_offset(i8 addrspace(4)* %fptr) #0 { + %fptr.offset = getelementptr inbounds i8, i8 addrspace(4)* %fptr, i64 4095 + %val = load volatile i8, i8 addrspace(4)* %fptr.offset + ret void +} + +; CHECK-LABEL: {{^}}load_flat_i8_max_offset_p1: +; CHECK: flat_load_ubyte v{{[0-9]+}}, v{{\[[0-9]+:[0-9]+\]}}{{$}} +define amdgpu_kernel void @load_flat_i8_max_offset_p1(i8 addrspace(4)* %fptr) #0 { + %fptr.offset = getelementptr inbounds i8, i8 addrspace(4)* %fptr, i64 4096 + %val = load volatile i8, i8 addrspace(4)* %fptr.offset + ret void +} + +; CHECK-LABEL: {{^}}load_flat_i8_neg_offset: +; CHECK: flat_load_ubyte v{{[0-9]+}}, v{{\[[0-9]+:[0-9]+\]}}{{$}} +define amdgpu_kernel void @load_flat_i8_neg_offset(i8 addrspace(4)* %fptr) #0 { + %fptr.offset = getelementptr inbounds i8, i8 addrspace(4)* %fptr, i64 -2 + %val = load volatile i8, i8 addrspace(4)* %fptr.offset + ret void +} + attributes #0 = { nounwind } attributes #1 = { nounwind convergent } -attributes #3 = { nounwind readnone } diff --git a/test/CodeGen/AMDGPU/flat_atomics.ll b/test/CodeGen/AMDGPU/flat_atomics.ll index cc95d80570e0..8e153181decb 100644 --- a/test/CodeGen/AMDGPU/flat_atomics.ll +++ b/test/CodeGen/AMDGPU/flat_atomics.ll @@ -1,8 +1,10 @@ -; RUN: llc -march=amdgcn -mcpu=bonaire -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s -; RUN: llc -march=amdgcn -mcpu=tonga -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s +; RUN: llc -march=amdgcn -mcpu=bonaire -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,CIVI %s +; RUN: llc -march=amdgcn -mcpu=tonga -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,CIVI %s +; RUN: llc -march=amdgcn -mcpu=gfx900 -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,GFX9 %s ; GCN-LABEL: {{^}}atomic_add_i32_offset: -; GCN: flat_atomic_add v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}}{{$}} +; CIVI: flat_atomic_add v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}}{{$}} +; GFX9: flat_atomic_add v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_add_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -10,8 +12,28 @@ entry: ret void } +; GCN-LABEL: {{^}}atomic_add_i32_max_offset: +; CIVI: flat_atomic_add v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}}{{$}} +; GFX9: flat_atomic_add v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} offset:4092{{$}} +define amdgpu_kernel void @atomic_add_i32_max_offset(i32 addrspace(4)* %out, i32 %in) { +entry: + %gep = getelementptr i32, i32 addrspace(4)* %out, i32 1023 + %val = atomicrmw volatile add i32 addrspace(4)* %gep, i32 %in seq_cst + ret void +} + +; GCN-LABEL: {{^}}atomic_add_i32_max_offset_p1: +; GCN: flat_atomic_add v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}}{{$}} +define amdgpu_kernel void @atomic_add_i32_max_offset_p1(i32 addrspace(4)* %out, i32 %in) { +entry: + %gep = getelementptr i32, i32 addrspace(4)* %out, i32 1024 + %val = atomicrmw volatile add i32 addrspace(4)* %gep, i32 %in seq_cst + ret void +} + ; GCN-LABEL: {{^}}atomic_add_i32_ret_offset: -; GCN: flat_atomic_add [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_add [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_add [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_add_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -22,7 +44,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_add_i32_addr64_offset: -; GCN: flat_atomic_add v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_add v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_add v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_add_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -32,7 +55,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_add_i32_ret_addr64_offset: -; GCN: flat_atomic_add [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_add [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_add [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_add_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -82,7 +106,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_and_i32_offset: -; GCN: flat_atomic_and v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_and v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_and v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_and_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -91,7 +116,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_and_i32_ret_offset: -; GCN: flat_atomic_and [[RET:v[0-9]]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_and [[RET:v[0-9]]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_and [[RET:v[0-9]]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_and_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -102,7 +128,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_and_i32_addr64_offset: -; GCN: flat_atomic_and v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_and v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_and v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_and_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -112,7 +139,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_and_i32_ret_addr64_offset: -; GCN: flat_atomic_and [[RET:v[0-9]]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_and [[RET:v[0-9]]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_and [[RET:v[0-9]]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_and_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -162,7 +190,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_sub_i32_offset: -; GCN: flat_atomic_sub v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_sub v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_sub v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_sub_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -171,7 +200,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_sub_i32_ret_offset: -; GCN: flat_atomic_sub [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_sub [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_sub [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_sub_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -182,7 +212,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_sub_i32_addr64_offset: -; GCN: flat_atomic_sub v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_sub v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_sub v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_sub_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -192,7 +223,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_sub_i32_ret_addr64_offset: -; GCN: flat_atomic_sub [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_sub [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_sub [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_sub_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -242,7 +274,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_max_i32_offset: -; GCN: flat_atomic_smax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_smax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_smax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_max_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -251,7 +284,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_max_i32_ret_offset: -; GCN: flat_atomic_smax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_smax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_smax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_max_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -262,7 +296,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_max_i32_addr64_offset: -; GCN: flat_atomic_smax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_smax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_smax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_max_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -272,7 +307,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_max_i32_ret_addr64_offset: -; GCN: flat_atomic_smax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_smax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_smax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_max_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -322,7 +358,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_umax_i32_offset: -; GCN: flat_atomic_umax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_umax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_umax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_umax_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -331,7 +368,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_umax_i32_ret_offset: -; GCN: flat_atomic_umax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_umax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_umax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_umax_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -342,7 +380,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_umax_i32_addr64_offset: -; GCN: flat_atomic_umax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_umax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_umax v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_umax_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -352,7 +391,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_umax_i32_ret_addr64_offset: -; GCN: flat_atomic_umax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_umax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_umax [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_umax_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -402,7 +442,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_min_i32_offset: -; GCN: flat_atomic_smin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_smin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_smin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_min_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -411,7 +452,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_min_i32_ret_offset: -; GCN: flat_atomic_smin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_smin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_smin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_min_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -422,7 +464,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_min_i32_addr64_offset: -; GCN: flat_atomic_smin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_smin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_smin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_min_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -432,7 +475,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_min_i32_ret_addr64_offset: -; GCN: flat_atomic_smin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_smin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_smin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_min_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -482,7 +526,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_umin_i32_offset: -; GCN: flat_atomic_umin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_umin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_umin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_umin_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -491,7 +536,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_umin_i32_ret_offset: -; GCN: flat_atomic_umin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_umin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_umin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_umin_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -502,7 +548,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_umin_i32_addr64_offset: -; GCN: flat_atomic_umin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_umin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_umin v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_umin_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -512,7 +559,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_umin_i32_ret_addr64_offset: -; GCN: flat_atomic_umin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_umin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_umin [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_umin_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -562,7 +610,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_or_i32_offset: -; GCN: flat_atomic_or v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}}{{$}} +; CIVI: flat_atomic_or v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_or v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_or_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -571,7 +620,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_or_i32_ret_offset: -; GCN: flat_atomic_or [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_or [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_or [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_or_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -582,7 +632,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_or_i32_addr64_offset: -; GCN: flat_atomic_or v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}}{{$}} +; CIVI: flat_atomic_or v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_or v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_or_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -592,7 +643,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_or_i32_ret_addr64_offset: -; GCN: flat_atomic_or [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_or [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_or [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_or_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -642,7 +694,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_xchg_i32_offset: -; GCN: flat_atomic_swap v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}}{{$}} +; CIVI: flat_atomic_swap v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_swap v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_xchg_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -651,7 +704,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_xchg_i32_ret_offset: -; GCN: flat_atomic_swap [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_swap [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_swap [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_xchg_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -662,7 +716,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_xchg_i32_addr64_offset: -; GCN: flat_atomic_swap v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}}{{$}} +; CIVI: flat_atomic_swap v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_swap v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_xchg_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -672,7 +727,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_xchg_i32_ret_addr64_offset: -; GCN: flat_atomic_swap [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_swap [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_swap [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_xchg_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -724,7 +780,8 @@ entry: ; CMP_SWAP ; GCN-LABEL: {{^}}atomic_cmpxchg_i32_offset: -; GCN: flat_atomic_cmpswap v[{{[0-9]+\:[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}]{{$}} +; CIVI: flat_atomic_cmpswap v[{{[0-9]+\:[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}]{{$}} +; GFX9: flat_atomic_cmpswap v[{{[0-9]+\:[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}] offset:16{{$}} define amdgpu_kernel void @atomic_cmpxchg_i32_offset(i32 addrspace(4)* %out, i32 %in, i32 %old) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -733,7 +790,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_cmpxchg_i32_ret_offset: -; GCN: flat_atomic_cmpswap v[[RET:[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}] glc{{$}} +; CIVI: flat_atomic_cmpswap v[[RET:[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}] glc{{$}} +; GFX9: flat_atomic_cmpswap v[[RET:[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}] offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, v[[RET]] define amdgpu_kernel void @atomic_cmpxchg_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i32 %old) { entry: @@ -745,7 +803,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_cmpxchg_i32_addr64_offset: -; GCN: flat_atomic_cmpswap v[{{[0-9]+\:[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}]{{$}} +; CIVI: flat_atomic_cmpswap v[{{[0-9]+\:[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}]{{$}} +; GFX9: flat_atomic_cmpswap v[{{[0-9]+\:[0-9]+}}], v[{{[0-9]+}}:{{[0-9]+}}] offset:16{{$}} define amdgpu_kernel void @atomic_cmpxchg_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index, i32 %old) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -755,7 +814,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_cmpxchg_i32_ret_addr64_offset: -; GCN: flat_atomic_cmpswap v[[RET:[0-9]+]], v[{{[0-9]+:[0-9]+}}], v[{{[0-9]+:[0-9]+}}] glc{{$}} +; CIVI: flat_atomic_cmpswap v[[RET:[0-9]+]], v[{{[0-9]+:[0-9]+}}], v[{{[0-9]+:[0-9]+}}] glc{{$}} +; GFX9: flat_atomic_cmpswap v[[RET:[0-9]+]], v[{{[0-9]+:[0-9]+}}], v[{{[0-9]+:[0-9]+}}] offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, v[[RET]] define amdgpu_kernel void @atomic_cmpxchg_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index, i32 %old) { entry: @@ -808,7 +868,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_xor_i32_offset: -; GCN: flat_atomic_xor v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}}{{$}} +; CIVI: flat_atomic_xor v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}}{{$}} +; GFX9: flat_atomic_xor v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_xor_i32_offset(i32 addrspace(4)* %out, i32 %in) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -817,7 +878,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_xor_i32_ret_offset: -; GCN: flat_atomic_xor [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_xor [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_xor [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_xor_i32_ret_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in) { entry: @@ -828,7 +890,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_xor_i32_addr64_offset: -; GCN: flat_atomic_xor v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; CIVI: flat_atomic_xor v[{{[0-9]+:[0-9]+}}], v{{[0-9]+$}} +; GFX9: flat_atomic_xor v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16{{$}} define amdgpu_kernel void @atomic_xor_i32_addr64_offset(i32 addrspace(4)* %out, i32 %in, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index @@ -838,7 +901,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_xor_i32_ret_addr64_offset: -; GCN: flat_atomic_xor [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; CIVI: flat_atomic_xor [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} glc{{$}} +; GFX9: flat_atomic_xor [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}], v{{[0-9]+}} offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_xor_i32_ret_addr64_offset(i32 addrspace(4)* %out, i32 addrspace(4)* %out2, i32 %in, i64 %index) { entry: @@ -888,7 +952,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_load_i32_offset: -; GCN: flat_load_dword [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}] glc{{$}} +; CIVI: flat_load_dword [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}] glc{{$}} +; GFX9: flat_load_dword [[RET:v[0-9]+]], v[{{[0-9]+}}:{{[0-9]+}}] offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_load_i32_offset(i32 addrspace(4)* %in, i32 addrspace(4)* %out) { entry: @@ -909,7 +974,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_load_i32_addr64_offset: -; GCN: flat_load_dword [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}] glc{{$}} +; CIVI: flat_load_dword [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}] glc{{$}} +; GFX9: flat_load_dword [[RET:v[0-9]+]], v[{{[0-9]+:[0-9]+}}] offset:16 glc{{$}} ; GCN: flat_store_dword v{{\[[0-9]+:[0-9]+\]}}, [[RET]] define amdgpu_kernel void @atomic_load_i32_addr64_offset(i32 addrspace(4)* %in, i32 addrspace(4)* %out, i64 %index) { entry: @@ -932,7 +998,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_store_i32_offset: -; GCN: flat_store_dword v[{{[0-9]+}}:{{[0-9]+}}], {{v[0-9]+}} glc{{$}} +; CIVI: flat_store_dword v[{{[0-9]+}}:{{[0-9]+}}], {{v[0-9]+}} glc{{$}} +; GFX9: flat_store_dword v[{{[0-9]+}}:{{[0-9]+}}], {{v[0-9]+}} offset:16 glc{{$}} define amdgpu_kernel void @atomic_store_i32_offset(i32 %in, i32 addrspace(4)* %out) { entry: %gep = getelementptr i32, i32 addrspace(4)* %out, i32 4 @@ -949,7 +1016,8 @@ entry: } ; GCN-LABEL: {{^}}atomic_store_i32_addr64_offset: -; GCN: flat_store_dword v[{{[0-9]+}}:{{[0-9]+}}], {{v[0-9]+}} glc{{$}} +; CIVI: flat_store_dword v[{{[0-9]+}}:{{[0-9]+}}], {{v[0-9]+}} glc{{$}} +; GFX9: flat_store_dword v[{{[0-9]+}}:{{[0-9]+}}], {{v[0-9]+}} offset:16 glc{{$}} define amdgpu_kernel void @atomic_store_i32_addr64_offset(i32 %in, i32 addrspace(4)* %out, i64 %index) { entry: %ptr = getelementptr i32, i32 addrspace(4)* %out, i64 %index diff --git a/test/CodeGen/AMDGPU/global_smrd_cfg.ll b/test/CodeGen/AMDGPU/global_smrd_cfg.ll index a6a04151caa9..be6e3fd05ae7 100644 --- a/test/CodeGen/AMDGPU/global_smrd_cfg.ll +++ b/test/CodeGen/AMDGPU/global_smrd_cfg.ll @@ -72,6 +72,39 @@ bb22: ; preds = %bb20, %bb11 br i1 %tmp31, label %bb7, label %bb11 } +; one more test to ensure that aliasing store after the load +; is considered clobbering if load parent block is the same +; as a loop header block. + +; CHECK-LABEL: %bb1 + +; Load from %arg has alias store that is after the load +; but is considered clobbering because of the loop. + +; CHECK: flat_load_dword + +define amdgpu_kernel void @cfg_selfloop(i32 addrspace(1)* nocapture readonly %arg, i32 addrspace(1)* nocapture %arg1, i32 %arg2) #0 { +bb: + br label %bb1 + +bb2: + ret void + +bb1: + %tmp13 = phi i32 [ %tmp25, %bb1 ], [ 0, %bb ] + %tmp14 = srem i32 %tmp13, %arg2 + %tmp15 = sext i32 %tmp14 to i64 + %tmp16 = getelementptr inbounds i32, i32 addrspace(1)* %arg, i64 %tmp15 + %tmp17 = load i32, i32 addrspace(1)* %tmp16, align 4, !tbaa !0 + %tmp19 = sext i32 %tmp13 to i64 + %tmp21 = getelementptr inbounds i32, i32 addrspace(1)* %arg1, i64 %tmp19 + store i32 %tmp17, i32 addrspace(1)* %tmp21, align 4, !tbaa !0 + %tmp25 = add nuw nsw i32 %tmp13, 1 + %tmp31 = icmp eq i32 %tmp25, 100 + br i1 %tmp31, label %bb2, label %bb1 +} + + attributes #0 = { "target-cpu"="fiji" } !0 = !{!1, !1, i64 0} diff --git a/test/CodeGen/AMDGPU/inserted-wait-states.mir b/test/CodeGen/AMDGPU/inserted-wait-states.mir index ff9fcd1c693f..c6fe6debd225 100644 --- a/test/CodeGen/AMDGPU/inserted-wait-states.mir +++ b/test/CodeGen/AMDGPU/inserted-wait-states.mir @@ -246,15 +246,15 @@ body: | S_BRANCH %bb.1 bb.1: - FLAT_STORE_DWORDX2 %vgpr0_vgpr1, %vgpr2_vgpr3, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORDX2 %vgpr0_vgpr1, %vgpr2_vgpr3, 0, 0, 0, implicit %exec, implicit %flat_scr %vgpr3 = V_MOV_B32_e32 0, implicit %exec - FLAT_STORE_DWORDX3 %vgpr0_vgpr1, %vgpr2_vgpr3_vgpr4, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORDX3 %vgpr0_vgpr1, %vgpr2_vgpr3_vgpr4, 0, 0, 0, implicit %exec, implicit %flat_scr %vgpr3 = V_MOV_B32_e32 0, implicit %exec - FLAT_STORE_DWORDX4 %vgpr0_vgpr1, %vgpr2_vgpr3_vgpr4_vgpr5, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORDX4 %vgpr0_vgpr1, %vgpr2_vgpr3_vgpr4_vgpr5, 0, 0, 0, implicit %exec, implicit %flat_scr %vgpr3 = V_MOV_B32_e32 0, implicit %exec - FLAT_ATOMIC_CMPSWAP_X2 %vgpr0_vgpr1, %vgpr2_vgpr3_vgpr4_vgpr5, 0, implicit %exec, implicit %flat_scr + FLAT_ATOMIC_CMPSWAP_X2 %vgpr0_vgpr1, %vgpr2_vgpr3_vgpr4_vgpr5, 0, 0, implicit %exec, implicit %flat_scr %vgpr3 = V_MOV_B32_e32 0, implicit %exec - FLAT_ATOMIC_FCMPSWAP_X2 %vgpr0_vgpr1, %vgpr2_vgpr3_vgpr4_vgpr5, 0, implicit %exec, implicit %flat_scr + FLAT_ATOMIC_FCMPSWAP_X2 %vgpr0_vgpr1, %vgpr2_vgpr3_vgpr4_vgpr5, 0, 0, implicit %exec, implicit %flat_scr %vgpr3 = V_MOV_B32_e32 0, implicit %exec S_ENDPGM diff --git a/test/CodeGen/AMDGPU/limit-coalesce.mir b/test/CodeGen/AMDGPU/limit-coalesce.mir index 7d6d8a5891cd..d6b3d7b14cd2 100644 --- a/test/CodeGen/AMDGPU/limit-coalesce.mir +++ b/test/CodeGen/AMDGPU/limit-coalesce.mir @@ -57,15 +57,15 @@ body: | %4.sub1 = COPY %3.sub0 undef %5.sub0 = COPY %4.sub1 %5.sub1 = COPY %4.sub0 - FLAT_STORE_DWORDX2 %vgpr0_vgpr1, killed %5, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORDX2 %vgpr0_vgpr1, killed %5, 0, 0, 0, implicit %exec, implicit %flat_scr %6 = IMPLICIT_DEF undef %7.sub0_sub1 = COPY %6 %7.sub2 = COPY %3.sub0 - FLAT_STORE_DWORDX3 %vgpr0_vgpr1, killed %7, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORDX3 %vgpr0_vgpr1, killed %7, 0, 0, 0, implicit %exec, implicit %flat_scr %8 = IMPLICIT_DEF undef %9.sub0_sub1_sub2 = COPY %8 %9.sub3 = COPY %3.sub0 - FLAT_STORE_DWORDX4 %vgpr0_vgpr1, killed %9, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORDX4 %vgpr0_vgpr1, killed %9, 0, 0, 0, implicit %exec, implicit %flat_scr ... diff --git a/test/CodeGen/AMDGPU/rename-independent-subregs-invalid-mac-operands.mir b/test/CodeGen/AMDGPU/rename-independent-subregs-invalid-mac-operands.mir index 1a0d68d81f97..31024277871d 100644 --- a/test/CodeGen/AMDGPU/rename-independent-subregs-invalid-mac-operands.mir +++ b/test/CodeGen/AMDGPU/rename-independent-subregs-invalid-mac-operands.mir @@ -58,12 +58,12 @@ body: | bb.3: %1 = COPY killed %17 - FLAT_STORE_DWORD undef %10, %1.sub2, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORD undef %10, %1.sub2, 0, 0, 0, implicit %exec, implicit %flat_scr %14 = COPY %1.sub1 %16 = COPY killed %1.sub0 undef %15.sub0 = COPY killed %16 %15.sub1 = COPY killed %14 - FLAT_STORE_DWORDX2 undef %11, killed %15, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORDX2 undef %11, killed %15, 0, 0, 0, implicit %exec, implicit %flat_scr S_ENDPGM ... diff --git a/test/CodeGen/AMDGPU/sdwa-scalar-ops.mir b/test/CodeGen/AMDGPU/sdwa-scalar-ops.mir index cd0d410368c7..ba937c927c70 100644 --- a/test/CodeGen/AMDGPU/sdwa-scalar-ops.mir +++ b/test/CodeGen/AMDGPU/sdwa-scalar-ops.mir @@ -214,26 +214,26 @@ body: | %15 = S_ADDC_U32 %7.sub1, %0.sub1, implicit-def dead %scc, implicit %scc %16 = REG_SEQUENCE %14, 1, %15, 2 %18 = COPY %16 - %17 = FLAT_LOAD_DWORD %18, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.uglygep45) + %17 = FLAT_LOAD_DWORD %18, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.uglygep45) %60 = V_BFE_U32 %17, 8, 8, implicit %exec %61 = V_LSHLREV_B32_e32 2, killed %60, implicit %exec %70 = V_ADD_I32_e32 %7.sub0, %61, implicit-def %vcc, implicit %exec %66 = COPY %13 %65 = V_ADDC_U32_e32 0, %66, implicit-def %vcc, implicit %vcc, implicit %exec %67 = REG_SEQUENCE %70, 1, killed %65, 2 - FLAT_STORE_DWORD %67, %30, 0, 0, implicit %exec, implicit %flat_scr :: (store 4 into %ir.tmp9) + FLAT_STORE_DWORD %67, %30, 0, 0, 0, implicit %exec, implicit %flat_scr :: (store 4 into %ir.tmp9) %37 = S_ADD_U32 %14, 4, implicit-def %scc %38 = S_ADDC_U32 %15, 0, implicit-def dead %scc, implicit %scc %71 = COPY killed %37 %72 = COPY killed %38 %41 = REG_SEQUENCE killed %71, 1, killed %72, 2 - %40 = FLAT_LOAD_DWORD killed %41, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.scevgep) + %40 = FLAT_LOAD_DWORD killed %41, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.scevgep) %73 = V_BFE_U32 %40, 8, 8, implicit %exec %74 = V_LSHLREV_B32_e32 2, killed %73, implicit %exec %83 = V_ADD_I32_e32 %7.sub0, %74, implicit-def %vcc, implicit %exec %78 = V_ADDC_U32_e32 0, %66, implicit-def %vcc, implicit %vcc, implicit %exec %80 = REG_SEQUENCE %83, 1, killed %78, 2 - FLAT_STORE_DWORD %80, %30, 0, 0, implicit %exec, implicit %flat_scr :: (store 4 into %ir.tmp17) + FLAT_STORE_DWORD %80, %30, 0, 0, 0, implicit %exec, implicit %flat_scr :: (store 4 into %ir.tmp17) %55 = S_ADD_U32 %0.sub0, 8, implicit-def %scc %56 = S_ADDC_U32 %0.sub1, 0, implicit-def dead %scc, implicit %scc %57 = REG_SEQUENCE %55, 1, killed %56, 2 @@ -377,26 +377,26 @@ body: | %15 = S_ADDC_U32 %7.sub1, %0.sub1, implicit-def dead %scc, implicit %scc %16 = REG_SEQUENCE %14, 1, %15, 2 %18 = COPY %16 - %17 = FLAT_LOAD_DWORD %18, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.uglygep45) + %17 = FLAT_LOAD_DWORD %18, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.uglygep45) %60 = V_BFE_U32 %17, 8, 8, implicit %exec %61 = V_LSHLREV_B32_e32 %84, killed %60, implicit %exec %70 = V_ADD_I32_e32 %7.sub0, %61, implicit-def %vcc, implicit %exec %66 = COPY %13 %65 = V_ADDC_U32_e32 0, %66, implicit-def %vcc, implicit %vcc, implicit %exec %67 = REG_SEQUENCE %70, 1, killed %65, 2 - FLAT_STORE_DWORD %67, %30, 0, 0, implicit %exec, implicit %flat_scr :: (store 4 into %ir.tmp9) + FLAT_STORE_DWORD %67, %30, 0, 0, 0, implicit %exec, implicit %flat_scr :: (store 4 into %ir.tmp9) %37 = S_ADD_U32 %14, 4, implicit-def %scc %38 = S_ADDC_U32 %15, 0, implicit-def dead %scc, implicit %scc %71 = COPY killed %37 %72 = COPY killed %38 %41 = REG_SEQUENCE killed %71, 1, killed %72, 2 - %40 = FLAT_LOAD_DWORD killed %41, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.scevgep) + %40 = FLAT_LOAD_DWORD killed %41, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.scevgep) %73 = V_BFE_U32 %40, 8, 8, implicit %exec %74 = V_LSHLREV_B32_e32 %84, killed %73, implicit %exec %83 = V_ADD_I32_e32 %7.sub0, %74, implicit-def %vcc, implicit %exec %78 = V_ADDC_U32_e32 0, %66, implicit-def %vcc, implicit %vcc, implicit %exec %80 = REG_SEQUENCE %83, 1, killed %78, 2 - FLAT_STORE_DWORD %80, %30, 0, 0, implicit %exec, implicit %flat_scr :: (store 4 into %ir.tmp17) + FLAT_STORE_DWORD %80, %30, 0, 0, 0, implicit %exec, implicit %flat_scr :: (store 4 into %ir.tmp17) %55 = S_ADD_U32 %0.sub0, 8, implicit-def %scc %56 = S_ADDC_U32 %0.sub1, 0, implicit-def dead %scc, implicit %scc %57 = REG_SEQUENCE %55, 1, killed %56, 2 diff --git a/test/CodeGen/AMDGPU/waitcnt.mir b/test/CodeGen/AMDGPU/waitcnt.mir index f754415dccb4..38662e83b359 100644 --- a/test/CodeGen/AMDGPU/waitcnt.mir +++ b/test/CodeGen/AMDGPU/waitcnt.mir @@ -51,21 +51,21 @@ name: flat_zero_waitcnt body: | bb.0: successors: %bb.1 - %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.global4) - %vgpr3_vgpr4_vgpr5_vgpr6 = FLAT_LOAD_DWORDX4 %vgpr7_vgpr8, 0, 0, implicit %exec, implicit %flat_scr :: (load 16 from %ir.global16) + %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.global4) + %vgpr3_vgpr4_vgpr5_vgpr6 = FLAT_LOAD_DWORDX4 %vgpr7_vgpr8, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 16 from %ir.global16) %vgpr0 = V_MOV_B32_e32 %vgpr1, implicit %exec S_BRANCH %bb.1 bb.1: successors: %bb.2 - %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, implicit %exec, implicit %flat_scr - %vgpr3_vgpr4_vgpr5_vgpr6 = FLAT_LOAD_DWORDX4 %vgpr7_vgpr8, 0, 0, implicit %exec, implicit %flat_scr :: (load 16 from %ir.global16) + %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, 0, implicit %exec, implicit %flat_scr + %vgpr3_vgpr4_vgpr5_vgpr6 = FLAT_LOAD_DWORDX4 %vgpr7_vgpr8, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 16 from %ir.global16) %vgpr0 = V_MOV_B32_e32 %vgpr1, implicit %exec S_BRANCH %bb.2 bb.2: - %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.flat4) - %vgpr3_vgpr4_vgpr5_vgpr6 = FLAT_LOAD_DWORDX4 %vgpr7_vgpr8, 0, 0, implicit %exec, implicit %flat_scr :: (load 16 from %ir.flat16) + %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 4 from %ir.flat4) + %vgpr3_vgpr4_vgpr5_vgpr6 = FLAT_LOAD_DWORDX4 %vgpr7_vgpr8, 0, 0, 0, implicit %exec, implicit %flat_scr :: (load 16 from %ir.flat16) %vgpr0 = V_MOV_B32_e32 %vgpr1, implicit %exec S_ENDPGM ... @@ -86,11 +86,11 @@ name: single_fallthrough_successor_no_end_block_wait body: | bb.0: successors: %bb.1 - %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, implicit %exec, implicit %flat_scr + %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, 0, implicit %exec, implicit %flat_scr bb.1: %vgpr3_vgpr4 = V_LSHLREV_B64 4, %vgpr7_vgpr8, implicit %exec - FLAT_STORE_DWORD %vgpr3_vgpr4, %vgpr0, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORD %vgpr3_vgpr4, %vgpr0, 0, 0, 0, implicit %exec, implicit %flat_scr S_ENDPGM ... --- @@ -114,15 +114,15 @@ name: single_branch_successor_not_next_block body: | bb.0: successors: %bb.2 - %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, implicit %exec, implicit %flat_scr + %vgpr0 = FLAT_LOAD_DWORD %vgpr1_vgpr2, 0, 0, 0, implicit %exec, implicit %flat_scr S_BRANCH %bb.2 bb.1: - FLAT_STORE_DWORD %vgpr8_vgpr9, %vgpr10, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORD %vgpr8_vgpr9, %vgpr10, 0, 0, 0, implicit %exec, implicit %flat_scr S_ENDPGM bb.2: %vgpr3_vgpr4 = V_LSHLREV_B64 4, %vgpr7_vgpr8, implicit %exec - FLAT_STORE_DWORD %vgpr3_vgpr4, %vgpr0, 0, 0, implicit %exec, implicit %flat_scr + FLAT_STORE_DWORD %vgpr3_vgpr4, %vgpr0, 0, 0, 0, implicit %exec, implicit %flat_scr S_ENDPGM ... diff --git a/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll b/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll index 05902c22fb98..6663a9210b87 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll +++ b/test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll @@ -621,28 +621,18 @@ define arm_aapcscc [3 x i32] @test_tiny_int_arrays([2 x i32] %arr) { ; CHECK: liveins: %r0, %r1 ; CHECK: [[R0:%[0-9]+]](s32) = COPY %r0 ; CHECK: [[R1:%[0-9]+]](s32) = COPY %r1 -; CHECK: [[ARG_ARR0:%[0-9]+]](s64) = IMPLICIT_DEF -; CHECK: [[ARG_ARR1:%[0-9]+]](s64) = G_INSERT [[ARG_ARR0]], [[R0]](s32), 0 -; CHECK: [[ARG_ARR2:%[0-9]+]](s64) = G_INSERT [[ARG_ARR1]], [[R1]](s32), 32 -; CHECK: [[ARG_ARR:%[0-9]+]](s64) = COPY [[ARG_ARR2]] +; CHECK: [[ARG_ARR:%[0-9]+]](s64) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32) ; CHECK: ADJCALLSTACKDOWN 0, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s64), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s64), 32 +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32) = G_UNMERGE_VALUES [[ARG_ARR]](s64) ; CHECK: %r0 = COPY [[R0]] ; CHECK: %r1 = COPY [[R1]] ; CHECK: BLX @tiny_int_arrays_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1, implicit-def %r0, implicit-def %r1 ; CHECK: [[R0:%[0-9]+]](s32) = COPY %r0 ; CHECK: [[R1:%[0-9]+]](s32) = COPY %r1 ; CHECK: [[R2:%[0-9]+]](s32) = COPY %r2 -; CHECK: [[RES_ARR0:%[0-9]+]](s96) = IMPLICIT_DEF -; CHECK: [[RES_ARR1:%[0-9]+]](s96) = G_INSERT [[RES_ARR0]], [[R0]](s32), 0 -; CHECK: [[RES_ARR2:%[0-9]+]](s96) = G_INSERT [[RES_ARR1]], [[R1]](s32), 32 -; CHECK: [[RES_ARR3:%[0-9]+]](s96) = G_INSERT [[RES_ARR2]], [[R2]](s32), 64 -; CHECK: [[RES_ARR:%[0-9]+]](s96) = COPY [[RES_ARR3]] +; CHECK: [[RES_ARR:%[0-9]+]](s96) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32), [[R2]](s32) ; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[RES_ARR]](s96), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[RES_ARR]](s96), 32 -; CHECK: [[R2:%[0-9]+]](s32) = G_EXTRACT [[RES_ARR]](s96), 64 +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32), [[R2:%[0-9]+]](s32) = G_UNMERGE_VALUES [[RES_ARR]](s96) ; FIXME: This doesn't seem correct with regard to the AAPCS docs (which say ; that composite types larger than 4 bytes should be passed through memory), ; but it's what DAGISel does. We should fix it in the common code for both. @@ -664,19 +654,11 @@ define arm_aapcscc void @test_multiple_int_arrays([2 x i32] %arr0, [2 x i32] %ar ; CHECK: [[R1:%[0-9]+]](s32) = COPY %r1 ; CHECK: [[R2:%[0-9]+]](s32) = COPY %r2 ; CHECK: [[R3:%[0-9]+]](s32) = COPY %r3 -; CHECK: [[ARG_ARR0_0:%[0-9]+]](s64) = IMPLICIT_DEF -; CHECK: [[ARG_ARR0_1:%[0-9]+]](s64) = G_INSERT [[ARG_ARR0_0]], [[R0]](s32), 0 -; CHECK: [[ARG_ARR0_2:%[0-9]+]](s64) = G_INSERT [[ARG_ARR0_1]], [[R1]](s32), 32 -; CHECK: [[ARG_ARR0:%[0-9]+]](s64) = COPY [[ARG_ARR0_2]] -; CHECK: [[ARG_ARR1_0:%[0-9]+]](s64) = IMPLICIT_DEF -; CHECK: [[ARG_ARR1_1:%[0-9]+]](s64) = G_INSERT [[ARG_ARR1_0]], [[R2]](s32), 0 -; CHECK: [[ARG_ARR1_2:%[0-9]+]](s64) = G_INSERT [[ARG_ARR1_1]], [[R3]](s32), 32 -; CHECK: [[ARG_ARR1:%[0-9]+]](s64) = COPY [[ARG_ARR1_2]] +; CHECK: [[ARG_ARR0:%[0-9]+]](s64) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32) +; CHECK: [[ARG_ARR1:%[0-9]+]](s64) = G_MERGE_VALUES [[R2]](s32), [[R3]](s32) ; CHECK: ADJCALLSTACKDOWN 0, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR0]](s64), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR0]](s64), 32 -; CHECK: [[R2:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR1]](s64), 0 -; CHECK: [[R3:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR1]](s64), 32 +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32) = G_UNMERGE_VALUES [[ARG_ARR0]](s64) +; CHECK: [[R2:%[0-9]+]](s32), [[R3:%[0-9]+]](s32) = G_UNMERGE_VALUES [[ARG_ARR1]](s64) ; CHECK: %r0 = COPY [[R0]] ; CHECK: %r1 = COPY [[R1]] ; CHECK: %r2 = COPY [[R2]] @@ -707,21 +689,9 @@ define arm_aapcscc void @test_large_int_arrays([20 x i32] %arr) { ; CHECK: [[FIRST_STACK_ELEMENT:%[0-9]+]](s32) = G_LOAD [[FIRST_STACK_ELEMENT_FI]]{{.*}}load 4 from %fixed-stack.[[FIRST_STACK_ID]] ; CHECK: [[LAST_STACK_ELEMENT_FI:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[LAST_STACK_ID]] ; CHECK: [[LAST_STACK_ELEMENT:%[0-9]+]](s32) = G_LOAD [[LAST_STACK_ELEMENT_FI]]{{.*}}load 4 from %fixed-stack.[[LAST_STACK_ID]] -; CHECK: [[ARG_ARR0:%[0-9]+]](s640) = IMPLICIT_DEF -; CHECK: [[ARG_ARR1:%[0-9]+]](s640) = G_INSERT [[ARG_ARR0]], [[R0]](s32), 0 -; CHECK: [[ARG_ARR2:%[0-9]+]](s640) = G_INSERT [[ARG_ARR1]], [[R1]](s32), 32 -; CHECK: [[ARG_ARR3:%[0-9]+]](s640) = G_INSERT [[ARG_ARR2]], [[R2]](s32), 64 -; CHECK: [[ARG_ARR4:%[0-9]+]](s640) = G_INSERT [[ARG_ARR3]], [[R3]](s32), 96 -; CHECK: [[ARG_ARR5:%[0-9]+]](s640) = G_INSERT [[ARG_ARR4]], [[FIRST_STACK_ELEMENT]](s32), 128 -; CHECK: [[ARG_ARR6:%[0-9]+]](s640) = G_INSERT {{%[0-9]+}}, [[LAST_STACK_ELEMENT]](s32), 608 -; CHECK: [[ARG_ARR:%[0-9]+]](s640) = COPY [[ARG_ARR6]] +; CHECK: [[ARG_ARR:%[0-9]+]](s640) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32), [[R2]](s32), [[R3]](s32), [[FIRST_STACK_ELEMENT]](s32), {{.*}}, [[LAST_STACK_ELEMENT]](s32) ; CHECK: ADJCALLSTACKDOWN 64, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s640), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s640), 32 -; CHECK: [[R2:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s640), 64 -; CHECK: [[R3:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s640), 96 -; CHECK: [[FIRST_STACK_ELEMENT:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s640), 128 -; CHECK: [[LAST_STACK_ELEMENT:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s640), 608 +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32), [[R2:%[0-9]+]](s32), [[R3:%[0-9]+]](s32), [[FIRST_STACK_ELEMENT:%[0-9]+]](s32), {{.*}}, [[LAST_STACK_ELEMENT:%[0-9]+]](s32) = G_UNMERGE_VALUES [[ARG_ARR]](s640) ; CHECK: %r0 = COPY [[R0]] ; CHECK: %r1 = COPY [[R1]] ; CHECK: %r2 = COPY [[R2]] @@ -761,15 +731,9 @@ define arm_aapcscc [2 x float] @test_fp_arrays_aapcs([3 x double] %arr) { ; BIG: [[ARR1:%[0-9]+]](s64) = G_MERGE_VALUES [[ARR1_1]](s32), [[ARR1_0]](s32) ; CHECK: [[ARR2_FI:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[ARR2_ID]] ; CHECK: [[ARR2:%[0-9]+]](s64) = G_LOAD [[ARR2_FI]]{{.*}}load 8 from %fixed-stack.[[ARR2_ID]] -; CHECK: [[ARR_MERGED_0:%[0-9]+]](s192) = IMPLICIT_DEF -; CHECK: [[ARR_MERGED_1:%[0-9]+]](s192) = G_INSERT [[ARR_MERGED_0]], [[ARR0]](s64), 0 -; CHECK: [[ARR_MERGED_2:%[0-9]+]](s192) = G_INSERT [[ARR_MERGED_1]], [[ARR1]](s64), 64 -; CHECK: [[ARR_MERGED_3:%[0-9]+]](s192) = G_INSERT [[ARR_MERGED_2]], [[ARR2]](s64), 128 -; CHECK: [[ARR_MERGED:%[0-9]+]](s192) = COPY [[ARR_MERGED_3]] +; CHECK: [[ARR_MERGED:%[0-9]+]](s192) = G_MERGE_VALUES [[ARR0]](s64), [[ARR1]](s64), [[ARR2]](s64) ; CHECK: ADJCALLSTACKDOWN 8, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[ARR0:%[0-9]+]](s64) = G_EXTRACT [[ARR_MERGED]](s192), 0 -; CHECK: [[ARR1:%[0-9]+]](s64) = G_EXTRACT [[ARR_MERGED]](s192), 64 -; CHECK: [[ARR2:%[0-9]+]](s64) = G_EXTRACT [[ARR_MERGED]](s192), 128 +; CHECK: [[ARR0:%[0-9]+]](s64), [[ARR1:%[0-9]+]](s64), [[ARR2:%[0-9]+]](s64) = G_UNMERGE_VALUES [[ARR_MERGED]](s192) ; CHECK: [[ARR0_0:%[0-9]+]](s32), [[ARR0_1:%[0-9]+]](s32) = G_UNMERGE_VALUES [[ARR0]](s64) ; LITTLE: %r0 = COPY [[ARR0_0]](s32) ; LITTLE: %r1 = COPY [[ARR0_1]](s32) @@ -787,13 +751,9 @@ define arm_aapcscc [2 x float] @test_fp_arrays_aapcs([3 x double] %arr) { ; CHECK: BLX @fp_arrays_aapcs_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1, implicit %r2, implicit %r3, implicit-def %r0, implicit-def %r1 ; CHECK: [[R0:%[0-9]+]](s32) = COPY %r0 ; CHECK: [[R1:%[0-9]+]](s32) = COPY %r1 -; CHECK: [[R_MERGED_0:%[0-9]+]](s64) = IMPLICIT_DEF -; CHECK: [[R_MERGED_1:%[0-9]+]](s64) = G_INSERT [[R_MERGED_0]], [[R0]](s32), 0 -; CHECK: [[R_MERGED_2:%[0-9]+]](s64) = G_INSERT [[R_MERGED_1]], [[R1]](s32), 32 -; CHECK: [[R_MERGED:%[0-9]+]](s64) = COPY [[R_MERGED_2]] +; CHECK: [[R_MERGED:%[0-9]+]](s64) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32) ; CHECK: ADJCALLSTACKUP 8, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[R_MERGED]](s64), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[R_MERGED]](s64), 32 +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32) = G_UNMERGE_VALUES [[R_MERGED]](s64) ; CHECK: %r0 = COPY [[R0]] ; CHECK: %r1 = COPY [[R1]] ; CHECK: BX_RET 14, _, implicit %r0, implicit %r1 @@ -826,33 +786,13 @@ define arm_aapcs_vfpcc [4 x float] @test_fp_arrays_aapcs_vfp([3 x double] %x, [3 ; CHECK: [[Z2:%[0-9]+]](s64) = G_LOAD [[Z2_FI]]{{.*}}load 8 ; CHECK: [[Z3_FI:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[Z3_ID]] ; CHECK: [[Z3:%[0-9]+]](s64) = G_LOAD [[Z3_FI]]{{.*}}load 8 -; CHECK: [[X_ARR_0:%[0-9]+]](s192) = IMPLICIT_DEF -; CHECK: [[X_ARR_1:%[0-9]+]](s192) = G_INSERT [[X_ARR_0]], [[X0]](s64), 0 -; CHECK: [[X_ARR_2:%[0-9]+]](s192) = G_INSERT [[X_ARR_1]], [[X1]](s64), 64 -; CHECK: [[X_ARR_3:%[0-9]+]](s192) = G_INSERT [[X_ARR_2]], [[X2]](s64), 128 -; CHECK: [[X_ARR:%[0-9]+]](s192) = COPY [[X_ARR_3]](s192) -; CHECK: [[Y_ARR_0:%[0-9]+]](s96) = IMPLICIT_DEF -; CHECK: [[Y_ARR_1:%[0-9]+]](s96) = G_INSERT [[Y_ARR_0]], [[Y0]](s32), 0 -; CHECK: [[Y_ARR_2:%[0-9]+]](s96) = G_INSERT [[Y_ARR_1]], [[Y1]](s32), 32 -; CHECK: [[Y_ARR_3:%[0-9]+]](s96) = G_INSERT [[Y_ARR_2]], [[Y2]](s32), 64 -; CHECK: [[Y_ARR:%[0-9]+]](s96) = COPY [[Y_ARR_3]](s96) -; CHECK: [[Z_ARR_0:%[0-9]+]](s256) = IMPLICIT_DEF -; CHECK: [[Z_ARR_1:%[0-9]+]](s256) = G_INSERT [[Z_ARR_0]], [[Z0]](s64), 0 -; CHECK: [[Z_ARR_2:%[0-9]+]](s256) = G_INSERT [[Z_ARR_1]], [[Z1]](s64), 64 -; CHECK: [[Z_ARR_3:%[0-9]+]](s256) = G_INSERT [[Z_ARR_2]], [[Z2]](s64), 128 -; CHECK: [[Z_ARR_4:%[0-9]+]](s256) = G_INSERT [[Z_ARR_3]], [[Z3]](s64), 192 -; CHECK: [[Z_ARR:%[0-9]+]](s256) = COPY [[Z_ARR_4]](s256) +; CHECK: [[X_ARR:%[0-9]+]](s192) = G_MERGE_VALUES [[X0]](s64), [[X1]](s64), [[X2]](s64) +; CHECK: [[Y_ARR:%[0-9]+]](s96) = G_MERGE_VALUES [[Y0]](s32), [[Y1]](s32), [[Y2]](s32) +; CHECK: [[Z_ARR:%[0-9]+]](s256) = G_MERGE_VALUES [[Z0]](s64), [[Z1]](s64), [[Z2]](s64), [[Z3]](s64) ; CHECK: ADJCALLSTACKDOWN 32, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[X0:%[0-9]+]](s64) = G_EXTRACT [[X_ARR]](s192), 0 -; CHECK: [[X1:%[0-9]+]](s64) = G_EXTRACT [[X_ARR]](s192), 64 -; CHECK: [[X2:%[0-9]+]](s64) = G_EXTRACT [[X_ARR]](s192), 128 -; CHECK: [[Y0:%[0-9]+]](s32) = G_EXTRACT [[Y_ARR]](s96), 0 -; CHECK: [[Y1:%[0-9]+]](s32) = G_EXTRACT [[Y_ARR]](s96), 32 -; CHECK: [[Y2:%[0-9]+]](s32) = G_EXTRACT [[Y_ARR]](s96), 64 -; CHECK: [[Z0:%[0-9]+]](s64) = G_EXTRACT [[Z_ARR]](s256), 0 -; CHECK: [[Z1:%[0-9]+]](s64) = G_EXTRACT [[Z_ARR]](s256), 64 -; CHECK: [[Z2:%[0-9]+]](s64) = G_EXTRACT [[Z_ARR]](s256), 128 -; CHECK: [[Z3:%[0-9]+]](s64) = G_EXTRACT [[Z_ARR]](s256), 192 +; CHECK: [[X0:%[0-9]+]](s64), [[X1:%[0-9]+]](s64), [[X2:%[0-9]+]](s64) = G_UNMERGE_VALUES [[X_ARR]](s192) +; CHECK: [[Y0:%[0-9]+]](s32), [[Y1:%[0-9]+]](s32), [[Y2:%[0-9]+]](s32) = G_UNMERGE_VALUES [[Y_ARR]](s96) +; CHECK: [[Z0:%[0-9]+]](s64), [[Z1:%[0-9]+]](s64), [[Z2:%[0-9]+]](s64), [[Z3:%[0-9]+]](s64) = G_UNMERGE_VALUES [[Z_ARR]](s256) ; CHECK: %d0 = COPY [[X0]](s64) ; CHECK: %d1 = COPY [[X1]](s64) ; CHECK: %d2 = COPY [[X2]](s64) @@ -880,17 +820,9 @@ define arm_aapcs_vfpcc [4 x float] @test_fp_arrays_aapcs_vfp([3 x double] %x, [3 ; CHECK: [[R1:%[0-9]+]](s32) = COPY %s1 ; CHECK: [[R2:%[0-9]+]](s32) = COPY %s2 ; CHECK: [[R3:%[0-9]+]](s32) = COPY %s3 -; CHECK: [[R_MERGED_0:%[0-9]+]](s128) = IMPLICIT_DEF -; CHECK: [[R_MERGED_1:%[0-9]+]](s128) = G_INSERT [[R_MERGED_0]], [[R0]](s32), 0 -; CHECK: [[R_MERGED_2:%[0-9]+]](s128) = G_INSERT [[R_MERGED_1]], [[R1]](s32), 32 -; CHECK: [[R_MERGED_3:%[0-9]+]](s128) = G_INSERT [[R_MERGED_2]], [[R2]](s32), 64 -; CHECK: [[R_MERGED_4:%[0-9]+]](s128) = G_INSERT [[R_MERGED_3]], [[R3]](s32), 96 -; CHECK: [[R_MERGED:%[0-9]+]](s128) = COPY [[R_MERGED_4]] +; CHECK: [[R_MERGED:%[0-9]+]](s128) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32), [[R2]](s32), [[R3]](s32) ; CHECK: ADJCALLSTACKUP 32, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[R_MERGED]](s128), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[R_MERGED]](s128), 32 -; CHECK: [[R2:%[0-9]+]](s32) = G_EXTRACT [[R_MERGED]](s128), 64 -; CHECK: [[R3:%[0-9]+]](s32) = G_EXTRACT [[R_MERGED]](s128), 96 +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32), [[R2:%[0-9]+]](s32), [[R3:%[0-9]+]](s32) = G_UNMERGE_VALUES [[R_MERGED]](s128) ; CHECK: %s0 = COPY [[R0]] ; CHECK: %s1 = COPY [[R1]] ; CHECK: %s2 = COPY [[R2]] @@ -919,21 +851,9 @@ define arm_aapcscc [2 x i32*] @test_tough_arrays([6 x [4 x i32]] %arr) { ; CHECK: [[FIRST_STACK_ELEMENT:%[0-9]+]](s32) = G_LOAD [[FIRST_STACK_ELEMENT_FI]]{{.*}}load 4 from %fixed-stack.[[FIRST_STACK_ID]] ; CHECK: [[LAST_STACK_ELEMENT_FI:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[LAST_STACK_ID]] ; CHECK: [[LAST_STACK_ELEMENT:%[0-9]+]](s32) = G_LOAD [[LAST_STACK_ELEMENT_FI]]{{.*}}load 4 from %fixed-stack.[[LAST_STACK_ID]] -; CHECK: [[ARG_ARR0:%[0-9]+]](s768) = IMPLICIT_DEF -; CHECK: [[ARG_ARR1:%[0-9]+]](s768) = G_INSERT [[ARG_ARR0]], [[R0]](s32), 0 -; CHECK: [[ARG_ARR2:%[0-9]+]](s768) = G_INSERT [[ARG_ARR1]], [[R1]](s32), 32 -; CHECK: [[ARG_ARR3:%[0-9]+]](s768) = G_INSERT [[ARG_ARR2]], [[R2]](s32), 64 -; CHECK: [[ARG_ARR4:%[0-9]+]](s768) = G_INSERT [[ARG_ARR3]], [[R3]](s32), 96 -; CHECK: [[ARG_ARR5:%[0-9]+]](s768) = G_INSERT [[ARG_ARR4]], [[FIRST_STACK_ELEMENT]](s32), 128 -; CHECK: [[ARG_ARR6:%[0-9]+]](s768) = G_INSERT {{%[0-9]+}}, [[LAST_STACK_ELEMENT]](s32), 736 -; CHECK: [[ARG_ARR:%[0-9]+]](s768) = COPY [[ARG_ARR6]] +; CHECK: [[ARG_ARR:%[0-9]+]](s768) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32), [[R2]](s32), [[R3]](s32), [[FIRST_STACK_ELEMENT]](s32), {{.*}}, [[LAST_STACK_ELEMENT]](s32) ; CHECK: ADJCALLSTACKDOWN 80, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s768), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s768), 32 -; CHECK: [[R2:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s768), 64 -; CHECK: [[R3:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s768), 96 -; CHECK: [[FIRST_STACK_ELEMENT:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s768), 128 -; CHECK: [[LAST_STACK_ELEMENT:%[0-9]+]](s32) = G_EXTRACT [[ARG_ARR]](s768), 736 +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32), [[R2:%[0-9]+]](s32), [[R3:%[0-9]+]](s32), [[FIRST_STACK_ELEMENT:%[0-9]+]](s32), {{.*}}, [[LAST_STACK_ELEMENT:%[0-9]+]](s32) = G_UNMERGE_VALUES [[ARG_ARR]](s768) ; CHECK: %r0 = COPY [[R0]] ; CHECK: %r1 = COPY [[R1]] ; CHECK: %r2 = COPY [[R2]] @@ -951,13 +871,9 @@ define arm_aapcscc [2 x i32*] @test_tough_arrays([6 x [4 x i32]] %arr) { ; CHECK: BLX @tough_arrays_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1, implicit %r2, implicit %r3, implicit-def %r0, implicit-def %r1 ; CHECK: [[R0:%[0-9]+]](s32) = COPY %r0 ; CHECK: [[R1:%[0-9]+]](s32) = COPY %r1 -; CHECK: [[RES_ARR0:%[0-9]+]](s64) = IMPLICIT_DEF -; CHECK: [[RES_ARR1:%[0-9]+]](s64) = G_INSERT [[RES_ARR0]], [[R0]](s32), 0 -; CHECK: [[RES_ARR2:%[0-9]+]](s64) = G_INSERT [[RES_ARR1]], [[R1]](s32), 32 -; CHECK: [[RES_ARR:%[0-9]+]](s64) = COPY [[RES_ARR2]] +; CHECK: [[RES_ARR:%[0-9]+]](s64) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32) ; CHECK: ADJCALLSTACKUP 80, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[RES_ARR]](s64), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[RES_ARR]](s64), 32 +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32) = G_UNMERGE_VALUES [[RES_ARR]](s64) ; CHECK: %r0 = COPY [[R0]] ; CHECK: %r1 = COPY [[R1]] ; CHECK: BX_RET 14, _, implicit %r0, implicit %r1 @@ -966,65 +882,28 @@ entry: ret [2 x i32*] %r } -declare arm_aapcscc {i32, i32} @structs_target({i32, i32}, {i32*, float, i32, double}) +declare arm_aapcscc {i32, i32} @structs_target({i32, i32}) -define arm_aapcscc {i32, i32} @test_structs({i32, i32} %x, {i32*, float, i32, double} %y) { +define arm_aapcscc {i32, i32} @test_structs({i32, i32} %x) { ; CHECK-LABEL: test_structs -; CHECK: fixedStack: -; CHECK-DAG: id: [[Y2_ID:[0-9]+]], type: default, offset: 0, size: 4, -; CHECK-DAG: id: [[Y3_ID:[0-9]+]], type: default, offset: 8, size: 8, -; CHECK: liveins: %r0, %r1, %r2, %r3 +; CHECK: liveins: %r0, %r1 ; CHECK-DAG: [[X0:%[0-9]+]](s32) = COPY %r0 ; CHECK-DAG: [[X1:%[0-9]+]](s32) = COPY %r1 -; CHECK-DAG: [[Y0:%[0-9]+]](s32) = COPY %r2 -; CHECK-DAG: [[Y1:%[0-9]+]](s32) = COPY %r3 -; CHECK: [[Y2_ADDR:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[Y2_ID]] -; CHECK: [[Y2:%[0-9]+]](s32) = G_LOAD [[Y2_ADDR]](p0){{.*}}load 4 -; CHECK: [[Y3_ADDR:%[0-9]+]](p0) = G_FRAME_INDEX %fixed-stack.[[Y3_ID]] -; CHECK: [[Y3:%[0-9]+]](s64) = G_LOAD [[Y3_ADDR]](p0){{.*}}load 8 -; CHECK: [[X_0:%[0-9]+]](s64) = IMPLICIT_DEF -; CHECK: [[X_1:%[0-9]+]](s64) = G_INSERT [[X_0]], [[X0]](s32), 0 -; CHECK: [[X_2:%[0-9]+]](s64) = G_INSERT [[X_1]], [[X1]](s32), 32 -; CHECK: [[X:%[0-9]+]](s64) = COPY [[X_2]] -; CHECK: [[Y_0:%[0-9]+]](s192) = IMPLICIT_DEF -; CHECK: [[Y_1:%[0-9]+]](s192) = G_INSERT [[Y_0]], [[Y0]](s32), 0 -; CHECK: [[Y_2:%[0-9]+]](s192) = G_INSERT [[Y_1]], [[Y1]](s32), 32 -; CHECK: [[Y_3:%[0-9]+]](s192) = G_INSERT [[Y_2]], [[Y2]](s32), 64 -; CHECK: [[Y_4:%[0-9]+]](s192) = G_INSERT [[Y_3]], [[Y3]](s64), 128 -; CHECK: [[Y:%[0-9]+]](s192) = COPY [[Y_4]] -; CHECK: ADJCALLSTACKDOWN 16, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[X0:%[0-9]+]](s32) = G_EXTRACT [[X]](s64), 0 -; CHECK: [[X1:%[0-9]+]](s32) = G_EXTRACT [[X]](s64), 32 -; CHECK: [[Y0:%[0-9]+]](s32) = G_EXTRACT [[Y]](s192), 0 -; CHECK: [[Y1:%[0-9]+]](s32) = G_EXTRACT [[Y]](s192), 32 -; CHECK: [[Y2:%[0-9]+]](s32) = G_EXTRACT [[Y]](s192), 64 -; CHECK: [[Y3:%[0-9]+]](s64) = G_EXTRACT [[Y]](s192), 128 +; CHECK: [[X:%[0-9]+]](s64) = G_MERGE_VALUES [[X0]](s32), [[X1]](s32) +; CHECK: ADJCALLSTACKDOWN 0, 0, 14, _, implicit-def %sp, implicit %sp +; CHECK: [[X0:%[0-9]+]](s32), [[X1:%[0-9]+]](s32) = G_UNMERGE_VALUES [[X]](s64) ; CHECK-DAG: %r0 = COPY [[X0]](s32) ; CHECK-DAG: %r1 = COPY [[X1]](s32) -; CHECK-DAG: %r2 = COPY [[Y0]](s32) -; CHECK-DAG: %r3 = COPY [[Y1]](s32) -; CHECK: [[SP:%[0-9]+]](p0) = COPY %sp -; CHECK: [[Y2_OFF:%[0-9]+]](s32) = G_CONSTANT i32 0 -; CHECK: [[Y2_ADDR:%[0-9]+]](p0) = G_GEP [[SP]], [[Y2_OFF]](s32) -; CHECK: G_STORE [[Y2]](s32), [[Y2_ADDR]](p0){{.*}}store 4 -; CHECK: [[SP:%[0-9]+]](p0) = COPY %sp -; CHECK: [[Y3_OFF:%[0-9]+]](s32) = G_CONSTANT i32 8 -; CHECK: [[Y3_ADDR:%[0-9]+]](p0) = G_GEP [[SP]], [[Y3_OFF]](s32) -; CHECK: G_STORE [[Y3]](s64), [[Y3_ADDR]](p0){{.*}}store 8 -; CHECK: BLX @structs_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1, implicit %r2, implicit %r3, implicit-def %r0, implicit-def %r1 +; CHECK: BLX @structs_target, csr_aapcs, implicit-def %lr, implicit %sp, implicit %r0, implicit %r1, implicit-def %r0, implicit-def %r1 ; CHECK: [[R0:%[0-9]+]](s32) = COPY %r0 ; CHECK: [[R1:%[0-9]+]](s32) = COPY %r1 -; CHECK: [[R_0:%[0-9]+]](s64) = IMPLICIT_DEF -; CHECK: [[R_1:%[0-9]+]](s64) = G_INSERT [[R_0]], [[R0]](s32), 0 -; CHECK: [[R_2:%[0-9]+]](s64) = G_INSERT [[R_1]], [[R1]](s32), 32 -; CHECK: [[R:%[0-9]+]](s64) = COPY [[R_2]] -; CHECK: ADJCALLSTACKUP 16, 0, 14, _, implicit-def %sp, implicit %sp -; CHECK: [[R0:%[0-9]+]](s32) = G_EXTRACT [[R]](s64), 0 -; CHECK: [[R1:%[0-9]+]](s32) = G_EXTRACT [[R]](s64), 32 +; CHECK: [[R:%[0-9]+]](s64) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32) +; CHECK: ADJCALLSTACKUP 0, 0, 14, _, implicit-def %sp, implicit %sp +; CHECK: [[R0:%[0-9]+]](s32), [[R1:%[0-9]+]](s32) = G_UNMERGE_VALUES [[R]](s64) ; CHECK: %r0 = COPY [[R0]](s32) ; CHECK: %r1 = COPY [[R1]](s32) ; CHECK: BX_RET 14, _, implicit %r0, implicit %r1 - %r = notail call arm_aapcscc {i32, i32} @structs_target({i32, i32} %x, {i32*, float, i32, double} %y) + %r = notail call arm_aapcscc {i32, i32} @structs_target({i32, i32} %x) ret {i32, i32} %r } diff --git a/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll b/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll index 2881740b016f..c778caacd0f4 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll +++ b/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll @@ -66,3 +66,24 @@ define arm_aapcscc i8 @test_udiv_i8(i8 %a, i8 %b) { ret i8 %r } +define arm_aapcscc i32 @test_srem_i32(i32 %x, i32 %y) { +; CHECK-LABEL: test_srem_i32: +; HWDIV: sdiv [[Q:r[0-9]+]], r0, r1 +; HWDIV: mul [[P:r[0-9]+]], [[Q]], r1 +; HWDIV: sub r0, r0, [[P]] +; SOFT-AEABI: blx __aeabi_idivmod +; SOFT-DEFAULT: blx __modsi3 + %r = srem i32 %x, %y + ret i32 %r +} + +define arm_aapcscc i32 @test_urem_i32(i32 %x, i32 %y) { +; CHECK-LABEL: test_urem_i32: +; HWDIV: udiv [[Q:r[0-9]+]], r0, r1 +; HWDIV: mul [[P:r[0-9]+]], [[Q]], r1 +; HWDIV: sub r0, r0, [[P]] +; SOFT-AEABI: blx __aeabi_uidivmod +; SOFT-DEFAULT: blx __umodsi3 + %r = urem i32 %x, %y + ret i32 %r +} diff --git a/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir b/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir index 6f3e09d328cf..c93e7fa0ec56 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir +++ b/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir @@ -11,6 +11,9 @@ define void @test_sdiv_i8() { ret void } define void @test_udiv_i8() { ret void } + + define void @test_srem_i32() { ret void } + define void @test_urem_i32() { ret void } ... --- name: test_sdiv_i32 @@ -228,3 +231,75 @@ body: | %r0 = COPY %2(s8) BX_RET 14, _, implicit %r0 ... +--- +name: test_srem_i32 +# CHECK-LABEL: name: test_srem_i32 +legalized: false +# CHECK: legalized: true +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0: + liveins: %r0, %r1 + + ; CHECK-DAG: [[X:%[0-9]+]](s32) = COPY %r0 + ; CHECK-DAG: [[Y:%[0-9]+]](s32) = COPY %r1 + %0(s32) = COPY %r0 + %1(s32) = COPY %r1 + ; HWDIV: [[Q:%[0-9]+]](s32) = G_SDIV [[X]], [[Y]] + ; HWDIV: [[P:%[0-9]+]](s32) = G_MUL [[Q]], [[Y]] + ; HWDIV: [[R:%[0-9]+]](s32) = G_SUB [[X]], [[P]] + ; SOFT: ADJCALLSTACKDOWN + ; SOFT-DAG: %r0 = COPY [[X]] + ; SOFT-DAG: %r1 = COPY [[Y]] + ; SOFT-AEABI: BLX $__aeabi_idivmod, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0, implicit-def %r1 + ; SOFT-AEABI: [[R:%[0-9]+]](s32) = COPY %r1 + ; SOFT-DEFAULT: BLX $__modsi3, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0 + ; SOFT-DEFAULT: [[R:%[0-9]+]](s32) = COPY %r0 + ; SOFT: ADJCALLSTACKUP + %2(s32) = G_SREM %0, %1 + ; CHECK: %r0 = COPY [[R]] + %r0 = COPY %2(s32) + BX_RET 14, _, implicit %r0 +... +--- +name: test_urem_i32 +# CHECK-LABEL: name: test_urem_i32 +legalized: false +# CHECK: legalized: true +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0: + liveins: %r0, %r1 + + ; CHECK-DAG: [[X:%[0-9]+]](s32) = COPY %r0 + ; CHECK-DAG: [[Y:%[0-9]+]](s32) = COPY %r1 + %0(s32) = COPY %r0 + %1(s32) = COPY %r1 + ; HWDIV: [[Q:%[0-9]+]](s32) = G_UDIV [[X]], [[Y]] + ; HWDIV: [[P:%[0-9]+]](s32) = G_MUL [[Q]], [[Y]] + ; HWDIV: [[R:%[0-9]+]](s32) = G_SUB [[X]], [[P]] + ; SOFT: ADJCALLSTACKDOWN + ; SOFT-DAG: %r0 = COPY [[X]] + ; SOFT-DAG: %r1 = COPY [[Y]] + ; SOFT-AEABI: BLX $__aeabi_uidivmod, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0, implicit-def %r1 + ; SOFT-AEABI: [[R:%[0-9]+]](s32) = COPY %r1 + ; SOFT-DEFAULT: BLX $__umodsi3, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0 + ; SOFT-DEFAULT: [[R:%[0-9]+]](s32) = COPY %r0 + ; SOFT: ADJCALLSTACKUP + %2(s32) = G_UREM %0, %1 + ; CHECK: %r0 = COPY [[R]] + %r0 = COPY %2(s32) + BX_RET 14, _, implicit %r0 +... diff --git a/test/CodeGen/ARM/GlobalISel/arm-unsupported.ll b/test/CodeGen/ARM/GlobalISel/arm-unsupported.ll index 34f00aebe1be..f2f9c5d2a81d 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-unsupported.ll +++ b/test/CodeGen/ARM/GlobalISel/arm-unsupported.ll @@ -65,6 +65,14 @@ define %large.struct @test_large_struct_return() { ret %large.struct %r } +%mixed.struct = type {i32*, float, i32} + +define %mixed.struct @test_mixed_struct(%mixed.struct %x) { +; CHECK: remark: {{.*}} unable to lower arguments: %mixed.struct (%mixed.struct)* +; CHECK-LABEL: warning: Instruction selection used fallback path for test_mixed_struct + ret %mixed.struct %x +} + define void @test_vararg_definition(i32 %a, ...) { ; CHECK: remark: {{.*}} unable to lower arguments: void (i32, ...)* ; CHECK-LABEL: warning: Instruction selection used fallback path for test_vararg_definition diff --git a/test/CodeGen/ARM/cortex-a57-misched-vfma.ll b/test/CodeGen/ARM/cortex-a57-misched-vfma.ll index 5f914323861a..e234e179ed07 100644 --- a/test/CodeGen/ARM/cortex-a57-misched-vfma.ll +++ b/test/CodeGen/ARM/cortex-a57-misched-vfma.ll @@ -156,3 +156,41 @@ define <2 x float> @Test4(<2 x float> %f1, <2 x float> %f2, <2 x float> %f3, <2 %sub2 = fsub <2 x float> %sub1, %mul3 ret <2 x float> %sub2 } + +define float @Test5(float %f1, float %f2, float %f3) { +; CHECK: ********** MI Scheduling ********** +; CHECK: Test5:BB#0 + +; CHECK-DEFAULT: VNMLS +; CHECK-FAST: VFNMS +; CHECK: Latency : 9 +; CHECK: Successors: +; CHECK: data +; > VMLAS not-optimized latency to VMOVRS = 9 +; CHECK-SAME: Latency=9 + +; f1 * f2 - f3 ==> VNMLS/VFNMS + %mul = fmul float %f1, %f2 + %sub = fsub float %mul, %f3 + ret float %sub +} + + +define float @Test6(float %f1, float %f2, float %f3) { +; CHECK: ********** MI Scheduling ********** +; CHECK: Test6:BB#0 + +; CHECK-DEFAULT: VNMLA +; CHECK-FAST: VFNMA +; CHECK: Latency : 9 +; CHECK: Successors: +; CHECK: data +; > VMLAS not-optimized latency to VMOVRS = 9 +; CHECK-SAME: Latency=9 + +; f1 * f2 - f3 ==> VNMLA/VFNMA + %mul = fmul float %f1, %f2 + %sub1 = fsub float -0.0, %mul + %sub2 = fsub float %sub1, %f2 + ret float %sub2 +} diff --git a/test/CodeGen/ARM/debug-info-blocks.ll b/test/CodeGen/ARM/debug-info-blocks.ll index 1e9d890e9333..6019a9410b03 100644 --- a/test/CodeGen/ARM/debug-info-blocks.ll +++ b/test/CodeGen/ARM/debug-info-blocks.ll @@ -273,6 +273,6 @@ define hidden void @foobar_func_block_invoke_0(i8* %.block_descriptor, %0* %load !160 = !DIFile(filename: "header.h", directory: "/Volumes/Sandbox/llvm") !161 = !{!"header2.h", !"/Volumes/Sandbox/llvm"} !162 = !{i32 1, !"Debug Info Version", i32 3} -!163 = !DIExpression(DW_OP_plus, 20, DW_OP_deref, DW_OP_plus, 4, DW_OP_deref, DW_OP_plus, 24) -!164 = !DIExpression(DW_OP_deref, DW_OP_plus, 24) -!165 = !DIExpression(DW_OP_deref, DW_OP_plus, 28) +!163 = !DIExpression(DW_OP_plus_uconst, 20, DW_OP_deref, DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_plus_uconst, 24) +!164 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 24) +!165 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 28) diff --git a/test/CodeGen/ARM/sincos.ll b/test/CodeGen/ARM/sincos.ll index 5be0044ddbd3..42a834d24b3e 100644 --- a/test/CodeGen/ARM/sincos.ll +++ b/test/CodeGen/ARM/sincos.ll @@ -1,10 +1,12 @@ ; RUN: llc < %s -mtriple=armv7-apple-ios6 -mcpu=cortex-a8 | FileCheck %s --check-prefix=NOOPT ; RUN: llc < %s -mtriple=armv7-apple-ios7 -mcpu=cortex-a8 | FileCheck %s --check-prefix=SINCOS -; RUN: llc < %s -mtriple=armv7-linux-gnu -mcpu=cortex-a8 | FileCheck %s --check-prefix=NOOPT-GNU +; RUN: llc < %s -mtriple=armv7-linux-gnu -mcpu=cortex-a8 | FileCheck %s --check-prefix=SINCOS-GNU ; RUN: llc < %s -mtriple=armv7-linux-gnueabi -mcpu=cortex-a8 \ ; RUN: --enable-unsafe-fp-math | FileCheck %s --check-prefix=SINCOS-GNU -; Combine sin / cos into a single call. +; Combine sin / cos into a single call unless they may write errno (as +; captured by readnone attrbiute, controlled by clang -fmath-errno +; setting). ; rdar://12856873 define float @test1(float %x) nounwind { @@ -19,12 +21,28 @@ entry: ; NOOPT: bl _sinf ; NOOPT: bl _cosf -; NOOPT-GNU-LABEL: test1: -; NOOPT-GNU: bl sinf -; NOOPT-GNU: bl cosf + %call = tail call float @sinf(float %x) readnone + %call1 = tail call float @cosf(float %x) readnone + %add = fadd float %call, %call1 + ret float %add +} - %call = tail call float @sinf(float %x) nounwind readnone - %call1 = tail call float @cosf(float %x) nounwind readnone +define float @test1_errno(float %x) nounwind { +entry: +; SINCOS-LABEL: test1_errno: +; SINCOS: bl _sinf +; SINCOS: bl _cosf + +; SINCOS-GNU-LABEL: test1_errno: +; SINCOS-GNU: bl sinf +; SINCOS-GNU: bl cosf + +; NOOPT-LABEL: test1_errno: +; NOOPT: bl _sinf +; NOOPT: bl _cosf + + %call = tail call float @sinf(float %x) + %call1 = tail call float @cosf(float %x) %add = fadd float %call, %call1 ret float %add } @@ -41,16 +59,33 @@ entry: ; NOOPT: bl _sin ; NOOPT: bl _cos -; NOOPT-GNU-LABEL: test2: -; NOOPT-GNU: bl sin -; NOOPT-GNU: bl cos - %call = tail call double @sin(double %x) nounwind readnone - %call1 = tail call double @cos(double %x) nounwind readnone + %call = tail call double @sin(double %x) readnone + %call1 = tail call double @cos(double %x) readnone %add = fadd double %call, %call1 ret double %add } -declare float @sinf(float) readonly -declare double @sin(double) readonly -declare float @cosf(float) readonly -declare double @cos(double) readonly +define double @test2_errno(double %x) nounwind { +entry: +; SINCOS-LABEL: test2_errno: +; SINCOS: bl _sin +; SINCOS: bl _cos + +; SINCOS-GNU-LABEL: test2_errno: +; SINCOS-GNU: bl sin +; SINCOS-GNU: bl cos + +; NOOPT-LABEL: test2_errno: +; NOOPT: bl _sin +; NOOPT: bl _cos + + %call = tail call double @sin(double %x) + %call1 = tail call double @cos(double %x) + %add = fadd double %call, %call1 + ret double %add +} + +declare float @sinf(float) +declare double @sin(double) +declare float @cosf(float) +declare double @cos(double) diff --git a/test/CodeGen/ARM/swifterror.ll b/test/CodeGen/ARM/swifterror.ll index 78764202f627..3fd57c592bfb 100644 --- a/test/CodeGen/ARM/swifterror.ll +++ b/test/CodeGen/ARM/swifterror.ll @@ -528,3 +528,31 @@ entry: tail call void @acallee(i8* null) ret void } + + +declare swiftcc void @foo2(%swift_error** swifterror) + +; Make sure we properly assign registers during fast-isel. +; CHECK-O0-LABEL: testAssign +; CHECK-O0: mov r8, #0 +; CHECK-O0: bl _foo2 +; CHECK-O0: str r8, [s[[STK:p.*]]] +; CHECK-O0: ldr r0, [s[[STK]]] +; CHECK-O0: pop + +; CHECK-APPLE-LABEL: testAssign +; CHECK-APPLE: mov r8, #0 +; CHECK-APPLE: bl _foo2 +; CHECK-APPLE: mov r0, r8 + +define swiftcc %swift_error* @testAssign(i8* %error_ref) { +entry: + %error_ptr = alloca swifterror %swift_error* + store %swift_error* null, %swift_error** %error_ptr + call swiftcc void @foo2(%swift_error** swifterror %error_ptr) + br label %a + +a: + %error = load %swift_error*, %swift_error** %error_ptr + ret %swift_error* %error +} diff --git a/test/CodeGen/BPF/rodata_1.ll b/test/CodeGen/BPF/rodata_1.ll new file mode 100644 index 000000000000..5566f76bb75c --- /dev/null +++ b/test/CodeGen/BPF/rodata_1.ll @@ -0,0 +1,52 @@ +; RUN: llc < %s -march=bpfel -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -march=bpfeb -verify-machineinstrs | FileCheck %s + +; Source code: +; struct test_t1 { +; char a, b, c; +; }; +; struct test_t2 { +; int a, b, c, d, e; +; }; +; +; struct test_t1 g1; +; struct test_t2 g2; +; int test() +; { +; struct test_t1 t1 = {.c = 1}; +; struct test_t2 t2 = {.c = 1}; +; g1 = t1; +; g2 = t2; +; return 0; +; } + +%struct.test_t1 = type { i8, i8, i8 } +%struct.test_t2 = type { i32, i32, i32, i32, i32 } + +@test.t1 = private unnamed_addr constant %struct.test_t1 { i8 0, i8 0, i8 1 }, align 1 +@test.t2 = private unnamed_addr constant %struct.test_t2 { i32 0, i32 0, i32 1, i32 0, i32 0 }, align 4 +@g1 = common local_unnamed_addr global %struct.test_t1 zeroinitializer, align 1 +@g2 = common local_unnamed_addr global %struct.test_t2 zeroinitializer, align 4 + +; Function Attrs: nounwind +define i32 @test() local_unnamed_addr #0 { +; CHECK-LABEL: test: + +entry: + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* getelementptr inbounds (%struct.test_t1, %struct.test_t1* @g1, i64 0, i32 0), i8* getelementptr inbounds (%struct.test_t1, %struct.test_t1* @test.t1, i64 0, i32 0), i64 3, i32 1, i1 false) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast (%struct.test_t2* @g2 to i8*), i8* bitcast (%struct.test_t2* @test.t2 to i8*), i64 20, i32 4, i1 false) +; CHECK: r1 = ll +; CHECK: r2 = 0 +; CHECK: *(u8 *)(r1 + 1) = r2 +; CHECK: r3 = 1 +; CHECK: *(u8 *)(r1 + 2) = r3 +; CHECK: r1 = ll +; CHECK: *(u32 *)(r1 + 8) = r3 + ret i32 0 +} +; CHECK: .section .rodata,"a",@progbits + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1 + +attributes #0 = { nounwind } +attributes #1 = { argmemonly nounwind } diff --git a/test/CodeGen/BPF/rodata_2.ll b/test/CodeGen/BPF/rodata_2.ll new file mode 100644 index 000000000000..74b3c3640c3f --- /dev/null +++ b/test/CodeGen/BPF/rodata_2.ll @@ -0,0 +1,51 @@ +; RUN: llc < %s -march=bpfel -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -march=bpfeb -verify-machineinstrs | FileCheck %s + +; Source code: +; struct test_t1 { +; char a; +; int b; +; }; +; struct test_t2 { +; char a, b; +; struct test_t1 c[2]; +; int d[2]; +; int e; +; }; +; struct test_t2 g; +; int test() +; { +; struct test_t2 t2 = {.c = {{}, {.b = 1}}, .d = {2, 3}}; +; g = t2; +; return 0; +; } + +%struct.test_t2 = type { i8, i8, [2 x %struct.test_t1], [2 x i32], i32 } +%struct.test_t1 = type { i8, i32 } + +@test.t2 = private unnamed_addr constant %struct.test_t2 { i8 0, i8 0, [2 x %struct.test_t1] [%struct.test_t1 zeroinitializer, %struct.test_t1 { i8 0, i32 1 }], [2 x i32] [i32 2, i32 3], i32 0 }, align 4 +@g = common local_unnamed_addr global %struct.test_t2 zeroinitializer, align 4 + +; Function Attrs: nounwind +define i32 @test() local_unnamed_addr #0 { +; CHECK-LABEL: test: + +entry: + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* getelementptr inbounds (%struct.test_t2, %struct.test_t2* @g, i64 0, i32 0), i8* getelementptr inbounds (%struct.test_t2, %struct.test_t2* @test.t2, i64 0, i32 0), i64 32, i32 4, i1 false) +; CHECK: r1 = ll +; CHECK: r2 = 0 +; CHECK: *(u32 *)(r1 + 28) = r2 +; CHECK: r3 = 3 +; CHECK: *(u32 *)(r1 + 24) = r3 +; CHECK: r3 = 2 +; CHECK: *(u32 *)(r1 + 20) = r3 +; CHECK: r3 = 1 +; CHECK: *(u32 *)(r1 + 16) = r3 + ret i32 0 +} +; CHECK: .section .rodata.cst32,"aM",@progbits,32 + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1 + +attributes #0 = { nounwind } +attributes #1 = { argmemonly nounwind } diff --git a/test/CodeGen/BPF/rodata_3.ll b/test/CodeGen/BPF/rodata_3.ll new file mode 100644 index 000000000000..814ce7645465 --- /dev/null +++ b/test/CodeGen/BPF/rodata_3.ll @@ -0,0 +1,41 @@ +; REQUIRES: x86_64-linux +; RUN: llc < %s -march=bpfel -verify-machineinstrs | FileCheck --check-prefix=CHECK-EL %s +; RUN: llc < %s -march=bpfeb -verify-machineinstrs | FileCheck --check-prefix=CHECK-EB %s +; +; This test requires little-endian host, so we specific x86_64-linux here. +; Source code: +; struct test_t1 { +; char a; +; int b, c, d; +; }; +; +; struct test_t1 g; +; int test() +; { +; struct test_t1 t1 = {.a = 1}; +; g = t1; +; return 0; +; } + +%struct.test_t1 = type { i8, i32, i32, i32 } + +@test.t1 = private unnamed_addr constant %struct.test_t1 { i8 1, i32 0, i32 0, i32 0 }, align 4 +@g = common local_unnamed_addr global %struct.test_t1 zeroinitializer, align 4 + +; Function Attrs: nounwind +define i32 @test() local_unnamed_addr #0 { +entry: + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* getelementptr inbounds (%struct.test_t1, %struct.test_t1* @g, i64 0, i32 0), i8* getelementptr inbounds (%struct.test_t1, %struct.test_t1* @test.t1, i64 0, i32 0), i64 16, i32 4, i1 false) +; CHECK-EL: r2 = 1 +; CHECK-EL: *(u32 *)(r1 + 0) = r2 +; CHECK-EB: r2 = 16777216 +; CHECK-EB: *(u32 *)(r1 + 0) = r2 + ret i32 0 +} +; CHECK-EL: .section .rodata.cst16,"aM",@progbits,16 +; CHECK-EB: .section .rodata.cst16,"aM",@progbits,16 + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1 + +attributes #0 = { nounwind } +attributes #1 = { argmemonly nounwind } diff --git a/test/CodeGen/BPF/rodata_4.ll b/test/CodeGen/BPF/rodata_4.ll new file mode 100644 index 000000000000..d6b9fba5be0a --- /dev/null +++ b/test/CodeGen/BPF/rodata_4.ll @@ -0,0 +1,43 @@ +; RUN: llc < %s -march=bpfel -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -march=bpfeb -verify-machineinstrs | FileCheck %s + +; Source code: +; struct test_t1 +; { +; short a; +; short b; +; char c; +; }; +; +; struct test_t1 g; +; int test() +; { +; struct test_t1 t1[] = {{50, 500, 5}, {60, 600, 6}, {70, 700, 7}, {80, 800, 8} }; +; +; g = t1[1]; +; return 0; +; } + +%struct.test_t1 = type { i16, i16, i8 } + +@test.t1 = private unnamed_addr constant [4 x %struct.test_t1] [%struct.test_t1 { i16 50, i16 500, i8 5 }, %struct.test_t1 { i16 60, i16 600, i8 6 }, %struct.test_t1 { i16 70, i16 700, i8 7 }, %struct.test_t1 { i16 80, i16 800, i8 8 }], align 2 +@g = common local_unnamed_addr global %struct.test_t1 zeroinitializer, align 2 + +; Function Attrs: nounwind +define i32 @test() local_unnamed_addr #0 { +; CHECK-LABEL: test: +entry: + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast (%struct.test_t1* @g to i8*), i8* bitcast (%struct.test_t1* getelementptr inbounds ([4 x %struct.test_t1], [4 x %struct.test_t1]* @test.t1, i64 0, i64 1) to i8*), i64 6, i32 2, i1 false) +; CHECK: r2 = 600 +; CHECK: *(u16 *)(r1 + 2) = r2 +; CHECK: r2 = 60 +; CHECK: *(u16 *)(r1 + 0) = r2 + ret i32 0 +} +; CHECK .section .rodata,"a",@progbits + +; Function Attrs: argmemonly nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1 + +attributes #0 = { nounwind } +attributes #1 = { argmemonly nounwind } diff --git a/test/CodeGen/Hexagon/loop-idiom/pmpy-shiftconv-fail.ll b/test/CodeGen/Hexagon/loop-idiom/pmpy-shiftconv-fail.ll new file mode 100644 index 000000000000..0abf8f873200 --- /dev/null +++ b/test/CodeGen/Hexagon/loop-idiom/pmpy-shiftconv-fail.ll @@ -0,0 +1,48 @@ +; RUN: opt -march=hexagon -hexagon-loop-idiom -S < %s | FileCheck %s +; REQUIRES: asserts +; +; Check for sane output, this used to crash. +; CHECK: define void @fred + +; The conversion of shifts from right to left failed, but the return +; code was not checked and the transformation proceeded. + +target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048" +target triple = "hexagon" + +@A = common global [256 x i32] zeroinitializer, align 8 + +; Function Attrs: noinline nounwind +define void @fred() local_unnamed_addr #0 { +b0: + br label %b1 + +b1: ; preds = %b13, %b0 + %v2 = phi i32 [ 0, %b0 ], [ %v16, %b13 ] + br label %b3 + +b3: ; preds = %b3, %b1 + %v4 = phi i32 [ %v2, %b1 ], [ %v10, %b3 ] + %v5 = phi i32 [ 0, %b1 ], [ %v11, %b3 ] + %v6 = and i32 %v4, 1 + %v7 = icmp ne i32 %v6, 0 + %v8 = lshr i32 %v4, 1 + %v9 = xor i32 %v8, 123456789 + %v10 = select i1 %v7, i32 %v9, i32 %v8 + %v11 = add nuw nsw i32 %v5, 1 + %v12 = icmp ne i32 %v11, 8 + br i1 %v12, label %b3, label %b13 + +b13: ; preds = %b3 + %v14 = phi i32 [ %v10, %b3 ] + %v15 = getelementptr inbounds [256 x i32], [256 x i32]* @A, i32 0, i32 %v2 + store i32 %v14, i32* %v15, align 4 + %v16 = add nuw nsw i32 %v2, 1 + %v17 = icmp ne i32 %v16, 256 + br i1 %v17, label %b1, label %b18 + +b18: ; preds = %b13 + ret void +} + +attributes #0 = { noinline nounwind "target-cpu"="hexagonv60" } diff --git a/test/CodeGen/Hexagon/mulh.ll b/test/CodeGen/Hexagon/mulh.ll new file mode 100644 index 000000000000..0442e28d4089 --- /dev/null +++ b/test/CodeGen/Hexagon/mulh.ll @@ -0,0 +1,27 @@ +; RUN: llc -march=hexagon < %s | FileCheck %s + +target triple = "hexagon" + +; CHECK-LABEL: danny: +; CHECK: r{{[0-9]+}} = mpy(r0,r1) +define i32 @danny(i32 %a0, i32 %a1) { +b2: + %v3 = sext i32 %a0 to i64 + %v4 = sext i32 %a1 to i64 + %v5 = mul nsw i64 %v3, %v4 + %v6 = ashr i64 %v5, 32 + %v7 = trunc i64 %v6 to i32 + ret i32 %v7 +} + +; CHECK-LABEL: sammy: +; CHECK: r{{[0-9]+}} = mpy(r0,r1) +define i32 @sammy(i32 %a0, i32 %a1) { +b2: + %v3 = sext i32 %a0 to i64 + %v4 = sext i32 %a1 to i64 + %v5 = mul nsw i64 %v3, %v4 + %v6 = lshr i64 %v5, 32 + %v7 = trunc i64 %v6 to i32 + ret i32 %v7 +} diff --git a/test/CodeGen/Hexagon/mux-kill.mir b/test/CodeGen/Hexagon/mux-kill.mir new file mode 100644 index 000000000000..6944050e3dab --- /dev/null +++ b/test/CodeGen/Hexagon/mux-kill.mir @@ -0,0 +1,15 @@ +# RUN: llc -march=hexagon -run-pass hexagon-gen-mux -o - %s -verify-machineinstrs | FileCheck %s +# CHECK: %r2 = C2_mux %p0, %r0, %r1 +--- +name: fred +tracksRegLiveness: true + +body: | + bb.0: + liveins: %d0, %p0 + + %r2 = A2_tfrt %p0, %r0 + %r0 = A2_tfr %r1 + %r2 = A2_tfrf %p0, killed %r1 +... + diff --git a/test/CodeGen/Hexagon/mux-kill2.mir b/test/CodeGen/Hexagon/mux-kill2.mir new file mode 100644 index 000000000000..5f34097af7cf --- /dev/null +++ b/test/CodeGen/Hexagon/mux-kill2.mir @@ -0,0 +1,17 @@ +# RUN: llc -march=hexagon -run-pass hexagon-gen-mux -o - -verify-machineinstrs %s | FileCheck %s +# CHECK: %r1 = C2_muxri %p0, 123, %r0 +# CHECK: %r2 = C2_muxir %p0, killed %r0, 321 +--- +name: fred +tracksRegLiveness: true + +body: | + bb.0: + liveins: %r0, %p0 + + %r2 = A2_tfrt %p0, %r0 + %r1 = C2_cmoveit %p0, 123 + %r1 = A2_tfrf %p0, killed %r0, implicit killed %r1 + %r2 = C2_cmoveif killed %p0, 321, implicit killed %r2 +... + diff --git a/test/CodeGen/Hexagon/store-imm-stack-object.ll b/test/CodeGen/Hexagon/store-imm-stack-object.ll new file mode 100644 index 000000000000..8de310953aee --- /dev/null +++ b/test/CodeGen/Hexagon/store-imm-stack-object.ll @@ -0,0 +1,86 @@ +; RUN: llc -march=hexagon < %s | FileCheck %s + +target triple = "hexagon" + +; CHECK-LABEL: test1: +; CHECK: [[REG1:(r[0-9]+)]] = ##875770417 +; CHECK-DAG: memw(r29+#4) = [[REG1]] +; CHECK-DAG: memw(r29+#8) = #51 +; CHECK-DAG: memh(r29+#12) = #50 +; CHECK-DAG: memb(r29+#15) = #49 +define void @test1() { +b0: + %v1 = alloca [1 x i8], align 1 + %v2 = alloca i16, align 2 + %v3 = alloca i32, align 4 + %v4 = alloca i32, align 4 + %v5 = getelementptr inbounds [1 x i8], [1 x i8]* %v1, i32 0, i32 0 + call void @llvm.lifetime.start(i64 1, i8* %v5) + store i8 49, i8* %v5, align 1 + %v6 = bitcast i16* %v2 to i8* + call void @llvm.lifetime.start(i64 2, i8* %v6) + store i16 50, i16* %v2, align 2 + %v7 = bitcast i32* %v3 to i8* + call void @llvm.lifetime.start(i64 4, i8* %v7) + store i32 51, i32* %v3, align 4 + %v8 = bitcast i32* %v4 to i8* + call void @llvm.lifetime.start(i64 4, i8* %v8) + store i32 875770417, i32* %v4, align 4 + call void @test4(i8* %v5, i8* %v6, i8* %v7, i8* %v8) + call void @llvm.lifetime.end(i64 4, i8* %v8) + call void @llvm.lifetime.end(i64 4, i8* %v7) + call void @llvm.lifetime.end(i64 2, i8* %v6) + call void @llvm.lifetime.end(i64 1, i8* %v5) + ret void +} + +; CHECK-LABEL: test2: +; CHECK-DAG: memw(r29+#208) = #51 +; CHECK-DAG: memh(r29+#212) = r{{[0-9]+}} +; CHECK-DAG: memb(r29+#215) = r{{[0-9]+}} +define void @test2() { +b0: + %v1 = alloca [1 x i8], align 1 + %v2 = alloca i16, align 2 + %v3 = alloca i32, align 4 + %v4 = alloca i32, align 4 + %v5 = alloca [100 x i8], align 8 + %v6 = alloca [101 x i8], align 8 + %v7 = getelementptr inbounds [1 x i8], [1 x i8]* %v1, i32 0, i32 0 + call void @llvm.lifetime.start(i64 1, i8* %v7) + store i8 49, i8* %v7, align 1 + %v8 = bitcast i16* %v2 to i8* + call void @llvm.lifetime.start(i64 2, i8* %v8) + store i16 50, i16* %v2, align 2 + %v9 = bitcast i32* %v3 to i8* + call void @llvm.lifetime.start(i64 4, i8* %v9) + store i32 51, i32* %v3, align 4 + %v10 = bitcast i32* %v4 to i8* + call void @llvm.lifetime.start(i64 4, i8* %v10) + store i32 875770417, i32* %v4, align 4 + %v11 = getelementptr inbounds [100 x i8], [100 x i8]* %v5, i32 0, i32 0 + call void @llvm.lifetime.start(i64 100, i8* %v11) + call void @llvm.memset.p0i8.i32(i8* %v11, i8 0, i32 100, i32 8, i1 false) + store i8 50, i8* %v11, align 8 + %v12 = getelementptr inbounds [101 x i8], [101 x i8]* %v6, i32 0, i32 0 + call void @llvm.lifetime.start(i64 101, i8* %v12) + call void @llvm.memset.p0i8.i32(i8* %v12, i8 0, i32 101, i32 8, i1 false) + store i8 49, i8* %v12, align 8 + call void @test3(i8* %v7, i8* %v8, i8* %v9, i8* %v10, i8* %v11, i8* %v12) + call void @llvm.lifetime.end(i64 101, i8* %v12) + call void @llvm.lifetime.end(i64 100, i8* %v11) + call void @llvm.lifetime.end(i64 4, i8* %v10) + call void @llvm.lifetime.end(i64 4, i8* %v9) + call void @llvm.lifetime.end(i64 2, i8* %v8) + call void @llvm.lifetime.end(i64 1, i8* %v7) + ret void +} + +declare void @llvm.lifetime.start(i64, i8* nocapture) #0 +declare void @llvm.lifetime.end(i64, i8* nocapture) #0 +declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i32, i1) #0 + +declare void @test3(i8*, i8*, i8*, i8*, i8*, i8*) +declare void @test4(i8*, i8*, i8*, i8*) + +attributes #0 = { argmemonly nounwind "target-cpu"="hexagonv60" } diff --git a/test/CodeGen/Mips/2008-06-05-Carry.ll b/test/CodeGen/Mips/2008-06-05-Carry.ll index c61e1cdedea7..5e6092fc7848 100644 --- a/test/CodeGen/Mips/2008-06-05-Carry.ll +++ b/test/CodeGen/Mips/2008-06-05-Carry.ll @@ -2,20 +2,21 @@ define i64 @add64(i64 %u, i64 %v) nounwind { entry: +; CHECK-LABEL: add64: ; CHECK: addu -; CHECK: sltu +; CHECK-DAG: sltu +; CHECK-DAG: addu ; CHECK: addu -; CHECK: addu - %tmp2 = add i64 %u, %v + %tmp2 = add i64 %u, %v ret i64 %tmp2 } define i64 @sub64(i64 %u, i64 %v) nounwind { entry: -; CHECK: sub64 +; CHECK-LABEL: sub64 +; CHECK-DAG: sltu +; CHECK-DAG: subu ; CHECK: subu -; CHECK: sltu -; CHECK: addu ; CHECK: subu %tmp2 = sub i64 %u, %v ret i64 %tmp2 diff --git a/test/CodeGen/Mips/brundef.ll b/test/CodeGen/Mips/brundef.ll new file mode 100644 index 000000000000..802556c7cabd --- /dev/null +++ b/test/CodeGen/Mips/brundef.ll @@ -0,0 +1,26 @@ +; RUN: llc -march=mips -mcpu=mips32 -verify-machineinstrs -o /dev/null < %s +; Confirm that MachineInstr branch simplification preserves +; register operand flags, such as the flag. + +define void @ham() { +bb: + %tmp = alloca i32, align 4 + %tmp13 = ptrtoint i32* %tmp to i32 + %tmp70 = icmp eq i32 undef, -1 + br i1 %tmp70, label %bb72, label %bb40 + +bb72: ; preds = %bb72, %bb + br i1 undef, label %bb40, label %bb72 + +bb40: ; preds = %bb72, %bb + %tmp41 = phi i32 [ %tmp13, %bb72 ], [ %tmp13, %bb ] + %tmp55 = inttoptr i32 %tmp41 to i32* + %tmp58 = insertelement <2 x i32*> undef, i32* %tmp55, i32 1 + br label %bb59 + +bb59: ; preds = %bb59, %bb40 + %tmp60 = phi <2 x i32*> [ %tmp61, %bb59 ], [ %tmp58, %bb40 ] + %tmp61 = getelementptr i32, <2 x i32*> %tmp60, <2 x i32> + %tmp62 = extractelement <2 x i32*> %tmp61, i32 1 + br label %bb59 +} diff --git a/test/CodeGen/Mips/dsp-patterns.ll b/test/CodeGen/Mips/dsp-patterns.ll index 837c0d8bfc52..250d3eff37dc 100644 --- a/test/CodeGen/Mips/dsp-patterns.ll +++ b/test/CodeGen/Mips/dsp-patterns.ll @@ -1,5 +1,5 @@ -; RUN: llc -march=mips -mattr=dsp < %s | FileCheck %s -check-prefix=R1 -; RUN: llc -march=mips -mattr=dspr2 < %s | FileCheck %s -check-prefix=R2 +; RUN: llc -march=mips -mcpu=mips32r2 -mattr=dsp < %s | FileCheck %s -check-prefix=R1 +; RUN: llc -march=mips -mcpu=mips32r2 -mattr=dspr2 < %s | FileCheck %s -check-prefix=R2 ; R1-LABEL: test_lbux: ; R1: lbux ${{[0-9]+}} diff --git a/test/CodeGen/Mips/llcarry.ll b/test/CodeGen/Mips/llcarry.ll index fcf129420234..b7cc6fc8ea75 100644 --- a/test/CodeGen/Mips/llcarry.ll +++ b/test/CodeGen/Mips/llcarry.ll @@ -14,9 +14,9 @@ entry: %add = add nsw i64 %1, %0 store i64 %add, i64* @k, align 8 ; 16: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} -; 16: sltu ${{[0-9]+}}, ${{[0-9]+}} -; 16: move ${{[0-9]+}}, $t8 ; 16: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; 16: sltu ${{[0-9]+}}, ${{[0-9]+}} +; 16: move ${{[0-9]+}}, $24 ; 16: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} ret void } @@ -28,8 +28,8 @@ entry: %sub = sub nsw i64 %0, %1 ; 16: subu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} ; 16: sltu ${{[0-9]+}}, ${{[0-9]+}} -; 16: move ${{[0-9]+}}, $t8 -; 16: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; 16: move ${{[0-9]+}}, $24 +; 16: subu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} ; 16: subu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} store i64 %sub, i64* @l, align 8 ret void @@ -41,8 +41,7 @@ entry: %add = add nsw i64 %0, 15 ; 16: addiu ${{[0-9]+}}, 15 ; 16: sltu ${{[0-9]+}}, ${{[0-9]+}} -; 16: move ${{[0-9]+}}, $t8 -; 16: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} +; 16: move ${{[0-9]+}}, $24 ; 16: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} store i64 %add, i64* @m, align 8 ret void diff --git a/test/CodeGen/Mips/llvm-ir/add.ll b/test/CodeGen/Mips/llvm-ir/add.ll index a5ecdda94ce2..63884eb03b8c 100644 --- a/test/CodeGen/Mips/llvm-ir/add.ll +++ b/test/CodeGen/Mips/llvm-ir/add.ll @@ -1,35 +1,35 @@ ; RUN: llc < %s -march=mips -mcpu=mips2 | FileCheck %s \ -; RUN: -check-prefixes=ALL,NOT-R2-R6,GP32 +; RUN: -check-prefixes=ALL,NOT-R2-R6,GP32,PRE4 ; RUN: llc < %s -march=mips -mcpu=mips32 | FileCheck %s \ -; RUN: -check-prefixes=ALL,NOT-R2-R6,GP32 +; RUN: -check-prefixes=ALL,NOT-R2-R6,GP32,GP32-CMOV ; RUN: llc < %s -march=mips -mcpu=mips32r2 | FileCheck %s \ -; RUN: -check-prefixes=ALL,R2-R6,GP32 +; RUN: -check-prefixes=ALL,R2-R6,GP32,GP32-CMOV ; RUN: llc < %s -march=mips -mcpu=mips32r3 | FileCheck %s \ -; RUN: -check-prefixes=ALL,R2-R6,GP32 +; RUN: -check-prefixes=ALL,R2-R6,GP32,GP32-CMOV ; RUN: llc < %s -march=mips -mcpu=mips32r5 | FileCheck %s \ -; RUN: -check-prefixes=ALL,R2-R6,GP32 +; RUN: -check-prefixes=ALL,R2-R6,GP32,GP32-CMOV ; RUN: llc < %s -march=mips -mcpu=mips32r6 | FileCheck %s \ ; RUN: -check-prefixes=ALL,R2-R6,GP32 ; RUN: llc < %s -march=mips64 -mcpu=mips3 | FileCheck %s \ -; RUN: -check-prefixes=ALL,NOT-R2-R6,GP64 +; RUN: -check-prefixes=ALL,NOT-R2-R6,GP64,GP64-NOT-R2-R6 ; RUN: llc < %s -march=mips64 -mcpu=mips4 | FileCheck %s \ -; RUN: -check-prefixes=ALL,NOT-R2-R6,GP64 +; RUN: -check-prefixes=ALL,NOT-R2-R6,GP64,GP64-NOT-R2-R6 ; RUN: llc < %s -march=mips64 -mcpu=mips64 | FileCheck %s \ -; RUN: -check-prefixes=ALL,NOT-R2-R6,GP64 +; RUN: -check-prefixes=ALL,NOT-R2-R6,GP64,GP64-NOT-R2-R6 ; RUN: llc < %s -march=mips64 -mcpu=mips64r2 | FileCheck %s \ -; RUN: -check-prefixes=ALL,R2-R6,GP64 +; RUN: -check-prefixes=ALL,R2-R6,GP64,GP64-R2-R6 ; RUN: llc < %s -march=mips64 -mcpu=mips64r3 | FileCheck %s \ -; RUN: -check-prefixes=ALL,R2-R6,GP64 +; RUN: -check-prefixes=ALL,R2-R6,GP64,GP64-R2-R6 ; RUN: llc < %s -march=mips64 -mcpu=mips64r5 | FileCheck %s \ -; RUN: -check-prefixes=ALL,R2-R6,GP64 +; RUN: -check-prefixes=ALL,R2-R6,GP64,GP64-R2-R6 ; RUN: llc < %s -march=mips64 -mcpu=mips64r6 | FileCheck %s \ -; RUN: -check-prefixes=ALL,R2-R6,GP64 +; RUN: -check-prefixes=ALL,R2-R6,GP64,GP64-R2-R6 ; RUN: llc < %s -march=mips -mcpu=mips32r3 -mattr=+micromips -O2 -verify-machineinstrs | FileCheck %s \ -; RUN: -check-prefixes=ALL,MMR6,MM32 +; RUN: -check-prefixes=ALL,MMR3,MM32 ; RUN: llc < %s -march=mips -mcpu=mips32r6 -mattr=+micromips -O2 | FileCheck %s \ ; RUN: -check-prefixes=ALL,MMR6,MM32 ; RUN: llc < %s -march=mips -mcpu=mips64r6 -target-abi n64 -mattr=+micromips -O2 | FileCheck %s \ -; RUN: -check-prefixes=ALL,MMR6,MM64 +; RUN: -check-prefixes=ALL,MM64 ; FIXME: This code sequence is inefficient as it should be 'subu $[[T0]], $zero, $[[T0]'. @@ -110,17 +110,17 @@ define signext i64 @add_i64(i64 signext %a, i64 signext %b) { entry: ; ALL-LABEL: add_i64: - ; GP32: addu $3, $5, $7 - ; GP32: sltu $[[T0:[0-9]+]], $3, $7 - ; GP32: addu $[[T1:[0-9]+]], $[[T0]], $6 - ; GP32: addu $2, $4, $[[T1]] + ; GP32-DAG: addu $[[T0:[0-9]+]], $4, $6 + ; GP32-DAG: addu $3, $5, $7 + ; GP32: sltu $[[T1:[0-9]+]], $3, $5 + ; GP32: addu $2, $[[T0]], $[[T1]] ; GP64: daddu $2, $4, $5 - ; MM32: addu16 $3, $5, $7 - ; MM32: sltu $[[T0:[0-9]+]], $3, $7 - ; MM32: addu $[[T1:[0-9]+]], $[[T0]], $6 - ; MM32: addu $2, $4, $[[T1]] + ; MM32-DAG: addu16 $3, $5, $7 + ; MM32-DAG: addu16 $[[T0:[0-9]+]], $4, $6 + ; MM32: sltu $[[T1:[0-9]+]], $3, $5 + ; MM32: addu16 $2, $[[T0]], $[[T1]] ; MM64: daddu $2, $4, $5 @@ -132,49 +132,108 @@ define signext i128 @add_i128(i128 signext %a, i128 signext %b) { entry: ; ALL-LABEL: add_i128: - ; GP32: lw $[[T0:[0-9]+]], 28($sp) - ; GP32: addu $[[T1:[0-9]+]], $7, $[[T0]] - ; GP32: sltu $[[T2:[0-9]+]], $[[T1]], $[[T0]] - ; GP32: lw $[[T3:[0-9]+]], 24($sp) - ; GP32: addu $[[T4:[0-9]+]], $[[T2]], $[[T3]] - ; GP32: addu $[[T5:[0-9]+]], $6, $[[T4]] - ; GP32: sltu $[[T6:[0-9]+]], $[[T5]], $[[T3]] - ; GP32: lw $[[T7:[0-9]+]], 20($sp) - ; GP32: addu $[[T8:[0-9]+]], $[[T6]], $[[T7]] - ; GP32: lw $[[T9:[0-9]+]], 16($sp) - ; GP32: addu $3, $5, $[[T8]] - ; GP32: sltu $[[T10:[0-9]+]], $3, $[[T7]] - ; GP32: addu $[[T11:[0-9]+]], $[[T10]], $[[T9]] - ; GP32: addu $2, $4, $[[T11]] - ; GP32: move $4, $[[T5]] - ; GP32: move $5, $[[T1]] + ; PRE4: move $[[R1:[0-9]+]], $5 + ; PRE4: move $[[R2:[0-9]+]], $4 + ; PRE4: lw $[[R3:[0-9]+]], 24($sp) + ; PRE4: addu $[[R4:[0-9]+]], $6, $[[R3]] + ; PRE4: lw $[[R5:[0-9]+]], 28($sp) + ; PRE4: addu $[[R6:[0-9]+]], $7, $[[R5]] + ; PRE4: sltu $[[R7:[0-9]+]], $[[R6]], $7 + ; PRE4: addu $[[R8:[0-9]+]], $[[R4]], $[[R7]] + ; PRE4: xor $[[R9:[0-9]+]], $[[R8]], $6 + ; PRE4: sltiu $[[R10:[0-9]+]], $[[R9]], 1 + ; PRE4: bnez $[[R10]], $BB5_2 + ; PRE4: sltu $[[R7]], $[[R8]], $6 + ; PRE4: lw $[[R12:[0-9]+]], 20($sp) + ; PRE4: addu $[[R13:[0-9]+]], $[[R1]], $[[R12]] + ; PRE4: lw $[[R14:[0-9]+]], 16($sp) + ; PRE4: addu $[[R15:[0-9]+]], $[[R13]], $[[R7]] + ; PRE4: addu $[[R16:[0-9]+]], $[[R2]], $[[R14]] + ; PRE4: sltu $[[R17:[0-9]+]], $[[R15]], $[[R13]] + ; PRE4: sltu $[[R18:[0-9]+]], $[[R13]], $[[R1]] + ; PRE4: addu $[[R19:[0-9]+]], $[[R16]], $[[R18]] + ; PRE4: addu $2, $[[R19]], $[[R17]] - ; GP64: daddu $3, $5, $7 - ; GP64: sltu $[[T0:[0-9]+]], $3, $7 - ; GP64: daddu $[[T1:[0-9]+]], $[[T0]], $6 - ; GP64: daddu $2, $4, $[[T1]] + ; GP32-CMOV: lw $[[T0:[0-9]+]], 24($sp) + ; GP32-CMOV: addu $[[T1:[0-9]+]], $6, $[[T0]] + ; GP32-CMOV: lw $[[T2:[0-9]+]], 28($sp) + ; GP32-CMOV: addu $[[T3:[0-9]+]], $7, $[[T2]] + ; GP32-CMOV: sltu $[[T4:[0-9]+]], $[[T3]], $7 + ; GP32-CMOV: addu $[[T5:[0-9]+]], $[[T1]], $[[T4]] + ; GP32-CMOV: sltu $[[T6:[0-9]+]], $[[T5]], $6 + ; GP32-CMOV: xor $[[T7:[0-9]+]], $[[T5]], $6 + ; GP32-CMOV: movz $[[T8:[0-9]+]], $[[T4]], $[[T7]] + ; GP32-CMOV: lw $[[T9:[0-9]+]], 20($sp) + ; GP32-CMOV: addu $[[T10:[0-9]+]], $5, $[[T4]] + ; GP32-CMOV: addu $[[T11:[0-9]+]], $[[T10]], $[[T8]] + ; GP32-CMOV: lw $[[T12:[0-9]+]], 16($sp) + ; GP32-CMOV: sltu $[[T13:[0-9]+]], $[[T11]], $[[T10]] + ; GP32-CMOV: addu $[[T14:[0-9]+]], $4, $[[T12]] + ; GP32-CMOV: sltu $[[T15:[0-9]+]], $[[T10]], $5 + ; GP32-CMOV: addu $[[T16:[0-9]+]], $[[T14]], $[[T15]] + ; GP32-CMOV: addu $[[T17:[0-9]+]], $[[T16]], $[[T13]] + ; GP32-CMOV: move $4, $[[T5]] + ; GP32-CMOV: move $5, $[[T3]] - ; MM32: lw $[[T0:[0-9]+]], 28($sp) - ; MM32: addu $[[T1:[0-9]+]], $7, $[[T0]] - ; MM32: sltu $[[T2:[0-9]+]], $[[T1]], $[[T0]] - ; MM32: lw $[[T3:[0-9]+]], 24($sp) - ; MM32: addu16 $[[T4:[0-9]+]], $[[T2]], $[[T3]] - ; MM32: addu16 $[[T5:[0-9]+]], $6, $[[T4]] - ; MM32: sltu $[[T6:[0-9]+]], $[[T5]], $[[T3]] - ; MM32: lw $[[T7:[0-9]+]], 20($sp) - ; MM32: addu16 $[[T8:[0-9]+]], $[[T6]], $[[T7]] - ; MM32: lw $[[T9:[0-9]+]], 16($sp) - ; MM32: addu16 $[[T10:[0-9]+]], $5, $[[T8]] - ; MM32: sltu $[[T11:[0-9]+]], $[[T10]], $[[T7]] - ; MM32: addu $[[T12:[0-9]+]], $[[T11]], $[[T9]] - ; MM32: addu16 $[[T13:[0-9]+]], $4, $[[T12]] - ; MM32: move $4, $[[T5]] - ; MM32: move $5, $[[T1]] + ; GP64: daddu $[[T0:[0-9]+]], $4, $6 + ; GP64: daddu $[[T1:[0-9]+]], $5, $7 + ; GP64: sltu $[[T2:[0-9]+]], $[[T1]], $5 + ; GP64-NOT-R2-R6: dsll $[[T3:[0-9]+]], $[[T2]], 32 + ; GP64-NOT-R2-R6: dsrl $[[T4:[0-9]+]], $[[T3]], 32 + ; GP64-R2-R6: dext $[[T4:[0-9]+]], $[[T2]], 0, 32 + ; GP64: daddu $2, $[[T0]], $[[T4]] + + ; MMR3: move $[[T1:[0-9]+]], $5 + ; MMR3-DAG: lw $[[T2:[0-9]+]], 32($sp) + ; MMR3: addu16 $[[T3:[0-9]+]], $6, $[[T2]] + ; MMR3-DAG: lw $[[T4:[0-9]+]], 36($sp) + ; MMR3: addu16 $[[T5:[0-9]+]], $7, $[[T4]] + ; MMR3: sltu $[[T6:[0-9]+]], $[[T5]], $7 + ; MMR3: addu16 $[[T7:[0-9]+]], $[[T3]], $[[T6]] + ; MMR3: sltu $[[T8:[0-9]+]], $[[T7]], $6 + ; MMR3: xor $[[T9:[0-9]+]], $[[T7]], $6 + ; MMR3: movz $[[T8]], $[[T6]], $[[T9]] + ; MMR3: lw $[[T10:[0-9]+]], 28($sp) + ; MMR3: addu16 $[[T11:[0-9]+]], $[[T1]], $[[T10]] + ; MMR3: addu16 $[[T12:[0-9]+]], $[[T11]], $[[T8]] + ; MMR3: lw $[[T13:[0-9]+]], 24($sp) + ; MMR3: sltu $[[T14:[0-9]+]], $[[T12]], $[[T11]] + ; MMR3: addu16 $[[T15:[0-9]+]], $4, $[[T13]] + ; MMR3: sltu $[[T16:[0-9]+]], $[[T11]], $[[T1]] + ; MMR3: addu16 $[[T17:[0-9]+]], $[[T15]], $[[T16]] + ; MMR3: addu16 $2, $2, $[[T14]] + + ; MMR6: move $[[T1:[0-9]+]], $5 + ; MMR6: move $[[T2:[0-9]+]], $4 + ; MMR6: lw $[[T3:[0-9]+]], 32($sp) + ; MMR6: addu16 $[[T4:[0-9]+]], $6, $[[T3]] + ; MMR6: lw $[[T5:[0-9]+]], 36($sp) + ; MMR6: addu16 $[[T6:[0-9]+]], $7, $[[T5]] + ; MMR6: sltu $[[T7:[0-9]+]], $[[T6]], $7 + ; MMR6: addu16 $[[T8:[0-9]+]], $[[T4]], $7 + ; MMR6: sltu $[[T9:[0-9]+]], $[[T8]], $6 + ; MMR6: xor $[[T10:[0-9]+]], $[[T4]], $6 + ; MMR6: sltiu $[[T11:[0-9]+]], $[[T10]], 1 + ; MMR6: seleqz $[[T12:[0-9]+]], $[[T9]], $[[T11]] + ; MMR6: selnez $[[T13:[0-9]+]], $[[T7]], $[[T11]] + ; MMR6: lw $[[T14:[0-9]+]], 24($sp) + ; MMR6: or $[[T15:[0-9]+]], $[[T13]], $[[T12]] + ; MMR6: addu16 $[[T16:[0-9]+]], $[[T2]], $[[T14]] + ; MMR6: lw $[[T17:[0-9]+]], 28($sp) + ; MMR6: addu16 $[[T18:[0-9]+]], $[[T1]], $[[T17]] + ; MMR6: addu16 $[[T19:[0-9]+]], $[[T18]], $[[T15]] + ; MMR6: sltu $[[T20:[0-9]+]], $[[T18]], $[[T1]] + ; MMR6: sltu $[[T21:[0-9]+]], $[[T17]], $[[T18]] + ; MMR6: addu16 $2, $[[T16]], $[[T20]] + ; MMR6: addu16 $2, $[[T20]], $[[T21]] + + ; MM64: daddu $[[T0:[0-9]+]], $4, $6 ; MM64: daddu $3, $5, $7 - ; MM64: sltu $[[T0:[0-9]+]], $3, $7 - ; MM64: daddu $[[T1:[0-9]+]], $[[T0]], $6 - ; MM64: daddu $2, $4, $[[T1]] + ; MM64: sltu $[[T1:[0-9]+]], $3, $5 + ; MM64: dsll $[[T2:[0-9]+]], $[[T1]], 32 + ; MM64: dsrl $[[T3:[0-9]+]], $[[T2]], 32 + ; MM64: daddu $2, $[[T0]], $[[T3]] %r = add i128 %a, %b ret i128 %r @@ -249,17 +308,16 @@ define signext i32 @add_i32_4(i32 signext %a) { define signext i64 @add_i64_4(i64 signext %a) { ; ALL-LABEL: add_i64_4: - ; GP32: addiu $[[T0:[0-9]+]], $5, 4 - ; GP32: addiu $[[T1:[0-9]+]], $zero, 4 - ; GP32: sltu $[[T1]], $[[T0]], $[[T1]] - ; GP32: addu $2, $4, $[[T1]] + ; GP32: addiu $3, $5, 4 + ; GP32: sltu $[[T0:[0-9]+]], $3, $5 + ; GP32: addu $2, $4, $[[T0]] + + ; MM32: addiur2 $[[T1:[0-9]+]], $5, 4 + ; MM32: sltu $[[T2:[0-9]+]], $[[T1]], $5 + ; MM32: addu16 $2, $4, $[[T2]] ; GP64: daddiu $2, $4, 4 - ; MM32: addiu $[[T0:[0-9]+]], $5, 4 - ; MM32: li16 $[[T1:[0-9]+]], 4 - ; MM32: sltu $[[T2:[0-9]+]], $[[T0]], $[[T1]] - ; MM32: addu $2, $4, $[[T2]] ; MM64: daddiu $2, $4, 4 @@ -270,38 +328,67 @@ define signext i64 @add_i64_4(i64 signext %a) { define signext i128 @add_i128_4(i128 signext %a) { ; ALL-LABEL: add_i128_4: - ; GP32: addiu $[[T0:[0-9]+]], $7, 4 - ; GP32: addiu $[[T1:[0-9]+]], $zero, 4 - ; GP32: sltu $[[T1]], $[[T0]], $[[T1]] - ; GP32: addu $[[T2:[0-9]+]], $6, $[[T1]] - ; GP32: sltu $[[T1]], $[[T2]], $zero - ; GP32: addu $[[T3:[0-9]+]], $5, $[[T1]] - ; GP32: sltu $[[T1]], $[[T3]], $zero - ; GP32: addu $[[T1]], $4, $[[T1]] - ; GP32: move $4, $[[T2]] - ; GP32: move $5, $[[T0]] + ; PRE4: move $[[T0:[0-9]+]], $5 + ; PRE4: addiu $[[T1:[0-9]+]], $7, 4 + ; PRE4: sltu $[[T2:[0-9]+]], $[[T1]], $7 + ; PRE4: xori $[[T3:[0-9]+]], $[[T2]], 1 + ; PRE4: bnez $[[T3]], $BB[[BB0:[0-9_]+]] + ; PRE4: addu $[[T4:[0-9]+]], $6, $[[T2]] + ; PRE4: sltu $[[T5:[0-9]+]], $[[T4]], $6 + ; PRE4; $BB[[BB0:[0-9]+]]: + ; PRE4: addu $[[T6:[0-9]+]], $[[T0]], $[[T5]] + ; PRE4: sltu $[[T7:[0-9]+]], $[[T6]], $[[T0]] + ; PRE4: addu $[[T8:[0-9]+]], $4, $[[T7]] + ; PRE4: move $4, $[[T4]] - ; GP64: daddiu $[[T0:[0-9]+]], $5, 4 - ; GP64: daddiu $[[T1:[0-9]+]], $zero, 4 - ; GP64: sltu $[[T1]], $[[T0]], $[[T1]] - ; GP64: daddu $2, $4, $[[T1]] + ; GP32-CMOV: addiu $[[T0:[0-9]+]], $7, 4 + ; GP32-CMOV: sltu $[[T1:[0-9]+]], $[[T0]], $7 + ; GP32-CMOV: addu $[[T2:[0-9]+]], $6, $[[T1]] + ; GP32-CMOV: sltu $[[T3:[0-9]+]], $[[T2]], $6 + ; GP32-CMOV: movz $[[T3]], $[[T1]], $[[T1]] + ; GP32-CMOV: addu $[[T4:[0-9]+]], $5, $[[T3]] + ; GP32-CMOV: sltu $[[T5:[0-9]+]], $[[T4]], $5 + ; GP32-CMOV: addu $[[T7:[0-9]+]], $4, $[[T5]] + ; GP32-CMOV: move $4, $[[T2]] + ; GP32-CMOV: move $5, $[[T0]] - ; MM32: addiu $[[T0:[0-9]+]], $7, 4 - ; MM32: li16 $[[T1:[0-9]+]], 4 - ; MM32: sltu $[[T1]], $[[T0]], $[[T1]] - ; MM32: addu16 $[[T2:[0-9]+]], $6, $[[T1]] - ; MM32: li16 $[[T1]], 0 - ; MM32: sltu $[[T3:[0-9]+]], $[[T2]], $[[T1]] - ; MM32: addu16 $[[T3]], $5, $[[T3]] - ; MM32: sltu $[[T1]], $[[T3]], $[[T1]] - ; MM32: addu16 $[[T1]], $4, $[[T1]] - ; MM32: move $4, $[[T2]] - ; MM32: move $5, $[[T0]] + ; GP64: daddiu $[[T0:[0-9]+]], $5, 4 + ; GP64: sltu $[[T1:[0-9]+]], $[[T0]], $5 + ; GP64-NOT-R2-R6: dsll $[[T2:[0-9]+]], $[[T1]], 32 + ; GP64-NOT-R2-R6: dsrl $[[T3:[0-9]+]], $[[T2]], 32 + ; GP64-R2-R6: dext $[[T3:[0-9]+]], $[[T1]], 0, 32 + + ; GP64: daddu $2, $4, $[[T3]] + + ; MMR3: addiur2 $[[T0:[0-9]+]], $7, 4 + ; MMR3: sltu $[[T1:[0-9]+]], $[[T0]], $7 + ; MMR3: sltu $[[T2:[0-9]+]], $[[T0]], $7 + ; MMR3: addu16 $[[T3:[0-9]+]], $6, $[[T2]] + ; MMR3: sltu $[[T4:[0-9]+]], $[[T3]], $6 + ; MMR3: movz $[[T4]], $[[T2]], $[[T1]] + ; MMR3: addu16 $[[T6:[0-9]+]], $5, $[[T4]] + ; MMR3: sltu $[[T7:[0-9]+]], $[[T6]], $5 + ; MMR3: addu16 $2, $4, $[[T7]] + + ; MMR6: addiur2 $[[T1:[0-9]+]], $7, 4 + ; MMR6: sltu $[[T2:[0-9]+]], $[[T1]], $7 + ; MMR6: xori $[[T3:[0-9]+]], $[[T2]], 1 + ; MMR6: selnez $[[T4:[0-9]+]], $[[T2]], $[[T3]] + ; MMR6: addu16 $[[T5:[0-9]+]], $6, $[[T2]] + ; MMR6: sltu $[[T6:[0-9]+]], $[[T5]], $6 + ; MMR6: seleqz $[[T7:[0-9]+]], $[[T6]], $[[T3]] + ; MMR6: or $[[T8:[0-9]+]], $[[T4]], $[[T7]] + ; MMR6: addu16 $[[T9:[0-9]+]], $5, $[[T8]] + ; MMR6: sltu $[[T10:[0-9]+]], $[[T9]], $5 + ; MMR6: addu16 $[[T11:[0-9]+]], $4, $[[T10]] + ; MMR6: move $4, $7 + ; MMR6: move $5, $[[T1]] ; MM64: daddiu $[[T0:[0-9]+]], $5, 4 - ; MM64: daddiu $[[T1:[0-9]+]], $zero, 4 - ; MM64: sltu $[[T1]], $[[T0]], $[[T1]] - ; MM64: daddu $2, $4, $[[T1]] + ; MM64: sltu $[[T1:[0-9]+]], $[[T0]], $5 + ; MM64: dsll $[[T2:[0-9]+]], $[[T1]], 32 + ; MM64: dsrl $[[T3:[0-9]+]], $[[T2]], 32 + ; MM64: daddu $2, $4, $[[T3]] %r = add i128 4, %a ret i128 %r @@ -380,16 +467,15 @@ define signext i64 @add_i64_3(i64 signext %a) { ; ALL-LABEL: add_i64_3: ; GP32: addiu $[[T0:[0-9]+]], $5, 3 - ; GP32: addiu $[[T1:[0-9]+]], $zero, 3 - ; GP32: sltu $[[T1]], $[[T0]], $[[T1]] + ; GP32: sltu $[[T1:[0-9]+]], $[[T0]], $5 ; GP32: addu $2, $4, $[[T1]] ; GP64: daddiu $2, $4, 3 - ; MM32: addiu $[[T0:[0-9]+]], $5, 3 - ; MM32: li16 $[[T1:[0-9]+]], 3 - ; MM32: sltu $[[T2:[0-9]+]], $[[T0]], $[[T1]] - ; MM32: addu $2, $4, $[[T2]] + ; MM32: move $[[T1:[0-9]+]], $5 + ; MM32: addius5 $[[T1]], 3 + ; MM32: sltu $[[T2:[0-9]+]], $[[T1]], $5 + ; MM32: addu16 $2, $4, $[[T2]] ; MM64: daddiu $2, $4, 3 @@ -400,38 +486,70 @@ define signext i64 @add_i64_3(i64 signext %a) { define signext i128 @add_i128_3(i128 signext %a) { ; ALL-LABEL: add_i128_3: - ; GP32: addiu $[[T0:[0-9]+]], $7, 3 - ; GP32: addiu $[[T1:[0-9]+]], $zero, 3 - ; GP32: sltu $[[T1]], $[[T0]], $[[T1]] - ; GP32: addu $[[T2:[0-9]+]], $6, $[[T1]] - ; GP32: sltu $[[T3:[0-9]+]], $[[T2]], $zero - ; GP32: addu $[[T4:[0-9]+]], $5, $[[T3]] - ; GP32: sltu $[[T5:[0-9]+]], $[[T4]], $zero - ; GP32: addu $[[T5]], $4, $[[T5]] - ; GP32: move $4, $[[T2]] - ; GP32: move $5, $[[T0]] + ; PRE4: move $[[T0:[0-9]+]], $5 + ; PRE4: addiu $[[T1:[0-9]+]], $7, 3 + ; PRE4: sltu $[[T2:[0-9]+]], $[[T1]], $7 + ; PRE4: xori $[[T3:[0-9]+]], $[[T2]], 1 + ; PRE4: bnez $[[T3]], $BB[[BB0:[0-9_]+]] + ; PRE4: addu $[[T4:[0-9]+]], $6, $[[T2]] + ; PRE4: sltu $[[T5:[0-9]+]], $[[T4]], $6 + ; PRE4; $BB[[BB0:[0-9]+]]: + ; PRE4: addu $[[T6:[0-9]+]], $[[T0]], $[[T5]] + ; PRE4: sltu $[[T7:[0-9]+]], $[[T6]], $[[T0]] + ; PRE4: addu $[[T8:[0-9]+]], $4, $[[T7]] + ; PRE4: move $4, $[[T4]] - ; GP64: daddiu $[[T0:[0-9]+]], $5, 3 - ; GP64: daddiu $[[T1:[0-9]+]], $zero, 3 - ; GP64: sltu $[[T1]], $[[T0]], $[[T1]] - ; GP64: daddu $2, $4, $[[T1]] + ; GP32-CMOV: addiu $[[T0:[0-9]+]], $7, 3 + ; GP32-CMOV: sltu $[[T1:[0-9]+]], $[[T0]], $7 + ; GP32-CMOV: addu $[[T2:[0-9]+]], $6, $[[T1]] + ; GP32-CMOV: sltu $[[T3:[0-9]+]], $[[T2]], $6 + ; GP32-CMOV: movz $[[T3]], $[[T1]], $[[T1]] + ; GP32-CMOV: addu $[[T4:[0-9]+]], $5, $[[T3]] + ; GP32-CMOV: sltu $[[T5:[0-9]+]], $[[T4]], $5 + ; GP32-CMOV: addu $[[T7:[0-9]+]], $4, $[[T5]] + ; GP32-CMOV: move $4, $[[T2]] + ; GP32-CMOV: move $5, $[[T0]] - ; MM32: addiu $[[T0:[0-9]+]], $7, 3 - ; MM32: li16 $[[T1:[0-9]+]], 3 - ; MM32: sltu $[[T1]], $[[T0]], $[[T1]] - ; MM32: addu16 $[[T2:[0-9]+]], $6, $[[T1]] - ; MM32: li16 $[[T3:[0-9]+]], 0 - ; MM32: sltu $[[T4:[0-9]+]], $[[T2]], $[[T3]] - ; MM32: addu16 $[[T4]], $5, $[[T4]] - ; MM32: sltu $[[T5:[0-9]+]], $[[T4]], $[[T3]] - ; MM32: addu16 $[[T5]], $4, $[[T5]] - ; MM32: move $4, $[[T2]] - ; MM32: move $5, $[[T0]] + ; GP64: daddiu $[[T0:[0-9]+]], $5, 3 + ; GP64: sltu $[[T1:[0-9]+]], $[[T0]], $5 + + ; GP64-NOT-R2-R6: dsll $[[T2:[0-9]+]], $[[T1]], 32 + ; GP64-NOT-R2-R6: dsrl $[[T3:[0-9]+]], $[[T2]], 32 + ; GP64-R2-R6: dext $[[T3:[0-9]+]], $[[T1]], 0, 32 + + ; GP64: daddu $2, $4, $[[T3]] + + ; MMR3: move $[[T1:[0-9]+]], $7 + ; MMR3: addius5 $[[T1]], 3 + ; MMR3: sltu $[[T2:[0-9]+]], $[[T1]], $7 + ; MMR3: sltu $[[T3:[0-9]+]], $[[T1]], $7 + ; MMR3: addu16 $[[T4:[0-9]+]], $6, $[[T3]] + ; MMR3: sltu $[[T5:[0-9]+]], $[[T4]], $6 + ; MMR3: movz $[[T5]], $[[T3]], $[[T2]] + ; MMR3: addu16 $[[T6:[0-9]+]], $5, $[[T5]] + ; MMR3: sltu $[[T7:[0-9]+]], $[[T6]], $5 + ; MMR3: addu16 $2, $4, $[[T7]] + + ; MMR6: move $[[T1:[0-9]+]], $7 + ; MMR6: addius5 $[[T1]], 3 + ; MMR6: sltu $[[T2:[0-9]+]], $[[T1]], $7 + ; MMR6: xori $[[T3:[0-9]+]], $[[T2]], 1 + ; MMR6: selnez $[[T4:[0-9]+]], $[[T2]], $[[T3]] + ; MMR6: addu16 $[[T5:[0-9]+]], $6, $[[T2]] + ; MMR6: sltu $[[T6:[0-9]+]], $[[T5]], $6 + ; MMR6: seleqz $[[T7:[0-9]+]], $[[T6]], $[[T3]] + ; MMR6: or $[[T8:[0-9]+]], $[[T4]], $[[T7]] + ; MMR6: addu16 $[[T9:[0-9]+]], $5, $[[T8]] + ; MMR6: sltu $[[T10:[0-9]+]], $[[T9]], $5 + ; MMR6: addu16 $[[T11:[0-9]+]], $4, $[[T10]] + ; MMR6: move $4, $[[T5]] + ; MMR6: move $5, $[[T1]] ; MM64: daddiu $[[T0:[0-9]+]], $5, 3 - ; MM64: daddiu $[[T1:[0-9]+]], $zero, 3 - ; MM64: sltu $[[T1]], $[[T0]], $[[T1]] - ; MM64: daddu $2, $4, $[[T1]] + ; MM64: sltu $[[T1:[0-9]+]], $[[T0]], $5 + ; MM64: dsll $[[T2:[0-9]+]], $[[T1]], 32 + ; MM64: dsrl $[[T3:[0-9]+]], $[[T2]], 32 + ; MM64: daddu $2, $4, $[[T3]] %r = add i128 3, %a ret i128 %r diff --git a/test/CodeGen/Mips/llvm-ir/sub.ll b/test/CodeGen/Mips/llvm-ir/sub.ll index a730063c552f..655addb10a64 100644 --- a/test/CodeGen/Mips/llvm-ir/sub.ll +++ b/test/CodeGen/Mips/llvm-ir/sub.ll @@ -1,5 +1,5 @@ ; RUN: llc < %s -march=mips -mcpu=mips2 | FileCheck %s \ -; RUN: -check-prefixes=NOT-R2-R6,GP32,GP32-NOT-MM,NOT-MM +; RUN: -check-prefixes=NOT-R2-R6,GP32,GP32-NOT-MM,NOT-MM,PRE4 ; RUN: llc < %s -march=mips -mcpu=mips32 | FileCheck %s \ ; RUN: -check-prefixes=NOT-R2-R6,GP32,GP32-NOT-MM,NOT-MM ; RUN: llc < %s -march=mips -mcpu=mips32r2 | FileCheck %s \ @@ -11,25 +11,25 @@ ; RUN: llc < %s -march=mips -mcpu=mips32r6 | FileCheck %s \ ; RUN: -check-prefixes=R2-R6,GP32,GP32-NOT-MM,NOT-MM ; RUN: llc < %s -march=mips -mcpu=mips32r3 -mattr=+micromips -verify-machineinstrs | FileCheck %s \ -; RUN: -check-prefixes=GP32-MM,GP32,MM +; RUN: -check-prefixes=GP32-MM,GP32,MM32,MMR3 ; RUN: llc < %s -march=mips -mcpu=mips32r6 -mattr=+micromips | FileCheck %s \ -; RUN: -check-prefixes=GP32-MM,GP32,MM +; RUN: -check-prefixes=GP32-MM,GP32,MM32,MMR6 ; RUN: llc < %s -march=mips64 -mcpu=mips3 | FileCheck %s \ -; RUN: -check-prefixes=NOT-R2-R6,GP64,NOT-MM +; RUN: -check-prefixes=NOT-R2-R6,GP64,NOT-MM,GP64-NOT-R2 ; RUN: llc < %s -march=mips64 -mcpu=mips4 | FileCheck %s \ -; RUN: -check-prefixes=NOT-R2-R6,GP64,NOT-MM +; RUN: -check-prefixes=NOT-R2-R6,GP64,NOT-MM,GP64-NOT-R2 ; RUN: llc < %s -march=mips64 -mcpu=mips64 | FileCheck %s \ -; RUN: -check-prefixes=NOT-R2-R6,GP64,NOT-MM +; RUN: -check-prefixes=NOT-R2-R6,GP64,NOT-MM,GP64-NOT-R2 ; RUN: llc < %s -march=mips64 -mcpu=mips64r2 | FileCheck %s \ -; RUN: -check-prefixes=R2-R6,GP64,NOT-MM +; RUN: -check-prefixes=R2-R6,GP64,NOT-MM,GP64-R2 ; RUN: llc < %s -march=mips64 -mcpu=mips64r3 | FileCheck %s \ -; RUN: -check-prefixes=R2-R6,GP64,NOT-MM +; RUN: -check-prefixes=R2-R6,GP64,NOT-MM,GP64-R2 ; RUN: llc < %s -march=mips64 -mcpu=mips64r5 | FileCheck %s \ -; RUN: -check-prefixes=R2-R6,GP64,NOT-MM +; RUN: -check-prefixes=R2-R6,GP64,NOT-MM,GP64-R2 ; RUN: llc < %s -march=mips64 -mcpu=mips64r6 | FileCheck %s \ -; RUN: -check-prefixes=R2-R6,GP64,NOT-MM +; RUN: -check-prefixes=R2-R6,GP64,NOT-MM,GP64-R2 ; RUN: llc < %s -march=mips64 -mcpu=mips64r6 -mattr=+micromips | FileCheck %s \ -; RUN: -check-prefixes=GP64,MM +; RUN: -check-prefixes=GP64,MM64 define signext i1 @sub_i1(i1 signext %a, i1 signext %b) { entry: @@ -100,10 +100,15 @@ define signext i64 @sub_i64(i64 signext %a, i64 signext %b) { entry: ; ALL-LABEL: sub_i64: - ; GP32-NOT-MM subu $3, $5, $7 - ; GP32: sltu $[[T0:[0-9]+]], $5, $7 - ; GP32: addu $[[T1:[0-9]+]], $[[T0]], $6 - ; GP32: subu $2, $4, $[[T1]] + ; GP32-NOT-MM: sltu $[[T0:[0-9]+]], $5, $7 + ; GP32-NOT-MM: subu $2, $4, $6 + ; GP32-NOT-MM: subu $2, $2, $[[T0]] + ; GP32-NOT-MM: subu $3, $5, $7 + + ; MM32: sltu $[[T0:[0-9]+]], $5, $7 + ; MM32: subu16 $3, $4, $6 + ; MM32: subu16 $2, $3, $[[T0]] + ; MM32: subu16 $3, $5, $7 ; GP64: dsubu $2, $4, $5 @@ -115,42 +120,109 @@ define signext i128 @sub_i128(i128 signext %a, i128 signext %b) { entry: ; ALL-LABEL: sub_i128: - ; GP32-NOT-MM: lw $[[T0:[0-9]+]], 20($sp) - ; GP32-NOT-MM: sltu $[[T1:[0-9]+]], $5, $[[T0]] - ; GP32-NOT-MM: lw $[[T2:[0-9]+]], 16($sp) - ; GP32-NOT-MM: addu $[[T3:[0-9]+]], $[[T1]], $[[T2]] - ; GP32-NOT-MM: lw $[[T4:[0-9]+]], 24($sp) - ; GP32-NOT-MM: lw $[[T5:[0-9]+]], 28($sp) - ; GP32-NOT-MM: subu $[[T6:[0-9]+]], $7, $[[T5]] - ; GP32-NOT-MM: subu $2, $4, $[[T3]] - ; GP32-NOT-MM: sltu $[[T8:[0-9]+]], $6, $[[T4]] - ; GP32-NOT-MM: addu $[[T9:[0-9]+]], $[[T8]], $[[T0]] - ; GP32-NOT-MM: subu $3, $5, $[[T9]] - ; GP32-NOT-MM: sltu $[[T10:[0-9]+]], $7, $[[T5]] - ; GP32-NOT-MM: addu $[[T11:[0-9]+]], $[[T10]], $[[T4]] - ; GP32-NOT-MM: subu $4, $6, $[[T11]] - ; GP32-NOT-MM: move $5, $[[T6]] +; PRE4: lw $[[T0:[0-9]+]], 24($sp) +; PRE4: lw $[[T1:[0-9]+]], 28($sp) +; PRE4: sltu $[[T2:[0-9]+]], $7, $[[T1]] +; PRE4: xor $[[T3:[0-9]+]], $6, $[[T0]] +; PRE4: sltiu $[[T4:[0-9]+]], $[[T3]], 1 +; PRE4: bnez $[[T4]] +; PRE4: move $[[T5:[0-9]+]], $[[T2]] +; PRE4: sltu $[[T5]], $6, $[[T0]] - ; GP32-MM: lw $[[T0:[0-9]+]], 20($sp) - ; GP32-MM: sltu $[[T1:[0-9]+]], $[[T2:[0-9]+]], $[[T0]] - ; GP32-MM: lw $[[T3:[0-9]+]], 16($sp) - ; GP32-MM: addu $[[T3]], $[[T1]], $[[T3]] - ; GP32-MM: lw $[[T4:[0-9]+]], 24($sp) - ; GP32-MM: lw $[[T5:[0-9]+]], 28($sp) - ; GP32-MM: subu $[[T1]], $7, $[[T5]] - ; GP32-MM: subu16 $[[T3]], $[[T6:[0-9]+]], $[[T3]] - ; GP32-MM: sltu $[[T6]], $6, $[[T4]] - ; GP32-MM: addu16 $[[T0]], $[[T6]], $[[T0]] - ; GP32-MM: subu16 $[[T0]], $5, $[[T0]] - ; GP32-MM: sltu $[[T6]], $7, $[[T5]] - ; GP32-MM: addu $[[T6]], $[[T6]], $[[T4]] - ; GP32-MM: subu16 $[[T6]], $6, $[[T6]] - ; GP32-MM: move $[[T2]], $[[T1]] +; PRE4: lw $[[T6:[0-9]+]], 20($sp) +; PRE4: subu $[[T7:[0-9]+]], $5, $[[T6]] +; PRE4: subu $[[T8:[0-9]+]], $[[T7]], $[[T5]] +; PRE4: sltu $[[T9:[0-9]+]], $[[T7]], $[[T5]] +; PRE4: sltu $[[T10:[0-9]+]], $5, $[[T6]] +; PRE4: lw $[[T11:[0-9]+]], 16($sp) +; PRE4: subu $[[T12:[0-9]+]], $4, $[[T11]] +; PRE4: subu $[[T13:[0-9]+]], $[[T12]], $[[T10]] +; PRE4: subu $[[T14:[0-9]+]], $[[T13]], $[[T9]] +; PRE4: subu $[[T15:[0-9]+]], $6, $[[T0]] +; PRE4: subu $[[T16:[0-9]+]], $[[T15]], $[[T2]] +; PRE4: subu $5, $7, $[[T1]] - ; GP64: dsubu $3, $5, $7 - ; GP64: sltu $[[T0:[0-9]+]], $5, $7 - ; GP64: daddu $[[T1:[0-9]+]], $[[T0]], $6 - ; GP64: dsubu $2, $4, $[[T1]] +; MMR3: lw $[[T1:[0-9]+]], 48($sp) +; MMR3: sltu $[[T2:[0-9]+]], $6, $[[T1]] +; MMR3: xor $[[T3:[0-9]+]], $6, $[[T1]] +; MMR3: lw $[[T4:[0-9]+]], 52($sp) +; MMR3: sltu $[[T5:[0-9]+]], $7, $[[T4]] +; MMR3: movz $[[T6:[0-9]+]], $[[T5]], $[[T3]] +; MMR3: lw $[[T7:[0-8]+]], 44($sp) +; MMR3: subu16 $[[T8:[0-9]+]], $5, $[[T7]] +; MMR3: subu16 $[[T9:[0-9]+]], $[[T8]], $[[T6]] +; MMR3: sltu $[[T10:[0-9]+]], $[[T8]], $[[T2]] +; MMR3: sltu $[[T11:[0-9]+]], $5, $[[T7]] +; MMR3: lw $[[T12:[0-9]+]], 40($sp) +; MMR3: lw $[[T13:[0-9]+]], 12($sp) +; MMR3: subu16 $[[T14:[0-9]+]], $[[T13]], $[[T12]] +; MMR3: subu16 $[[T15:[0-9]+]], $[[T14]], $[[T11]] +; MMR3: subu16 $[[T16:[0-9]+]], $[[T15]], $[[T10]] +; MMR3: subu16 $[[T17:[0-9]+]], $6, $[[T1]] +; MMR3: subu16 $[[T18:[0-9]+]], $[[T17]], $7 +; MMR3: lw $[[T19:[0-9]+]], 8($sp) +; MMR3: lw $[[T20:[0-9]+]], 0($sp) +; MMR3: subu16 $5, $[[T19]], $[[T20]] + +; MMR6: move $[[T0:[0-9]+]], $7 +; MMR6: sw $[[T0]], 8($sp) +; MMR6: move $[[T1:[0-9]+]], $5 +; MMR6: sw $4, 12($sp) +; MMR6: lw $[[T2:[0-9]+]], 48($sp) +; MMR6: sltu $[[T3:[0-9]+]], $6, $[[T2]] +; MMR6: xor $[[T4:[0-9]+]], $6, $[[T2]] +; MMR6: sltiu $[[T5:[0-9]+]], $[[T4]], 1 +; MMR6: seleqz $[[T6:[0-9]+]], $[[T3]], $[[T5]] +; MMR6: lw $[[T7:[0-9]+]], 52($sp) +; MMR6: sltu $[[T8:[0-9]+]], $[[T0]], $[[T7]] +; MMR6: selnez $[[T9:[0-9]+]], $[[T8]], $[[T5]] +; MMR6: or $[[T10:[0-9]+]], $[[T9]], $[[T6]] +; MMR6: lw $[[T11:[0-9]+]], 44($sp) +; MMR6: subu16 $[[T12:[0-9]+]], $[[T1]], $[[T11]] +; MMR6: subu16 $[[T13:[0-9]+]], $[[T12]], $[[T7]] +; MMR6: sltu $[[T16:[0-9]+]], $[[T12]], $[[T7]] +; MMR6: sltu $[[T17:[0-9]+]], $[[T1]], $[[T11]] +; MMR6: lw $[[T18:[0-9]+]], 40($sp) +; MMR6: lw $[[T19:[0-9]+]], 12($sp) +; MMR6: subu16 $[[T20:[0-9]+]], $[[T19]], $[[T18]] +; MMR6: subu16 $[[T21:[0-9]+]], $[[T20]], $[[T17]] +; MMR6: subu16 $[[T22:[0-9]+]], $[[T21]], $[[T16]] +; MMR6: subu16 $[[T23:[0-9]+]], $6, $[[T2]] +; MMR6: subu16 $4, $[[T23]], $5 +; MMR6: lw $[[T24:[0-9]+]], 8($sp) +; MMR6: lw $[[T25:[0-9]+]], 0($sp) +; MMR6: subu16 $5, $[[T24]], $[[T25]] +; MMR6: lw $3, 4($sp) + +; FIXME: The sltu, dsll, dsrl pattern here occurs when an i32 is zero +; extended to 64 bits. Fortunately slt(i)(u) actually gives an i1. +; These should be combined away. + +; GP64-NOT-R2: dsubu $1, $4, $6 +; GP64-NOT-R2: sltu $[[T0:[0-9]+]], $5, $7 +; GP64-NOT-R2: dsll $[[T1:[0-9]+]], $[[T0]], 32 +; GP64-NOT-R2: dsrl $[[T2:[0-9]+]], $[[T1]], 32 +; GP64-NOT-R2: dsubu $2, $1, $[[T2]] +; GP64-NOT-R2: dsubu $3, $5, $7 + +; FIXME: Likewise for the sltu, dext here. + +; GP64-R2: dsubu $1, $4, $6 +; GP64-R2: sltu $[[T0:[0-9]+]], $5, $7 +; GP64-R2: dext $[[T1:[0-9]+]], $[[T0]], 0, 32 +; GP64-R2: dsubu $2, $1, $[[T1]] +; GP64-R2: dsubu $3, $5, $7 + +; FIXME: Again, redundant sign extension. Also, microMIPSR6 has the +; dext instruction which should be used here. + +; MM64: dsubu $[[T0:[0-9]+]], $4, $6 +; MM64: sltu $[[T1:[0-9]+]], $5, $7 +; MM64: dsll $[[T2:[0-9]+]], $[[T1]], 32 +; MM64: dsrl $[[T3:[0-9]+]], $[[T2]], 32 +; MM64: dsubu $2, $[[T0]], $[[T3]] +; MM64: dsubu $3, $5, $7 +; MM64: jr $ra %r = sub i128 %a, %b ret i128 %r diff --git a/test/CodeGen/Mips/longbranch.ll b/test/CodeGen/Mips/longbranch.ll index 11bc6d390319..c616089c6df0 100644 --- a/test/CodeGen/Mips/longbranch.ll +++ b/test/CodeGen/Mips/longbranch.ll @@ -1,17 +1,17 @@ -; RUN: llc -march=mipsel -relocation-model=pic < %s | FileCheck %s -; RUN: llc -march=mipsel -force-mips-long-branch -O3 -relocation-model=pic < %s \ +; RUN: llc -march=mipsel -relocation-model=pic < %s -verify-machineinstrs | FileCheck %s +; RUN: llc -march=mipsel -force-mips-long-branch -O3 -relocation-model=pic < %s -verify-machineinstrs \ ; RUN: | FileCheck %s -check-prefix=O32 ; RUN: llc -march=mipsel -mcpu=mips32r6 -force-mips-long-branch -O3 \ -; RUN: -relocation-model=pic -asm-show-inst < %s | FileCheck %s -check-prefix=O32-R6 +; RUN: -relocation-model=pic -asm-show-inst < %s -verify-machineinstrs | FileCheck %s -check-prefix=O32-R6 ; RUN: llc -march=mips64el -mcpu=mips4 -target-abi=n64 -force-mips-long-branch -O3 -relocation-model=pic \ -; RUN: < %s | FileCheck %s -check-prefix=N64 +; RUN: < %s -verify-machineinstrs | FileCheck %s -check-prefix=N64 ; RUN: llc -march=mips64el -mcpu=mips64 -target-abi=n64 -force-mips-long-branch -O3 -relocation-model=pic \ -; RUN: < %s | FileCheck %s -check-prefix=N64 +; RUN: < %s -verify-machineinstrs | FileCheck %s -check-prefix=N64 ; RUN: llc -march=mips64el -mcpu=mips64r6 -target-abi=n64 -force-mips-long-branch -O3 \ -; RUN: -relocation-model=pic -asm-show-inst < %s | FileCheck %s -check-prefix=N64-R6 +; RUN: -relocation-model=pic -asm-show-inst < %s -verify-machineinstrs | FileCheck %s -check-prefix=N64-R6 ; RUN: llc -march=mipsel -mcpu=mips32r2 -mattr=micromips \ -; RUN: -force-mips-long-branch -O3 -relocation-model=pic < %s | FileCheck %s -check-prefix=MICROMIPS -; RUN: llc -mtriple=mipsel-none-nacl -force-mips-long-branch -O3 -relocation-model=pic < %s \ +; RUN: -force-mips-long-branch -O3 -relocation-model=pic < %s -verify-machineinstrs | FileCheck %s -check-prefix=MICROMIPS +; RUN: llc -mtriple=mipsel-none-nacl -force-mips-long-branch -O3 -relocation-model=pic < %s -verify-machineinstrs \ ; RUN: | FileCheck %s -check-prefix=NACL @@ -59,9 +59,9 @@ end: ; Check for long branch expansion: ; O32: addiu $sp, $sp, -8 ; O32-NEXT: sw $ra, 0($sp) -; O32-NEXT: lui $1, %hi(($[[BB2:BB[0-9_]+]])-($[[BB1:BB[0-9_]+]])) +; O32-NEXT: lui $1, %hi(($BB0_[[BB2:[0-9]+]])-($[[BB1:BB[0-9_]+]])) ; O32-NEXT: bal $[[BB1]] -; O32-NEXT: addiu $1, $1, %lo(($[[BB2]])-($[[BB1]])) +; O32-NEXT: addiu $1, $1, %lo(($BB0_[[BB2]])-($[[BB1]])) ; O32-NEXT: $[[BB1]]: ; O32-NEXT: addu $1, $ra, $1 ; O32-NEXT: lw $ra, 0($sp) @@ -72,7 +72,7 @@ end: ; O32: lw $[[R1:[0-9]+]], %got(x)($[[GP]]) ; O32: addiu $[[R2:[0-9]+]], $zero, 1 ; O32: sw $[[R2]], 0($[[R1]]) -; O32: $[[BB2]]: +; O32: # BB#[[BB2]]: ; O32: jr $ra ; O32: nop @@ -90,10 +90,10 @@ end: ; Check for long branch expansion: ; N64: daddiu $sp, $sp, -16 ; N64-NEXT: sd $ra, 0($sp) -; N64-NEXT: daddiu $1, $zero, %hi([[BB2:\.LBB[0-9_]+]]-[[BB1:\.LBB[0-9_]+]]) +; N64-NEXT: daddiu $1, $zero, %hi(.LBB0_[[BB2:[0-9_]+]]-[[BB1:\.LBB[0-9_]+]]) ; N64-NEXT: dsll $1, $1, 16 ; N64-NEXT: bal [[BB1]] -; N64-NEXT: daddiu $1, $1, %lo([[BB2]]-[[BB1]]) +; N64-NEXT: daddiu $1, $1, %lo(.LBB0_[[BB2]]-[[BB1]]) ; N64-NEXT: [[BB1]]: ; N64-NEXT: daddu $1, $ra, $1 ; N64-NEXT: ld $ra, 0($sp) @@ -105,7 +105,7 @@ end: ; N64: addiu $[[R3:[0-9]+]], $zero, 1 ; N64: ld $[[R2:[0-9]+]], %got_disp(x)($[[GP]]) ; N64: sw $[[R3]], 0($[[R2]]) -; N64: [[BB2]]: +; N64: # BB#[[BB2]]: ; N64: jr $ra ; N64: nop @@ -125,9 +125,9 @@ end: ; Check for long branch expansion: ; MICROMIPS: addiu $sp, $sp, -8 ; MICROMIPS-NEXT: sw $ra, 0($sp) -; MICROMIPS-NEXT: lui $1, %hi(($[[BB2:BB[0-9_]+]])-($[[BB1:BB[0-9_]+]])) +; MICROMIPS-NEXT: lui $1, %hi(($BB0_[[BB2:[0-9]+]])-($[[BB1:BB[0-9_]+]])) ; MICROMIPS-NEXT: bal $[[BB1]] -; MICROMIPS-NEXT: addiu $1, $1, %lo(($[[BB2]])-($[[BB1]])) +; MICROMIPS-NEXT: addiu $1, $1, %lo(($BB0_[[BB2]])-($[[BB1]])) ; MICROMIPS-NEXT: $[[BB1]]: ; MICROMIPS-NEXT: addu $1, $ra, $1 ; MICROMIPS-NEXT: lw $ra, 0($sp) @@ -138,7 +138,7 @@ end: ; MICROMIPS: lw $[[R1:[0-9]+]], %got(x)($[[GP]]) ; MICROMIPS: li16 $[[R2:[0-9]+]], 1 ; MICROMIPS: sw16 $[[R2]], 0($[[R1]]) -; MICROMIPS: $[[BB2]]: +; MICROMIPS: # BB#[[BB2]]: ; MICROMIPS: jrc $ra @@ -154,9 +154,9 @@ end: ; Check for long branch expansion: ; NACL: addiu $sp, $sp, -8 ; NACL-NEXT: sw $ra, 0($sp) -; NACL-NEXT: lui $1, %hi(($[[BB2:BB[0-9_]+]])-($[[BB1:BB[0-9_]+]])) +; NACL-NEXT: lui $1, %hi(($BB0_[[BB2:[0-9]+]])-($[[BB1:BB[0-9_]+]])) ; NACL-NEXT: bal $[[BB1]] -; NACL-NEXT: addiu $1, $1, %lo(($[[BB2]])-($[[BB1]])) +; NACL-NEXT: addiu $1, $1, %lo(($BB0_[[BB2]])-($[[BB1]])) ; NACL-NEXT: $[[BB1]]: ; NACL-NEXT: addu $1, $ra, $1 ; NACL-NEXT: lw $ra, 0($sp) @@ -169,7 +169,7 @@ end: ; NACL: addiu $[[R2:[0-9]+]], $zero, 1 ; NACL: sw $[[R2]], 0($[[R1]]) ; NACL: .p2align 4 -; NACL-NEXT: $[[BB2]]: +; NACL-NEXT: # BB#[[BB2]]: ; NACL: jr $ra ; NACL: nop } diff --git a/test/CodeGen/Mips/madd-msub.ll b/test/CodeGen/Mips/madd-msub.ll index 7baba005a072..3e1a2e8b9708 100644 --- a/test/CodeGen/Mips/madd-msub.ll +++ b/test/CodeGen/Mips/madd-msub.ll @@ -25,11 +25,11 @@ ; 32R6-DAG: mul $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} ; 32R6-DAG: addu $[[T1:[0-9]+]], $[[T0]], $6 -; 32R6-DAG: sltu $[[T2:[0-9]+]], $[[T1]], $6 -; 32R6-DAG: sra $[[T3:[0-9]+]], $6, 31 -; 32R6-DAG: addu $[[T4:[0-9]+]], $[[T2]], $[[T3]] -; 32R6-DAG: muh $[[T5:[0-9]+]], ${{[45]}}, ${{[45]}} -; 32R6-DAG: addu $2, $[[T5]], $[[T4]] +; 32R6-DAG: sltu $[[T2:[0-9]+]], $[[T1]], $[[T0]] +; 32R6-DAG: muh $[[T3:[0-9]+]], ${{[45]}}, ${{[45]}} +; 32R6-DAG: sra $[[T4:[0-9]+]], $6, 31 +; 32R6-DAG: addu $[[T5:[0-9]+]], $[[T3]], $[[T4]] +; 32R6-DAG: addu $2, $[[T5]], $[[T2]] ; 64-DAG: sll $[[T0:[0-9]+]], $4, 0 ; 64-DAG: sll $[[T1:[0-9]+]], $5, 0 @@ -71,7 +71,7 @@ entry: ; 32R6-DAG: mul $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} ; 32R6-DAG: addu $[[T1:[0-9]+]], $[[T0]], $6 -; 32R6-DAG: sltu $[[T2:[0-9]+]], $[[T1]], $6 +; 32R6-DAG: sltu $[[T2:[0-9]+]], $[[T1]], $[[T0]] ; FIXME: There's a redundant move here. We should remove it ; 32R6-DAG: muhu $[[T3:[0-9]+]], ${{[45]}}, ${{[45]}} ; 32R6-DAG: addu $2, $[[T3]], $[[T2]] @@ -109,10 +109,10 @@ entry: ; 32R6-DAG: mul $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} ; 32R6-DAG: addu $[[T1:[0-9]+]], $[[T0]], $7 -; 32R6-DAG: sltu $[[T2:[0-9]+]], $[[T1]], $7 -; 32R6-DAG: addu $[[T4:[0-9]+]], $[[T2]], $6 -; 32R6-DAG: muh $[[T5:[0-9]+]], ${{[45]}}, ${{[45]}} -; 32R6-DAG: addu $2, $[[T5]], $[[T4]] +; 32R6-DAG: sltu $[[T2:[0-9]+]], $[[T1]], $1 +; 32R6-DAG: muh $[[T3:[0-9]+]], ${{[45]}}, ${{[45]}} +; 32R6-DAG: addu $[[T4:[0-9]+]], $[[T3]], $6 +; 32R6-DAG: addu $2, $[[T4]], $[[T2]] ; 64-DAG: sll $[[T0:[0-9]+]], $4, 0 ; 64-DAG: sll $[[T1:[0-9]+]], $5, 0 @@ -134,6 +134,17 @@ entry: ret i64 %add } +; ALL-LABEL: madd4 +; ALL-NOT: madd ${{[0-9]+}}, ${{[0-9]+}} + +define i32 @madd4(i32 %a, i32 %b, i32 %c) { +entry: + %mul = mul nsw i32 %a, %b + %add = add nsw i32 %c, %mul + + ret i32 %add +} + ; ALL-LABEL: msub1: ; 32-DAG: sra $[[T0:[0-9]+]], $6, 31 @@ -148,13 +159,13 @@ entry: ; DSP-DAG: mfhi $2, $[[AC]] ; DSP-DAG: mflo $3, $[[AC]] -; 32R6-DAG: muh $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} -; 32R6-DAG: mul $[[T1:[0-9]+]], ${{[45]}}, ${{[45]}} -; 32R6-DAG: sltu $[[T3:[0-9]+]], $6, $[[T1]] -; 32R6-DAG: addu $[[T4:[0-9]+]], $[[T3]], $[[T0]] -; 32R6-DAG: sra $[[T5:[0-9]+]], $6, 31 -; 32R6-DAG: subu $2, $[[T5]], $[[T4]] -; 32R6-DAG: subu $3, $6, $[[T1]] +; 32R6-DAG: mul $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} +; 32R6-DAG: sltu $[[T1:[0-9]+]], $6, $[[T0]] +; 32R6-DAG: muh $[[T2:[0-9]+]], ${{[45]}}, ${{[45]}} +; 32R6-DAG: sra $[[T3:[0-9]+]], $6, 31 +; 32R6-DAG: subu $[[T4:[0-9]+]], $[[T3]], $[[T2]] +; 32R6-DAG: subu $2, $[[T4]], $[[T1]] +; 32R6-DAG: subu $3, $6, $[[T0]] ; 64-DAG: sll $[[T0:[0-9]+]], $4, 0 ; 64-DAG: sll $[[T1:[0-9]+]], $5, 0 @@ -194,13 +205,12 @@ entry: ; DSP-DAG: mfhi $2, $[[AC]] ; DSP-DAG: mflo $3, $[[AC]] -; 32R6-DAG: muhu $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} -; 32R6-DAG: mul $[[T1:[0-9]+]], ${{[45]}}, ${{[45]}} - -; 32R6-DAG: sltu $[[T2:[0-9]+]], $6, $[[T1]] -; 32R6-DAG: addu $[[T3:[0-9]+]], $[[T2]], $[[T0]] -; 32R6-DAG: negu $2, $[[T3]] -; 32R6-DAG: subu $3, $6, $[[T1]] +; 32R6-DAG: mul $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} +; 32R6-DAG: sltu $[[T1:[0-9]+]], $6, $[[T0]] +; 32R6-DAG: muhu $[[T2:[0-9]+]], ${{[45]}}, ${{[45]}} +; 32R6-DAG: negu $[[T3:[0-9]+]], $[[T2]] +; 32R6-DAG: subu $2, $[[T3]], $[[T1]] +; 32R6-DAG: subu $3, $6, $[[T0]] ; 64-DAG: d[[m:m]]ult $5, $4 ; 64-DAG: [[m]]flo $[[T0:[0-9]+]] @@ -234,12 +244,12 @@ entry: ; DSP-DAG: mfhi $2, $[[AC]] ; DSP-DAG: mflo $3, $[[AC]] -; 32R6-DAG: muh $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} -; 32R6-DAG: mul $[[T1:[0-9]+]], ${{[45]}}, ${{[45]}} -; 32R6-DAG: sltu $[[T2:[0-9]+]], $7, $[[T1]] -; 32R6-DAG: addu $[[T3:[0-9]+]], $[[T2]], $[[T0]] -; 32R6-DAG: subu $2, $6, $[[T3]] -; 32R6-DAG: subu $3, $7, $[[T1]] +; 32R6-DAG: mul $[[T0:[0-9]+]], ${{[45]}}, ${{[45]}} +; 32R6-DAG: sltu $[[T1:[0-9]+]], $7, $[[T0]] +; 32R6-DAG: muh $[[T2:[0-9]+]], ${{[45]}}, ${{[45]}} +; 32R6-DAG: subu $[[T3:[0-9]+]], $6, $[[T2]] +; 32R6-DAG: subu $2, $[[T3]], $[[T1]] +; 32R6-DAG: subu $3, $7, $[[T0]] ; 64-DAG: sll $[[T0:[0-9]+]], $4, 0 ; 64-DAG: sll $[[T1:[0-9]+]], $5, 0 @@ -260,3 +270,14 @@ entry: %sub = sub nsw i64 %c, %mul ret i64 %sub } + +; ALL-LABEL: msub4 +; ALL-NOT: msub ${{[0-9]+}}, ${{[0-9]+}} + +define i32 @msub4(i32 %a, i32 %b, i32 %c) { +entry: + %mul = mul nsw i32 %a, %b + %sub = sub nsw i32 %c, %mul + + ret i32 %sub +} diff --git a/test/CodeGen/PowerPC/atomic-2.ll b/test/CodeGen/PowerPC/atomic-2.ll index 2039c1f57f17..f402cb78bd18 100644 --- a/test/CodeGen/PowerPC/atomic-2.ll +++ b/test/CodeGen/PowerPC/atomic-2.ll @@ -109,7 +109,7 @@ entry: %tmp = load atomic i64, i64* %mem acquire, align 64 ; CHECK-NOT: ldarx ; CHECK: ld [[VAL:r[0-9]+]] -; CHECK: cmpw [[CR:cr[0-9]+]], [[VAL]], [[VAL]] +; CHECK: cmpd [[CR:cr[0-9]+]], [[VAL]], [[VAL]] ; CHECK: bne- [[CR]], .+4 ; CHECK: isync ret i64 %tmp diff --git a/test/CodeGen/PowerPC/atomics-constant.ll b/test/CodeGen/PowerPC/atomics-constant.ll index a92ca813af85..77825c608a3b 100644 --- a/test/CodeGen/PowerPC/atomics-constant.ll +++ b/test/CodeGen/PowerPC/atomics-constant.ll @@ -11,7 +11,7 @@ define i64 @foo() { ; CHECK-NEXT: addis 3, 2, .LC0@toc@ha ; CHECK-NEXT: li 4, 0 ; CHECK-NEXT: ld 3, .LC0@toc@l(3) -; CHECK-NEXT: cmpw 7, 4, 4 +; CHECK-NEXT: cmpd 7, 4, 4 ; CHECK-NEXT: ld 3, 0(3) ; CHECK-NEXT: bne- 7, .+4 ; CHECK-NEXT: isync diff --git a/test/CodeGen/PowerPC/atomics-regression.ll b/test/CodeGen/PowerPC/atomics-regression.ll index 054d3a4146b0..d57b3a203791 100644 --- a/test/CodeGen/PowerPC/atomics-regression.ll +++ b/test/CodeGen/PowerPC/atomics-regression.ll @@ -23,7 +23,7 @@ define i8 @test2(i8* %ptr) { ; PPC64LE-LABEL: test2: ; PPC64LE: # BB#0: ; PPC64LE-NEXT: lbz 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: blr @@ -37,7 +37,7 @@ define i8 @test3(i8* %ptr) { ; PPC64LE-NEXT: sync ; PPC64LE-NEXT: ori 2, 2, 0 ; PPC64LE-NEXT: lbz 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: blr @@ -67,7 +67,7 @@ define i16 @test6(i16* %ptr) { ; PPC64LE-LABEL: test6: ; PPC64LE: # BB#0: ; PPC64LE-NEXT: lhz 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: blr @@ -81,7 +81,7 @@ define i16 @test7(i16* %ptr) { ; PPC64LE-NEXT: sync ; PPC64LE-NEXT: ori 2, 2, 0 ; PPC64LE-NEXT: lhz 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: blr @@ -111,7 +111,7 @@ define i32 @test10(i32* %ptr) { ; PPC64LE-LABEL: test10: ; PPC64LE: # BB#0: ; PPC64LE-NEXT: lwz 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: blr @@ -125,7 +125,7 @@ define i32 @test11(i32* %ptr) { ; PPC64LE-NEXT: sync ; PPC64LE-NEXT: ori 2, 2, 0 ; PPC64LE-NEXT: lwz 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: blr @@ -155,7 +155,7 @@ define i64 @test14(i64* %ptr) { ; PPC64LE-LABEL: test14: ; PPC64LE: # BB#0: ; PPC64LE-NEXT: ld 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: blr @@ -169,7 +169,7 @@ define i64 @test15(i64* %ptr) { ; PPC64LE-NEXT: sync ; PPC64LE-NEXT: ori 2, 2, 0 ; PPC64LE-NEXT: ld 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: blr @@ -9566,7 +9566,7 @@ define i32 @test_ordering0(i32* %ptr1, i32* %ptr2) { ; PPC64LE-LABEL: test_ordering0: ; PPC64LE: # BB#0: ; PPC64LE-NEXT: lwz 4, 0(3) -; PPC64LE-NEXT: cmpw 7, 4, 4 +; PPC64LE-NEXT: cmpd 7, 4, 4 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: lwz 3, 0(3) @@ -9583,7 +9583,7 @@ define i32 @test_ordering1(i32* %ptr1, i32 %val1, i32* %ptr2) { ; PPC64LE-LABEL: test_ordering1: ; PPC64LE: # BB#0: ; PPC64LE-NEXT: lwz 3, 0(3) -; PPC64LE-NEXT: cmpw 7, 3, 3 +; PPC64LE-NEXT: cmpd 7, 3, 3 ; PPC64LE-NEXT: bne- 7, .+4 ; PPC64LE-NEXT: isync ; PPC64LE-NEXT: stw 4, 0(5) diff --git a/test/CodeGen/PowerPC/licm-tocReg.ll b/test/CodeGen/PowerPC/licm-tocReg.ll new file mode 100644 index 000000000000..ecdfcba6e3b7 --- /dev/null +++ b/test/CodeGen/PowerPC/licm-tocReg.ll @@ -0,0 +1,110 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu < %s | FileCheck %s + +; The instructions ADDIStocHA/LDtocL are used to calculate the address of +; globals. The ones that are in bb.3.if.end could not be hoisted by Machine +; LICM due to BCTRL_LDinto_toc in bb2.if.then. This call causes the compiler +; to insert a save TOC to stack before the call and load into X2 to restore TOC +; after. By communicating to Machine LICM that X2 is guaranteed to have the +; same value before and after BCTRL_LDinto_toc, these instructions can be +; hoisted out of bb.3.if.end to outside of the loop. + +; Pre Machine LICM MIR +; +;body: +; bb.0.entry: +; successors: %bb.2.if.then(0x40000000), %bb.3.if.end(0x40000000) +; liveins: %x3 +; +; %4 = COPY %x3 +; %5 = ADDIStocHA %x2, @ga +; %6 = LDtocL @ga, killed %5 :: (load 8 from got) +; %7 = LWZ 0, %6 :: (volatile dereferenceable load 4 from @ga) +; %8 = ADDIStocHA %x2, @gb +; %9 = LDtocL @gb, killed %8 :: (load 8 from got) +; %10 = LWZ 0, killed %9 :: (volatile dereferenceable load 4 from @gb) +; %0 = LWZ 0, %6 :: (volatile dereferenceable load 4 from @ga) +; %11 = CMPW killed %7, killed %10 +; BCC 44, killed %11, %bb.2.if.then +; B %bb.3.if.end +; +; bb.2.if.then: +; %1 = PHI %0, %bb.0.entry, %3, %bb.3.if.end +; ADJCALLSTACKDOWN 32, 0, implicit-def dead %r1, implicit %r1 +; %20 = COPY %x2 +; STD %20, 24, %x1 :: (store 8 into stack + 24) +; %21 = EXTSW_32_64 %1 +; %x3 = COPY %21 +; %x12 = COPY %4 +; MTCTR8 %4, implicit-def %ctr8 +; BCTRL8_LDinto_toc 24, %x1, csr_svr464_altivec, implicit-def dead %lr8, implicit-def dead %x2, implicit %ctr8, implicit %rm, implicit %x3, implicit %x12, implicit %x2, implicit-def %r1, implicit-def %x3 +; ADJCALLSTACKUP 32, 0, implicit-def dead %r1, implicit %r1 +; %22 = COPY %x3 +; %x3 = COPY %22 +; BLR8 implicit %lr8, implicit %rm, implicit %x3 +; +; bb.3.if.end: +; successors: %bb.2.if.then(0x04000000), %bb.3.if.end(0x7c000000) +; +; %2 = PHI %0, %bb.0.entry, %3, %bb.3.if.end +; %12 = ADDI %2, 1 +; %13 = ADDIStocHA %x2, @ga +; %14 = LDtocL @ga, killed %13 :: (load 8 from got) +; STW killed %12, 0, %14 :: (volatile store 4 into @ga) +; %15 = LWZ 0, %14 :: (volatile dereferenceable load 4 from @ga) +; %16 = ADDIStocHA %x2, @gb +; %17 = LDtocL @gb, killed %16 :: (load 8 from got) +; %18 = LWZ 0, killed %17 :: (volatile dereferenceable load 4 from @gb) +; %3 = LWZ 0, %14 :: (volatile dereferenceable load 4 from @ga) +; %19 = CMPW killed %15, killed %18 +; BCC 44, killed %19, %bb.2.if.then +; B %bb.3.if.end + +@ga = external global i32, align 4 +@gb = external global i32, align 4 + +; Function Attrs: nounwind +define signext i32 @test(i32 (i32)* nocapture %FP) local_unnamed_addr #0 { +; CHECK-LABEL: test: +; CHECK: # BB#0: # %entry +; CHECK-NEXT: addis 4, 2, .LC0@toc@ha +; CHECK-NEXT: addis 5, 2, .LC1@toc@ha +; CHECK-NEXT: ld 4, .LC0@toc@l(4) +; CHECK-NEXT: ld 5, .LC1@toc@l(5) +; CHECK-NEXT: lwz 6, 0(4) +; CHECK-NEXT: lwz 5, 0(5) +; CHECK-NEXT: cmpw 6, 5 +; CHECK-NEXT: lwz 5, 0(4) +; CHECK-NEXT: mr 4, 3 +; CHECK-NEXT: bgt 0, .LBB0_3 +; CHECK-NEXT: # BB#1: +; CHECK-NEXT: addis 3, 2, .LC0@toc@ha +; CHECK-NEXT: addis 6, 2, .LC1@toc@ha +; CHECK-NEXT: ld 3, .LC0@toc@l(3) +; CHECK-NEXT: ld 6, .LC1@toc@l(6) +; CHECK-NEXT: .p2align 5 +; CHECK-NEXT: .LBB0_2: # %if.end +; CHECK-NOT: addis {{[0-9]+}}, 2, .LC0@toc@ha +; CHECK-NOT: addis {{[0-9]+}}, 2, .LC1@toc@ha +; CHECK: blr +entry: + %0 = load volatile i32, i32* @ga, align 4 + %1 = load volatile i32, i32* @gb, align 4 + %cmp1 = icmp sgt i32 %0, %1 + %2 = load volatile i32, i32* @ga, align 4 + br i1 %cmp1, label %if.then, label %if.end + +if.then: ; preds = %if.end, %entry + %.lcssa = phi i32 [ %2, %entry ], [ %6, %if.end ] + %call = tail call signext i32 %FP(i32 signext %.lcssa) #1 + ret i32 %call + +if.end: ; preds = %entry, %if.end + %3 = phi i32 [ %6, %if.end ], [ %2, %entry ] + %inc = add nsw i32 %3, 1 + store volatile i32 %inc, i32* @ga, align 4 + %4 = load volatile i32, i32* @ga, align 4 + %5 = load volatile i32, i32* @gb, align 4 + %cmp = icmp sgt i32 %4, %5 + %6 = load volatile i32, i32* @ga, align 4 + br i1 %cmp, label %if.then, label %if.end +} diff --git a/test/CodeGen/PowerPC/logic-ops-on-compares.ll b/test/CodeGen/PowerPC/logic-ops-on-compares.ll index 5a507e9ff678..df021c20ea86 100644 --- a/test/CodeGen/PowerPC/logic-ops-on-compares.ll +++ b/test/CodeGen/PowerPC/logic-ops-on-compares.ll @@ -40,8 +40,8 @@ return: ; preds = %if.end, %if.then ret i32 %retval.0 } -define void @neg_truncate_i32_eq(i32 *%ptr) { -; CHECK-LABEL: neg_truncate_i32_eq: +define void @neg_truncate_i32(i32 *%ptr) { +; CHECK-LABEL: neg_truncate_i32: ; CHECK: # BB#0: # %entry ; CHECK-NEXT: lwz r3, 0(r3) ; CHECK-NEXT: rldicl. r3, r3, 0, 63 @@ -66,8 +66,8 @@ if.end29: ; preds = %if.else } ; Function Attrs: nounwind -define i64 @logic_eq_64(i64 %a, i64 %b, i64 %c) { -; CHECK-LABEL: logic_eq_64: +define i64 @logic_ne_64(i64 %a, i64 %b, i64 %c) { +; CHECK-LABEL: logic_ne_64: ; CHECK: xor r7, r3, r4 ; CHECK-NEXT: li r6, 55 ; CHECK-NEXT: xor r5, r5, r6 @@ -99,8 +99,8 @@ return: ; preds = %if.end, %if.then ret i64 %retval.0 } -define void @neg_truncate_i64_eq(i64 *%ptr) { -; CHECK-LABEL: neg_truncate_i64_eq: +define void @neg_truncate_i64(i64 *%ptr) { +; CHECK-LABEL: neg_truncate_i64: ; CHECK: # BB#0: # %entry ; CHECK-NEXT: ld r3, 0(r3) ; CHECK-NEXT: rldicl. r3, r3, 0, 63 @@ -124,67 +124,6 @@ if.end29: ; preds = %if.else } -; Function Attrs: nounwind -define i64 @logic_ne_64(i64 %a, i64 %b, i64 %c) { -; CHECK-LABEL: logic_ne_64: -; CHECK: xor r7, r3, r4 -; CHECK-NEXT: li r6, 55 -; CHECK-NEXT: addic r8, r7, -1 -; CHECK-NEXT: xor r5, r5, r6 -; CHECK-NEXT: subfe r7, r8, r7 -; CHECK-NEXT: cntlzd r5, r5 -; CHECK-NEXT: addic r12, r4, -1 -; CHECK-NEXT: rldicl r5, r5, 58, 63 -; CHECK-NEXT: subfe r6, r12, r4 -; CHECK-NEXT: and r6, r7, r6 -; CHECK-NEXT: or. r5, r6, r5 -; CHECK-NEXT: bc 4, 1 -entry: - %tobool = icmp ne i64 %a, %b - %tobool1 = icmp ne i64 %b, 0 - %or.cond = and i1 %tobool, %tobool1 - %tobool3 = icmp eq i64 %c, 55 - %or.cond5 = or i1 %or.cond, %tobool3 - br i1 %or.cond5, label %if.end, label %if.then - -if.then: ; preds = %entry - %call = tail call i64 @foo64(i64 %a) #2 - br label %return - -if.end: ; preds = %entry - %call4 = tail call i64 @bar64(i64 %b) #2 - br label %return - -return: ; preds = %if.end, %if.then - %retval.0 = phi i64 [ %call4, %if.end ], [ %call, %if.then ] - ret i64 %retval.0 -} - -define void @neg_truncate_i64_ne(i64 *%ptr) { -; CHECK-LABEL: neg_truncate_i64_ne: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: ld r3, 0(r3) -; CHECK-NEXT: andi. r3, r3, 1 -; CHECK-NEXT: bclr 12, 1, 0 -; CHECK-NEXT: # BB#1: # %if.end29.thread136 -; CHECK-NEXT: .LBB5_2: # %if.end29 -entry: - %0 = load i64, i64* %ptr, align 4 - %rem17127 = and i64 %0, 1 - %cmp18 = icmp ne i64 %rem17127, 0 - br label %if.else - -if.else: ; preds = %entry - br i1 %cmp18, label %if.end29, label %if.end29.thread136 - -if.end29.thread136: ; preds = %if.else - unreachable - -if.end29: ; preds = %if.else - ret void - -} - declare signext i32 @foo(i32 signext) declare signext i32 @bar(i32 signext) declare i64 @foo64(i64) diff --git a/test/CodeGen/PowerPC/ppc64-P9-mod.ll b/test/CodeGen/PowerPC/ppc64-P9-mod.ll new file mode 100644 index 000000000000..46e347becbb6 --- /dev/null +++ b/test/CodeGen/PowerPC/ppc64-P9-mod.ll @@ -0,0 +1,263 @@ +; RUN: llc < %s -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr9 -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr9 -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 | FileCheck %s -check-prefix=CHECK-PWR8 -implicit-check-not mod[us][wd] + +@mod_resultsw = common local_unnamed_addr global i32 0, align 4 +@mod_resultud = common local_unnamed_addr global i64 0, align 8 +@div_resultsw = common local_unnamed_addr global i32 0, align 4 +@mod_resultuw = common local_unnamed_addr global i32 0, align 4 +@div_resultuw = common local_unnamed_addr global i32 0, align 4 +@div_resultsd = common local_unnamed_addr global i64 0, align 8 +@mod_resultsd = common local_unnamed_addr global i64 0, align 8 +@div_resultud = common local_unnamed_addr global i64 0, align 8 + +; Function Attrs: norecurse nounwind +define void @modulo_sw(i32 signext %a, i32 signext %b) local_unnamed_addr { +entry: + %rem = srem i32 %a, %b + store i32 %rem, i32* @mod_resultsw, align 4 + ret void +; CHECK-LABEL: modulo_sw +; CHECK: modsw {{[0-9]+}}, 3, 4 +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_sw +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i32 @modulo_uw(i32 zeroext %a, i32 zeroext %b) local_unnamed_addr { +entry: + %rem = urem i32 %a, %b + ret i32 %rem +; CHECK-LABEL: modulo_uw +; CHECK: moduw {{[0-9]+}}, 3, 4 +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_uw +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind readnone +define i64 @modulo_sd(i64 %a, i64 %b) local_unnamed_addr { +entry: + %rem = srem i64 %a, %b + ret i64 %rem +; CHECK-LABEL: modulo_sd +; CHECK: modsd {{[0-9]+}}, 3, 4 +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_sd +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind +define void @modulo_ud(i64 %a, i64 %b) local_unnamed_addr { +entry: + %rem = urem i64 %a, %b + store i64 %rem, i64* @mod_resultud, align 8 + ret void +; CHECK-LABEL: modulo_ud +; CHECK: modud {{[0-9]+}}, 3, 4 +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_ud +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind +define void @modulo_div_sw(i32 signext %a, i32 signext %b) local_unnamed_addr { +entry: + %rem = srem i32 %a, %b + store i32 %rem, i32* @mod_resultsw, align 4 + %div = sdiv i32 %a, %b + store i32 %div, i32* @div_resultsw, align 4 + ret void +; CHECK-LABEL: modulo_div_sw +; CHECK-NOT: modsw +; CHECK: div +; CHECK-NOT: modsw +; CHECK: mull +; CHECK-NOT: modsw +; CHECK: sub +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_div_sw +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind +define void @modulo_div_abc_sw(i32 signext %a, i32 signext %b, i32 signext %c) local_unnamed_addr { +entry: + %rem = srem i32 %a, %c + store i32 %rem, i32* @mod_resultsw, align 4 + %div = sdiv i32 %b, %c + store i32 %div, i32* @div_resultsw, align 4 + ret void +; CHECK-LABEL: modulo_div_abc_sw +; CHECK: modsw {{[0-9]+}}, 3, 5 +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_div_abc_sw +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind +define void @modulo_div_uw(i32 zeroext %a, i32 zeroext %b) local_unnamed_addr { +entry: + %rem = urem i32 %a, %b + store i32 %rem, i32* @mod_resultuw, align 4 + %div = udiv i32 %a, %b + store i32 %div, i32* @div_resultuw, align 4 + ret void +; CHECK-LABEL: modulo_div_uw +; CHECK-NOT: modsw +; CHECK: div +; CHECK-NOT: modsw +; CHECK: mull +; CHECK-NOT: modsw +; CHECK: sub +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_div_uw +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind +define void @modulo_div_swuw(i32 signext %a, i32 signext %b) local_unnamed_addr { +entry: + %rem = srem i32 %a, %b + store i32 %rem, i32* @mod_resultsw, align 4 + %div = udiv i32 %a, %b + store i32 %div, i32* @div_resultsw, align 4 + ret void +; CHECK-LABEL: modulo_div_swuw +; CHECK: modsw {{[0-9]+}}, 3, 4 +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_div_swuw +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind +define void @modulo_div_udsd(i64 %a, i64 %b) local_unnamed_addr { +entry: + %rem = urem i64 %a, %b + store i64 %rem, i64* @mod_resultud, align 8 + %div = sdiv i64 %a, %b + store i64 %div, i64* @div_resultsd, align 8 + ret void +; CHECK-LABEL: modulo_div_udsd +; CHECK: modud {{[0-9]+}}, 3, 4 +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_div_udsd +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind +define void @modulo_const32_sw(i32 signext %a) local_unnamed_addr { +entry: + %rem = srem i32 %a, 32 + store i32 %rem, i32* @mod_resultsw, align 4 + ret void +; CHECK-LABEL: modulo_const32_sw +; CHECK-NOT: modsw +; CHECK: srawi +; CHECK-NOT: modsw +; CHECK: addze +; CHECK-NOT: modsw +; CHECK: slwi +; CHECK-NOT: modsw +; CHECK: subf +; CHECK-NOT: modsw +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_const32_sw +; CHECK-PWR8: srawi +; CHECK-PWR8: addze +; CHECK-PWR8: slwi +; CHECK-PWR8: subf +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind readnone +define signext i32 @modulo_const3_sw(i32 signext %a) local_unnamed_addr { +entry: + %rem = srem i32 %a, 3 + ret i32 %rem +; CHECK-LABEL: modulo_const3_sw +; CHECK-NOT: modsw +; CHECK: mull +; CHECK-NOT: modsw +; CHECK: sub +; CHECK-NOT: modsw +; CHECK: blr +; CHECK-PWR8-LABEL: modulo_const3_sw +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind readnone +define signext i32 @const2_modulo_sw(i32 signext %a) local_unnamed_addr { +entry: + %rem = srem i32 2, %a + ret i32 %rem +; CHECK-LABEL: const2_modulo_sw +; CHECK: modsw {{[0-9]+}}, {{[0-9]+}}, 3 +; CHECK: blr +; CHECK-PWR8-LABEL: const2_modulo_sw +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + +; Function Attrs: norecurse nounwind +; FIXME On power 9 this test will still produce modsw because the divide is in +; a different block than the remainder. Due to the nature of the SDAG we cannot +; see the div in the other block. +define void @blocks_modulo_div_sw(i32 signext %a, i32 signext %b, i32 signext %c) local_unnamed_addr { +entry: + %div = sdiv i32 %a, %b + store i32 %div, i32* @div_resultsw, align 4 + %cmp = icmp sgt i32 %c, 0 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %rem = srem i32 %a, %b + store i32 %rem, i32* @mod_resultsw, align 4 + br label %if.end + +if.end: ; preds = %if.then, %entry + ret void +; CHECK-LABEL: blocks_modulo_div_sw +; CHECK: div +; CHECK: modsw {{[0-9]+}}, 3, 4 +; CHECK: blr +; CHECK-PWR8-LABEL: blocks_modulo_div_sw +; CHECK-PWR8: div +; CHECK-PWR8: mull +; CHECK-PWR8: sub +; CHECK-PWR8: blr +} + + diff --git a/test/CodeGen/PowerPC/testComparesinesll.ll b/test/CodeGen/PowerPC/testComparesinesll.ll deleted file mode 100644 index 9e9369455857..000000000000 --- a/test/CodeGen/PowerPC/testComparesinesll.ll +++ /dev/null @@ -1,125 +0,0 @@ -; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -O2 \ -; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ -; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ -; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ -; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py - -@glob = common local_unnamed_addr global i64 0, align 8 - -define signext i32 @test_inesll(i64 %a, i64 %b) { -; CHECK-LABEL: test_inesll: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: addic r4, r3, -1 -; CHECK-NEXT: subfe r3, r4, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define signext i32 @test_inesll_sext(i64 %a, i64 %b) { -; CHECK-LABEL: test_inesll_sext: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %sub = sext i1 %cmp to i32 - ret i32 %sub -} - -define signext i32 @test_inesll_z(i64 %a) { -; CHECK-LABEL: test_inesll_z: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addic r4, r3, -1 -; CHECK-NEXT: subfe r3, r4, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define signext i32 @test_inesll_sext_z(i64 %a) { -; CHECK-LABEL: test_inesll_sext_z: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %sub = sext i1 %cmp to i32 - ret i32 %sub -} - -define void @test_inesll_store(i64 %a, i64 %b) { -; CHECK-LABEL: test_inesll_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r5, r2, .LC0@toc@ha -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: ld r12, .LC0@toc@l(r5) -; CHECK-NEXT: addic r5, r3, -1 -; CHECK-NEXT: subfe r3, r5, r3 -; CHECK-NEXT: std r3, 0(r12) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = zext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_inesll_sext_store(i64 %a, i64 %b) { -; CHECK-LABEL: test_inesll_sext_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r5, r2, .LC0@toc@ha -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: ld r12, .LC0@toc@l(r5) -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: std r3, 0(r12) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = sext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_inesll_z_store(i64 %a) { -; CHECK-LABEL: test_inesll_z_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r4, r2, .LC0@toc@ha -; CHECK-NEXT: addic r5, r3, -1 -; CHECK-NEXT: ld r4, .LC0@toc@l(r4) -; CHECK-NEXT: subfe r3, r5, r3 -; CHECK-NEXT: std r3, 0(r4) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = zext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_inesll_sext_z_store(i64 %a) { -; CHECK-LABEL: test_inesll_sext_z_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r4, r2, .LC0@toc@ha -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: ld r4, .LC0@toc@l(r4) -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: std r3, 0(r4) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = sext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} diff --git a/test/CodeGen/PowerPC/testComparesineull.ll b/test/CodeGen/PowerPC/testComparesineull.ll deleted file mode 100644 index 7f0fed15157c..000000000000 --- a/test/CodeGen/PowerPC/testComparesineull.ll +++ /dev/null @@ -1,125 +0,0 @@ -; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -O2 \ -; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ -; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ -; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ -; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py - -@glob = common local_unnamed_addr global i64 0, align 8 - -define signext i32 @test_ineull(i64 %a, i64 %b) { -; CHECK-LABEL: test_ineull: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: addic r4, r3, -1 -; CHECK-NEXT: subfe r3, r4, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define signext i32 @test_ineull_sext(i64 %a, i64 %b) { -; CHECK-LABEL: test_ineull_sext: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %sub = sext i1 %cmp to i32 - ret i32 %sub -} - -define signext i32 @test_ineull_z(i64 %a) { -; CHECK-LABEL: test_ineull_z: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addic r4, r3, -1 -; CHECK-NEXT: subfe r3, r4, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define signext i32 @test_ineull_sext_z(i64 %a) { -; CHECK-LABEL: test_ineull_sext_z: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %sub = sext i1 %cmp to i32 - ret i32 %sub -} - -define void @test_ineull_store(i64 %a, i64 %b) { -; CHECK-LABEL: test_ineull_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r5, r2, .LC0@toc@ha -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: ld r12, .LC0@toc@l(r5) -; CHECK-NEXT: addic r5, r3, -1 -; CHECK-NEXT: subfe r3, r5, r3 -; CHECK-NEXT: std r3, 0(r12) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = zext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_ineull_sext_store(i64 %a, i64 %b) { -; CHECK-LABEL: test_ineull_sext_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r5, r2, .LC0@toc@ha -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: ld r12, .LC0@toc@l(r5) -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: std r3, 0(r12) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = sext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_ineull_z_store(i64 %a) { -; CHECK-LABEL: test_ineull_z_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r4, r2, .LC0@toc@ha -; CHECK-NEXT: addic r5, r3, -1 -; CHECK-NEXT: ld r4, .LC0@toc@l(r4) -; CHECK-NEXT: subfe r3, r5, r3 -; CHECK-NEXT: std r3, 0(r4) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = zext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_ineull_sext_z_store(i64 %a) { -; CHECK-LABEL: test_ineull_sext_z_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r4, r2, .LC0@toc@ha -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: ld r4, .LC0@toc@l(r4) -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: std r3, 0(r4) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = sext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} diff --git a/test/CodeGen/PowerPC/testComparesllnesll.ll b/test/CodeGen/PowerPC/testComparesllnesll.ll deleted file mode 100644 index d87ff55739fc..000000000000 --- a/test/CodeGen/PowerPC/testComparesllnesll.ll +++ /dev/null @@ -1,125 +0,0 @@ -; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -O2 \ -; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ -; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ -; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ -; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py - -@glob = common local_unnamed_addr global i64 0, align 8 - -define i64 @test_llnesll(i64 %a, i64 %b) { -; CHECK-LABEL: test_llnesll: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: addic r4, r3, -1 -; CHECK-NEXT: subfe r3, r4, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = zext i1 %cmp to i64 - ret i64 %conv1 -} - -define i64 @test_llnesll_sext(i64 %a, i64 %b) { -; CHECK-LABEL: test_llnesll_sext: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = sext i1 %cmp to i64 - ret i64 %conv1 -} - -define i64 @test_llnesll_z(i64 %a) { -; CHECK-LABEL: test_llnesll_z: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addic r4, r3, -1 -; CHECK-NEXT: subfe r3, r4, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = zext i1 %cmp to i64 - ret i64 %conv1 -} - -define i64 @test_llnesll_sext_z(i64 %a) { -; CHECK-LABEL: test_llnesll_sext_z: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = sext i1 %cmp to i64 - ret i64 %conv1 -} - -define void @test_llnesll_store(i64 %a, i64 %b) { -; CHECK-LABEL: test_llnesll_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r5, r2, .LC0@toc@ha -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: ld r12, .LC0@toc@l(r5) -; CHECK-NEXT: addic r5, r3, -1 -; CHECK-NEXT: subfe r3, r5, r3 -; CHECK-NEXT: std r3, 0(r12) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = zext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_llnesll_sext_store(i64 %a, i64 %b) { -; CHECK-LABEL: test_llnesll_sext_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r5, r2, .LC0@toc@ha -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: ld r12, .LC0@toc@l(r5) -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: std r3, 0(r12) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = sext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_llnesll_z_store(i64 %a) { -; CHECK-LABEL: test_llnesll_z_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r4, r2, .LC0@toc@ha -; CHECK-NEXT: addic r5, r3, -1 -; CHECK-NEXT: ld r4, .LC0@toc@l(r4) -; CHECK-NEXT: subfe r3, r5, r3 -; CHECK-NEXT: std r3, 0(r4) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = zext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_llnesll_sext_z_store(i64 %a) { -; CHECK-LABEL: test_llnesll_sext_z_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r4, r2, .LC0@toc@ha -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: ld r4, .LC0@toc@l(r4) -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: std r3, 0(r4) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = sext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} diff --git a/test/CodeGen/PowerPC/testComparesllneull.ll b/test/CodeGen/PowerPC/testComparesllneull.ll deleted file mode 100644 index 7309d5899068..000000000000 --- a/test/CodeGen/PowerPC/testComparesllneull.ll +++ /dev/null @@ -1,125 +0,0 @@ -; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -O2 \ -; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ -; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ -; RUN: -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ -; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py - -@glob = common local_unnamed_addr global i64 0, align 8 - -define i64 @test_llneull(i64 %a, i64 %b) { -; CHECK-LABEL: test_llneull: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: addic r4, r3, -1 -; CHECK-NEXT: subfe r3, r4, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = zext i1 %cmp to i64 - ret i64 %conv1 -} - -define i64 @test_llneull_sext(i64 %a, i64 %b) { -; CHECK-LABEL: test_llneull_sext: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = sext i1 %cmp to i64 - ret i64 %conv1 -} - -define i64 @test_llneull_z(i64 %a) { -; CHECK-LABEL: test_llneull_z: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addic r4, r3, -1 -; CHECK-NEXT: subfe r3, r4, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = zext i1 %cmp to i64 - ret i64 %conv1 -} - -define i64 @test_llneull_sext_z(i64 %a) { -; CHECK-LABEL: test_llneull_sext_z: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = sext i1 %cmp to i64 - ret i64 %conv1 -} - -define void @test_llneull_store(i64 %a, i64 %b) { -; CHECK-LABEL: test_llneull_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r5, r2, .LC0@toc@ha -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: ld r12, .LC0@toc@l(r5) -; CHECK-NEXT: addic r5, r3, -1 -; CHECK-NEXT: subfe r3, r5, r3 -; CHECK-NEXT: std r3, 0(r12) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = zext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_llneull_sext_store(i64 %a, i64 %b) { -; CHECK-LABEL: test_llneull_sext_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r5, r2, .LC0@toc@ha -; CHECK-NEXT: xor r3, r3, r4 -; CHECK-NEXT: ld r12, .LC0@toc@l(r5) -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: std r3, 0(r12) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, %b - %conv1 = sext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_llneull_z_store(i64 %a) { -; CHECK-LABEL: test_llneull_z_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r4, r2, .LC0@toc@ha -; CHECK-NEXT: addic r5, r3, -1 -; CHECK-NEXT: ld r4, .LC0@toc@l(r4) -; CHECK-NEXT: subfe r3, r5, r3 -; CHECK-NEXT: std r3, 0(r4) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = zext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} - -define void @test_llneull_sext_z_store(i64 %a) { -; CHECK-LABEL: test_llneull_sext_z_store: -; CHECK: # BB#0: # %entry -; CHECK-NEXT: addis r4, r2, .LC0@toc@ha -; CHECK-NEXT: subfic r3, r3, 0 -; CHECK-NEXT: ld r4, .LC0@toc@l(r4) -; CHECK-NEXT: subfe r3, r3, r3 -; CHECK-NEXT: std r3, 0(r4) -; CHECK-NEXT: blr -entry: - %cmp = icmp ne i64 %a, 0 - %conv1 = sext i1 %cmp to i64 - store i64 %conv1, i64* @glob, align 8 - ret void -} diff --git a/test/CodeGen/PowerPC/vec_revb.ll b/test/CodeGen/PowerPC/vec_revb.ll new file mode 100644 index 000000000000..c09164bae13e --- /dev/null +++ b/test/CodeGen/PowerPC/vec_revb.ll @@ -0,0 +1,54 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr9 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr9 < %s | FileCheck %s + +define <8 x i16> @testXXBRH(<8 x i16> %a) { +; CHECK-LABEL: testXXBRH: +; CHECK: # BB#0: # %entry +; CHECK-NEXT: xxbrh 34, 34 +; CHECK-NEXT: blr + +entry: + %0 = bitcast <8 x i16> %a to <16 x i8> + %1 = shufflevector <16 x i8> %0, <16 x i8> undef, <16 x i32> + %2 = bitcast <16 x i8> %1 to <8 x i16> + ret <8 x i16> %2 +} + +define <4 x i32> @testXXBRW(<4 x i32> %a) { +; CHECK-LABEL: testXXBRW: +; CHECK: # BB#0: # %entry +; CHECK-NEXT: xxbrw 34, 34 +; CHECK-NEXT: blr + +entry: + %0 = bitcast <4 x i32> %a to <16 x i8> + %1 = shufflevector <16 x i8> %0, <16 x i8> undef, <16 x i32> + %2 = bitcast <16 x i8> %1 to <4 x i32> + ret <4 x i32> %2 +} + +define <2 x double> @testXXBRD(<2 x double> %a) { +; CHECK-LABEL: testXXBRD: +; CHECK: # BB#0: # %entry +; CHECK-NEXT: xxbrd 34, 34 +; CHECK-NEXT: blr + +entry: + %0 = bitcast <2 x double> %a to <16 x i8> + %1 = shufflevector <16 x i8> %0, <16 x i8> undef, <16 x i32> + %2 = bitcast <16 x i8> %1 to <2 x double> + ret <2 x double> %2 +} + +define <1 x i128> @testXXBRQ(<1 x i128> %a) { +; CHECK-LABEL: testXXBRQ: +; CHECK: # BB#0: # %entry +; CHECK-NEXT: xxbrq 34, 34 +; CHECK-NEXT: blr + +entry: + %0 = bitcast <1 x i128> %a to <16 x i8> + %1 = shufflevector <16 x i8> %0, <16 x i8> undef, <16 x i32> + %2 = bitcast <16 x i8> %1 to <1 x i128> + ret <1 x i128> %2 +} diff --git a/test/CodeGen/SystemZ/fp-sincos-01.ll b/test/CodeGen/SystemZ/fp-sincos-01.ll index cd182a590eee..4a38d7afba2c 100644 --- a/test/CodeGen/SystemZ/fp-sincos-01.ll +++ b/test/CodeGen/SystemZ/fp-sincos-01.ll @@ -1,6 +1,6 @@ ; Test that combined sin/cos library call is emitted when appropriate -; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s --check-prefix=CHECK-NOOPT +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s --check-prefix=CHECK-OPT ; RUN: llc < %s -mtriple=s390x-linux-gnu -enable-unsafe-fp-math | FileCheck %s --check-prefix=CHECK-OPT define float @f1(float %x) { @@ -8,10 +8,18 @@ define float @f1(float %x) { ; CHECK-OPT: brasl %r14, sincosf@PLT ; CHECK-OPT: le %f0, 164(%r15) ; CHECK-OPT: aeb %f0, 160(%r15) + %tmp1 = call float @sinf(float %x) readnone + %tmp2 = call float @cosf(float %x) readnone + %add = fadd float %tmp1, %tmp2 + ret float %add +} -; CHECK-NOOPT-LABEL: f1: -; CHECK-NOOPT: brasl %r14, sinf@PLT -; CHECK-NOOPT: brasl %r14, cosf@PLT +define float @f1_errno(float %x) { +; CHECK-OPT-LABEL: f1_errno: +; CHECK-OPT: brasl %r14, sinf@PLT +; CHECK-OPT: ler %f9, %f0 +; CHECK-OPT: brasl %r14, cosf@PLT +; CHECK-OPT: aebr %f0, %f9 %tmp1 = call float @sinf(float %x) %tmp2 = call float @cosf(float %x) %add = fadd float %tmp1, %tmp2 @@ -23,10 +31,18 @@ define double @f2(double %x) { ; CHECK-OPT: brasl %r14, sincos@PLT ; CHECK-OPT: ld %f0, 168(%r15) ; CHECK-OPT: adb %f0, 160(%r15) + %tmp1 = call double @sin(double %x) readnone + %tmp2 = call double @cos(double %x) readnone + %add = fadd double %tmp1, %tmp2 + ret double %add +} -; CHECK-NOOPT-LABEL: f2: -; CHECK-NOOPT: brasl %r14, sin@PLT -; CHECK-NOOPT: brasl %r14, cos@PLT +define double @f2_errno(double %x) { +; CHECK-OPT-LABEL: f2_errno: +; CHECK-OPT: brasl %r14, sin@PLT +; CHECK-OPT: ldr %f9, %f0 +; CHECK-OPT: brasl %r14, cos@PLT +; CHECK-OPT: adbr %f0, %f9 %tmp1 = call double @sin(double %x) %tmp2 = call double @cos(double %x) %add = fadd double %tmp1, %tmp2 @@ -37,20 +53,27 @@ define fp128 @f3(fp128 %x) { ; CHECK-OPT-LABEL: f3: ; CHECK-OPT: brasl %r14, sincosl@PLT ; CHECK-OPT: axbr + %tmp1 = call fp128 @sinl(fp128 %x) readnone + %tmp2 = call fp128 @cosl(fp128 %x) readnone + %add = fadd fp128 %tmp1, %tmp2 + ret fp128 %add +} -; CHECK-NOOPT-LABEL: f3: -; CHECK-NOOPT: brasl %r14, sinl@PLT -; CHECK-NOOPT: brasl %r14, cosl@PLT +define fp128 @f3_errno(fp128 %x) { +; CHECK-OPT-LABEL: f3_errno: +; CHECK-OPT: brasl %r14, sinl@PLT +; CHECK-OPT: brasl %r14, cosl@PLT +; CHECK-OPT: axbr %tmp1 = call fp128 @sinl(fp128 %x) %tmp2 = call fp128 @cosl(fp128 %x) %add = fadd fp128 %tmp1, %tmp2 ret fp128 %add } -declare float @sinf(float) readonly -declare double @sin(double) readonly -declare fp128 @sinl(fp128) readonly -declare float @cosf(float) readonly -declare double @cos(double) readonly -declare fp128 @cosl(fp128) readonly +declare float @sinf(float) +declare double @sin(double) +declare fp128 @sinl(fp128) +declare float @cosf(float) +declare double @cos(double) +declare fp128 @cosl(fp128) diff --git a/test/CodeGen/X86/2012-01-11-split-cv.ll b/test/CodeGen/X86/2012-01-11-split-cv.ll index 212acedafb94..34ec48a02517 100644 --- a/test/CodeGen/X86/2012-01-11-split-cv.ll +++ b/test/CodeGen/X86/2012-01-11-split-cv.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mattr=+avx -mtriple=i686-unknown-unknown | FileCheck %s define void @add18i16(<18 x i16>* nocapture sret %ret, <18 x i16>* %bp) nounwind { @@ -12,7 +12,6 @@ define void @add18i16(<18 x i16>* nocapture sret %ret, <18 x i16>* %bp) nounwind ; CHECK-NEXT: vmovups %ymm0, (%eax) ; CHECK-NEXT: vzeroupper ; CHECK-NEXT: retl $4 -; %b = load <18 x i16>, <18 x i16>* %bp, align 16 %x = add <18 x i16> zeroinitializer, %b store <18 x i16> %x, <18 x i16>* %ret, align 16 diff --git a/test/CodeGen/X86/StackColoring.ll b/test/CodeGen/X86/StackColoring.ll index 93888c470e2d..47c74175f949 100644 --- a/test/CodeGen/X86/StackColoring.ll +++ b/test/CodeGen/X86/StackColoring.ll @@ -582,12 +582,76 @@ if.end: ; preds = %if.then, %entry ret i32 %x.addr.0 } +;CHECK-LABEL: multi_segment: +;YESCOLOR: subq $256, %rsp +;NOFIRSTUSE: subq $256, %rsp +;NOCOLOR: subq $512, %rsp +define i1 @multi_segment(i1, i1) +{ +entry-block: + %foo = alloca [32 x i64] + %bar = alloca [32 x i64] + %foo_i8 = bitcast [32 x i64]* %foo to i8* + %bar_i8 = bitcast [32 x i64]* %bar to i8* + call void @llvm.lifetime.start.p0i8(i64 256, i8* %bar_i8) + call void @baz([32 x i64]* %bar, i32 1) + call void @llvm.lifetime.end.p0i8(i64 256, i8* %bar_i8) + call void @llvm.lifetime.start.p0i8(i64 256, i8* %foo_i8) + call void @baz([32 x i64]* %foo, i32 1) + call void @llvm.lifetime.end.p0i8(i64 256, i8* %foo_i8) + call void @llvm.lifetime.start.p0i8(i64 256, i8* %bar_i8) + call void @baz([32 x i64]* %bar, i32 1) + call void @llvm.lifetime.end.p0i8(i64 256, i8* %bar_i8) + ret i1 true +} + +;CHECK-LABEL: pr32488: +;YESCOLOR: subq $256, %rsp +;NOFIRSTUSE: subq $256, %rsp +;NOCOLOR: subq $512, %rsp +define i1 @pr32488(i1, i1) +{ +entry-block: + %foo = alloca [32 x i64] + %bar = alloca [32 x i64] + %foo_i8 = bitcast [32 x i64]* %foo to i8* + %bar_i8 = bitcast [32 x i64]* %bar to i8* + br i1 %0, label %if_false, label %if_true +if_false: + call void @llvm.lifetime.start.p0i8(i64 256, i8* %bar_i8) + call void @baz([32 x i64]* %bar, i32 0) + br i1 %1, label %if_false.1, label %onerr +if_false.1: + call void @llvm.lifetime.end.p0i8(i64 256, i8* %bar_i8) + br label %merge +if_true: + call void @llvm.lifetime.start.p0i8(i64 256, i8* %foo_i8) + call void @baz([32 x i64]* %foo, i32 1) + br i1 %1, label %if_true.1, label %onerr +if_true.1: + call void @llvm.lifetime.end.p0i8(i64 256, i8* %foo_i8) + br label %merge +merge: + ret i1 false +onerr: + call void @llvm.lifetime.end.p0i8(i64 256, i8* %foo_i8) + call void @llvm.lifetime.end.p0i8(i64 256, i8* %bar_i8) + call void @destructor() + ret i1 true +} + +%Data = type { [32 x i64] } + +declare void @destructor() + declare void @inita(i32*) declare void @initb(i32*,i32*,i32*) declare void @bar([100 x i32]* , [100 x i32]*) nounwind +declare void @baz([32 x i64]*, i32) + declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) nounwind declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) nounwind diff --git a/test/CodeGen/X86/add-sub-nsw-nuw.ll b/test/CodeGen/X86/add-sub-nsw-nuw.ll index f5bffb2386bd..d02736de55d3 100644 --- a/test/CodeGen/X86/add-sub-nsw-nuw.ll +++ b/test/CodeGen/X86/add-sub-nsw-nuw.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=i386-apple-darwin < %s | FileCheck %s ; PR30841: https://llvm.org/bugs/show_bug.cgi?id=30841 @@ -12,7 +12,6 @@ define i8 @PR30841(i64 %argc) { ; CHECK-NEXT: negl %eax ; CHECK-NEXT: ## kill: %AL %AL %EAX ; CHECK-NEXT: retl -; entry: %or = or i64 %argc, -4294967296 br label %end diff --git a/test/CodeGen/X86/addcarry.ll b/test/CodeGen/X86/addcarry.ll index 3c84af4aa9ec..cffcfd8e8a42 100644 --- a/test/CodeGen/X86/addcarry.ll +++ b/test/CodeGen/X86/addcarry.ll @@ -81,6 +81,30 @@ entry: ret void } +define i8 @e(i32* nocapture %a, i32 %b) nounwind { +; CHECK-LABEL: e: +; CHECK: # BB#0: +; CHECK-NEXT: # kill: %ESI %ESI %RSI +; CHECK-NEXT: movl (%rdi), %ecx +; CHECK-NEXT: leal (%rsi,%rcx), %edx +; CHECK-NEXT: addl %esi, %edx +; CHECK-NEXT: setb %al +; CHECK-NEXT: addl %esi, %ecx +; CHECK-NEXT: movl %edx, (%rdi) +; CHECK-NEXT: adcb $0, %al +; CHECK-NEXT: retq + %1 = load i32, i32* %a, align 4 + %2 = add i32 %1, %b + %3 = icmp ult i32 %2, %b + %4 = zext i1 %3 to i8 + %5 = add i32 %2, %b + store i32 %5, i32* %a, align 4 + %6 = icmp ult i32 %5, %b + %7 = zext i1 %6 to i8 + %8 = add nuw nsw i8 %7, %4 + ret i8 %8 +} + %scalar = type { [4 x i64] } define %scalar @pr31719(%scalar* nocapture readonly %this, %scalar %arg.b) { diff --git a/test/CodeGen/X86/avx-vperm2x128.ll b/test/CodeGen/X86/avx-vperm2x128.ll index f4a77c370db5..9a21f4b5caba 100644 --- a/test/CodeGen/X86/avx-vperm2x128.ll +++ b/test/CodeGen/X86/avx-vperm2x128.ll @@ -50,16 +50,10 @@ entry: } define <8 x float> @shuffle_v8f32_01230123_mem(<8 x float>* %pa, <8 x float>* %pb) nounwind uwtable readnone ssp { -; AVX1-LABEL: shuffle_v8f32_01230123_mem: -; AVX1: ## BB#0: ## %entry -; AVX1-NEXT: vmovaps (%rdi), %ymm0 -; AVX1-NEXT: vinsertf128 $1, %xmm0, %ymm0, %ymm0 -; AVX1-NEXT: retq -; -; AVX2-LABEL: shuffle_v8f32_01230123_mem: -; AVX2: ## BB#0: ## %entry -; AVX2-NEXT: vperm2f128 {{.*#+}} ymm0 = mem[0,1,0,1] -; AVX2-NEXT: retq +; ALL-LABEL: shuffle_v8f32_01230123_mem: +; ALL: ## BB#0: ## %entry +; ALL-NEXT: vperm2f128 {{.*#+}} ymm0 = mem[0,1,0,1] +; ALL-NEXT: retq entry: %a = load <8 x float>, <8 x float>* %pa %b = load <8 x float>, <8 x float>* %pb @@ -195,17 +189,15 @@ define <16 x i16> @shuffle_v16i16_4501_mem(<16 x i16>* %a, <16 x i16>* %b) nounw ; AVX1-LABEL: shuffle_v16i16_4501_mem: ; AVX1: ## BB#0: ## %entry ; AVX1-NEXT: vmovdqa (%rdi), %ymm0 -; AVX1-NEXT: vmovaps (%rsi), %ymm1 ; AVX1-NEXT: vpaddw {{.*}}(%rip), %xmm0, %xmm0 -; AVX1-NEXT: vinsertf128 $1, %xmm0, %ymm1, %ymm0 +; AVX1-NEXT: vperm2f128 {{.*#+}} ymm0 = mem[0,1],ymm0[0,1] ; AVX1-NEXT: retq ; ; AVX2-LABEL: shuffle_v16i16_4501_mem: ; AVX2: ## BB#0: ## %entry ; AVX2-NEXT: vmovdqa (%rdi), %ymm0 -; AVX2-NEXT: vmovdqa (%rsi), %ymm1 ; AVX2-NEXT: vpaddw {{.*}}(%rip), %ymm0, %ymm0 -; AVX2-NEXT: vinserti128 $1, %xmm0, %ymm1, %ymm0 +; AVX2-NEXT: vperm2i128 {{.*#+}} ymm0 = mem[0,1],ymm0[0,1] ; AVX2-NEXT: retq entry: %c = load <16 x i16>, <16 x i16>* %a diff --git a/test/CodeGen/X86/bt.ll b/test/CodeGen/X86/bt.ll index cebcba38bd4f..064058115684 100644 --- a/test/CodeGen/X86/bt.ll +++ b/test/CodeGen/X86/bt.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f | FileCheck %s ; PR3253 @@ -24,7 +24,12 @@ define void @test2(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB0_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB0_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = lshr i32 %x, %n %tmp3 = and i32 %tmp29, 1 @@ -44,7 +49,13 @@ define void @test2b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB1_1 -; +; CHECK-NEXT: # BB#2: # %UnifiedReturnBlock +; CHECK-NEXT: retq +; CHECK-NEXT: .LBB1_1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: retq entry: %tmp29 = lshr i32 %x, %n %tmp3 = and i32 1, %tmp29 @@ -64,7 +75,12 @@ define void @atest2(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB2_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB2_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = ashr i32 %x, %n %tmp3 = and i32 %tmp29, 1 @@ -84,7 +100,13 @@ define void @atest2b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB3_1 -; +; CHECK-NEXT: # BB#2: # %UnifiedReturnBlock +; CHECK-NEXT: retq +; CHECK-NEXT: .LBB3_1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: retq entry: %tmp29 = ashr i32 %x, %n %tmp3 = and i32 1, %tmp29 @@ -104,7 +126,13 @@ define void @test3(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB4_1 -; +; CHECK-NEXT: # BB#2: # %UnifiedReturnBlock +; CHECK-NEXT: retq +; CHECK-NEXT: .LBB4_1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %tmp29, %x @@ -124,7 +152,13 @@ define void @test3b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB5_1 -; +; CHECK-NEXT: # BB#2: # %UnifiedReturnBlock +; CHECK-NEXT: retq +; CHECK-NEXT: .LBB5_1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %x, %tmp29 @@ -144,7 +178,12 @@ define void @testne2(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB6_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB6_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = lshr i32 %x, %n %tmp3 = and i32 %tmp29, 1 @@ -164,7 +203,12 @@ define void @testne2b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB7_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB7_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = lshr i32 %x, %n %tmp3 = and i32 1, %tmp29 @@ -184,7 +228,12 @@ define void @atestne2(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB8_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB8_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = ashr i32 %x, %n %tmp3 = and i32 %tmp29, 1 @@ -204,7 +253,12 @@ define void @atestne2b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB9_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB9_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = ashr i32 %x, %n %tmp3 = and i32 1, %tmp29 @@ -224,7 +278,12 @@ define void @testne3(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB10_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB10_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %tmp29, %x @@ -244,7 +303,12 @@ define void @testne3b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB11_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB11_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %x, %tmp29 @@ -264,7 +328,12 @@ define void @query2(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB12_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB12_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = lshr i32 %x, %n %tmp3 = and i32 %tmp29, 1 @@ -284,7 +353,12 @@ define void @query2b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB13_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB13_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = lshr i32 %x, %n %tmp3 = and i32 1, %tmp29 @@ -304,7 +378,12 @@ define void @aquery2(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB14_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB14_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = ashr i32 %x, %n %tmp3 = and i32 %tmp29, 1 @@ -324,7 +403,12 @@ define void @aquery2b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB15_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB15_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = ashr i32 %x, %n %tmp3 = and i32 1, %tmp29 @@ -344,7 +428,12 @@ define void @query3(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB16_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB16_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %tmp29, %x @@ -364,7 +453,12 @@ define void @query3b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB17_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB17_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %x, %tmp29 @@ -384,7 +478,12 @@ define void @query3x(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB18_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB18_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %tmp29, %x @@ -404,7 +503,12 @@ define void @query3bx(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jae .LBB19_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB19_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %x, %tmp29 @@ -424,7 +528,12 @@ define void @queryne2(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB20_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB20_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = lshr i32 %x, %n %tmp3 = and i32 %tmp29, 1 @@ -444,7 +553,12 @@ define void @queryne2b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB21_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB21_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = lshr i32 %x, %n %tmp3 = and i32 1, %tmp29 @@ -464,7 +578,12 @@ define void @aqueryne2(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB22_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB22_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = ashr i32 %x, %n %tmp3 = and i32 %tmp29, 1 @@ -484,7 +603,12 @@ define void @aqueryne2b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB23_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB23_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = ashr i32 %x, %n %tmp3 = and i32 1, %tmp29 @@ -504,7 +628,12 @@ define void @queryne3(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB24_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB24_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %tmp29, %x @@ -524,7 +653,12 @@ define void @queryne3b(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB25_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB25_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %x, %tmp29 @@ -544,7 +678,12 @@ define void @queryne3x(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB26_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB26_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %tmp29, %x @@ -564,7 +703,12 @@ define void @queryne3bx(i32 %x, i32 %n) nounwind { ; CHECK: # BB#0: # %entry ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: jb .LBB27_2 -; +; CHECK-NEXT: # BB#1: # %bb +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq foo +; CHECK-NEXT: popq %rax +; CHECK-NEXT: .LBB27_2: # %UnifiedReturnBlock +; CHECK-NEXT: retq entry: %tmp29 = shl i32 1, %n %tmp3 = and i32 %x, %tmp29 @@ -588,7 +732,6 @@ define zeroext i1 @invert(i32 %flags, i32 %flag) nounwind { ; CHECK-NEXT: btl %esi, %edi ; CHECK-NEXT: setb %al ; CHECK-NEXT: retq -; %neg = xor i32 %flags, -1 %shl = shl i32 1, %flag %and = and i32 %shl, %neg @@ -598,8 +741,10 @@ define zeroext i1 @invert(i32 %flags, i32 %flag) nounwind { define zeroext i1 @extend(i32 %bit, i64 %bits) { ; CHECK-LABEL: extend: -; CHECK: # BB#0: -; CHECK-NEXT: btl %edi, %esi +; CHECK: # BB#0: # %entry +; CHECK-NEXT: btl %edi, %esi +; CHECK-NEXT: setb %al +; CHECK-NEXT: retq entry: %and = and i32 %bit, 31 %sh_prom = zext i32 %and to i64 diff --git a/test/CodeGen/X86/cmov-into-branch.ll b/test/CodeGen/X86/cmov-into-branch.ll index 6e4762b2e793..e38039501646 100644 --- a/test/CodeGen/X86/cmov-into-branch.ll +++ b/test/CodeGen/X86/cmov-into-branch.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s ; cmp with single-use load, should not form branch. @@ -9,7 +9,6 @@ define i32 @test1(double %a, double* nocapture %b, i32 %x, i32 %y) { ; CHECK-NEXT: cmovbel %edx, %esi ; CHECK-NEXT: movl %esi, %eax ; CHECK-NEXT: retq -; %load = load double, double* %b, align 8 %cmp = fcmp olt double %load, %a %cond = select i1 %cmp, i32 %x, i32 %y @@ -24,7 +23,6 @@ define i32 @test2(double %a, double %b, i32 %x, i32 %y) { ; CHECK-NEXT: cmovbel %esi, %edi ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: retq -; %cmp = fcmp ogt double %a, %b %cond = select i1 %cmp, i32 %x, i32 %y ret i32 %cond @@ -39,7 +37,6 @@ define i32 @test4(i32 %a, i32* nocapture %b, i32 %x, i32 %y) { ; CHECK-NEXT: cmovael %ecx, %edx ; CHECK-NEXT: addl %edx, %eax ; CHECK-NEXT: retq -; %load = load i32, i32* %b, align 4 %cmp = icmp ult i32 %load, %a %cond = select i1 %cmp, i32 %x, i32 %y @@ -56,7 +53,6 @@ define i32 @test5(i32 %a, i32* nocapture %b, i32 %x, i32 %y) { ; CHECK-NEXT: cmovael %edx, %ecx ; CHECK-NEXT: movl %ecx, %eax ; CHECK-NEXT: retq -; %load = load i32, i32* %b, align 4 %cmp = icmp ult i32 %load, %a %cmp1 = icmp ugt i32 %load, %a @@ -73,7 +69,6 @@ define i32 @weighted_select1(i32 %a, i32 %b) { ; CHECK-NEXT: cmovnel %edi, %esi ; CHECK-NEXT: movl %esi, %eax ; CHECK-NEXT: retq -; %cmp = icmp ne i32 %a, 0 %sel = select i1 %cmp, i32 %a, i32 %b, !prof !0 ret i32 %sel @@ -84,12 +79,12 @@ define i32 @weighted_select2(i32 %a, i32 %b) { ; CHECK-LABEL: weighted_select2: ; CHECK: # BB#0: ; CHECK-NEXT: testl %edi, %edi -; CHECK-NEXT: jne [[LABEL_BB5:.*]] -; CHECK: movl %esi, %edi -; CHECK-NEXT: [[LABEL_BB5]] +; CHECK-NEXT: jne .LBB5_2 +; CHECK-NEXT: # BB#1: # %select.false +; CHECK-NEXT: movl %esi, %edi +; CHECK-NEXT: .LBB5_2: # %select.end ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: retq -; %cmp = icmp ne i32 %a, 0 %sel = select i1 %cmp, i32 %a, i32 %b, !prof !1 ret i32 %sel @@ -103,14 +98,14 @@ define i32 @weighted_select3(i32 %a, i32 %b) { ; CHECK-LABEL: weighted_select3: ; CHECK: # BB#0: ; CHECK-NEXT: testl %edi, %edi -; CHECK-NEXT: je [[LABEL_BB6:.*]] -; CHECK: movl %edi, %eax +; CHECK-NEXT: je .LBB6_1 +; CHECK-NEXT: # BB#2: # %select.end +; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: retq -; CHECK: [[LABEL_BB6]] +; CHECK-NEXT: .LBB6_1: # %select.false ; CHECK-NEXT: movl %esi, %edi ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: retq -; %cmp = icmp ne i32 %a, 0 %sel = select i1 %cmp, i32 %a, i32 %b, !prof !2 ret i32 %sel @@ -124,7 +119,6 @@ define i32 @unweighted_select(i32 %a, i32 %b) { ; CHECK-NEXT: cmovnel %edi, %esi ; CHECK-NEXT: movl %esi, %eax ; CHECK-NEXT: retq -; %cmp = icmp ne i32 %a, 0 %sel = select i1 %cmp, i32 %a, i32 %b, !prof !3 ret i32 %sel diff --git a/test/CodeGen/X86/combine-64bit-vec-binop.ll b/test/CodeGen/X86/combine-64bit-vec-binop.ll index 2842cb1d9b6e..2935a2095bbf 100644 --- a/test/CodeGen/X86/combine-64bit-vec-binop.ll +++ b/test/CodeGen/X86/combine-64bit-vec-binop.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=sse4.1 | FileCheck %s --check-prefix=SSE41 define double @test1_add(double %A, double %B) { @@ -6,7 +6,6 @@ define double @test1_add(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: paddd %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x i32> %2 = bitcast double %B to <2 x i32> %add = add <2 x i32> %1, %2 @@ -19,7 +18,6 @@ define double @test2_add(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: paddw %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <4 x i16> %2 = bitcast double %B to <4 x i16> %add = add <4 x i16> %1, %2 @@ -32,7 +30,6 @@ define double @test3_add(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: paddb %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <8 x i8> %2 = bitcast double %B to <8 x i8> %add = add <8 x i8> %1, %2 @@ -45,7 +42,6 @@ define double @test1_sub(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: psubd %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x i32> %2 = bitcast double %B to <2 x i32> %sub = sub <2 x i32> %1, %2 @@ -58,7 +54,6 @@ define double @test2_sub(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: psubw %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <4 x i16> %2 = bitcast double %B to <4 x i16> %sub = sub <4 x i16> %1, %2 @@ -71,7 +66,6 @@ define double @test3_sub(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: psubb %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <8 x i8> %2 = bitcast double %B to <8 x i8> %sub = sub <8 x i8> %1, %2 @@ -84,7 +78,6 @@ define double @test1_mul(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: pmulld %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x i32> %2 = bitcast double %B to <2 x i32> %mul = mul <2 x i32> %1, %2 @@ -97,7 +90,6 @@ define double @test2_mul(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: pmullw %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <4 x i16> %2 = bitcast double %B to <4 x i16> %mul = mul <4 x i16> %1, %2 @@ -114,7 +106,6 @@ define double @test3_mul(double %A, double %B) { ; SSE41-NEXT: pmullw %xmm2, %xmm0 ; SSE41-NEXT: pshufb {{.*#+}} xmm0 = xmm0[0,2,4,6,8,10,12,14,u,u,u,u,u,u,u,u] ; SSE41-NEXT: retq -; %1 = bitcast double %A to <8 x i8> %2 = bitcast double %B to <8 x i8> %mul = mul <8 x i8> %1, %2 @@ -127,7 +118,6 @@ define double @test1_and(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: andps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x i32> %2 = bitcast double %B to <2 x i32> %and = and <2 x i32> %1, %2 @@ -140,7 +130,6 @@ define double @test2_and(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: andps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <4 x i16> %2 = bitcast double %B to <4 x i16> %and = and <4 x i16> %1, %2 @@ -153,7 +142,6 @@ define double @test3_and(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: andps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <8 x i8> %2 = bitcast double %B to <8 x i8> %and = and <8 x i8> %1, %2 @@ -166,7 +154,6 @@ define double @test1_or(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: orps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x i32> %2 = bitcast double %B to <2 x i32> %or = or <2 x i32> %1, %2 @@ -179,7 +166,6 @@ define double @test2_or(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: orps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <4 x i16> %2 = bitcast double %B to <4 x i16> %or = or <4 x i16> %1, %2 @@ -192,7 +178,6 @@ define double @test3_or(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: orps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <8 x i8> %2 = bitcast double %B to <8 x i8> %or = or <8 x i8> %1, %2 @@ -205,7 +190,6 @@ define double @test1_xor(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: xorps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x i32> %2 = bitcast double %B to <2 x i32> %xor = xor <2 x i32> %1, %2 @@ -218,7 +202,6 @@ define double @test2_xor(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: xorps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <4 x i16> %2 = bitcast double %B to <4 x i16> %xor = xor <4 x i16> %1, %2 @@ -231,7 +214,6 @@ define double @test3_xor(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: xorps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <8 x i8> %2 = bitcast double %B to <8 x i8> %xor = xor <8 x i8> %1, %2 @@ -244,7 +226,6 @@ define double @test_fadd(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: addps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x float> %2 = bitcast double %B to <2 x float> %add = fadd <2 x float> %1, %2 @@ -257,7 +238,6 @@ define double @test_fsub(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: subps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x float> %2 = bitcast double %B to <2 x float> %sub = fsub <2 x float> %1, %2 @@ -270,7 +250,6 @@ define double @test_fmul(double %A, double %B) { ; SSE41: # BB#0: ; SSE41-NEXT: mulps %xmm1, %xmm0 ; SSE41-NEXT: retq -; %1 = bitcast double %A to <2 x float> %2 = bitcast double %B to <2 x float> %mul = fmul <2 x float> %1, %2 diff --git a/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll b/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll index 4dc5b1ba0339..9dd184c8ab31 100644 --- a/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll +++ b/test/CodeGen/X86/element-wise-atomic-memory-intrinsics.ll @@ -2,47 +2,47 @@ define i8* @test_memcpy1(i8* %P, i8* %Q) { ; CHECK: test_memcpy - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 4 %P, i8* align 4 %Q, i64 1, i32 1) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 1, i32 1) ret i8* %P + ; 3rd arg (%edx) -- length ; CHECK-DAG: movl $1, %edx - ; CHECK-DAG: movl $1, %ecx - ; CHECK: __llvm_memcpy_element_atomic_1 + ; CHECK: __llvm_memcpy_element_unordered_atomic_1 } define i8* @test_memcpy2(i8* %P, i8* %Q) { ; CHECK: test_memcpy2 - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 4 %P, i8* align 4 %Q, i64 2, i32 2) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 2, i32 2) ret i8* %P + ; 3rd arg (%edx) -- length ; CHECK-DAG: movl $2, %edx - ; CHECK-DAG: movl $2, %ecx - ; CHECK: __llvm_memcpy_element_atomic_2 + ; CHECK: __llvm_memcpy_element_unordered_atomic_2 } define i8* @test_memcpy4(i8* %P, i8* %Q) { ; CHECK: test_memcpy4 - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 4 %P, i8* align 4 %Q, i64 4, i32 4) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %P, i8* align 4 %Q, i32 4, i32 4) ret i8* %P + ; 3rd arg (%edx) -- length ; CHECK-DAG: movl $4, %edx - ; CHECK-DAG: movl $4, %ecx - ; CHECK: __llvm_memcpy_element_atomic_4 + ; CHECK: __llvm_memcpy_element_unordered_atomic_4 } define i8* @test_memcpy8(i8* %P, i8* %Q) { ; CHECK: test_memcpy8 - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 8 %P, i8* align 8 %Q, i64 8, i32 8) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %P, i8* align 8 %Q, i32 8, i32 8) ret i8* %P + ; 3rd arg (%edx) -- length ; CHECK-DAG: movl $8, %edx - ; CHECK-DAG: movl $8, %ecx - ; CHECK: __llvm_memcpy_element_atomic_8 + ; CHECK: __llvm_memcpy_element_unordered_atomic_8 } define i8* @test_memcpy16(i8* %P, i8* %Q) { ; CHECK: test_memcpy16 - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 16 %P, i8* align 16 %Q, i64 16, i32 16) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %P, i8* align 16 %Q, i32 16, i32 16) ret i8* %P + ; 3rd arg (%edx) -- length ; CHECK-DAG: movl $16, %edx - ; CHECK-DAG: movl $16, %ecx - ; CHECK: __llvm_memcpy_element_atomic_16 + ; CHECK: __llvm_memcpy_element_unordered_atomic_16 } define void @test_memcpy_args(i8** %Storage) { @@ -51,18 +51,15 @@ define void @test_memcpy_args(i8** %Storage) { %Src.addr = getelementptr i8*, i8** %Storage, i64 1 %Src = load i8*, i8** %Src.addr - ; First argument + ; 1st arg (%rdi) ; CHECK-DAG: movq (%rdi), [[REG1:%r.+]] ; CHECK-DAG: movq [[REG1]], %rdi - ; Second argument + ; 2nd arg (%rsi) ; CHECK-DAG: movq 8(%rdi), %rsi - ; Third argument + ; 3rd arg (%edx) -- length ; CHECK-DAG: movl $4, %edx - ; Fourth argument - ; CHECK-DAG: movl $4, %ecx - ; CHECK: __llvm_memcpy_element_atomic_4 - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 4 %Dst, i8* align 4 %Src, i64 4, i32 4) - ret void + ; CHECK: __llvm_memcpy_element_unordered_atomic_4 + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 4 %Dst, i8* align 4 %Src, i32 4, i32 4) ret void } -declare void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* nocapture, i8* nocapture, i64, i32) nounwind +declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind diff --git a/test/CodeGen/X86/fast-isel-select-sse.ll b/test/CodeGen/X86/fast-isel-select-sse.ll index 499fe5ba54a2..1b6bb36b77c8 100644 --- a/test/CodeGen/X86/fast-isel-select-sse.ll +++ b/test/CodeGen/X86/fast-isel-select-sse.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -verify-machineinstrs | FileCheck %s --check-prefix=SSE ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -verify-machineinstrs -fast-isel -fast-isel-abort=1 | FileCheck %s --check-prefix=SSE ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -verify-machineinstrs -mattr=avx | FileCheck %s --check-prefix=AVX @@ -29,7 +29,6 @@ define float @select_fcmp_oeq_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp oeq float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -56,7 +55,6 @@ define double @select_fcmp_oeq_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp oeq double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -84,7 +82,6 @@ define float @select_fcmp_ogt_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ogt float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -112,7 +109,6 @@ define double @select_fcmp_ogt_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ogt double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -140,7 +136,6 @@ define float @select_fcmp_oge_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp oge float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -168,7 +163,6 @@ define double @select_fcmp_oge_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp oge double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -195,7 +189,6 @@ define float @select_fcmp_olt_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp olt float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -222,7 +215,6 @@ define double @select_fcmp_olt_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp olt double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -249,7 +241,6 @@ define float @select_fcmp_ole_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ole float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -276,7 +267,6 @@ define double @select_fcmp_ole_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ole double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -303,7 +293,6 @@ define float @select_fcmp_ord_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ord float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -330,7 +319,6 @@ define double @select_fcmp_ord_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ord double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -357,7 +345,6 @@ define float @select_fcmp_uno_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp uno float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -384,7 +371,6 @@ define double @select_fcmp_uno_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp uno double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -411,7 +397,6 @@ define float @select_fcmp_ugt_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ugt float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -438,7 +423,6 @@ define double @select_fcmp_ugt_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ugt double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -465,7 +449,6 @@ define float @select_fcmp_uge_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp uge float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -492,7 +475,6 @@ define double @select_fcmp_uge_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp uge double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -520,7 +502,6 @@ define float @select_fcmp_ult_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ult float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -548,7 +529,6 @@ define double @select_fcmp_ult_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ult double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -576,7 +556,6 @@ define float @select_fcmp_ule_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ule float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -604,7 +583,6 @@ define double @select_fcmp_ule_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp ule double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 @@ -631,7 +609,6 @@ define float @select_fcmp_une_f32(float %a, float %b, float %c, float %d) { ; AVX512-NEXT: vmovss %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovaps %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp une float %a, %b %2 = select i1 %1, float %c, float %d ret float %2 @@ -658,7 +635,6 @@ define double @select_fcmp_une_f64(double %a, double %b, double %c, double %d) { ; AVX512-NEXT: vmovsd %xmm2, %xmm0, %xmm3 {%k1} ; AVX512-NEXT: vmovapd %xmm3, %xmm0 ; AVX512-NEXT: retq -; %1 = fcmp une double %a, %b %2 = select i1 %1, double %c, double %d ret double %2 diff --git a/test/CodeGen/X86/fp-logic-replace.ll b/test/CodeGen/X86/fp-logic-replace.ll index 308b42e10caa..e62b2f3db237 100644 --- a/test/CodeGen/X86/fp-logic-replace.ll +++ b/test/CodeGen/X86/fp-logic-replace.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -show-mc-encoding -mattr=+sse2 | FileCheck %s --check-prefix=SSE ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -show-mc-encoding -mattr=+avx | FileCheck %s --check-prefix=AVX ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -show-mc-encoding -mattr=+avx512dq,+avx512vl | FileCheck %s --check-prefix=AVX512DQ diff --git a/test/CodeGen/X86/fp-logic.ll b/test/CodeGen/X86/fp-logic.ll index 973e0644b4e9..976470a83030 100644 --- a/test/CodeGen/X86/fp-logic.ll +++ b/test/CodeGen/X86/fp-logic.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=sse2 < %s | FileCheck %s ; PR22428: https://llvm.org/bugs/show_bug.cgi?id=22428 @@ -22,7 +22,6 @@ define i32 @f1(float %x, i32 %y) { ; CHECK-NEXT: movd %xmm0, %eax ; CHECK-NEXT: andl %edi, %eax ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 %bc1, %y ret i32 %and @@ -36,7 +35,6 @@ define i32 @f2(float %x, i32 %y) { ; CHECK-NEXT: movd %xmm0, %eax ; CHECK-NEXT: andl %edi, %eax ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 %y, %bc1 ret i32 %and @@ -50,7 +48,6 @@ define i32 @f3(float %x) { ; CHECK-NEXT: movd %xmm0, %eax ; CHECK-NEXT: andl $1, %eax ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 %bc1, 1 ret i32 %and @@ -64,7 +61,6 @@ define i32 @f4(float %x) { ; CHECK-NEXT: movd %xmm0, %eax ; CHECK-NEXT: andl $2, %eax ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 2, %bc1 ret i32 %and @@ -78,7 +74,6 @@ define float @f5(float %x, i32 %y) { ; CHECK-NEXT: movd %edi, %xmm1 ; CHECK-NEXT: pand %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 %bc1, %y %bc2 = bitcast i32 %and to float @@ -93,7 +88,6 @@ define float @f6(float %x, i32 %y) { ; CHECK-NEXT: movd %edi, %xmm1 ; CHECK-NEXT: pand %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 %y, %bc1 %bc2 = bitcast i32 %and to float @@ -108,7 +102,6 @@ define float @f7(float %x) { ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero ; CHECK-NEXT: andps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 %bc1, 3 %bc2 = bitcast i32 %and to float @@ -123,7 +116,6 @@ define float @f8(float %x) { ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero ; CHECK-NEXT: andps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 4, %bc1 %bc2 = bitcast i32 %and to float @@ -138,7 +130,6 @@ define i32 @f9(float %x, float %y) { ; CHECK-NEXT: pand %xmm1, %xmm0 ; CHECK-NEXT: movd %xmm0, %eax ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %bc2 = bitcast float %y to i32 %and = and i32 %bc1, %bc2 @@ -152,7 +143,6 @@ define float @f10(float %x, float %y) { ; CHECK: # BB#0: ; CHECK-NEXT: andps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %bc2 = bitcast float %y to i32 %and = and i32 %bc1, %bc2 @@ -165,7 +155,6 @@ define float @or(float %x, float %y) { ; CHECK: # BB#0: ; CHECK-NEXT: orps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %bc2 = bitcast float %y to i32 %and = or i32 %bc1, %bc2 @@ -178,7 +167,6 @@ define float @xor(float %x, float %y) { ; CHECK: # BB#0: ; CHECK-NEXT: xorps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %bc2 = bitcast float %y to i32 %and = xor i32 %bc1, %bc2 @@ -192,7 +180,6 @@ define float @f7_or(float %x) { ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero ; CHECK-NEXT: orps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = or i32 %bc1, 3 %bc2 = bitcast i32 %and to float @@ -205,7 +192,6 @@ define float @f7_xor(float %x) { ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero ; CHECK-NEXT: xorps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = xor i32 %bc1, 3 %bc2 = bitcast i32 %and to float @@ -219,7 +205,6 @@ define double @doubles(double %x, double %y) { ; CHECK: # BB#0: ; CHECK-NEXT: andps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast double %x to i64 %bc2 = bitcast double %y to i64 %and = and i64 %bc1, %bc2 @@ -233,7 +218,6 @@ define double @f7_double(double %x) { ; CHECK-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero ; CHECK-NEXT: andps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast double %x to i64 %and = and i64 %bc1, 3 %bc2 = bitcast i64 %and to double @@ -250,7 +234,6 @@ define float @movmsk(float %x) { ; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero ; CHECK-NEXT: andps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %and = and i32 %bc1, 2147483648 %bc2 = bitcast i32 %and to float @@ -262,7 +245,6 @@ define double @bitcast_fabs(double %x) { ; CHECK: # BB#0: ; CHECK-NEXT: andps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast double %x to i64 %and = and i64 %bc1, 9223372036854775807 %bc2 = bitcast i64 %and to double @@ -274,7 +256,6 @@ define float @bitcast_fneg(float %x) { ; CHECK: # BB#0: ; CHECK-NEXT: xorps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast float %x to i32 %xor = xor i32 %bc1, 2147483648 %bc2 = bitcast i32 %xor to float @@ -286,7 +267,6 @@ define <2 x double> @bitcast_fabs_vec(<2 x double> %x) { ; CHECK: # BB#0: ; CHECK-NEXT: andps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast <2 x double> %x to <2 x i64> %and = and <2 x i64> %bc1, %bc2 = bitcast <2 x i64> %and to <2 x double> @@ -298,7 +278,6 @@ define <4 x float> @bitcast_fneg_vec(<4 x float> %x) { ; CHECK: # BB#0: ; CHECK-NEXT: xorps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %bc1 = bitcast <4 x float> %x to <4 x i32> %xor = xor <4 x i32> %bc1, %bc2 = bitcast <4 x i32> %xor to <4 x float> diff --git a/test/CodeGen/X86/fp-select-cmp-and.ll b/test/CodeGen/X86/fp-select-cmp-and.ll index e012809cf480..651d7a3351c6 100644 --- a/test/CodeGen/X86/fp-select-cmp-and.ll +++ b/test/CodeGen/X86/fp-select-cmp-and.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=sse4.2 | FileCheck %s define double @test1(double %a, double %b, double %eps) { @@ -7,7 +7,6 @@ define double @test1(double %a, double %b, double %eps) { ; CHECK-NEXT: cmpltsd %xmm2, %xmm0 ; CHECK-NEXT: andpd %xmm1, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp olt double %a, %eps %cond = select i1 %cmp, double %b, double 0.000000e+00 ret double %cond @@ -19,7 +18,6 @@ define double @test2(double %a, double %b, double %eps) { ; CHECK-NEXT: cmplesd %xmm2, %xmm0 ; CHECK-NEXT: andpd %xmm1, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp ole double %a, %eps %cond = select i1 %cmp, double %b, double 0.000000e+00 ret double %cond @@ -32,7 +30,6 @@ define double @test3(double %a, double %b, double %eps) { ; CHECK-NEXT: andpd %xmm1, %xmm2 ; CHECK-NEXT: movapd %xmm2, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp ogt double %a, %eps %cond = select i1 %cmp, double %b, double 0.000000e+00 ret double %cond @@ -45,7 +42,6 @@ define double @test4(double %a, double %b, double %eps) { ; CHECK-NEXT: andpd %xmm1, %xmm2 ; CHECK-NEXT: movapd %xmm2, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp oge double %a, %eps %cond = select i1 %cmp, double %b, double 0.000000e+00 ret double %cond @@ -57,7 +53,6 @@ define double @test5(double %a, double %b, double %eps) { ; CHECK-NEXT: cmpltsd %xmm2, %xmm0 ; CHECK-NEXT: andnpd %xmm1, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp olt double %a, %eps %cond = select i1 %cmp, double 0.000000e+00, double %b ret double %cond @@ -69,7 +64,6 @@ define double @test6(double %a, double %b, double %eps) { ; CHECK-NEXT: cmplesd %xmm2, %xmm0 ; CHECK-NEXT: andnpd %xmm1, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp ole double %a, %eps %cond = select i1 %cmp, double 0.000000e+00, double %b ret double %cond @@ -82,7 +76,6 @@ define double @test7(double %a, double %b, double %eps) { ; CHECK-NEXT: andnpd %xmm1, %xmm2 ; CHECK-NEXT: movapd %xmm2, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp ogt double %a, %eps %cond = select i1 %cmp, double 0.000000e+00, double %b ret double %cond @@ -95,7 +88,6 @@ define double @test8(double %a, double %b, double %eps) { ; CHECK-NEXT: andnpd %xmm1, %xmm2 ; CHECK-NEXT: movapd %xmm2, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp oge double %a, %eps %cond = select i1 %cmp, double 0.000000e+00, double %b ret double %cond @@ -107,7 +99,6 @@ define float @test9(float %a, float %b, float %eps) { ; CHECK-NEXT: cmpltss %xmm2, %xmm0 ; CHECK-NEXT: andps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp olt float %a, %eps %cond = select i1 %cmp, float %b, float 0.000000e+00 ret float %cond @@ -119,7 +110,6 @@ define float @test10(float %a, float %b, float %eps) { ; CHECK-NEXT: cmpless %xmm2, %xmm0 ; CHECK-NEXT: andps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp ole float %a, %eps %cond = select i1 %cmp, float %b, float 0.000000e+00 ret float %cond @@ -132,7 +122,6 @@ define float @test11(float %a, float %b, float %eps) { ; CHECK-NEXT: andps %xmm1, %xmm2 ; CHECK-NEXT: movaps %xmm2, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp ogt float %a, %eps %cond = select i1 %cmp, float %b, float 0.000000e+00 ret float %cond @@ -145,7 +134,6 @@ define float @test12(float %a, float %b, float %eps) { ; CHECK-NEXT: andps %xmm1, %xmm2 ; CHECK-NEXT: movaps %xmm2, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp oge float %a, %eps %cond = select i1 %cmp, float %b, float 0.000000e+00 ret float %cond @@ -157,7 +145,6 @@ define float @test13(float %a, float %b, float %eps) { ; CHECK-NEXT: cmpltss %xmm2, %xmm0 ; CHECK-NEXT: andnps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp olt float %a, %eps %cond = select i1 %cmp, float 0.000000e+00, float %b ret float %cond @@ -169,7 +156,6 @@ define float @test14(float %a, float %b, float %eps) { ; CHECK-NEXT: cmpless %xmm2, %xmm0 ; CHECK-NEXT: andnps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp ole float %a, %eps %cond = select i1 %cmp, float 0.000000e+00, float %b ret float %cond @@ -182,7 +168,6 @@ define float @test15(float %a, float %b, float %eps) { ; CHECK-NEXT: andnps %xmm1, %xmm2 ; CHECK-NEXT: movaps %xmm2, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp ogt float %a, %eps %cond = select i1 %cmp, float 0.000000e+00, float %b ret float %cond @@ -195,7 +180,6 @@ define float @test16(float %a, float %b, float %eps) { ; CHECK-NEXT: andnps %xmm1, %xmm2 ; CHECK-NEXT: movaps %xmm2, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp oge float %a, %eps %cond = select i1 %cmp, float 0.000000e+00, float %b ret float %cond @@ -210,7 +194,6 @@ define float @test17(float %a, float %b, float %c, float %eps) { ; CHECK-NEXT: orps %xmm2, %xmm3 ; CHECK-NEXT: movaps %xmm3, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp oge float %a, %eps %cond = select i1 %cmp, float %c, float %b ret float %cond @@ -225,7 +208,6 @@ define double @test18(double %a, double %b, double %c, double %eps) { ; CHECK-NEXT: orpd %xmm2, %xmm3 ; CHECK-NEXT: movapd %xmm3, %xmm0 ; CHECK-NEXT: retq -; %cmp = fcmp oge double %a, %eps %cond = select i1 %cmp, double %c, double %b ret double %cond diff --git a/test/CodeGen/X86/immediate_merging64.ll b/test/CodeGen/X86/immediate_merging64.ll index ea8ace12a868..4bc9d4af6440 100644 --- a/test/CodeGen/X86/immediate_merging64.ll +++ b/test/CodeGen/X86/immediate_merging64.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s ; Check that multiple instances of 64-bit constants encodable as @@ -14,7 +14,6 @@ define i1 @imm_multiple_users(i64 %a, i64* %b) optsize { ; CHECK-NEXT: cmpq %rax, %rdi ; CHECK-NEXT: sete %al ; CHECK-NEXT: retq -; store i64 -1, i64* %b, align 8 %cmp = icmp eq i64 %a, -1 ret i1 %cmp @@ -32,7 +31,6 @@ define void @memset_zero(i8* noalias nocapture %D) optsize { ; CHECK-NEXT: movq %rax, 7(%rdi) ; CHECK-NEXT: movq %rax, (%rdi) ; CHECK-NEXT: retq -; tail call void @llvm.memset.p0i8.i64(i8* %D, i8 0, i64 15, i32 1, i1 false) ret void } diff --git a/test/CodeGen/X86/lea-opt-with-debug.mir b/test/CodeGen/X86/lea-opt-with-debug.mir index 0a477706df15..03a745888b5a 100644 --- a/test/CodeGen/X86/lea-opt-with-debug.mir +++ b/test/CodeGen/X86/lea-opt-with-debug.mir @@ -49,7 +49,7 @@ !5 = !{i32 2, !"Dwarf Version", i32 4} !6 = !{i32 2, !"Debug Info Version", i32 3} !7 = !{i32 1, !"PIC Level", i32 2} - !8 = !DIExpression(DW_OP_plus, 8, DW_OP_stack_value) + !8 = !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) !9 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 7, type: !10, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !0, variables: !11) !10 = !DISubroutineType(types: !3) !11 = !{!12} diff --git a/test/CodeGen/X86/loop-search.ll b/test/CodeGen/X86/loop-search.ll index 6b29a726fc1f..fda4ecec0e6a 100644 --- a/test/CodeGen/X86/loop-search.ll +++ b/test/CodeGen/X86/loop-search.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s ; This test comes from PR27136 @@ -35,7 +35,6 @@ define zeroext i1 @search(i32 %needle, i32* nocapture readonly %haystack, i32 %c ; CHECK-NEXT: movb $1, %al ; CHECK-NEXT: ## kill: %AL %AL %EAX ; CHECK-NEXT: retq -; entry: %cmp5 = icmp sgt i32 %count, 0 br i1 %cmp5, label %for.body.preheader, label %cleanup diff --git a/test/CodeGen/X86/mask-negated-bool.ll b/test/CodeGen/X86/mask-negated-bool.ll index c5c121c52966..779641cee7d2 100644 --- a/test/CodeGen/X86/mask-negated-bool.ll +++ b/test/CodeGen/X86/mask-negated-bool.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s define i32 @mask_negated_zext_bool1(i1 %x) { @@ -7,7 +7,6 @@ define i32 @mask_negated_zext_bool1(i1 %x) { ; CHECK-NEXT: andl $1, %edi ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: retq -; %ext = zext i1 %x to i32 %neg = sub i32 0, %ext %and = and i32 %neg, 1 @@ -19,7 +18,6 @@ define i32 @mask_negated_zext_bool2(i1 zeroext %x) { ; CHECK: # BB#0: ; CHECK-NEXT: movzbl %dil, %eax ; CHECK-NEXT: retq -; %ext = zext i1 %x to i32 %neg = sub i32 0, %ext %and = and i32 %neg, 1 @@ -31,7 +29,6 @@ define <4 x i32> @mask_negated_zext_bool_vec(<4 x i1> %x) { ; CHECK: # BB#0: ; CHECK-NEXT: andps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %ext = zext <4 x i1> %x to <4 x i32> %neg = sub <4 x i32> zeroinitializer, %ext %and = and <4 x i32> %neg, @@ -44,7 +41,6 @@ define i32 @mask_negated_sext_bool1(i1 %x) { ; CHECK-NEXT: andl $1, %edi ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: retq -; %ext = sext i1 %x to i32 %neg = sub i32 0, %ext %and = and i32 %neg, 1 @@ -56,7 +52,6 @@ define i32 @mask_negated_sext_bool2(i1 zeroext %x) { ; CHECK: # BB#0: ; CHECK-NEXT: movzbl %dil, %eax ; CHECK-NEXT: retq -; %ext = sext i1 %x to i32 %neg = sub i32 0, %ext %and = and i32 %neg, 1 @@ -68,7 +63,6 @@ define <4 x i32> @mask_negated_sext_bool_vec(<4 x i1> %x) { ; CHECK: # BB#0: ; CHECK-NEXT: andps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %ext = sext <4 x i1> %x to <4 x i32> %neg = sub <4 x i32> zeroinitializer, %ext %and = and <4 x i32> %neg, diff --git a/test/CodeGen/X86/memset-2.ll b/test/CodeGen/X86/memset-2.ll index a02ef29ca6b3..1ac972048f12 100644 --- a/test/CodeGen/X86/memset-2.ll +++ b/test/CodeGen/X86/memset-2.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=i386-apple-darwin9 -mcpu=yonah < %s | FileCheck %s define fastcc void @t1() nounwind { @@ -10,7 +10,6 @@ define fastcc void @t1() nounwind { ; CHECK-NEXT: pushl $0 ; CHECK-NEXT: calll _memset ; CHECK-NEXT: addl $16, %esp -; entry: call void @llvm.memset.p0i8.i32(i8* null, i8 0, i32 188, i32 1, i1 false) unreachable @@ -23,7 +22,6 @@ define fastcc void @t2(i8 signext %c) nounwind { ; CHECK-NEXT: movl %ecx, {{[0-9]+}}(%esp) ; CHECK-NEXT: movl $76, {{[0-9]+}}(%esp) ; CHECK-NEXT: calll _memset -; entry: call void @llvm.memset.p0i8.i32(i8* undef, i8 %c, i32 76, i32 1, i1 false) unreachable @@ -40,7 +38,6 @@ define void @t3(i8* nocapture %s, i8 %a) nounwind { ; CHECK-NEXT: movl %ecx, 4(%eax) ; CHECK-NEXT: movl %ecx, (%eax) ; CHECK-NEXT: retl -; entry: tail call void @llvm.memset.p0i8.i32(i8* %s, i8 %a, i32 8, i32 1, i1 false) ret void @@ -58,7 +55,6 @@ define void @t4(i8* nocapture %s, i8 %a) nounwind { ; CHECK-NEXT: movw %cx, 12(%eax) ; CHECK-NEXT: movb %cl, 14(%eax) ; CHECK-NEXT: retl -; entry: tail call void @llvm.memset.p0i8.i32(i8* %s, i8 %a, i32 15, i32 1, i1 false) ret void diff --git a/test/CodeGen/X86/memset-nonzero.ll b/test/CodeGen/X86/memset-nonzero.ll index 769fe87880b0..13258fd81de5 100644 --- a/test/CodeGen/X86/memset-nonzero.ll +++ b/test/CodeGen/X86/memset-nonzero.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=x86_64-unknown-unknown < %s -mattr=sse | FileCheck %s --check-prefix=SSE ; RUN: llc -mtriple=x86_64-unknown-unknown < %s -mattr=sse2 | FileCheck %s --check-prefix=SSE ; RUN: llc -mtriple=x86_64-unknown-unknown < %s -mattr=sse2,-slow-unaligned-mem-16 | FileCheck %s --check-prefix=SSE2FAST @@ -26,7 +26,6 @@ define void @memset_16_nonzero_bytes(i8* %x) { ; AVX-NEXT: vmovaps {{.*#+}} xmm0 = [42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42] ; AVX-NEXT: vmovups %xmm0, (%rdi) ; AVX-NEXT: retq -; %call = tail call i8* @__memset_chk(i8* %x, i32 42, i64 16, i64 -1) ret void } @@ -54,7 +53,6 @@ define void @memset_32_nonzero_bytes(i8* %x) { ; AVX-NEXT: vmovups %ymm0, (%rdi) ; AVX-NEXT: vzeroupper ; AVX-NEXT: retq -; %call = tail call i8* @__memset_chk(i8* %x, i32 42, i64 32, i64 -1) ret void } @@ -89,7 +87,6 @@ define void @memset_64_nonzero_bytes(i8* %x) { ; AVX-NEXT: vmovups %ymm0, (%rdi) ; AVX-NEXT: vzeroupper ; AVX-NEXT: retq -; %call = tail call i8* @__memset_chk(i8* %x, i32 42, i64 64, i64 -1) ret void } @@ -138,7 +135,6 @@ define void @memset_128_nonzero_bytes(i8* %x) { ; AVX-NEXT: vmovups %ymm0, (%rdi) ; AVX-NEXT: vzeroupper ; AVX-NEXT: retq -; %call = tail call i8* @__memset_chk(i8* %x, i32 42, i64 128, i64 -1) ret void } @@ -189,7 +185,6 @@ define void @memset_256_nonzero_bytes(i8* %x) { ; AVX-NEXT: vmovups %ymm0, (%rdi) ; AVX-NEXT: vzeroupper ; AVX-NEXT: retq -; %call = tail call i8* @__memset_chk(i8* %x, i32 42, i64 256, i64 -1) ret void } @@ -231,7 +226,6 @@ define void @memset_16_nonconst_bytes(i8* %x, i8 %c) { ; AVX2-NEXT: vpbroadcastb %xmm0, %xmm0 ; AVX2-NEXT: vmovdqu %xmm0, (%rdi) ; AVX2-NEXT: retq -; tail call void @llvm.memset.p0i8.i64(i8* %x, i8 %c, i64 16, i32 1, i1 false) ret void } @@ -275,7 +269,6 @@ define void @memset_32_nonconst_bytes(i8* %x, i8 %c) { ; AVX2-NEXT: vmovdqu %ymm0, (%rdi) ; AVX2-NEXT: vzeroupper ; AVX2-NEXT: retq -; tail call void @llvm.memset.p0i8.i64(i8* %x, i8 %c, i64 32, i32 1, i1 false) ret void } @@ -327,7 +320,6 @@ define void @memset_64_nonconst_bytes(i8* %x, i8 %c) { ; AVX2-NEXT: vmovdqu %ymm0, (%rdi) ; AVX2-NEXT: vzeroupper ; AVX2-NEXT: retq -; tail call void @llvm.memset.p0i8.i64(i8* %x, i8 %c, i64 64, i32 1, i1 false) ret void } @@ -395,7 +387,6 @@ define void @memset_128_nonconst_bytes(i8* %x, i8 %c) { ; AVX2-NEXT: vmovdqu %ymm0, (%rdi) ; AVX2-NEXT: vzeroupper ; AVX2-NEXT: retq -; tail call void @llvm.memset.p0i8.i64(i8* %x, i8 %c, i64 128, i32 1, i1 false) ret void } @@ -461,7 +452,6 @@ define void @memset_256_nonconst_bytes(i8* %x, i8 %c) { ; AVX2-NEXT: vmovdqu %ymm0, (%rdi) ; AVX2-NEXT: vzeroupper ; AVX2-NEXT: retq -; tail call void @llvm.memset.p0i8.i64(i8* %x, i8 %c, i64 256, i32 1, i1 false) ret void } diff --git a/test/CodeGen/X86/memset64-on-x86-32.ll b/test/CodeGen/X86/memset64-on-x86-32.ll index 861cb88b0f57..a7a3c61b1392 100644 --- a/test/CodeGen/X86/memset64-on-x86-32.ll +++ b/test/CodeGen/X86/memset64-on-x86-32.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i386-unknown-unknown -mattr=sse4.2 | FileCheck %s --check-prefix=FAST ; RUN: llc < %s -mtriple=i386-unknown-unknown -mattr=ssse3 | FileCheck %s --check-prefix=SLOW_32 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=ssse3 | FileCheck %s --check-prefix=SLOW_64 @@ -51,7 +51,6 @@ define void @bork() nounwind { ; SLOW_64-NEXT: movq $0, 8 ; SLOW_64-NEXT: movq $0, 0 ; SLOW_64-NEXT: retq -; call void @llvm.memset.p0i8.i64(i8* null, i8 0, i64 80, i32 4, i1 false) ret void } diff --git a/test/CodeGen/X86/negate-i1.ll b/test/CodeGen/X86/negate-i1.ll index f1678a1b22ff..13f831fd37b7 100644 --- a/test/CodeGen/X86/negate-i1.ll +++ b/test/CodeGen/X86/negate-i1.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=X64 ; RUN: llc < %s -mtriple=i386-unknown-unknown | FileCheck %s --check-prefix=X32 @@ -16,7 +16,6 @@ define i8 @select_i8_neg1_or_0(i1 %a) { ; X32-NEXT: andb $1, %al ; X32-NEXT: negb %al ; X32-NEXT: retl -; %b = sext i1 %a to i8 ret i8 %b } @@ -33,7 +32,6 @@ define i8 @select_i8_neg1_or_0_zeroext(i1 zeroext %a) { ; X32-NEXT: movb {{[0-9]+}}(%esp), %al ; X32-NEXT: negb %al ; X32-NEXT: retl -; %b = sext i1 %a to i8 ret i8 %b } @@ -53,7 +51,6 @@ define i16 @select_i16_neg1_or_0(i1 %a) { ; X32-NEXT: negl %eax ; X32-NEXT: # kill: %AX %AX %EAX ; X32-NEXT: retl -; %b = sext i1 %a to i16 ret i16 %b } @@ -72,7 +69,6 @@ define i16 @select_i16_neg1_or_0_zeroext(i1 zeroext %a) { ; X32-NEXT: negl %eax ; X32-NEXT: # kill: %AX %AX %EAX ; X32-NEXT: retl -; %b = sext i1 %a to i16 ret i16 %b } @@ -91,7 +87,6 @@ define i32 @select_i32_neg1_or_0(i1 %a) { ; X32-NEXT: andl $1, %eax ; X32-NEXT: negl %eax ; X32-NEXT: retl -; %b = sext i1 %a to i32 ret i32 %b } @@ -108,7 +103,6 @@ define i32 @select_i32_neg1_or_0_zeroext(i1 zeroext %a) { ; X32-NEXT: movzbl {{[0-9]+}}(%esp), %eax ; X32-NEXT: negl %eax ; X32-NEXT: retl -; %b = sext i1 %a to i32 ret i32 %b } @@ -129,7 +123,6 @@ define i64 @select_i64_neg1_or_0(i1 %a) { ; X32-NEXT: negl %eax ; X32-NEXT: movl %eax, %edx ; X32-NEXT: retl -; %b = sext i1 %a to i64 ret i64 %b } @@ -147,7 +140,6 @@ define i64 @select_i64_neg1_or_0_zeroext(i1 zeroext %a) { ; X32-NEXT: negl %eax ; X32-NEXT: movl %eax, %edx ; X32-NEXT: retl -; %b = sext i1 %a to i64 ret i64 %b } diff --git a/test/CodeGen/X86/negate-shift.ll b/test/CodeGen/X86/negate-shift.ll index 54ffc8e71e07..cbe2f9456fa1 100644 --- a/test/CodeGen/X86/negate-shift.ll +++ b/test/CodeGen/X86/negate-shift.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=X64 define i32 @neg_lshr_signbit(i32 %x) { @@ -7,7 +7,6 @@ define i32 @neg_lshr_signbit(i32 %x) { ; X64-NEXT: sarl $31, %edi ; X64-NEXT: movl %edi, %eax ; X64-NEXT: retq -; %sh = lshr i32 %x, 31 %neg = sub i32 0, %sh ret i32 %neg @@ -19,7 +18,6 @@ define i64 @neg_ashr_signbit(i64 %x) { ; X64-NEXT: shrq $63, %rdi ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: retq -; %sh = ashr i64 %x, 63 %neg = sub i64 0, %sh ret i64 %neg @@ -30,7 +28,6 @@ define <4 x i32> @neg_ashr_signbit_vec(<4 x i32> %x) { ; X64: # BB#0: ; X64-NEXT: psrld $31, %xmm0 ; X64-NEXT: retq -; %sh = ashr <4 x i32> %x, %neg = sub <4 x i32> zeroinitializer, %sh ret <4 x i32> %neg @@ -41,7 +38,6 @@ define <8 x i16> @neg_lshr_signbit_vec(<8 x i16> %x) { ; X64: # BB#0: ; X64-NEXT: psraw $15, %xmm0 ; X64-NEXT: retq -; %sh = lshr <8 x i16> %x, %neg = sub <8 x i16> zeroinitializer, %sh ret <8 x i16> %neg diff --git a/test/CodeGen/X86/negate.ll b/test/CodeGen/X86/negate.ll index 6f07378e0e46..5bdb11479afc 100644 --- a/test/CodeGen/X86/negate.ll +++ b/test/CodeGen/X86/negate.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s define i32 @negate_nuw(i32 %x) { @@ -6,7 +6,6 @@ define i32 @negate_nuw(i32 %x) { ; CHECK: # BB#0: ; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: retq -; %neg = sub nuw i32 0, %x ret i32 %neg } @@ -16,7 +15,6 @@ define <4 x i32> @negate_nuw_vec(<4 x i32> %x) { ; CHECK: # BB#0: ; CHECK-NEXT: xorps %xmm0, %xmm0 ; CHECK-NEXT: retq -; %neg = sub nuw <4 x i32> zeroinitializer, %x ret <4 x i32> %neg } @@ -26,7 +24,6 @@ define i8 @negate_zero_or_minsigned_nsw(i8 %x) { ; CHECK: # BB#0: ; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: retq -; %signbit = and i8 %x, 128 %neg = sub nsw i8 0, %signbit ret i8 %neg @@ -37,7 +34,6 @@ define <4 x i32> @negate_zero_or_minsigned_nsw_vec(<4 x i32> %x) { ; CHECK: # BB#0: ; CHECK-NEXT: xorps %xmm0, %xmm0 ; CHECK-NEXT: retq -; %signbit = shl <4 x i32> %x, %neg = sub nsw <4 x i32> zeroinitializer, %signbit ret <4 x i32> %neg @@ -49,7 +45,6 @@ define i8 @negate_zero_or_minsigned(i8 %x) { ; CHECK-NEXT: shlb $7, %dil ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: retq -; %signbit = shl i8 %x, 7 %neg = sub i8 0, %signbit ret i8 %neg @@ -60,7 +55,6 @@ define <4 x i32> @negate_zero_or_minsigned_vec(<4 x i32> %x) { ; CHECK: # BB#0: ; CHECK-NEXT: andps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %signbit = and <4 x i32> %x, %neg = sub <4 x i32> zeroinitializer, %signbit ret <4 x i32> %neg diff --git a/test/CodeGen/X86/negative-sin.ll b/test/CodeGen/X86/negative-sin.ll index bc38021b5620..94369e3e8d0f 100644 --- a/test/CodeGen/X86/negative-sin.ll +++ b/test/CodeGen/X86/negative-sin.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=avx | FileCheck %s declare double @sin(double %f) @@ -16,7 +16,6 @@ define double @strict(double %e) nounwind { ; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq -; %f = fsub double 0.0, %e %g = call double @sin(double %f) readonly %h = fsub double 0.0, %g @@ -29,8 +28,7 @@ define double @strict(double %e) nounwind { define double @fast(double %e) nounwind { ; CHECK-LABEL: fast: ; CHECK: # BB#0: -; CHECK-NEXT: jmp sin -; +; CHECK-NEXT: jmp sin # TAILCALL %f = fsub fast double 0.0, %e %g = call double @sin(double %f) readonly %h = fsub fast double 0.0, %g @@ -42,8 +40,7 @@ define double @fast(double %e) nounwind { define double @nsz(double %e) nounwind { ; CHECK-LABEL: nsz: ; CHECK: # BB#0: -; CHECK-NEXT: jmp sin -; +; CHECK-NEXT: jmp sin # TAILCALL %f = fsub nsz double 0.0, %e %g = call double @sin(double %f) readonly %h = fsub nsz double 0.0, %g @@ -62,7 +59,6 @@ define double @semi_strict1(double %e) nounwind { ; CHECK-NEXT: vxorpd {{.*}}(%rip), %xmm0, %xmm0 ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq -; %f = fsub double 0.0, %e %g = call double @sin(double %f) readonly %h = fsub nsz double 0.0, %g @@ -80,7 +76,6 @@ define double @semi_strict2(double %e) nounwind { ; CHECK-NEXT: vaddsd %xmm1, %xmm0, %xmm0 ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq -; %f = fsub nsz double 0.0, %e %g = call double @sin(double %f) readonly %h = fsub double 0.0, %g @@ -93,8 +88,7 @@ define double @semi_strict2(double %e) nounwind { define double @fn_attr(double %e) nounwind #0 { ; CHECK-LABEL: fn_attr: ; CHECK: # BB#0: -; CHECK-NEXT: jmp sin -; +; CHECK-NEXT: jmp sin # TAILCALL %f = fsub double 0.0, %e %g = call double @sin(double %f) readonly %h = fsub double 0.0, %g diff --git a/test/CodeGen/X86/no-sse2-avg.ll b/test/CodeGen/X86/no-sse2-avg.ll index 0ed0a7f74cb3..e4b97c17047c 100644 --- a/test/CodeGen/X86/no-sse2-avg.ll +++ b/test/CodeGen/X86/no-sse2-avg.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; REQUIRES: asserts ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=-sse2 | FileCheck %s @@ -23,7 +23,6 @@ define <16 x i8> @PR27973() { ; CHECK-NEXT: movb $0, (%rdi) ; CHECK-NEXT: movq %rdi, %rax ; CHECK-NEXT: retq -; %t0 = zext <16 x i8> zeroinitializer to <16 x i32> %t1 = add nuw nsw <16 x i32> %t0, %t2 = lshr <16 x i32> %t1, diff --git a/test/CodeGen/X86/not-and-simplify.ll b/test/CodeGen/X86/not-and-simplify.ll index 83b2be83d552..87aa10a6e296 100644 --- a/test/CodeGen/X86/not-and-simplify.ll +++ b/test/CodeGen/X86/not-and-simplify.ll @@ -1,5 +1,4 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=-bmi | FileCheck %s --check-prefix=ALL --check-prefix=NO_BMI ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi | FileCheck %s --check-prefix=ALL --check-prefix=BMI diff --git a/test/CodeGen/X86/pr13577.ll b/test/CodeGen/X86/pr13577.ll index 1b1622513ea6..665df2c183bf 100644 --- a/test/CodeGen/X86/pr13577.ll +++ b/test/CodeGen/X86/pr13577.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-darwin | FileCheck %s ; CHECK-LABEL: LCPI0_0: @@ -12,12 +12,11 @@ define x86_fp80 @foo(x86_fp80 %a) { ; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) ; CHECK-NEXT: fstpt -{{[0-9]+}}(%rsp) ; CHECK-NEXT: testb $-128, -{{[0-9]+}}(%rsp) -; CHECK-NEXT: flds LCPI0_0(%rip) -; CHECK-NEXT: flds LCPI0_1(%rip) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: flds {{.*}}(%rip) ; CHECK-NEXT: fcmovne %st(1), %st(0) ; CHECK-NEXT: fstp %st(1) ; CHECK-NEXT: retq -; %1 = tail call x86_fp80 @copysignl(x86_fp80 0xK7FFF8000000000000000, x86_fp80 %a) nounwind readnone ret x86_fp80 %1 } @@ -34,7 +33,6 @@ define float @pr26070() { ; CHECK-NEXT: shufps {{.*#+}} xmm0 = xmm0[0,0,0,0] ; CHECK-NEXT: orps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %c = call float @copysignf(float 1.0, float undef) readnone ret float %c } diff --git a/test/CodeGen/X86/pr18014.ll b/test/CodeGen/X86/pr18014.ll index bb3b9c23f1e3..cba065002d57 100644 --- a/test/CodeGen/X86/pr18014.ll +++ b/test/CodeGen/X86/pr18014.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=sse4.1 | FileCheck %s ; Ensure PSRAD is generated as the condition is consumed by both PADD and @@ -14,7 +14,6 @@ define <4 x i32> @foo(<4 x i32>* %p, <4 x i1> %cond, <4 x i32> %v1, <4 x i32> %v ; CHECK-NEXT: movaps %xmm2, (%rdi) ; CHECK-NEXT: movdqa %xmm1, %xmm0 ; CHECK-NEXT: retq -; %sext_cond = sext <4 x i1> %cond to <4 x i32> %t1 = add <4 x i32> %v1, %sext_cond %t2 = select <4 x i1> %cond, <4 x i32> %v1, <4 x i32> %v2 diff --git a/test/CodeGen/X86/pr32368.ll b/test/CodeGen/X86/pr32368.ll new file mode 100644 index 000000000000..b0f0b123cca1 --- /dev/null +++ b/test/CodeGen/X86/pr32368.ll @@ -0,0 +1,153 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK --check-prefix=SSE +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx | FileCheck %s --check-prefix=CHECK --check-prefix=AVX1 +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx2 | FileCheck %s --check-prefix=CHECK --check-prefix=AVX2 +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512f | FileCheck %s --check-prefix=CHECK --check-prefix=AVX512 + +define <4 x float> @PR32368_128(<4 x float>) { +; SSE-LABEL: PR32368_128: +; SSE: # BB#0: +; SSE-NEXT: andps {{.*}}(%rip), %xmm0 +; SSE-NEXT: addps %xmm0, %xmm0 +; SSE-NEXT: andps {{.*}}(%rip), %xmm0 +; SSE-NEXT: retq +; +; AVX1-LABEL: PR32368_128: +; AVX1: # BB#0: +; AVX1-NEXT: vandps {{.*}}(%rip), %xmm0, %xmm0 +; AVX1-NEXT: vaddps %xmm0, %xmm0, %xmm0 +; AVX1-NEXT: vandps {{.*}}(%rip), %xmm0, %xmm0 +; AVX1-NEXT: retq +; +; AVX2-LABEL: PR32368_128: +; AVX2: # BB#0: +; AVX2-NEXT: vbroadcastss {{.*}}(%rip), %xmm1 +; AVX2-NEXT: vandps %xmm1, %xmm0, %xmm0 +; AVX2-NEXT: vaddps %xmm0, %xmm0, %xmm0 +; AVX2-NEXT: vbroadcastss {{.*}}(%rip), %xmm1 +; AVX2-NEXT: vandps %xmm1, %xmm0, %xmm0 +; AVX2-NEXT: retq +; +; AVX512-LABEL: PR32368_128: +; AVX512: # BB#0: +; AVX512-NEXT: vbroadcastss {{.*}}(%rip), %xmm1 +; AVX512-NEXT: vandps %xmm1, %xmm0, %xmm0 +; AVX512-NEXT: vaddps %xmm0, %xmm0, %xmm0 +; AVX512-NEXT: vbroadcastss {{.*}}(%rip), %xmm1 +; AVX512-NEXT: vandps %xmm1, %xmm0, %xmm0 +; AVX512-NEXT: retq + %2 = bitcast <4 x float> %0 to <4 x i32> + %3 = and <4 x i32> %2, + %4 = bitcast <4 x i32> %3 to <4 x float> + %5 = fmul <4 x float> %4, + %6 = bitcast <4 x float> %5 to <4 x i32> + %7 = and <4 x i32> %6, + %8 = bitcast <4 x i32> %7 to <4 x float> + ret <4 x float> %8 +} + +define <8 x float> @PR32368_256(<8 x float>) { +; SSE-LABEL: PR32368_256: +; SSE: # BB#0: +; SSE-NEXT: movaps {{.*#+}} xmm2 = [4294967004,4294967004,4294967004,4294967004] +; SSE-NEXT: andps %xmm2, %xmm0 +; SSE-NEXT: andps %xmm2, %xmm1 +; SSE-NEXT: addps %xmm1, %xmm1 +; SSE-NEXT: addps %xmm0, %xmm0 +; SSE-NEXT: movaps {{.*#+}} xmm2 = [291,291,291,291] +; SSE-NEXT: andps %xmm2, %xmm0 +; SSE-NEXT: andps %xmm2, %xmm1 +; SSE-NEXT: retq +; +; AVX1-LABEL: PR32368_256: +; AVX1: # BB#0: +; AVX1-NEXT: vandps {{.*}}(%rip), %ymm0, %ymm0 +; AVX1-NEXT: vaddps %ymm0, %ymm0, %ymm0 +; AVX1-NEXT: vandps {{.*}}(%rip), %ymm0, %ymm0 +; AVX1-NEXT: retq +; +; AVX2-LABEL: PR32368_256: +; AVX2: # BB#0: +; AVX2-NEXT: vbroadcastss {{.*}}(%rip), %ymm1 +; AVX2-NEXT: vandps %ymm1, %ymm0, %ymm0 +; AVX2-NEXT: vaddps %ymm0, %ymm0, %ymm0 +; AVX2-NEXT: vbroadcastss {{.*}}(%rip), %ymm1 +; AVX2-NEXT: vandps %ymm1, %ymm0, %ymm0 +; AVX2-NEXT: retq +; +; AVX512-LABEL: PR32368_256: +; AVX512: # BB#0: +; AVX512-NEXT: vbroadcastss {{.*}}(%rip), %ymm1 +; AVX512-NEXT: vandps %ymm1, %ymm0, %ymm0 +; AVX512-NEXT: vaddps %ymm0, %ymm0, %ymm0 +; AVX512-NEXT: vbroadcastss {{.*}}(%rip), %ymm1 +; AVX512-NEXT: vandps %ymm1, %ymm0, %ymm0 +; AVX512-NEXT: retq + %2 = bitcast <8 x float> %0 to <8 x i32> + %3 = and <8 x i32> %2, + %4 = bitcast <8 x i32> %3 to <8 x float> + %5 = fmul <8 x float> %4, + %6 = bitcast <8 x float> %5 to <8 x i32> + %7 = and <8 x i32> %6, + %8 = bitcast <8 x i32> %7 to <8 x float> + ret <8 x float> %8 +} + +define <16 x float> @PR32368_512(<16 x float>) { +; SSE-LABEL: PR32368_512: +; SSE: # BB#0: +; SSE-NEXT: movaps {{.*#+}} xmm4 = [4294967004,4294967004,4294967004,4294967004] +; SSE-NEXT: andps %xmm4, %xmm0 +; SSE-NEXT: andps %xmm4, %xmm1 +; SSE-NEXT: andps %xmm4, %xmm2 +; SSE-NEXT: andps %xmm4, %xmm3 +; SSE-NEXT: addps %xmm3, %xmm3 +; SSE-NEXT: addps %xmm2, %xmm2 +; SSE-NEXT: addps %xmm1, %xmm1 +; SSE-NEXT: addps %xmm0, %xmm0 +; SSE-NEXT: movaps {{.*#+}} xmm4 = [291,291,291,291] +; SSE-NEXT: andps %xmm4, %xmm0 +; SSE-NEXT: andps %xmm4, %xmm1 +; SSE-NEXT: andps %xmm4, %xmm2 +; SSE-NEXT: andps %xmm4, %xmm3 +; SSE-NEXT: retq +; +; AVX1-LABEL: PR32368_512: +; AVX1: # BB#0: +; AVX1-NEXT: vmovaps {{.*#+}} ymm2 = [4294967004,4294967004,4294967004,4294967004,4294967004,4294967004,4294967004,4294967004] +; AVX1-NEXT: vandps %ymm2, %ymm0, %ymm0 +; AVX1-NEXT: vandps %ymm2, %ymm1, %ymm1 +; AVX1-NEXT: vaddps %ymm1, %ymm1, %ymm1 +; AVX1-NEXT: vaddps %ymm0, %ymm0, %ymm0 +; AVX1-NEXT: vmovaps {{.*#+}} ymm2 = [291,291,291,291,291,291,291,291] +; AVX1-NEXT: vandps %ymm2, %ymm0, %ymm0 +; AVX1-NEXT: vandps %ymm2, %ymm1, %ymm1 +; AVX1-NEXT: retq +; +; AVX2-LABEL: PR32368_512: +; AVX2: # BB#0: +; AVX2-NEXT: vbroadcastss {{.*}}(%rip), %ymm2 +; AVX2-NEXT: vandps %ymm2, %ymm0, %ymm0 +; AVX2-NEXT: vandps %ymm2, %ymm1, %ymm1 +; AVX2-NEXT: vaddps %ymm1, %ymm1, %ymm1 +; AVX2-NEXT: vaddps %ymm0, %ymm0, %ymm0 +; AVX2-NEXT: vbroadcastss {{.*}}(%rip), %ymm2 +; AVX2-NEXT: vandps %ymm2, %ymm0, %ymm0 +; AVX2-NEXT: vandps %ymm2, %ymm1, %ymm1 +; AVX2-NEXT: retq +; +; AVX512-LABEL: PR32368_512: +; AVX512: # BB#0: +; AVX512-NEXT: vpandd {{.*}}(%rip){1to16}, %zmm0, %zmm0 +; AVX512-NEXT: vaddps %zmm0, %zmm0, %zmm0 +; AVX512-NEXT: vpandd {{.*}}(%rip){1to16}, %zmm0, %zmm0 +; AVX512-NEXT: retq + %2 = bitcast <16 x float> %0 to <16 x i32> + %3 = and <16 x i32> %2, + %4 = bitcast <16 x i32> %3 to <16 x float> + %5 = fmul <16 x float> %4, + %6 = bitcast <16 x float> %5 to <16 x i32> + %7 = and <16 x i32> %6, + %8 = bitcast <16 x i32> %7 to <16 x float> + ret <16 x float> %8 +} diff --git a/test/CodeGen/X86/rem.ll b/test/CodeGen/X86/rem.ll index cc591e5ac00b..7b138f02eb4a 100644 --- a/test/CodeGen/X86/rem.ll +++ b/test/CodeGen/X86/rem.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i386-unknown-unknown | FileCheck %s define i32 @test1(i32 %X) { @@ -19,7 +19,6 @@ define i32 @test1(i32 %X) { ; CHECK-NEXT: subl %eax, %ecx ; CHECK-NEXT: movl %ecx, %eax ; CHECK-NEXT: retl -; %tmp1 = srem i32 %X, 255 ret i32 %tmp1 } @@ -35,7 +34,6 @@ define i32 @test2(i32 %X) { ; CHECK-NEXT: andl $-256, %ecx ; CHECK-NEXT: subl %ecx, %eax ; CHECK-NEXT: retl -; %tmp1 = srem i32 %X, 256 ret i32 %tmp1 } @@ -54,7 +52,6 @@ define i32 @test3(i32 %X) { ; CHECK-NEXT: subl %eax, %ecx ; CHECK-NEXT: movl %ecx, %eax ; CHECK-NEXT: retl -; %tmp1 = urem i32 %X, 255 ret i32 %tmp1 } @@ -64,7 +61,6 @@ define i32 @test4(i32 %X) { ; CHECK: # BB#0: ; CHECK-NEXT: movzbl {{[0-9]+}}(%esp), %eax ; CHECK-NEXT: retl -; %tmp1 = urem i32 %X, 256 ret i32 %tmp1 } @@ -77,8 +73,8 @@ define i32 @test5(i32 %X) nounwind readnone { ; CHECK-NEXT: idivl {{[0-9]+}}(%esp) ; CHECK-NEXT: movl %edx, %eax ; CHECK-NEXT: retl -; entry: %0 = srem i32 41, %X ret i32 %0 } + diff --git a/test/CodeGen/X86/sar_fold64.ll b/test/CodeGen/X86/sar_fold64.ll index 213ca95fc78d..66ad8c3f40fa 100644 --- a/test/CodeGen/X86/sar_fold64.ll +++ b/test/CodeGen/X86/sar_fold64.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s define i32 @shl48sar47(i64 %a) #0 { @@ -8,7 +8,6 @@ define i32 @shl48sar47(i64 %a) #0 { ; CHECK-NEXT: addl %eax, %eax ; CHECK-NEXT: # kill: %EAX %EAX %RAX ; CHECK-NEXT: retq -; %1 = shl i64 %a, 48 %2 = ashr exact i64 %1, 47 %3 = trunc i64 %2 to i32 @@ -22,7 +21,6 @@ define i32 @shl48sar49(i64 %a) #0 { ; CHECK-NEXT: shrq %rax ; CHECK-NEXT: # kill: %EAX %EAX %RAX ; CHECK-NEXT: retq -; %1 = shl i64 %a, 48 %2 = ashr exact i64 %1, 49 %3 = trunc i64 %2 to i32 @@ -36,7 +34,6 @@ define i32 @shl56sar55(i64 %a) #0 { ; CHECK-NEXT: addl %eax, %eax ; CHECK-NEXT: # kill: %EAX %EAX %RAX ; CHECK-NEXT: retq -; %1 = shl i64 %a, 56 %2 = ashr exact i64 %1, 55 %3 = trunc i64 %2 to i32 @@ -50,7 +47,6 @@ define i32 @shl56sar57(i64 %a) #0 { ; CHECK-NEXT: shrq %rax ; CHECK-NEXT: # kill: %EAX %EAX %RAX ; CHECK-NEXT: retq -; %1 = shl i64 %a, 56 %2 = ashr exact i64 %1, 57 %3 = trunc i64 %2 to i32 @@ -64,7 +60,6 @@ define i8 @all_sign_bit_ashr(i8 %x) { ; CHECK-NEXT: negb %dil ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: retq -; %and = and i8 %x, 1 %neg = sub i8 0, %and %sar = ashr i8 %neg, 6 @@ -79,7 +74,6 @@ define <4 x i32> @all_sign_bit_ashr_vec(<4 x i32> %x) { ; CHECK-NEXT: psubd %xmm0, %xmm1 ; CHECK-NEXT: movdqa %xmm1, %xmm0 ; CHECK-NEXT: retq -; %and = and <4 x i32> %x, %neg = sub <4 x i32> zeroinitializer, %and %sar = ashr <4 x i32> %neg, diff --git a/test/CodeGen/X86/select-with-and-or.ll b/test/CodeGen/X86/select-with-and-or.ll index f49da8576d18..45e4384d0fa1 100644 --- a/test/CodeGen/X86/select-with-and-or.ll +++ b/test/CodeGen/X86/select-with-and-or.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx | FileCheck %s define <4 x i32> @test1(<4 x float> %a, <4 x float> %b, <4 x i32> %c) { @@ -7,7 +7,6 @@ define <4 x i32> @test1(<4 x float> %a, <4 x float> %b, <4 x i32> %c) { ; CHECK-NEXT: vcmpnleps %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: vandps %xmm2, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ult <4 x float> %a, %b %r = select <4 x i1> %f, <4 x i32> %c, <4 x i32> zeroinitializer ret <4 x i32> %r @@ -19,7 +18,6 @@ define <4 x i32> @test2(<4 x float> %a, <4 x float> %b, <4 x i32> %c) { ; CHECK-NEXT: vcmpnleps %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: vorps %xmm2, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ult <4 x float> %a, %b %r = select <4 x i1> %f, <4 x i32> , <4 x i32> %c ret <4 x i32> %r @@ -31,7 +29,6 @@ define <4 x i32> @test3(<4 x float> %a, <4 x float> %b, <4 x i32> %c) { ; CHECK-NEXT: vcmpleps %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: vandps %xmm2, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ult <4 x float> %a, %b %r = select <4 x i1> %f, <4 x i32> zeroinitializer, <4 x i32> %c ret <4 x i32> %r @@ -43,7 +40,6 @@ define <4 x i32> @test4(<4 x float> %a, <4 x float> %b, <4 x i32> %c) { ; CHECK-NEXT: vcmpleps %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: vorps %xmm2, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ult <4 x float> %a, %b %r = select <4 x i1> %f, <4 x i32> %c, <4 x i32> ret <4 x i32> %r @@ -54,7 +50,6 @@ define <4 x i32> @test5(<4 x float> %a, <4 x float> %b, <4 x i32> %c) { ; CHECK: # BB#0: ; CHECK-NEXT: vcmpnleps %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ult <4 x float> %a, %b %r = sext <4 x i1> %f to <4 x i32> ret <4 x i32> %r @@ -65,7 +60,6 @@ define <4 x i32> @test6(<4 x float> %a, <4 x float> %b, <4 x i32> %c) { ; CHECK: # BB#0: ; CHECK-NEXT: vcmpleps %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: retq -; %not.f = fcmp oge <4 x float> %a, %b %r = sext <4 x i1> %not.f to <4 x i32> ret <4 x i32> %r @@ -77,7 +71,6 @@ define <4 x i32> @test7(<4 x float> %a, <4 x float> %b, <4 x i32>* %p) { ; CHECK-NEXT: vcmpnleps %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: vandps (%rdi), %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ult <4 x float> %a, %b %l = load <4 x i32>, <4 x i32>* %p, align 16 %r = select <4 x i1> %f, <4 x i32> %l, <4 x i32> zeroinitializer @@ -92,7 +85,6 @@ define <2 x double> @test1f(<2 x double> %a, <2 x double> %b, <2 x double> %c) { ; CHECK-NEXT: vcmpltpd %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: vandpd %xmm2, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ogt <2 x double> %a, %b %r = select <2 x i1> %f, <2 x double> %c, <2 x double> zeroinitializer ret <2 x double> %r @@ -104,7 +96,6 @@ define <2 x double> @test2f(<2 x double> %a, <2 x double> %b, <2 x double> %c) { ; CHECK-NEXT: vcmplepd %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: vorpd %xmm2, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp oge <2 x double> %a, %b %r = select <2 x i1> %f, <2 x double> , <2 x double> %c ret <2 x double> %r @@ -116,7 +107,6 @@ define <2 x double> @test3f(<2 x double> %a, <2 x double> %b, <2 x double> %c) { ; CHECK-NEXT: vcmpnltpd %xmm1, %xmm0, %xmm0 ; CHECK-NEXT: vandpd %xmm2, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp olt <2 x double> %a, %b %r = select <2 x i1> %f, <2 x double> zeroinitializer, <2 x double> %c ret <2 x double> %r @@ -128,7 +118,6 @@ define <2 x double> @test4f(<2 x double> %a, <2 x double> %b, <2 x double> %c) { ; CHECK-NEXT: vcmpnlepd %xmm1, %xmm0, %xmm0 ; CHECK-NEXT: vorpd %xmm2, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ole <2 x double> %a, %b %r = select <2 x i1> %f, <2 x double> %c, <2 x double> ret <2 x double> %r @@ -139,7 +128,6 @@ define <2 x double> @test5f(<2 x double> %a, <2 x double> %b, <2 x double> %c) { ; CHECK: # BB#0: ; CHECK-NEXT: vcmpnlepd %xmm1, %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ugt <2 x double> %a, %b %r = select <2 x i1> %f, <2 x double> , <2 x double> zeroinitializer ret <2 x double> %r @@ -150,7 +138,6 @@ define <2 x double> @test6f(<2 x double> %a, <2 x double> %b, <2 x double> %c) { ; CHECK: # BB#0: ; CHECK-NEXT: vcmpltpd %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp ule <2 x double> %a, %b %r = select <2 x i1> %f, <2 x double> zeroinitializer, <2 x double> ret <2 x double> %r @@ -162,7 +149,6 @@ define <2 x double> @test7f(<2 x double> %a, <2 x double> %b, <2 x double>* %p) ; CHECK-NEXT: vcmpeqpd %xmm1, %xmm0, %xmm0 ; CHECK-NEXT: vandpd (%rdi), %xmm0, %xmm0 ; CHECK-NEXT: retq -; %f = fcmp oeq <2 x double> %a, %b %l = load <2 x double>, <2 x double>* %p, align 16 %r = select <2 x i1> %f, <2 x double> %l, <2 x double> zeroinitializer diff --git a/test/CodeGen/X86/sext-setcc-self.ll b/test/CodeGen/X86/sext-setcc-self.ll index e739d21e64e0..9cbd3d85b381 100644 --- a/test/CodeGen/X86/sext-setcc-self.ll +++ b/test/CodeGen/X86/sext-setcc-self.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s define <4 x i32> @test_ueq(<4 x float> %in) { @@ -6,7 +6,6 @@ define <4 x i32> @test_ueq(<4 x float> %in) { ; CHECK: # BB#0: ; CHECK-NEXT: pcmpeqd %xmm0, %xmm0 ; CHECK-NEXT: retq -; %t0 = fcmp ueq <4 x float> %in, %in %t1 = sext <4 x i1> %t0 to <4 x i32> ret <4 x i32> %t1 @@ -17,7 +16,6 @@ define <4 x i32> @test_uge(<4 x float> %in) { ; CHECK: # BB#0: ; CHECK-NEXT: pcmpeqd %xmm0, %xmm0 ; CHECK-NEXT: retq -; %t0 = fcmp uge <4 x float> %in, %in %t1 = sext <4 x i1> %t0 to <4 x i32> ret <4 x i32> %t1 @@ -28,7 +26,6 @@ define <4 x i32> @test_ule(<4 x float> %in) { ; CHECK: # BB#0: ; CHECK-NEXT: pcmpeqd %xmm0, %xmm0 ; CHECK-NEXT: retq -; %t0 = fcmp ule <4 x float> %in, %in %t1 = sext <4 x i1> %t0 to <4 x i32> ret <4 x i32> %t1 @@ -39,7 +36,6 @@ define <4 x i32> @test_one(<4 x float> %in) { ; CHECK: # BB#0: ; CHECK-NEXT: xorps %xmm0, %xmm0 ; CHECK-NEXT: retq -; %t0 = fcmp one <4 x float> %in, %in %t1 = sext <4 x i1> %t0 to <4 x i32> ret <4 x i32> %t1 @@ -50,7 +46,6 @@ define <4 x i32> @test_ogt(<4 x float> %in) { ; CHECK: # BB#0: ; CHECK-NEXT: xorps %xmm0, %xmm0 ; CHECK-NEXT: retq -; %t0 = fcmp ogt <4 x float> %in, %in %t1 = sext <4 x i1> %t0 to <4 x i32> ret <4 x i32> %t1 @@ -61,7 +56,6 @@ define <4 x i32> @test_olt(<4 x float> %in) { ; CHECK: # BB#0: ; CHECK-NEXT: xorps %xmm0, %xmm0 ; CHECK-NEXT: retq -; %t0 = fcmp olt <4 x float> %in, %in %t1 = sext <4 x i1> %t0 to <4 x i32> ret <4 x i32> %t1 diff --git a/test/CodeGen/X86/shift-pcmp.ll b/test/CodeGen/X86/shift-pcmp.ll index adfd2f143d17..f509da2674bc 100644 --- a/test/CodeGen/X86/shift-pcmp.ll +++ b/test/CodeGen/X86/shift-pcmp.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -o - -mtriple=x86_64-unknown-unknown -mattr=+sse2 | FileCheck %s --check-prefix=SSE ; RUN: llc < %s -o - -mtriple=x86_64-unknown-unknown -mattr=+avx | FileCheck %s --check-prefix=AVX @@ -14,7 +14,6 @@ define <8 x i16> @foo(<8 x i16> %a, <8 x i16> %b) { ; AVX-NEXT: vpcmpeqw %xmm1, %xmm0, %xmm0 ; AVX-NEXT: vpand {{.*}}(%rip), %xmm0, %xmm0 ; AVX-NEXT: retq -; %icmp = icmp eq <8 x i16> %a, %b %zext = zext <8 x i1> %icmp to <8 x i16> %shl = shl nuw nsw <8 x i16> %zext, @@ -34,7 +33,6 @@ define <8 x i16> @bar(<8 x i16> %a, <8 x i16> %b) { ; AVX-NEXT: vpcmpeqw %xmm1, %xmm0, %xmm0 ; AVX-NEXT: vpand {{.*}}(%rip), %xmm0, %xmm0 ; AVX-NEXT: retq -; %icmp = icmp eq <8 x i16> %a, %b %zext = zext <8 x i1> %icmp to <8 x i16> %shl = shl nuw nsw <8 x i16> %zext, diff --git a/test/CodeGen/X86/sincos-opt.ll b/test/CodeGen/X86/sincos-opt.ll index f0dff3b806c5..e2fd63eab30f 100644 --- a/test/CodeGen/X86/sincos-opt.ll +++ b/test/CodeGen/X86/sincos-opt.ll @@ -1,10 +1,12 @@ ; RUN: llc < %s -mtriple=x86_64-apple-macosx10.9.0 -mcpu=core2 | FileCheck %s --check-prefix=OSX_SINCOS ; RUN: llc < %s -mtriple=x86_64-apple-macosx10.8.0 -mcpu=core2 | FileCheck %s --check-prefix=OSX_NOOPT -; RUN: llc < %s -mtriple=x86_64-pc-linux-gnu -mcpu=core2 | FileCheck %s --check-prefix=GNU_NOOPT -; RUN: llc < %s -mtriple=x86_64-pc-linux-gnu -mcpu=core2 -enable-unsafe-fp-math | FileCheck %s --check-prefix=GNU_SINCOS -; RUN: llc < %s -mtriple=x86_64-pc-linux-gnux32 -mcpu=core2 -enable-unsafe-fp-math | FileCheck %s --check-prefix=GNUX32_SINCOS +; RUN: llc < %s -mtriple=x86_64-pc-linux-gnu -mcpu=core2 | FileCheck %s --check-prefix=GNU_SINCOS +; RUN: llc < %s -mtriple=x86_64-pc-linux-gnu -mcpu=core2 -enable-unsafe-fp-math | FileCheck %s --check-prefix=GNU_SINCOS_FASTMATH +; RUN: llc < %s -mtriple=x86_64-pc-linux-gnux32 -mcpu=core2 -enable-unsafe-fp-math | FileCheck %s --check-prefix=GNU_SINCOS_FASTMATH -; Combine sin / cos into a single call. +; Combine sin / cos into a single call unless they may write errno (as +; captured by readnone attrbiute, controlled by clang -fmath-errno +; setting). ; rdar://13087969 ; rdar://13599493 @@ -15,25 +17,44 @@ entry: ; GNU_SINCOS: movss 4(%rsp), %xmm0 ; GNU_SINCOS: addss (%rsp), %xmm0 -; GNUX32_SINCOS-LABEL: test1: -; GNUX32_SINCOS: callq sincosf -; GNUX32_SINCOS: movss 4(%esp), %xmm0 -; GNUX32_SINCOS: addss (%esp), %xmm0 - -; GNU_NOOPT: test1 -; GNU_NOOPT: callq sinf -; GNU_NOOPT: callq cosf +; GNU_SINCOS_FASTMATH-LABEL: test1: +; GNU_SINCOS_FASTMATH: callq sincosf +; GNU_SINCOS_FASTMATH: movss 4(%{{[re]}}sp), %xmm0 +; GNU_SINCOS_FASTMATH: addss (%{{[re]}}sp), %xmm0 ; OSX_SINCOS-LABEL: test1: ; OSX_SINCOS: callq ___sincosf_stret ; OSX_SINCOS: movshdup {{.*}} xmm1 = xmm0[1,1,3,3] ; OSX_SINCOS: addss %xmm1, %xmm0 -; OSX_NOOPT: test1 +; OSX_NOOPT-LABEL: test1: ; OSX_NOOPT: callq _sinf ; OSX_NOOPT: callq _cosf - %call = tail call float @sinf(float %x) nounwind readnone - %call1 = tail call float @cosf(float %x) nounwind readnone + %call = tail call float @sinf(float %x) readnone + %call1 = tail call float @cosf(float %x) readnone + %add = fadd float %call, %call1 + ret float %add +} + +define float @test1_errno(float %x) nounwind { +entry: +; GNU_SINCOS-LABEL: test1_errno: +; GNU_SINCOS: callq sinf +; GNU_SINCOS: callq cosf + +; GNU_SINCOS_FASTMATH-LABEL: test1_errno: +; GNU_SINCOS_FASTMATH: callq sinf +; GNU_SINCOS_FASTMATH: callq cosf + +; OSX_SINCOS-LABEL: test1_errno: +; OSX_SINCOS: callq _sinf +; OSX_SINCOS: callq _cosf + +; OSX_NOOPT-LABEL: test1_errno: +; OSX_NOOPT: callq _sinf +; OSX_NOOPT: callq _cosf + %call = tail call float @sinf(float %x) + %call1 = tail call float @cosf(float %x) %add = fadd float %call, %call1 ret float %add } @@ -45,24 +66,43 @@ entry: ; GNU_SINCOS: movsd 16(%rsp), %xmm0 ; GNU_SINCOS: addsd 8(%rsp), %xmm0 -; GNUX32_SINCOS-LABEL: test2: -; GNUX32_SINCOS: callq sincos -; GNUX32_SINCOS: movsd 16(%esp), %xmm0 -; GNUX32_SINCOS: addsd 8(%esp), %xmm0 - -; GNU_NOOPT: test2: -; GNU_NOOPT: callq sin -; GNU_NOOPT: callq cos +; GNU_SINCOS_FASTMATH-LABEL: test2: +; GNU_SINCOS_FASTMATH: callq sincos +; GNU_SINCOS_FASTMATH: movsd 16(%{{[re]}}sp), %xmm0 +; GNU_SINCOS_FASTMATH: addsd 8(%{{[re]}}sp), %xmm0 ; OSX_SINCOS-LABEL: test2: ; OSX_SINCOS: callq ___sincos_stret ; OSX_SINCOS: addsd %xmm1, %xmm0 -; OSX_NOOPT: test2 +; OSX_NOOPT-LABEL: test2: ; OSX_NOOPT: callq _sin ; OSX_NOOPT: callq _cos - %call = tail call double @sin(double %x) nounwind readnone - %call1 = tail call double @cos(double %x) nounwind readnone + %call = tail call double @sin(double %x) readnone + %call1 = tail call double @cos(double %x) readnone + %add = fadd double %call, %call1 + ret double %add +} + +define double @test2_errno(double %x) nounwind { +entry: +; GNU_SINCOS-LABEL: test2_errno: +; GNU_SINCOS: callq sin +; GNU_SINCOS: callq cos + +; GNU_SINCOS_FASTMATH-LABEL: test2_errno: +; GNU_SINCOS_FASTMATH: callq sin +; GNU_SINCOS_FASTMATH: callq cos + +; OSX_SINCOS-LABEL: test2_errno: +; OSX_SINCOS: callq _sin +; OSX_SINCOS: callq _cos + +; OSX_NOOPT-LABEL: test2_errno: +; OSX_NOOPT: callq _sin +; OSX_NOOPT: callq _cos + %call = tail call double @sin(double %x) + %call1 = tail call double @cos(double %x) %add = fadd double %call, %call1 ret double %add } @@ -70,29 +110,40 @@ entry: define x86_fp80 @test3(x86_fp80 %x) nounwind { entry: ; GNU_SINCOS-LABEL: test3: -; GNU_SINCOS: callq sinl -; GNU_SINCOS: callq cosl -; GNU_SINCOS: ret +; GNU_SINCOS: callq sincosl +; GNU_SINCOS: fldt 16(%rsp) +; GNU_SINCOS: fldt 32(%rsp) +; GNU_SINCOS: faddp %st(1) -; GNUX32_SINCOS-LABEL: test3: -; GNUX32_SINCOS: callq sinl -; GNUX32_SINCOS: callq cosl -; GNUX32_SINCOS: ret - -; GNU_NOOPT: test3: -; GNU_NOOPT: callq sinl -; GNU_NOOPT: callq cosl - - %call = tail call x86_fp80 @sinl(x86_fp80 %x) nounwind - %call1 = tail call x86_fp80 @cosl(x86_fp80 %x) nounwind +; GNU_SINCOS_FASTMATH-LABEL: test3: +; GNU_SINCOS_FASTMATH: fsin +; GNU_SINCOS_FASTMATH: fcos +; GNU_SINCOS_FASTMATH: faddp %st(1) +; GNU_SINCOS_FASTMATH: ret + %call = tail call x86_fp80 @sinl(x86_fp80 %x) readnone + %call1 = tail call x86_fp80 @cosl(x86_fp80 %x) readnone %add = fadd x86_fp80 %call, %call1 ret x86_fp80 %add } -declare float @sinf(float) readonly -declare double @sin(double) readonly -declare float @cosf(float) readonly -declare double @cos(double) readonly +define x86_fp80 @test3_errno(x86_fp80 %x) nounwind { +entry: +; GNU_SINCOS-LABEL: test3_errno: +; GNU_SINCOS: callq sinl +; GNU_SINCOS: callq cosl +; GNU_SINCOS_FASTMATH-LABEL: test3_errno: +; GNU_SINCOS_FASTMATH: callq sinl +; GNU_SINCOS_FASTMATH: callq cosl + %call = tail call x86_fp80 @sinl(x86_fp80 %x) + %call1 = tail call x86_fp80 @cosl(x86_fp80 %x) + %add = fadd x86_fp80 %call, %call1 + ret x86_fp80 %add +} + +declare float @sinf(float) +declare double @sin(double) +declare float @cosf(float) +declare double @cos(double) declare x86_fp80 @sinl(x86_fp80) declare x86_fp80 @cosl(x86_fp80) diff --git a/test/CodeGen/X86/sse-intrinsics-x86-upgrade.ll b/test/CodeGen/X86/sse-intrinsics-x86-upgrade.ll index 77497d38c897..2ecba887f7cb 100644 --- a/test/CodeGen/X86/sse-intrinsics-x86-upgrade.ll +++ b/test/CodeGen/X86/sse-intrinsics-x86-upgrade.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i686-apple-darwin -mattr=+sse2 | FileCheck %s define void @test_x86_sse_storeu_ps(i8* %a0, <4 x float> %a1) { diff --git a/test/CodeGen/X86/sse41-intrinsics-x86-upgrade.ll b/test/CodeGen/X86/sse41-intrinsics-x86-upgrade.ll index 26af37e30295..9bda90a23023 100644 --- a/test/CodeGen/X86/sse41-intrinsics-x86-upgrade.ll +++ b/test/CodeGen/X86/sse41-intrinsics-x86-upgrade.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i386-apple-darwin -mattr=+sse4.1 | FileCheck %s ; This test works just like the non-upgrade one except that it only checks @@ -230,7 +230,6 @@ define <16 x i8> @max_epi8(<16 x i8> %a0, <16 x i8> %a1) { ; CHECK: ## BB#0: ; CHECK-NEXT: pmaxsb %xmm1, %xmm0 ; CHECK-NEXT: retl -; %res = call <16 x i8> @llvm.x86.sse41.pmaxsb(<16 x i8> %a0, <16 x i8> %a1) ret <16 x i8> %res } @@ -241,7 +240,6 @@ define <16 x i8> @min_epi8(<16 x i8> %a0, <16 x i8> %a1) { ; CHECK: ## BB#0: ; CHECK-NEXT: pminsb %xmm1, %xmm0 ; CHECK-NEXT: retl -; %res = call <16 x i8> @llvm.x86.sse41.pminsb(<16 x i8> %a0, <16 x i8> %a1) ret <16 x i8> %res } @@ -252,7 +250,6 @@ define <8 x i16> @max_epu16(<8 x i16> %a0, <8 x i16> %a1) { ; CHECK: ## BB#0: ; CHECK-NEXT: pmaxuw %xmm1, %xmm0 ; CHECK-NEXT: retl -; %res = call <8 x i16> @llvm.x86.sse41.pmaxuw(<8 x i16> %a0, <8 x i16> %a1) ret <8 x i16> %res } @@ -263,7 +260,6 @@ define <8 x i16> @min_epu16(<8 x i16> %a0, <8 x i16> %a1) { ; CHECK: ## BB#0: ; CHECK-NEXT: pminuw %xmm1, %xmm0 ; CHECK-NEXT: retl -; %res = call <8 x i16> @llvm.x86.sse41.pminuw(<8 x i16> %a0, <8 x i16> %a1) ret <8 x i16> %res } @@ -274,7 +270,6 @@ define <4 x i32> @max_epi32(<4 x i32> %a0, <4 x i32> %a1) { ; CHECK: ## BB#0: ; CHECK-NEXT: pmaxsd %xmm1, %xmm0 ; CHECK-NEXT: retl -; %res = call <4 x i32> @llvm.x86.sse41.pmaxsd(<4 x i32> %a0, <4 x i32> %a1) ret <4 x i32> %res } @@ -285,7 +280,6 @@ define <4 x i32> @min_epi32(<4 x i32> %a0, <4 x i32> %a1) { ; CHECK: ## BB#0: ; CHECK-NEXT: pminsd %xmm1, %xmm0 ; CHECK-NEXT: retl -; %res = call <4 x i32> @llvm.x86.sse41.pminsd(<4 x i32> %a0, <4 x i32> %a1) ret <4 x i32> %res } @@ -296,7 +290,6 @@ define <4 x i32> @max_epu32(<4 x i32> %a0, <4 x i32> %a1) { ; CHECK: ## BB#0: ; CHECK-NEXT: pmaxud %xmm1, %xmm0 ; CHECK-NEXT: retl -; %res = call <4 x i32> @llvm.x86.sse41.pmaxud(<4 x i32> %a0, <4 x i32> %a1) ret <4 x i32> %res } @@ -307,7 +300,6 @@ define <4 x i32> @min_epu32(<4 x i32> %a0, <4 x i32> %a1) { ; CHECK: ## BB#0: ; CHECK-NEXT: pminud %xmm1, %xmm0 ; CHECK-NEXT: retl -; %res = call <4 x i32> @llvm.x86.sse41.pminud(<4 x i32> %a0, <4 x i32> %a1) ret <4 x i32> %res } diff --git a/test/CodeGen/X86/stack-folding-int-avx512.ll b/test/CodeGen/X86/stack-folding-int-avx512.ll index 38e19efb7132..362e656b4f22 100644 --- a/test/CodeGen/X86/stack-folding-int-avx512.ll +++ b/test/CodeGen/X86/stack-folding-int-avx512.ll @@ -1,4 +1,4 @@ -; RUN: llc -O3 -disable-peephole -mtriple=x86_64-unknown-unknown -mattr=+avx512f,+avx512bw,+avx512dq,+avx512vbmi < %s | FileCheck %s +; RUN: llc -O3 -disable-peephole -mtriple=x86_64-unknown-unknown -mattr=+avx512f,+avx512bw,+avx512dq,+avx512vbmi,+avx512cd < %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-unknown" @@ -450,6 +450,24 @@ define <64 x i8> @stack_fold_palignr_maskz(<64 x i8> %a0, <64 x i8> %a1, i64 %ma ret <64 x i8> %4 } +define <16 x i32> @stack_fold_vpconflictd(<16 x i32> %a0) { + ;CHECK-LABEL: stack_fold_vpconflictd + ;CHECK: vpconflictd {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}} {{.*#+}} 64-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <16 x i32> @llvm.x86.avx512.mask.conflict.d.512(<16 x i32> %a0, <16 x i32> undef, i16 -1) + ret <16 x i32> %2 +} +declare <16 x i32> @llvm.x86.avx512.mask.conflict.d.512(<16 x i32>, <16 x i32>, i16) nounwind readonly + +define <8 x i64> @stack_fold_vpconflictq(<8 x i64> %a0) { + ;CHECK-LABEL: stack_fold_vpconflictq + ;CHECK: vpconflictq {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}} {{.*#+}} 64-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <8 x i64> @llvm.x86.avx512.mask.conflict.q.512(<8 x i64> %a0, <8 x i64> undef, i8 -1) + ret <8 x i64> %2 +} +declare <8 x i64> @llvm.x86.avx512.mask.conflict.q.512(<8 x i64>, <8 x i64>, i8) nounwind readnone + define i64 @stack_fold_pcmpeqb(<64 x i8> %a0, <64 x i8> %a1) { ;CHECK-LABEL: stack_fold_pcmpeqb ;CHECK: vpcmpeqb {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}}, {{%k[0-7]}} {{.*#+}} 64-byte Folded Reload @@ -486,6 +504,61 @@ define i32 @stack_fold_pcmpeqw(<32 x i16> %a0, <32 x i16> %a1) { ret i32 %3 } +define i16 @stack_fold_pcmpeqd_mask(<16 x i32> %a0, <16 x i32> %a1, <16 x i32>* %a2, i16 %mask) { + ;CHECK-LABEL: stack_fold_pcmpeqd_mask + ;CHECK: vpcmpeqd {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}}, {{%k[0-7]}} {{{%k[0-7]}}} {{.*#+}} 64-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + ; load and add are here to keep the operations below the side effecting block and to avoid folding the wrong load + %2 = load <16 x i32>, <16 x i32>* %a2 + %3 = add <16 x i32> %a1, %2 + %4 = bitcast i16 %mask to <16 x i1> + %5 = icmp eq <16 x i32> %3, %a0 + %6 = and <16 x i1> %4, %5 + %7 = bitcast <16 x i1> %6 to i16 + ret i16 %7 +} + +define i16 @stack_fold_pcmpeqd_mask_commuted(<16 x i32> %a0, <16 x i32> %a1, <16 x i32>* %a2, i16 %mask) { + ;CHECK-LABEL: stack_fold_pcmpeqd_mask_commuted + ;CHECK: vpcmpeqd {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}}, {{%k[0-7]}} {{{%k[0-7]}}} {{.*#+}} 64-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + ; load and add are here to keep the operations below the side effecting block and to avoid folding the wrong load + %2 = load <16 x i32>, <16 x i32>* %a2 + %3 = add <16 x i32> %a1, %2 + %4 = bitcast i16 %mask to <16 x i1> + %5 = icmp eq <16 x i32> %a0, %3 + %6 = and <16 x i1> %4, %5 + %7 = bitcast <16 x i1> %6 to i16 + ret i16 %7 +} + +define i16 @stack_fold_pcmpled_mask(<16 x i32> %a0, <16 x i32> %a1, <16 x i32>* %a2, i16 %mask) { + ;CHECK-LABEL: stack_fold_pcmpled_mask + ;CHECK: vpcmpled {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}}, {{%k[0-7]}} {{{%k[0-7]}}} {{.*#+}} 64-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + ; load and add are here to keep the operations below the side effecting block and to avoid folding the wrong load + %2 = load <16 x i32>, <16 x i32>* %a2 + %3 = add <16 x i32> %a1, %2 + %4 = bitcast i16 %mask to <16 x i1> + %5 = icmp sge <16 x i32> %a0, %3 + %6 = and <16 x i1> %4, %5 + %7 = bitcast <16 x i1> %6 to i16 + ret i16 %7 +} + +define i16 @stack_fold_pcmpleud(<16 x i32> %a0, <16 x i32> %a1, <16 x i32>* %a2, i16 %mask) { + ;CHECK-LABEL: stack_fold_pcmpleud + ;CHECK: vpcmpleud {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}}, {{%k[0-7]}} {{.*#+}} 64-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = load <16 x i32>, <16 x i32>* %a2 + %3 = add <16 x i32> %a1, %2 + %4 = bitcast i16 %mask to <16 x i1> + %5 = icmp uge <16 x i32> %a0, %3 + %6 = and <16 x i1> %5, %4 + %7 = bitcast <16 x i1> %6 to i16 + ret i16 %7 +} + define <64 x i8> @stack_fold_permbvar(<64 x i8> %a0, <64 x i8> %a1) { ;CHECK-LABEL: stack_fold_permbvar ;CHECK: vpermb {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}}, {{%zmm[0-9][0-9]*}} {{.*#+}} 64-byte Folded Reload @@ -740,6 +813,24 @@ define <8 x i16> @stack_fold_pinsrw(<8 x i16> %a0, i16 %a1) { ret <8 x i16> %2 } +define <16 x i32> @stack_fold_vplzcntd(<16 x i32> %a0) { + ;CHECK-LABEL: stack_fold_vplzcntd + ;CHECK: vplzcntd {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}} {{.*#+}} 64-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <16 x i32> @llvm.ctlz.v16i32(<16 x i32> %a0) + ret <16 x i32> %2 +} +declare <16 x i32> @llvm.ctlz.v16i32(<16 x i32>) nounwind readonly + +define <8 x i64> @stack_fold_vplzcntq(<8 x i64> %a0) { + ;CHECK-LABEL: stack_fold_vplzcntq + ;CHECK: vplzcntq {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}} {{.*#+}} 64-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <8 x i64> @llvm.ctlz.v8i64(<8 x i64> %a0) + ret <8 x i64> %2 +} +declare <8 x i64> @llvm.ctlz.v8i64(<8 x i64>) nounwind readnone + define <32 x i16> @stack_fold_pmaddubsw_zmm(<64 x i8> %a0, <64 x i8> %a1) { ;CHECK-LABEL: stack_fold_pmaddubsw_zmm ;CHECK: vpmaddubsw {{-?[0-9]*}}(%rsp), {{%zmm[0-9][0-9]*}}, {{%zmm[0-9][0-9]*}} {{.*#+}} 64-byte Folded Reload diff --git a/test/CodeGen/X86/stack-folding-int-avx512vl.ll b/test/CodeGen/X86/stack-folding-int-avx512vl.ll index 7ce798f778a3..26e97ea4e599 100644 --- a/test/CodeGen/X86/stack-folding-int-avx512vl.ll +++ b/test/CodeGen/X86/stack-folding-int-avx512vl.ll @@ -1,4 +1,4 @@ -; RUN: llc -O3 -disable-peephole -mtriple=x86_64-unknown-unknown -mattr=+avx512vl,+avx512bw,+avx512dq,+avx512vbmi < %s | FileCheck %s +; RUN: llc -O3 -disable-peephole -mtriple=x86_64-unknown-unknown -mattr=+avx512vl,+avx512bw,+avx512dq,+avx512vbmi,+avx512cd < %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-unknown" @@ -81,6 +81,42 @@ define <16 x i16> @stack_fold_pavgw_ymm(<16 x i16> %a0, <16 x i16> %a1) { } declare <16 x i16> @llvm.x86.avx2.pavg.w(<16 x i16>, <16 x i16>) nounwind readnone +define <4 x i32> @stack_fold_vpconflictd(<4 x i32> %a0) { + ;CHECK-LABEL: stack_fold_vpconflictd + ;CHECK: vpconflictd {{-?[0-9]*}}(%rsp), {{%xmm[0-9][0-9]*}} {{.*#+}} 16-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <4 x i32> @llvm.x86.avx512.mask.conflict.d.128(<4 x i32> %a0, <4 x i32> undef, i8 -1) + ret <4 x i32> %2 +} +declare <4 x i32> @llvm.x86.avx512.mask.conflict.d.128(<4 x i32>, <4 x i32>, i8) nounwind readonly + +define <8 x i32> @stack_fold_vpconflictd_ymm(<8 x i32> %a0) { + ;CHECK-LABEL: stack_fold_vpconflictd_ymm + ;CHECK: vpconflictd {{-?[0-9]*}}(%rsp), {{%ymm[0-9][0-9]*}} {{.*#+}} 32-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <8 x i32> @llvm.x86.avx512.mask.conflict.d.256(<8 x i32> %a0, <8 x i32> undef, i8 -1) + ret <8 x i32> %2 +} +declare <8 x i32> @llvm.x86.avx512.mask.conflict.d.256(<8 x i32>, <8 x i32>, i8) nounwind readonly + +define <2 x i64> @stack_fold_vpconflictq(<2 x i64> %a0) { + ;CHECK-LABEL: stack_fold_vpconflictq + ;CHECK: vpconflictq {{-?[0-9]*}}(%rsp), {{%xmm[0-9][0-9]*}} {{.*#+}} 16-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <2 x i64> @llvm.x86.avx512.mask.conflict.q.128(<2 x i64> %a0, <2 x i64> undef, i8 -1) + ret <2 x i64> %2 +} +declare <2 x i64> @llvm.x86.avx512.mask.conflict.q.128(<2 x i64>, <2 x i64>, i8) nounwind readnone + +define <4 x i64> @stack_fold_vpconflictq_ymm(<4 x i64> %a0) { + ;CHECK-LABEL: stack_fold_vpconflictq_ymm + ;CHECK: vpconflictq {{-?[0-9]*}}(%rsp), {{%ymm[0-9][0-9]*}} {{.*#+}} 32-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <4 x i64> @llvm.x86.avx512.mask.conflict.q.256(<4 x i64> %a0, <4 x i64> undef, i8 -1) + ret <4 x i64> %2 +} +declare <4 x i64> @llvm.x86.avx512.mask.conflict.q.256(<4 x i64>, <4 x i64>, i8) nounwind readnone + define <4 x i32> @stack_fold_extracti32x4(<8 x i32> %a0, <8 x i32> %a1) { ;CHECK-LABEL: stack_fold_extracti32x4 ;CHECK: vextracti128 $1, {{%ymm[0-9][0-9]*}}, {{-?[0-9]*}}(%rsp) {{.*#+}} 16-byte Folded Spill @@ -708,6 +744,42 @@ define <16 x i16> @stack_fold_permwvar(<16 x i16> %a0, <16 x i16> %a1) { } declare <16 x i16> @llvm.x86.avx512.mask.permvar.hi.256(<16 x i16>, <16 x i16>, <16 x i16>, i16) nounwind readonly +define <4 x i32> @stack_fold_vplzcntd(<4 x i32> %a0) { + ;CHECK-LABEL: stack_fold_vplzcntd + ;CHECK: vplzcntd {{-?[0-9]*}}(%rsp), {{%xmm[0-9][0-9]*}} {{.*#+}} 16-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a0) + ret <4 x i32> %2 +} +declare <4 x i32> @llvm.ctlz.v4i32(<4 x i32>) nounwind readonly + +define <8 x i32> @stack_fold_vplzcntd_ymm(<8 x i32> %a0) { + ;CHECK-LABEL: stack_fold_vplzcntd_ymm + ;CHECK: vplzcntd {{-?[0-9]*}}(%rsp), {{%ymm[0-9][0-9]*}} {{.*#+}} 32-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <8 x i32> @llvm.ctlz.v8i32(<8 x i32> %a0) + ret <8 x i32> %2 +} +declare <8 x i32> @llvm.ctlz.v8i32(<8 x i32>) nounwind readonly + +define <2 x i64> @stack_fold_vplzcntq(<2 x i64> %a0) { + ;CHECK-LABEL: stack_fold_vplzcntq + ;CHECK: vplzcntq {{-?[0-9]*}}(%rsp), {{%xmm[0-9][0-9]*}} {{.*#+}} 16-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %a0) + ret <2 x i64> %2 +} +declare <2 x i64> @llvm.ctlz.v2i64(<2 x i64>) nounwind readnone + +define <4 x i64> @stack_fold_vplzcntq_ymm(<4 x i64> %a0) { + ;CHECK-LABEL: stack_fold_vplzcntq_ymm + ;CHECK: vplzcntq {{-?[0-9]*}}(%rsp), {{%ymm[0-9][0-9]*}} {{.*#+}} 32-byte Folded Reload + %1 = tail call <2 x i64> asm sideeffect "nop", "=x,~{xmm1},~{xmm2},~{xmm3},~{xmm4},~{xmm5},~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{flags}"() + %2 = call <4 x i64> @llvm.ctlz.v4i64(<4 x i64> %a0) + ret <4 x i64> %2 +} +declare <4 x i64> @llvm.ctlz.v4i64(<4 x i64>) nounwind readnone + define <8 x i16> @stack_fold_pmaddubsw(<16 x i8> %a0, <16 x i8> %a1) { ;CHECK-LABEL: stack_fold_pmaddubsw ;CHECK: vpmaddubsw {{-?[0-9]*}}(%rsp), {{%xmm[0-9][0-9]*}}, {{%xmm[0-9][0-9]*}} {{.*#+}} 16-byte Folded Reload diff --git a/test/CodeGen/X86/statepoint-live-in.ll b/test/CodeGen/X86/statepoint-live-in.ll index aaa4d7c8422a..0179d37ad4e1 100644 --- a/test/CodeGen/X86/statepoint-live-in.ll +++ b/test/CodeGen/X86/statepoint-live-in.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -verify-machineinstrs -O3 < %s | FileCheck %s target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.11.0" @@ -16,7 +16,6 @@ define void @test1(i32 %a) gc "statepoint-example" { ; CHECK-NEXT: Ltmp0: ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq -; entry: ; We expect the argument to be passed in an extra register to bar %statepoint_token1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 1, i32 %a) @@ -49,7 +48,6 @@ define void @test2(i32 %a, i32 %b) gc "statepoint-example" { ; CHECK-NEXT: popq %rbx ; CHECK-NEXT: popq %rbp ; CHECK-NEXT: retq -; entry: ; Because the first call clobbers esi, we have to move the values into ; new registers. Note that they stay in the registers for both calls. @@ -68,7 +66,6 @@ define void @test3(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 % ; CHECK-NEXT: Ltmp3: ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq -; entry: ; We directly reference the argument slot %statepoint_token1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 9, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i) @@ -89,7 +86,6 @@ define void @test4(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 % ; CHECK-NEXT: Ltmp4: ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq -; entry: %statepoint_token1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 26, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n, i32 %o, i32 %p, i32 %q, i32 %r, i32 %s, i32 %t, i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z) ret void @@ -111,7 +107,6 @@ define i32 addrspace(1)* @test5(i32 %a, i32 addrspace(1)* %p) gc "statepoint-ex ; CHECK-NEXT: movq (%rsp), %rax ; CHECK-NEXT: popq %rcx ; CHECK-NEXT: retq -; entry: %token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 1, i32 %a, i32 addrspace(1)* %p, i32 addrspace(1)* %p) %p2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %token, i32 9, i32 9) @@ -139,7 +134,6 @@ define void @test6(i32 %a) gc "statepoint-example" { ; CHECK-NEXT: addq $16, %rsp ; CHECK-NEXT: popq %rbx ; CHECK-NEXT: retq -; entry: call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @baz, i32 0, i32 0, i32 0, i32 1, i32 %a) call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 1, i32 %a) diff --git a/test/CodeGen/X86/swifterror.ll b/test/CodeGen/X86/swifterror.ll index 5704d1919988..1ecd33743d21 100644 --- a/test/CodeGen/X86/swifterror.ll +++ b/test/CodeGen/X86/swifterror.ll @@ -712,3 +712,111 @@ trueBB: falseBB: ret void } + + +declare swiftcc void @foo2(%swift_error** swifterror) + +; Make sure we properly assign registers during fast-isel. +; CHECK-O0-LABEL: testAssign +; CHECK-O0: pushq %r12 +; CHECK-O0: xorl [[ZERO:%[a-z0-9]+]], [[ZERO]] +; CHECK-O0: movl [[ZERO]], %r12d +; CHECK-O0: callq _foo2 +; CHECK-O0: movq %r12, [[SLOT:[-a-z0-9\(\)\%]*]] +; +; CHECK-O0: movq [[SLOT]], %rax +; CHECK-O0: popq %r12 +; CHECK-O0: retq + +; CHECK-APPLE-LABEL: testAssign +; CHECK-APPLE: pushq %r12 +; CHECK-APPLE: xorl %r12d, %r12d +; CHECK-APPLE: callq _foo2 +; CHECK-APPLE: movq %r12, %rax +; CHECK-APPLE: popq %r12 +; CHECK-APPLE: retq + +define swiftcc %swift_error* @testAssign(i8* %error_ref) { +entry: + %error_ptr = alloca swifterror %swift_error* + store %swift_error* null, %swift_error** %error_ptr + call swiftcc void @foo2(%swift_error** swifterror %error_ptr) + br label %a + +a: + %error = load %swift_error*, %swift_error** %error_ptr + ret %swift_error* %error +} + +; CHECK-O0-LABEL: testAssign2 +; CHECK-O0: movq %r12, {{.*}} +; CHECK-O0: movq %r12, [[SLOT:[-a-z0-9\(\)\%]*]] +; CHECK-O0: jmp +; CHECK-O0: movq [[SLOT]], %rax +; CHECK-O0: movq %rax, [[SLOT2:[-a-z0-9\(\)\%]*]] +; CHECK-O0: movq [[SLOT2]], %r12 +; CHECK-O0: retq + +; CHECK-APPLE-LABEL: testAssign2 +; CHECK-APPLE: movq %r12, %rax +; CHECK-APPLE: retq +define swiftcc %swift_error* @testAssign2(i8* %error_ref, %swift_error** swifterror %err) { +entry: + br label %a + +a: + %error = load %swift_error*, %swift_error** %err + ret %swift_error* %error +} + +; CHECK-O0-LABEL: testAssign3 +; CHECK-O0: callq _foo2 +; CHECK-O0: movq %r12, [[SLOT:[-a-z0-9\(\)\%]*]] +; CHECK-O0: movq [[SLOT]], %rax +; CHECK-O0: movq %rax, [[SLOT2:[-a-z0-9\(\)\%]*]] +; CHECK-O0: movq [[SLOT2]], %r12 +; CHECK-O0: addq $24, %rsp +; CHECK-O0: retq + +; CHECK-APPLE-LABEL: testAssign3 +; CHECK-APPLE: callq _foo2 +; CHECK-APPLE: movq %r12, %rax +; CHECK-APPLE: retq + +define swiftcc %swift_error* @testAssign3(i8* %error_ref, %swift_error** swifterror %err) { +entry: + call swiftcc void @foo2(%swift_error** swifterror %err) + br label %a + +a: + %error = load %swift_error*, %swift_error** %err + ret %swift_error* %error +} + + +; CHECK-O0-LABEL: testAssign4 +; CHECK-O0: callq _foo2 +; CHECK-O0: xorl %ecx, %ecx +; CHECK-O0: movl %ecx, %eax +; CHECK-O0: movq %rax, [[SLOT:[-a-z0-9\(\)\%]*]] +; CHECK-O0: movq [[SLOT]], %rax +; CHECK-O0: movq %rax, [[SLOT2:[-a-z0-9\(\)\%]*]] +; CHECK-O0: movq [[SLOT2]], %r12 +; CHECK-O0: retq + +; CHECK-APPLE-LABEL: testAssign4 +; CHECK-APPLE: callq _foo2 +; CHECK-APPLE: xorl %eax, %eax +; CHECK-APPLE: xorl %r12d, %r12d +; CHECK-APPLE: retq + +define swiftcc %swift_error* @testAssign4(i8* %error_ref, %swift_error** swifterror %err) { +entry: + call swiftcc void @foo2(%swift_error** swifterror %err) + store %swift_error* null, %swift_error** %err + br label %a + +a: + %error = load %swift_error*, %swift_error** %err + ret %swift_error* %error +} diff --git a/test/CodeGen/X86/urem-i8-constant.ll b/test/CodeGen/X86/urem-i8-constant.ll index 45717f985c23..2a659b20de8f 100644 --- a/test/CodeGen/X86/urem-i8-constant.ll +++ b/test/CodeGen/X86/urem-i8-constant.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i386-unknown-unknown | FileCheck %s define i8 @foo(i8 %tmp325) { @@ -14,7 +14,6 @@ define i8 @foo(i8 %tmp325) { ; CHECK-NEXT: subb %al, %cl ; CHECK-NEXT: movl %ecx, %eax ; CHECK-NEXT: retl -; %t546 = urem i8 %tmp325, 37 ret i8 %t546 } diff --git a/test/CodeGen/X86/urem-power-of-two.ll b/test/CodeGen/X86/urem-power-of-two.ll index 469c573443ea..1b56c87aad5f 100644 --- a/test/CodeGen/X86/urem-power-of-two.ll +++ b/test/CodeGen/X86/urem-power-of-two.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s ; The easy case: a constant power-of-2 divisor. @@ -9,7 +9,6 @@ define i64 @const_pow_2(i64 %x) { ; CHECK-NEXT: andl $31, %edi ; CHECK-NEXT: movq %rdi, %rax ; CHECK-NEXT: retq -; %urem = urem i64 %x, 32 ret i64 %urem } @@ -25,7 +24,6 @@ define i25 @shift_left_pow_2(i25 %x, i25 %y) { ; CHECK-NEXT: addl $33554431, %eax # imm = 0x1FFFFFF ; CHECK-NEXT: andl %edi, %eax ; CHECK-NEXT: retq -; %shl = shl i25 1, %y %urem = urem i25 %x, %shl ret i25 %urem @@ -43,7 +41,6 @@ define i16 @shift_right_pow_2(i16 %x, i16 %y) { ; CHECK-NEXT: andl %edi, %eax ; CHECK-NEXT: # kill: %AX %AX %EAX ; CHECK-NEXT: retq -; %shr = lshr i16 -32768, %y %urem = urem i16 %x, %shr ret i16 %urem @@ -61,7 +58,6 @@ define i8 @and_pow_2(i8 %x, i8 %y) { ; CHECK-NEXT: movzbl %ah, %eax # NOREX ; CHECK-NEXT: # kill: %AL %AL %EAX ; CHECK-NEXT: retq -; %and = and i8 %y, 4 %urem = urem i8 %x, %and ret i8 %urem @@ -74,7 +70,6 @@ define <4 x i32> @vec_const_pow_2(<4 x i32> %x) { ; CHECK: # BB#0: ; CHECK-NEXT: andps {{.*}}(%rip), %xmm0 ; CHECK-NEXT: retq -; %urem = urem <4 x i32> %x, ret <4 x i32> %urem } diff --git a/test/CodeGen/X86/vec3.ll b/test/CodeGen/X86/vec3.ll index 8eaf9f4f48e4..e9c47ffd21c6 100644 --- a/test/CodeGen/X86/vec3.ll +++ b/test/CodeGen/X86/vec3.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=sse | FileCheck %s define <3 x float> @fadd(<3 x float> %v, float %d) { @@ -7,7 +7,6 @@ define <3 x float> @fadd(<3 x float> %v, float %d) { ; CHECK-NEXT: shufps {{.*#+}} xmm1 = xmm1[0,0,0,3] ; CHECK-NEXT: addps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %ins = insertelement <3 x float> undef, float %d, i32 0 %splat = shufflevector <3 x float> %ins, <3 x float> undef, <3 x i32> zeroinitializer %add = fadd <3 x float> %splat, %v @@ -23,7 +22,6 @@ define <3 x float> @fdiv(<3 x float> %v, float %d) { ; CHECK-NEXT: divps %xmm0, %xmm1 ; CHECK-NEXT: movaps %xmm1, %xmm0 ; CHECK-NEXT: retq -; %ins = insertelement <3 x float> undef, float %d, i32 0 %splat = shufflevector <3 x float> %ins, <3 x float> undef, <3 x i32> zeroinitializer %div = fdiv <3 x float> %splat, %v diff --git a/test/CodeGen/X86/vector-compare-combines.ll b/test/CodeGen/X86/vector-compare-combines.ll index c25474d92f9c..bd7cbfb4bac0 100644 --- a/test/CodeGen/X86/vector-compare-combines.ll +++ b/test/CodeGen/X86/vector-compare-combines.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse4.2 | FileCheck %s --check-prefix=SSE --check-prefix=SSE42 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx | FileCheck %s --check-prefix=AVX --check-prefix=AVX1 @@ -17,7 +17,6 @@ define <4 x i32> @PR27924_cmpeq(<4 x i32> %a, <4 x i32> %b) { ; AVX: # BB#0: ; AVX-NEXT: vpcmpeqd %xmm0, %xmm0, %xmm0 ; AVX-NEXT: retq -; %cmp = icmp sgt <4 x i32> %a, %b %max = select <4 x i1> %cmp, <4 x i32> %a, <4 x i32> %b %sse_max = tail call <4 x i32> @llvm.x86.sse41.pmaxsd(<4 x i32> %a, <4 x i32> %b) @@ -36,7 +35,6 @@ define <4 x i32> @PR27924_cmpgt(<4 x i32> %a, <4 x i32> %b) { ; AVX: # BB#0: ; AVX-NEXT: vxorps %xmm0, %xmm0, %xmm0 ; AVX-NEXT: retq -; %cmp = icmp sgt <4 x i32> %a, %b %max = select <4 x i1> %cmp, <4 x i32> %a, <4 x i32> %b %sse_max = tail call <4 x i32> @llvm.x86.sse41.pmaxsd(<4 x i32> %a, <4 x i32> %b) diff --git a/test/CodeGen/X86/vector-shuffle-256-v16.ll b/test/CodeGen/X86/vector-shuffle-256-v16.ll index fad5586dd77c..d34728df29b7 100644 --- a/test/CodeGen/X86/vector-shuffle-256-v16.ll +++ b/test/CodeGen/X86/vector-shuffle-256-v16.ll @@ -1559,6 +1559,24 @@ define <16 x i16> @shuffle_v16i16_17_18_19_20_21_22_23_zz_25_26_27_28_29_30_31_z ret <16 x i16> %shuffle } +define <16 x i16> @shuffle_v16i16_06_07_01_02_07_00_04_05_14_15_09_10_15_08_12_13(<16 x i16> %a) { +; AVX1-LABEL: shuffle_v16i16_06_07_01_02_07_00_04_05_14_15_09_10_15_08_12_13: +; AVX1: # BB#0: +; AVX1-NEXT: vextractf128 $1, %ymm0, %xmm1 +; AVX1-NEXT: vmovdqa {{.*#+}} xmm2 = [12,13,14,15,2,3,4,5,14,15,0,1,8,9,10,11] +; AVX1-NEXT: vpshufb %xmm2, %xmm1, %xmm1 +; AVX1-NEXT: vpshufb %xmm2, %xmm0, %xmm0 +; AVX1-NEXT: vinsertf128 $1, %xmm1, %ymm0, %ymm0 +; AVX1-NEXT: retq +; +; AVX2OR512VL-LABEL: shuffle_v16i16_06_07_01_02_07_00_04_05_14_15_09_10_15_08_12_13: +; AVX2OR512VL: # BB#0: +; AVX2OR512VL-NEXT: vpshufb {{.*#+}} ymm0 = ymm0[12,13,14,15,2,3,4,5,14,15,0,1,8,9,10,11,28,29,30,31,18,19,20,21,30,31,16,17,24,25,26,27] +; AVX2OR512VL-NEXT: retq + %1 = shufflevector <16 x i16> %a, <16 x i16> undef, <16 x i32> + ret <16 x i16> %1 +} + ; ; Shuffle to logical bit shifts ; diff --git a/test/CodeGen/X86/vzero-excess.ll b/test/CodeGen/X86/vzero-excess.ll index 0ed90741b61e..9ddafec65182 100644 --- a/test/CodeGen/X86/vzero-excess.ll +++ b/test/CodeGen/X86/vzero-excess.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx | FileCheck %s ; In the following 4 tests, the existing call to VZU/VZA ensures clean state before diff --git a/test/CodeGen/X86/x86-interleaved-access.ll b/test/CodeGen/X86/x86-interleaved-access.ll index 74214aa1b8b7..ec8bce1b43cc 100644 --- a/test/CodeGen/X86/x86-interleaved-access.ll +++ b/test/CodeGen/X86/x86-interleaved-access.ll @@ -9,8 +9,8 @@ define <4 x double> @load_factorf64_4(<16 x double>* %ptr) { ; AVX-NEXT: vmovupd 32(%rdi), %ymm1 ; AVX-NEXT: vmovupd 64(%rdi), %ymm2 ; AVX-NEXT: vmovupd 96(%rdi), %ymm3 -; AVX-NEXT: vinsertf128 $1, %xmm2, %ymm0, %ymm4 -; AVX-NEXT: vinsertf128 $1, %xmm3, %ymm1, %ymm5 +; AVX-NEXT: vperm2f128 {{.*#+}} ymm4 = ymm0[0,1],ymm2[0,1] +; AVX-NEXT: vperm2f128 {{.*#+}} ymm5 = ymm1[0,1],ymm3[0,1] ; AVX-NEXT: vhaddpd %ymm5, %ymm4, %ymm4 ; AVX-NEXT: vperm2f128 {{.*#+}} ymm0 = ymm0[2,3],ymm2[2,3] ; AVX-NEXT: vperm2f128 {{.*#+}} ymm1 = ymm1[2,3],ymm3[2,3] @@ -37,8 +37,8 @@ define <4 x double> @load_factorf64_2(<16 x double>* %ptr) { ; AVX-NEXT: vmovupd 32(%rdi), %ymm1 ; AVX-NEXT: vmovupd 64(%rdi), %ymm2 ; AVX-NEXT: vmovupd 96(%rdi), %ymm3 -; AVX-NEXT: vinsertf128 $1, %xmm2, %ymm0, %ymm4 -; AVX-NEXT: vinsertf128 $1, %xmm3, %ymm1, %ymm5 +; AVX-NEXT: vperm2f128 {{.*#+}} ymm4 = ymm0[0,1],ymm2[0,1] +; AVX-NEXT: vperm2f128 {{.*#+}} ymm5 = ymm1[0,1],ymm3[0,1] ; AVX-NEXT: vunpcklpd {{.*#+}} ymm4 = ymm4[0],ymm5[0],ymm4[2],ymm5[2] ; AVX-NEXT: vperm2f128 {{.*#+}} ymm0 = ymm0[2,3],ymm2[2,3] ; AVX-NEXT: vperm2f128 {{.*#+}} ymm1 = ymm1[2,3],ymm3[2,3] @@ -53,25 +53,15 @@ define <4 x double> @load_factorf64_2(<16 x double>* %ptr) { } define <4 x double> @load_factorf64_1(<16 x double>* %ptr) { -; AVX1-LABEL: load_factorf64_1: -; AVX1: # BB#0: -; AVX1-NEXT: vmovups (%rdi), %ymm0 -; AVX1-NEXT: vmovups 32(%rdi), %ymm1 -; AVX1-NEXT: vinsertf128 $1, 64(%rdi), %ymm0, %ymm0 -; AVX1-NEXT: vinsertf128 $1, 96(%rdi), %ymm1, %ymm1 -; AVX1-NEXT: vunpcklpd {{.*#+}} ymm0 = ymm0[0],ymm1[0],ymm0[2],ymm1[2] -; AVX1-NEXT: vmulpd %ymm0, %ymm0, %ymm0 -; AVX1-NEXT: retq -; -; AVX2-LABEL: load_factorf64_1: -; AVX2: # BB#0: -; AVX2-NEXT: vmovupd (%rdi), %ymm0 -; AVX2-NEXT: vmovupd 32(%rdi), %ymm1 -; AVX2-NEXT: vinsertf128 $1, 64(%rdi), %ymm0, %ymm0 -; AVX2-NEXT: vinsertf128 $1, 96(%rdi), %ymm1, %ymm1 -; AVX2-NEXT: vunpcklpd {{.*#+}} ymm0 = ymm0[0],ymm1[0],ymm0[2],ymm1[2] -; AVX2-NEXT: vmulpd %ymm0, %ymm0, %ymm0 -; AVX2-NEXT: retq +; AVX-LABEL: load_factorf64_1: +; AVX: # BB#0: +; AVX-NEXT: vmovupd (%rdi), %ymm0 +; AVX-NEXT: vmovupd 32(%rdi), %ymm1 +; AVX-NEXT: vperm2f128 {{.*#+}} ymm0 = ymm0[0,1],mem[0,1] +; AVX-NEXT: vperm2f128 {{.*#+}} ymm1 = ymm1[0,1],mem[0,1] +; AVX-NEXT: vunpcklpd {{.*#+}} ymm0 = ymm0[0],ymm1[0],ymm0[2],ymm1[2] +; AVX-NEXT: vmulpd %ymm0, %ymm0, %ymm0 +; AVX-NEXT: retq %wide.vec = load <16 x double>, <16 x double>* %ptr, align 16 %strided.v0 = shufflevector <16 x double> %wide.vec, <16 x double> undef, <4 x i32> %strided.v3 = shufflevector <16 x double> %wide.vec, <16 x double> undef, <4 x i32> @@ -86,8 +76,8 @@ define <4 x i64> @load_factori64_4(<16 x i64>* %ptr) { ; AVX1-NEXT: vmovupd 32(%rdi), %ymm1 ; AVX1-NEXT: vmovupd 64(%rdi), %ymm2 ; AVX1-NEXT: vmovupd 96(%rdi), %ymm3 -; AVX1-NEXT: vinsertf128 $1, %xmm2, %ymm0, %ymm4 -; AVX1-NEXT: vinsertf128 $1, %xmm3, %ymm1, %ymm5 +; AVX1-NEXT: vperm2f128 {{.*#+}} ymm4 = ymm0[0,1],ymm2[0,1] +; AVX1-NEXT: vperm2f128 {{.*#+}} ymm5 = ymm1[0,1],ymm3[0,1] ; AVX1-NEXT: vperm2f128 {{.*#+}} ymm0 = ymm0[2,3],ymm2[2,3] ; AVX1-NEXT: vperm2f128 {{.*#+}} ymm1 = ymm1[2,3],ymm3[2,3] ; AVX1-NEXT: vunpcklpd {{.*#+}} ymm2 = ymm4[0],ymm5[0],ymm4[2],ymm5[2] @@ -113,8 +103,8 @@ define <4 x i64> @load_factori64_4(<16 x i64>* %ptr) { ; AVX2-NEXT: vmovdqu 32(%rdi), %ymm1 ; AVX2-NEXT: vmovdqu 64(%rdi), %ymm2 ; AVX2-NEXT: vmovdqu 96(%rdi), %ymm3 -; AVX2-NEXT: vinserti128 $1, %xmm2, %ymm0, %ymm4 -; AVX2-NEXT: vinserti128 $1, %xmm3, %ymm1, %ymm5 +; AVX2-NEXT: vperm2i128 {{.*#+}} ymm4 = ymm0[0,1],ymm2[0,1] +; AVX2-NEXT: vperm2i128 {{.*#+}} ymm5 = ymm1[0,1],ymm3[0,1] ; AVX2-NEXT: vperm2i128 {{.*#+}} ymm0 = ymm0[2,3],ymm2[2,3] ; AVX2-NEXT: vperm2i128 {{.*#+}} ymm1 = ymm1[2,3],ymm3[2,3] ; AVX2-NEXT: vpunpcklqdq {{.*#+}} ymm2 = ymm4[0],ymm5[0],ymm4[2],ymm5[2] diff --git a/test/DebugInfo/COFF/array-odr-violation.ll b/test/DebugInfo/COFF/array-odr-violation.ll index 471c18f00afd..1041a90f0343 100644 --- a/test/DebugInfo/COFF/array-odr-violation.ll +++ b/test/DebugInfo/COFF/array-odr-violation.ll @@ -65,7 +65,7 @@ attributes #1 = { nounwind readnone } !llvm.dbg.cu = !{!2, !11} !llvm.ident = !{!13, !13} -!llvm.module.flags = !{!14, !18, !19, !20} +!llvm.module.flags = !{!18, !19, !20} !0 = !DIGlobalVariableExpression(var: !1) !1 = distinct !DIGlobalVariable(name: "a", linkageName: "\01?a@@3TYYSTYPE@@A", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) @@ -81,10 +81,6 @@ attributes #1 = { nounwind readnone } !11 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !12, producer: "clang version 5.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4) !12 = !DIFile(filename: "b.cpp", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "9cfd390d8827beab36769147bb037abc") !13 = !{!"clang version 5.0.0 "} -!14 = !{i32 6, !"Linker Options", !15} -!15 = !{!16, !17} -!16 = !{!"/DEFAULTLIB:libcmt.lib"} -!17 = !{!"/DEFAULTLIB:oldnames.lib"} !18 = !{i32 2, !"CodeView", i32 1} !19 = !{i32 2, !"Debug Info Version", i32 3} !20 = !{i32 1, !"PIC Level", i32 2} diff --git a/test/DebugInfo/COFF/inlining-same-name.ll b/test/DebugInfo/COFF/inlining-same-name.ll index fda5a6dc6ff5..4a9c9924135d 100644 --- a/test/DebugInfo/COFF/inlining-same-name.ll +++ b/test/DebugInfo/COFF/inlining-same-name.ll @@ -39,12 +39,11 @@ define void @main(i32* %i.i) !dbg !16 { ret void } -!llvm.module.flags = !{!0, !1, !2} +!llvm.module.flags = !{!0, !1} !llvm.dbg.cu = !{!4} !0 = !{i32 2, !"CodeView", i32 1} !1 = !{i32 2, !"Debug Info Version", i32 3} -!2 = !{i32 6, !"Linker Options", !{}} !4 = distinct !DICompileUnit(language: DW_LANG_D, file: !5, producer: "LDC (http://wiki.dlang.org/LDC)", isOptimized: false, runtimeVersion: 1, emissionKind: FullDebug) !5 = !DIFile(filename: "opover2.d", directory: "C:\5CLDC\5Cninja-ldc\5C..\5Cldc\5Ctests\5Cd2\5Cdmd-testsuite\5Crunnable") !6 = !DILocation(line: 302, column: 9, scope: !7, inlinedAt: !15) diff --git a/test/DebugInfo/Generic/block-asan.ll b/test/DebugInfo/Generic/block-asan.ll index f1f8b35df27c..73df59bf3d5d 100644 --- a/test/DebugInfo/Generic/block-asan.ll +++ b/test/DebugInfo/Generic/block-asan.ll @@ -13,7 +13,7 @@ ; Check that the location of the ASAN instrumented __block variable is ; correct. -; CHECK: !DIExpression(DW_OP_plus, 8, DW_OP_deref, DW_OP_plus, 24) +; CHECK: !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref, DW_OP_plus_uconst, 24) target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" @@ -79,7 +79,7 @@ attributes #3 = { nounwind } !19 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed) !20 = !DIDerivedType(tag: DW_TAG_member, name: "__size", size: 32, align: 32, offset: 160, file: !1, scope: !5, baseType: !19) !21 = !DIDerivedType(tag: DW_TAG_member, name: "x", size: 32, align: 32, offset: 192, file: !1, scope: !5, baseType: !19) -!22 = !DIExpression(DW_OP_plus, 8, DW_OP_deref, DW_OP_plus, 24) +!22 = !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref, DW_OP_plus_uconst, 24) !23 = !DILocation(line: 4, column: 15, scope: !4) !24 = !DILocation(line: 4, column: 3, scope: !4) !25 = !DILocation(line: 5, column: 3, scope: !4) diff --git a/test/DebugInfo/Inputs/dwarfdump-str-offsets-dwp.x86_64.o b/test/DebugInfo/Inputs/dwarfdump-str-offsets-dwp.x86_64.o new file mode 100644 index 0000000000000000000000000000000000000000..b3c73f72d2465c6b3769f9a3f95891919418be2a GIT binary patch literal 3328 zcmb_ePique5U-gwA&P=w6*c%L8+TRwlQtVL4y53Bs>;?}O^t`HH{a#hQ_qyxN(<{GU zEfxykqyU$pZ#fj;?asblVYLE#ka@k<3KnZYI68ZK`sUTqr8o+f7s423qQ#}=!_cp` znu%Y6iF?svIFW?yWMZaT+U_lH_m*L9ZK*f$kF{G#yu3g$`fwR~a2a-EH3L%IK^#xw zGbGp?j`R3v&PBAZ;Nv(CP+!HTFbuzrcq8!vZv>z?T_6>}`w7T~VSEOlK$CFQJQlOT zqs%NabG1>Oog5nm!isPhe?8n>&3M_}+WffDF^nQHc@E73*xKl9Y<9Lbq1)+hb)icq zL^zGa8^lM;eldQ*k#x$q&*(PCrX<1eoW$jDJey+-aV}{P^}hwD)oA%F@vmzT^}6s449|sc zI7E*?;)(XzmXC;9uH!W>_JE>g=QD=2>L==nX@!k7m`7j=Y_2s*Mvg|ioLHNko3q3mt zA0;qXE&CVzc2bKIm{Iy%wWRRA-cDklctJCUR4?`P-W?^WYxQ~@u8aq(kxNc9qDG?~ zChZiC!-q9jC|*v2rj;Z48&b2?h!{-kUJ2uNGipiY&Pr={7G8_E5@)6J63m55CkLxk z7kQLXN{w_4e%K0Rt4K>XD#a*9iaBi@qb0REjJMYodF(C6t=*66_d~pT8+ehIGxjDu z52}dwm`2$owSj)U)()AI;lqmZTzuAahH`%Sv5AutJIAHgRmz&0=EjYeb!C!dU75ag zU70Sot~56N8Oo@gW9RrNHo1O`JjOne)eWA>l`&p^8|b9@ z=QRoSirDK0clq7;7y6y9sqe(F_qOFe$(g@Pi1t3R^FQUxKP5!h_grmu{s(l}Jt6L> zY^d88`Ugvp>#y$q=^$ofA_VFE2w?9=%YBX9to(mwStOQvmZ%)JRU5yNshV>J9czaj_J>aU zu*%VQ2Ygh`YX_b7hdy~@udK9Z8~T47K9vK-?d7VH-^7=d0K6KbU zD(707+~Y_u?LjN?)fd^*rPO1vv}ajC?ys5G-CB2P^Q>{*3fcSz3Bqpqy}?XL(Iqp9 zJ#y%+4vq2I^$q==z*yONRqDTUwXb)#E8m>n*FLk^bfnF-sHfzBXV2Apoo$XSPpvvn)(NtMCGwZ9pdkWW8hAgz)N?mjLwJd{fAc1`J?RdK~Z`ZQ{ zt0m9fn4b~so|SjnIWQ0x8WC0fmu;O}q#c&Df5a9ZkBEEqE5*UHA0CKyo;WApDp&2> zdH9TB$|_fO_ZLqON_I}3v}m+XiK^CZRqM*j)kHE*DGO6;r3H${xw6#8PinU;e{Dm2 z>gC?piN6VI=<7~9M9%$F2w1qkyfQlGdRCh1?d^^YPd$+LwDv{3GA+2~Z%-zC7}fMc`vtQmaMt^Qny_o3>vjoY9m3r9&8^35^#c{M z`nyFN*1WU*>3C^Pkd#QuCWnkRNQ!FR+VXaR&O{L%+eZyU>hkh(4Uvpj1_u|)FBG0T zr@a&q{%*?Dz#YPSot>@=nT}JZ7B3E+*|RF`{ob7uI}(XKY{Kd1XfhaMI_UJuSSX)w zHyT%GSE;R5@@J|VOg69*qODS!D&#eKi`7tVlFtwnfIo)6h&I1JfW(p z#+WR^rYAz=MEId3sVgRuTA5@@WJu^XS}mGlQ@s{Kl7Y_~Cu&>B z&d_J~|1)POJTHH9Omy*?$DN-Q=UF3c^TKT(Sf;mlcC^fUAv!vvHM+gNwPkxry)%2e zYwP*O&LfVJ`sUU?r|XULjjqfF*MnQYixUq{+kY!-lclbp zV6R29fA;d1m;P|wvt+4p*OGb*G1SCQK{1h^I3h z`vP3Nd$F9qj_JP;;o?*H6~kdhe0SIfWQzQupW{rQ!{PV|%IEMKOkc|3{YA1}?i=*8jp=W2IQqA7_#c@5HisW$`cV#VVR|>?us`sXM!LcTJeN~U@8|F@ znf?ujw~d9%Ssus%57KNV04847 z5)m%$-zLH#2Ky{xIQGv};t=8D{O^fyaegAy>GT?VMVVTovFK}vV9{5p1)ILsMg(oO z(Ws}NQXl4XGut(`)n>hwfh?G!Cbf}AE%f6H7<01PEJUcVRNKu&@Fg>PK^V z5u@5*B7&*frWamXP?BV|skN1)Y+1?*gMoOv6Uvq?NKuS__fyq6UCtP`?CD_fE{wHO zWiaU(qF-6I!a{o|HoeuBJRkNVm-dvLYckty)@0o(wPl6QZZs!>J*lqBpb@lMBGARy z)EdfH8-f4dlui#)d|sHa2?mbROK{L4;#BekwE>3nh^|>oz&S=-h63ZDKQb2#&tM60 z?%?|abBOmA?^89!9%C_Lc7-KHe~5=~57t6{kz(HdA-Ra!nT+=wO?>}j)&IMn`tW_k zy2wAGn7{g6tRSwFsf4euW%0OA=y#0?ClFv9&ri%z7Q4C_xK|8PnfKl72ZN9~Y(IB{ zA|gJ16Sd)9h}_6ZcK%H)51b#2B%UYk3(Oav6Y|_(ap(sa5bygk#r)MDWQDpQh!V~Z zU%!Uh_?+PXJ*&^#czx~|@ef#h4kQy1AD>BW{`&7=|19D9q5tvp;rmad7@w0uWHx&# zfL%k%wPWrEa^TLkBs-dOAY?&XR-IU diUmUb$@Jmtzep4EYlo0KENKxd2+ZI8`!7(UcEA7t literal 0 HcmV?d00001 diff --git a/test/DebugInfo/MIR/ARM/split-superreg-complex.mir b/test/DebugInfo/MIR/ARM/split-superreg-complex.mir index 2e8d9977a649..0ebde3c1eb35 100644 --- a/test/DebugInfo/MIR/ARM/split-superreg-complex.mir +++ b/test/DebugInfo/MIR/ARM/split-superreg-complex.mir @@ -57,7 +57,7 @@ !17 = !{!18} !18 = !DISubrange(count: 4) !19 = !DILocation(line: 4, column: 13, scope: !9) - !20 = !DIExpression(DW_OP_plus, 1, DW_OP_minus, 1) + !20 = !DIExpression(DW_OP_plus_uconst, 1, DW_OP_constu, 1, DW_OP_minus) !21 = !DILocation(line: 4, column: 7, scope: !9) !22 = !DILocation(line: 5, column: 9, scope: !9) !23 = !DILocation(line: 5, column: 18, scope: !9) diff --git a/test/DebugInfo/PDB/Inputs/unknown-symbol.yaml b/test/DebugInfo/PDB/Inputs/unknown-symbol.yaml new file mode 100644 index 000000000000..a2966c437879 --- /dev/null +++ b/test/DebugInfo/PDB/Inputs/unknown-symbol.yaml @@ -0,0 +1,10 @@ +--- +DbiStream: + Modules: + - Module: unknown-symbol.yaml + Modi: + Records: + - Kind: S_ANNOTATION + UnknownSym: + Data: 123456789ABCDEF0 +... diff --git a/test/DebugInfo/PDB/pdb-unknown-symbol.test b/test/DebugInfo/PDB/pdb-unknown-symbol.test new file mode 100644 index 000000000000..3d2547ee51a9 --- /dev/null +++ b/test/DebugInfo/PDB/pdb-unknown-symbol.test @@ -0,0 +1,6 @@ +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.pdb %p/Inputs/unknown-symbol.yaml +; RUN: llvm-pdbutil pdb2yaml -minimal -module-syms -no-file-headers %t.pdb | FileCheck %s + +CHECK: - Kind: S_ANNOTATION +CHECK: UnknownSym: +CHECK: Data: 123456789ABCDEF0 diff --git a/test/DebugInfo/PDB/pdb-yaml-types.test b/test/DebugInfo/PDB/pdb-yaml-types.test deleted file mode 100644 index f65d9edaa549..000000000000 --- a/test/DebugInfo/PDB/pdb-yaml-types.test +++ /dev/null @@ -1,74 +0,0 @@ -RUN: llvm-pdbutil pdb2yaml -tpi-stream %p/Inputs/big-read.pdb > %t.yaml -RUN: FileCheck -check-prefix=YAML %s < %t.yaml -RUN: llvm-pdbutil yaml2pdb %t.yaml -pdb %t.pdb -RUN: llvm-pdbutil raw -tpi-records %t.pdb | FileCheck %s --check-prefix=PDB - -Only verify the beginning of the type stream. - -YAML: TpiStream: -YAML-NEXT: Version: VC80 -YAML-NEXT: Records: -YAML-NEXT: - Kind: LF_ARGLIST -YAML-NEXT: ArgList: -YAML-NEXT: ArgIndices: [ ] -YAML-NEXT: - Kind: LF_PROCEDURE -YAML-NEXT: Procedure: -YAML-NEXT: ReturnType: 3 -YAML-NEXT: CallConv: NearC -YAML-NEXT: Options: [ None ] -YAML-NEXT: ParameterCount: 0 -YAML-NEXT: ArgumentList: 4096 -YAML-NEXT: - Kind: LF_PROCEDURE -YAML-NEXT: Procedure: -YAML-NEXT: ReturnType: 116 -YAML-NEXT: CallConv: NearC -YAML-NEXT: Options: [ None ] -YAML-NEXT: ParameterCount: 0 -YAML-NEXT: ArgumentList: 4096 - -This test is mostly checking to make sure we include the type index offset -table, and eventually hash codes. The type index offsets should be similar to -what are already present in big-read.pdb. - -PDB: Type Info Stream (TPI) { -PDB-NEXT: TPI Version: 20040203 -PDB-NEXT: Record count: 728 -PDB-NEXT: Records [ -PDB-NEXT: { -PDB-NEXT: ArgList (0x1000) { -PDB-NEXT: TypeLeafKind: LF_ARGLIST (0x1201) -PDB-NEXT: NumArgs: 0 -PDB-NEXT: Arguments [ -PDB-NEXT: ] -PDB-NEXT: } -PDB-NEXT: } -PDB-NEXT: { -PDB-NEXT: Procedure (0x1001) { -PDB-NEXT: TypeLeafKind: LF_PROCEDURE (0x1008) -PDB-NEXT: ReturnType: void (0x3) -PDB-NEXT: CallingConvention: NearC (0x0) -PDB-NEXT: FunctionOptions [ (0x0) -PDB-NEXT: ] -PDB-NEXT: NumParameters: 0 -PDB-NEXT: ArgListType: () (0x1000) -PDB-NEXT: } -PDB-NEXT: } -PDB-NEXT: { -PDB-NEXT: Procedure (0x1002) { -PDB-NEXT: TypeLeafKind: LF_PROCEDURE (0x1008) -PDB-NEXT: ReturnType: int (0x74) -PDB-NEXT: CallingConvention: NearC (0x0) -PDB-NEXT: FunctionOptions [ (0x0) -PDB-NEXT: ] -PDB-NEXT: NumParameters: 0 -PDB-NEXT: ArgListType: () (0x1000) -PDB-NEXT: } -PDB-NEXT: } -... -PDB: TypeIndexOffsets [ -PDB-NEXT: Index: 0x1000, Offset: 0 -PDB-NEXT: Index: 0x106c, Offset: 8,116 -PDB-NEXT: Index: 0x1118, Offset: 16,372 -PDB-NEXT: Index: 0x11df, Offset: 24,564 -PDB-NEXT: Index: 0x128e, Offset: 32,752 -PDB-NEXT: ] diff --git a/test/DebugInfo/PDB/pdbdump-debug-subsections.test b/test/DebugInfo/PDB/pdbdump-debug-subsections.test index 52f7bb52da2a..4338f11587ce 100644 --- a/test/DebugInfo/PDB/pdbdump-debug-subsections.test +++ b/test/DebugInfo/PDB/pdbdump-debug-subsections.test @@ -1,6 +1,5 @@ ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.pdb %p/Inputs/debug-subsections.yaml ; RUN: llvm-pdbutil pdb2yaml -all -no-file-headers %t.pdb | FileCheck --check-prefix=YAML %s -; RUN: llvm-pdbutil raw -subsections=all %t.pdb | FileCheck --check-prefix=RAW %s YAML: Modules: YAML-NEXT: - Module: Foo.obj @@ -61,150 +60,7 @@ YAML-NEXT: EndDelta: 0 YAML-NEXT: Columns: YAML-NEXT: - !InlineeLines YAML-NEXT: HasExtraFiles: false -YAML-NEXT: Sites: +YAML-NEXT: Sites: YAML-NEXT: - FileName: 'f:\dd\externalapis\windows\10\sdk\inc\winerror.h' YAML-NEXT: LineNum: 26950 YAML-NEXT: Inlinee: 22767 - - -RAW: DBI Stream { -RAW: Modules [ -RAW-NEXT: { -RAW-NEXT: Name: Foo.obj -RAW: Subsections [ -RAW-NEXT: CrossModuleExports [ -RAW-NEXT: Export { -RAW-NEXT: Local: 0x12F4 -RAW-NEXT: Global: 0x2443 -RAW-NEXT: } -RAW-NEXT: Export { -RAW-NEXT: Local: 0x80001083 -RAW-NEXT: Global: 0x23A3 -RAW-NEXT: } -RAW-NEXT: ] -RAW-NEXT: ] -RAW-NEXT: } -RAW-NEXT: { -RAW-NEXT: Name: Bar.obj -RAW: Subsections [ -RAW-NEXT: CrossModuleExports [ -RAW-NEXT: Export { -RAW-NEXT: Local: 0x10A9 -RAW-NEXT: Global: 0x17D1 -RAW-NEXT: } -RAW-NEXT: Export { -RAW-NEXT: Local: 0x10C9 -RAW-NEXT: Global: 0x1245 -RAW-NEXT: } -RAW-NEXT: ] -RAW-NEXT: CrossModuleImports [ -RAW-NEXT: ModuleImport { -RAW-NEXT: Module: Foo.obj -RAW-NEXT: Imports: [0x12F4, 0x80001083] -RAW-NEXT: } -RAW-NEXT: ] -RAW-NEXT: ] -RAW-NEXT: } -RAW-NEXT: { -RAW-NEXT: Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -RAW: Subsections [ -RAW-NEXT: FileChecksums { -RAW-NEXT: Checksum { -RAW-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp -RAW-NEXT: Kind: MD5 (0x1) -RAW-NEXT: Checksum ( -RAW-NEXT: 0000: A0A5BD0D 3ECD93FC 29D19DE8 26FBF4BC |....>...)...&...| -RAW-NEXT: ) -RAW-NEXT: } -RAW-NEXT: Checksum { -RAW-NEXT: FileName: f:\dd\externalapis\windows\10\sdk\inc\winerror.h -RAW-NEXT: Kind: MD5 (0x1) -RAW-NEXT: Checksum ( -RAW-NEXT: 0000: 1154D69F 5B265019 6E1FC34F 4134E56B |.T..[&P.n..OA4.k| -RAW-NEXT: ) -RAW-NEXT: } -RAW-NEXT: } -RAW-NEXT: Lines { -RAW-NEXT: RelocSegment: 1 -RAW-NEXT: RelocOffset: 100016 -RAW-NEXT: CodeSize: 10 -RAW-NEXT: HasColumns: No -RAW-NEXT: FileEntry { -RAW-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp -RAW-NEXT: Line { -RAW-NEXT: Offset: 0 -RAW-NEXT: LineNumberStart: 5 -RAW-NEXT: EndDelta: 0 -RAW-NEXT: IsStatement: Yes -RAW-NEXT: } -RAW-NEXT: Line { -RAW-NEXT: Offset: 3 -RAW-NEXT: LineNumberStart: 6 -RAW-NEXT: EndDelta: 0 -RAW-NEXT: IsStatement: Yes -RAW-NEXT: } -RAW-NEXT: Line { -RAW-NEXT: Offset: 8 -RAW-NEXT: LineNumberStart: 7 -RAW-NEXT: EndDelta: 0 -RAW-NEXT: IsStatement: Yes -RAW-NEXT: } -RAW-NEXT: } -RAW-NEXT: } -RAW-NEXT: InlineeLines { -RAW-NEXT: HasExtraFiles: No -RAW-NEXT: Lines [ -RAW-NEXT: Inlinee { -RAW-NEXT: FileName: f:\dd\externalapis\windows\10\sdk\inc\winerror.h -RAW-NEXT: Function { -RAW-NEXT: Index: 0x58ef (unknown function) -RAW-NEXT: } -RAW-NEXT: SourceLine: 26950 -RAW-NEXT: } -RAW-NEXT: ] -RAW-NEXT: } -RAW-NEXT: ] -RAW-NEXT: } -RAW-NEXT: { -RAW-NEXT: Name: ObjFileSubsections -RAW-NEXT: Debug Stream Index: 11 -RAW-NEXT: Object File Name: ObjFileSubsections -RAW-NEXT: Num Files: 0 -RAW-NEXT: Source File Name Idx: 0 -RAW-NEXT: Pdb File Name Idx: 0 -RAW-NEXT: Line Info Byte Size: 0 -RAW-NEXT: C13 Line Info Byte Size: 116 -RAW-NEXT: Symbol Byte Size: 4 -RAW-NEXT: Type Server Index: 0 -RAW-NEXT: Has EC Info: No -RAW-NEXT: Subsections [ -RAW-NEXT: String Table [ -RAW-NEXT: String1 -RAW-NEXT: String2 -RAW-NEXT: String3 -RAW-NEXT: ] -RAW-NEXT: Symbols [ -RAW-NEXT: { -RAW-NEXT: ObjectName { -RAW-NEXT: Signature: 0x0 -RAW-NEXT: ObjectName: ObjFileSubsections -RAW-NEXT: } -RAW-NEXT: } -RAW-NEXT: ] -RAW-NEXT: FrameData [ -RAW-NEXT: Frame { -RAW-NEXT: Rva: 6 -RAW-NEXT: CodeSize: 1 -RAW-NEXT: LocalSize: 2 -RAW-NEXT: ParamsSize: 4 -RAW-NEXT: MaxStackSize: 3 -RAW-NEXT: FrameFunc: MyFunc -RAW-NEXT: PrologSize: 5 -RAW-NEXT: SavedRegsSize: 7 -RAW-NEXT: Flags: 0 -RAW-NEXT: } -RAW-NEXT: ] -RAW-NEXT: ] -RAW-NEXT: } -RAW-NEXT: ] -RAW-NEXT: } diff --git a/test/DebugInfo/PDB/pdbdump-headers.test b/test/DebugInfo/PDB/pdbdump-headers.test index 82fe91dd20aa..fa9a25108fac 100644 --- a/test/DebugInfo/PDB/pdbdump-headers.test +++ b/test/DebugInfo/PDB/pdbdump-headers.test @@ -1,2901 +1,1082 @@ -; RUN: llvm-pdbutil raw -headers -string-table -tpi-records -tpi-record-bytes -module-syms \ -; RUN: -sym-record-bytes -globals -publics -module-files \ -; RUN: -stream-summary -stream-blocks -ipi-records -ipi-record-bytes \ -; RUN: -section-contribs -section-map -section-headers -subsections=all \ -; RUN: -tpi-hash -fpo -page-stats %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s ; RUN: llvm-pdbutil raw -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s -; RUN: llvm-pdbutil raw -headers -modules -module-files \ +; RUN: llvm-pdbutil raw -summary -modules -files \ ; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s -; RUN: not llvm-pdbutil raw -headers %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s +; RUN: not llvm-pdbutil raw -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s -; EMPTY: FileHeaders { -; EMPTY-NEXT: BlockSize: 4096 -; EMPTY-NEXT: FreeBlockMap: 2 -; EMPTY-NEXT: NumBlocks: 25 -; EMPTY-NEXT: NumDirectoryBytes: 136 -; EMPTY-NEXT: Unknown1: 0 -; EMPTY-NEXT: BlockMapAddr: 24 -; EMPTY-NEXT: NumDirectoryBlocks: 1 -; EMPTY-NEXT: DirectoryBlocks: [23] -; EMPTY-NEXT: NumStreams: 17 -; EMPTY-NEXT: } -; EMPTY-NEXT: Streams [ -; EMPTY-NEXT: Stream 0: [Old MSF Directory] (40 bytes) -; EMPTY-NEXT: Stream 1: [PDB Stream] (118 bytes) -; EMPTY-NEXT: Stream 2: [TPI Stream] (5392 bytes) -; EMPTY-NEXT: Stream 3: [DBI Stream] (739 bytes) -; EMPTY-NEXT: Stream 4: [IPI Stream] (784 bytes) -; EMPTY-NEXT: Stream 5: [Named Stream "/LinkInfo"] (0 bytes) -; EMPTY-NEXT: Stream 6: [Global Symbol Hash] (556 bytes) -; EMPTY-NEXT: Stream 7: [Public Symbol Hash] (604 bytes) -; EMPTY-NEXT: Stream 8: [Public Symbol Records] (104 bytes) -; EMPTY-NEXT: Stream 9: [Named Stream "/src/headerblock"] (0 bytes) -; EMPTY-NEXT: Stream 10: [Section Header Data] (160 bytes) -; EMPTY-NEXT: Stream 11: [New FPO Data] (32 bytes) -; EMPTY-NEXT: Stream 12: [Module "d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj"] (308 bytes) -; EMPTY-NEXT: Stream 13: [Named Stream "/names"] (239 bytes) -; EMPTY-NEXT: Stream 14: [Module "* Linker *"] (520 bytes) -; EMPTY-NEXT: Stream 15: [TPI Hash] (308 bytes) -; EMPTY-NEXT: Stream 16: [IPI Hash] (68 bytes) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Msf Free Pages: [3, 4, 5, 8, 9] -; EMPTY-NEXT: Orphaned Pages: [] -; EMPTY-NEXT: Multiply Used Pages: [] -; EMPTY-NEXT: Use After Free Pages: [] -; EMPTY-NEXT: StreamBlocks [ -; EMPTY-NEXT: Stream 0: [8] -; EMPTY-NEXT: Stream 1: [19] -; EMPTY-NEXT: Stream 2: [18, 17] -; EMPTY-NEXT: Stream 3: [14] -; EMPTY-NEXT: Stream 4: [20] -; EMPTY-NEXT: Stream 5: [] -; EMPTY-NEXT: Stream 6: [11] -; EMPTY-NEXT: Stream 7: [13] -; EMPTY-NEXT: Stream 8: [12] -; EMPTY-NEXT: Stream 9: [] -; EMPTY-NEXT: Stream 10: [10] -; EMPTY-NEXT: Stream 11: [15] -; EMPTY-NEXT: Stream 12: [6] -; EMPTY-NEXT: Stream 13: [16] -; EMPTY-NEXT: Stream 14: [7] -; EMPTY-NEXT: Stream 15: [21] -; EMPTY-NEXT: Stream 16: [22] -; EMPTY-NEXT: ] -; EMPTY-NEXT: String Table { -; EMPTY-NEXT: 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)' -; EMPTY-NEXT: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' -; EMPTY-NEXT: '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = ' -; EMPTY-NEXT: } -; EMPTY-NEXT: PDB Stream { -; EMPTY-NEXT: Version: 20000404 -; EMPTY-NEXT: Signature: 0x54E507E2 -; EMPTY-NEXT: Age: 1 -; EMPTY-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} -; EMPTY-NEXT: Features: 0x1 -; EMPTY-NEXT: Named Streams { -; EMPTY-NEXT: /names: 13 -; EMPTY-NEXT: /LinkInfo: 5 -; EMPTY-NEXT: /src/headerblock: 9 -; EMPTY-NEXT: } -; EMPTY-NEXT: } -; EMPTY-NEXT: Type Info Stream (TPI) { -; EMPTY-NEXT: TPI Version: 20040203 -; EMPTY-NEXT: Record count: 75 -; EMPTY-NEXT: Records [ -; EMPTY-NEXT: { -; EMPTY-NEXT: ArgList (0x1000) { -; EMPTY-NEXT: TypeLeafKind: LF_ARGLIST (0x1201) -; EMPTY-NEXT: NumArgs: 0 -; EMPTY-NEXT: Arguments [ -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 |....| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Procedure (0x1001) { -; EMPTY-NEXT: TypeLeafKind: LF_PROCEDURE (0x1008) -; EMPTY-NEXT: ReturnType: int (0x74) -; EMPTY-NEXT: CallingConvention: NearC (0x0) -; EMPTY-NEXT: FunctionOptions [ (0x0) -; EMPTY-NEXT: ] -; EMPTY-NEXT: NumParameters: 0 -; EMPTY-NEXT: ArgListType: () (0x1000) -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 74000000 00000000 00100000 |t...........| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: FieldList (0x1002) { -; EMPTY-NEXT: TypeLeafKind: LF_FIELDLIST (0x1203) -; EMPTY-NEXT: Enumerator { -; EMPTY-NEXT: TypeLeafKind: LF_ENUMERATE (0x1502) -; EMPTY-NEXT: AccessSpecifier: Public (0x3) -; EMPTY-NEXT: EnumValue: 1 -; EMPTY-NEXT: Name: apartment -; EMPTY-NEXT: } -; EMPTY-NEXT: Enumerator { -; EMPTY-NEXT: TypeLeafKind: LF_ENUMERATE (0x1502) -; EMPTY-NEXT: AccessSpecifier: Public (0x3) -; EMPTY-NEXT: EnumValue: 2 -; EMPTY-NEXT: Name: single -; EMPTY-NEXT: } -; EMPTY-NEXT: Enumerator { -; EMPTY-NEXT: TypeLeafKind: LF_ENUMERATE (0x1502) -; EMPTY-NEXT: AccessSpecifier: Public (0x3) -; EMPTY-NEXT: EnumValue: 3 -; EMPTY-NEXT: Name: free -; EMPTY-NEXT: } -; EMPTY-NEXT: Enumerator { -; EMPTY-NEXT: TypeLeafKind: LF_ENUMERATE (0x1502) -; EMPTY-NEXT: AccessSpecifier: Public (0x3) -; EMPTY-NEXT: EnumValue: 4 -; EMPTY-NEXT: Name: neutral -; EMPTY-NEXT: } -; EMPTY-NEXT: Enumerator { -; EMPTY-NEXT: TypeLeafKind: LF_ENUMERATE (0x1502) -; EMPTY-NEXT: AccessSpecifier: Public (0x3) -; EMPTY-NEXT: EnumValue: 5 -; EMPTY-NEXT: Name: both -; EMPTY-NEXT: } -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 02150300 01006170 6172746D 656E7400 |......apartment.| -; EMPTY-NEXT: 0010: 02150300 02007369 6E676C65 00F3F2F1 |......single....| -; EMPTY-NEXT: 0020: 02150300 03006672 656500F1 02150300 |......free......| -; EMPTY-NEXT: 0030: 04006E65 75747261 6C00F2F1 02150300 |..neutral.......| -; EMPTY-NEXT: 0040: 0500626F 746800F1 |..both..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY: Hash { -; EMPTY-NEXT: Number of Hash Buckets: 262143 -; EMPTY-NEXT: Hash Key Size: 4 -; EMPTY-NEXT: Values: [205956, 163561, 59811, 208239, 16377, 247078, 194342, 254156, 194536, 167492, 185421, 119540, 261871, 198119, 48056, 251486, 134580, 148190, 113636, 53336, 55779, 220695, 198114, 148734, 81128, 60158, 217249, 174209, 159978, 249504, 141941, 238785, 6214, 94935, 151449, 135589, 73373, 96512, 254299, 17744, 239514, 173189, 130544, 204437, 238560, 144673, 115151, 197306, 256035, 101096, 231280, 52156, 48854, 170035, 177041, 102745, 16947, 183703, 98548, 35693, 171328, 203640, 139292, 49018, 43821, 202555, 165040, 215835, 142625, 52534, 44186, 103930, 110942, 17991, 213215] -; EMPTY-NEXT: Adjusters [ -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: TypeIndexOffsets [ -; EMPTY-NEXT: Index: 0x1000, Offset: 0 -; EMPTY-NEXT: ] -; EMPTY: Type Info Stream (IPI) { -; EMPTY-NEXT: IPI Version: 20040203 -; EMPTY-NEXT: Record count: 15 -; EMPTY-NEXT: Records [ -; EMPTY-NEXT: { -; EMPTY-NEXT: UdtModSourceLine (0x1000) { -; EMPTY-NEXT: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; EMPTY-NEXT: UDT: __vc_attributes::threadingAttribute (0x100B) -; EMPTY-NEXT: SourceFile: (0x1) -; EMPTY-NEXT: LineNumber: 481 -; EMPTY-NEXT: Module: 1 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 0B100000 01000000 E1010000 0100F2F1 |................| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: UdtModSourceLine (0x1001) { -; EMPTY-NEXT: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; EMPTY-NEXT: UDT: __vc_attributes::event_receiverAttribute (0x1017) -; EMPTY-NEXT: SourceFile: (0x1) -; EMPTY-NEXT: LineNumber: 194 -; EMPTY-NEXT: Module: 1 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 17100000 01000000 C2000000 0100F2F1 |................| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: UdtModSourceLine (0x1002) { -; EMPTY-NEXT: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; EMPTY-NEXT: UDT: __vc_attributes::aggregatableAttribute (0x1021) -; EMPTY-NEXT: SourceFile: (0x1) -; EMPTY-NEXT: LineNumber: 603 -; EMPTY-NEXT: Module: 1 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 21100000 01000000 5B020000 0100F2F1 |!.......[.......| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: UdtModSourceLine (0x1003) { -; EMPTY-NEXT: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; EMPTY-NEXT: UDT: __vc_attributes::event_sourceAttribute (0x102C) -; EMPTY-NEXT: SourceFile: (0x1) -; EMPTY-NEXT: LineNumber: 1200 -; EMPTY-NEXT: Module: 1 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 2C100000 01000000 B0040000 0100F2F1 |,...............| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: UdtModSourceLine (0x1004) { -; EMPTY-NEXT: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; EMPTY-NEXT: UDT: __vc_attributes::moduleAttribute (0x103A) -; EMPTY-NEXT: SourceFile: (0x1) -; EMPTY-NEXT: LineNumber: 540 -; EMPTY-NEXT: Module: 1 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 3A100000 01000000 1C020000 0100F2F1 |:...............| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: UdtModSourceLine (0x1005) { -; EMPTY-NEXT: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; EMPTY-NEXT: UDT: __vc_attributes::helper_attributes::usageAttribute (0x1042) -; EMPTY-NEXT: SourceFile: (0x1) -; EMPTY-NEXT: LineNumber: 108 -; EMPTY-NEXT: Module: 1 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 42100000 01000000 6C000000 0100F2F1 |B.......l.......| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: UdtModSourceLine (0x1006) { -; EMPTY-NEXT: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; EMPTY-NEXT: UDT: __vc_attributes::helper_attributes::v1_alttypeAttribute (0x104A) -; EMPTY-NEXT: SourceFile: (0x1) -; EMPTY-NEXT: LineNumber: 96 -; EMPTY-NEXT: Module: 1 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 4A100000 01000000 60000000 0100F2F1 |J.......`.......| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: StringId (0x1007) { -; EMPTY-NEXT: TypeLeafKind: LF_STRING_ID (0x1605) -; EMPTY-NEXT: Id: 0x0 -; EMPTY-NEXT: StringData: d:\src\llvm\test\DebugInfo\PDB\Inputs -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 643A5C73 72635C6C 6C766D5C |....d:\src\llvm\| -; EMPTY-NEXT: 0010: 74657374 5C446562 7567496E 666F5C50 |test\DebugInfo\P| -; EMPTY-NEXT: 0020: 44425C49 6E707574 7300F2F1 |DB\Inputs...| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: StringId (0x1008) { -; EMPTY-NEXT: TypeLeafKind: LF_STRING_ID (0x1605) -; EMPTY-NEXT: Id: 0x0 -; EMPTY-NEXT: StringData: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 433A5C50 726F6772 616D2046 |....C:\Program F| -; EMPTY-NEXT: 0010: 696C6573 20287838 36295C4D 6963726F |iles (x86)\Micro| -; EMPTY-NEXT: 0020: 736F6674 20566973 75616C20 53747564 |soft Visual Stud| -; EMPTY-NEXT: 0030: 696F2031 322E305C 56435C42 494E5C63 |io 12.0\VC\BIN\c| -; EMPTY-NEXT: 0040: 6C2E6578 6500F2F1 |l.exe...| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: StringId (0x1009) { -; EMPTY-NEXT: TypeLeafKind: LF_STRING_ID (0x1605) -; EMPTY-NEXT: Id: 0x0 -; EMPTY-NEXT: StringData: empty.cpp -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 656D7074 792E6370 7000F2F1 |....empty.cpp...| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: StringId (0x100A) { -; EMPTY-NEXT: TypeLeafKind: LF_STRING_ID (0x1605) -; EMPTY-NEXT: Id: 0x0 -; EMPTY-NEXT: StringData: d:\src\llvm\test\DebugInfo\PDB\Inputs\vc120.pdb -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 643A5C73 72635C6C 6C766D5C |....d:\src\llvm\| -; EMPTY-NEXT: 0010: 74657374 5C446562 7567496E 666F5C50 |test\DebugInfo\P| -; EMPTY-NEXT: 0020: 44425C49 6E707574 735C7663 3132302E |DB\Inputs\vc120.| -; EMPTY-NEXT: 0030: 70646200 |pdb.| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: StringId (0x100B) { -; EMPTY-NEXT: TypeLeafKind: LF_STRING_ID (0x1605) -; EMPTY-NEXT: Id: 0x0 -; EMPTY-NEXT: StringData: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 2D5A6920 2D4D5420 2D492243 |....-Zi -MT -I"C| -; EMPTY-NEXT: 0010: 3A5C5072 6F677261 6D204669 6C657320 |:\Program Files | -; EMPTY-NEXT: 0020: 28783836 295C4D69 63726F73 6F667420 |(x86)\Microsoft | -; EMPTY-NEXT: 0030: 56697375 616C2053 74756469 6F203132 |Visual Studio 12| -; EMPTY-NEXT: 0040: 2E305C56 435C494E 434C5544 4522202D |.0\VC\INCLUDE" -| -; EMPTY-NEXT: 0050: 4922433A 5C50726F 6772616D 2046696C |I"C:\Program Fil| -; EMPTY-NEXT: 0060: 65732028 78383629 5C4D6963 726F736F |es (x86)\Microso| -; EMPTY-NEXT: 0070: 66742056 69737561 6C205374 7564696F |ft Visual Studio| -; EMPTY-NEXT: 0080: 2031322E 305C5643 5C41544C 4D46435C | 12.0\VC\ATLMFC\| -; EMPTY-NEXT: 0090: 494E434C 55444522 202D4922 433A5C50 |INCLUDE" -I"C:\P| -; EMPTY-NEXT: 00A0: 726F6772 616D2046 696C6573 20287838 |rogram Files (x8| -; EMPTY-NEXT: 00B0: 36295C57 696E646F 7773204B 6974735C |6)\Windows Kits\| -; EMPTY-NEXT: 00C0: 382E315C 696E636C 7564655C 73686172 |8.1\include\shar| -; EMPTY-NEXT: 00D0: 65642220 2D492243 3A5C5072 6F677261 |ed" -I"C:\Progra| -; EMPTY-NEXT: 00E0: 6D204669 6C657320 28783836 295C5769 |m Files (x86)\Wi| -; EMPTY-NEXT: 00F0: 6E646F77 7300F2F1 |ndows...| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: StringList (0x100C) { -; EMPTY-NEXT: TypeLeafKind: LF_SUBSTR_LIST (0x1604) -; EMPTY-NEXT: NumStrings: 1 -; EMPTY-NEXT: Strings [ -; EMPTY-NEXT: String: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 01000000 0B100000 |........| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: StringId (0x100D) { -; EMPTY-NEXT: TypeLeafKind: LF_STRING_ID (0x1605) -; EMPTY-NEXT: Id: "-Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows" (0x100C) -; EMPTY-NEXT: StringData: Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TP -X -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 0C100000 204B6974 735C382E 315C696E |.... Kits\8.1\in| -; EMPTY-NEXT: 0010: 636C7564 655C756D 22202D49 22433A5C |clude\um" -I"C:\| -; EMPTY-NEXT: 0020: 50726F67 72616D20 46696C65 73202878 |Program Files (x| -; EMPTY-NEXT: 0030: 3836295C 57696E64 6F777320 4B697473 |86)\Windows Kits| -; EMPTY-NEXT: 0040: 5C382E31 5C696E63 6C756465 5C77696E |\8.1\include\win| -; EMPTY-NEXT: 0050: 72742220 2D545020 2D5800F1 |rt" -TP -X..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: BuildInfo (0x100E) { -; EMPTY-NEXT: TypeLeafKind: LF_BUILDINFO (0x1603) -; EMPTY-NEXT: NumArgs: 5 -; EMPTY-NEXT: Arguments [ -; EMPTY-NEXT: ArgType: d:\src\llvm\test\DebugInfo\PDB\Inputs (0x1007) -; EMPTY-NEXT: ArgType: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe (0x1008) -; EMPTY-NEXT: ArgType: empty.cpp (0x1009) -; EMPTY-NEXT: ArgType: d:\src\llvm\test\DebugInfo\PDB\Inputs\vc120.pdb (0x100A) -; EMPTY-NEXT: ArgType: Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TP -X (0x100D) -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 05000710 00000810 00000910 00000A10 |................| -; EMPTY-NEXT: 0010: 00000D10 0000F2F1 |........| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: TypeIndexOffsets [ -; EMPTY-NEXT: Index: 0x1000, Offset: 0 -; EMPTY-NEXT: ] -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY: DBI Stream { -; EMPTY-NEXT: Dbi Version: 19990903 -; EMPTY-NEXT: Age: 1 -; EMPTY-NEXT: Incremental Linking: Yes -; EMPTY-NEXT: Has CTypes: No -; EMPTY-NEXT: Is Stripped: No -; EMPTY-NEXT: Machine Type: x86 -; EMPTY-NEXT: Symbol Record Stream Index: 8 -; EMPTY-NEXT: Public Symbol Stream Index: 7 -; EMPTY-NEXT: Global Symbol Stream Index: 6 -; EMPTY-NEXT: Toolchain Version: 12.0 -; EMPTY-NEXT: mspdb120.dll version: 12.0.31101 -; EMPTY-NEXT: Modules [ -; EMPTY-NEXT: { -; EMPTY-NEXT: Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; EMPTY-NEXT: Debug Stream Index: 12 -; EMPTY-NEXT: Object File Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; EMPTY-NEXT: Num Files: 1 -; EMPTY-NEXT: Source File Name Idx: 0 -; EMPTY-NEXT: Pdb File Name Idx: 0 -; EMPTY-NEXT: Line Info Byte Size: 0 -; EMPTY-NEXT: C13 Line Info Byte Size: 88 -; EMPTY-NEXT: Symbol Byte Size: 208 -; EMPTY-NEXT: Type Server Index: 0 -; EMPTY-NEXT: Has EC Info: No -; EMPTY-NEXT: 1 Contributing Source Files [ -; EMPTY-NEXT: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp -; EMPTY-NEXT: ] -; EMPTY-NEXT: Symbols [ -; EMPTY-NEXT: { -; EMPTY-NEXT: ObjectName { -; EMPTY-NEXT: Signature: 0x0 -; EMPTY-NEXT: ObjectName: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 643A5C73 72635C6C 6C766D5C |....d:\src\llvm\| -; EMPTY-NEXT: 0010: 74657374 5C446562 7567496E 666F5C50 |test\DebugInfo\P| -; EMPTY-NEXT: 0020: 44425C49 6E707574 735C656D 7074792E |DB\Inputs\empty.| -; EMPTY-NEXT: 0030: 6F626A00 |obj.| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: CompilerFlags3 { -; EMPTY-NEXT: Language: Cpp (0x1) -; EMPTY-NEXT: Flags [ (0x2000) -; EMPTY-NEXT: SecurityChecks (0x2000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Machine: Pentium3 (0x7) -; EMPTY-NEXT: FrontendVersion: 18.0.31101.0 -; EMPTY-NEXT: BackendVersion: 18.0.31101.0 -; EMPTY-NEXT: VersionName: Microsoft (R) Optimizing Compiler -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 01200000 07001200 00007D79 00001200 |. ........}y....| -; EMPTY-NEXT: 0010: 00007D79 00004D69 63726F73 6F667420 |..}y..Microsoft | -; EMPTY-NEXT: 0020: 28522920 4F707469 6D697A69 6E672043 |(R) Optimizing C| -; EMPTY-NEXT: 0030: 6F6D7069 6C657200 |ompiler.| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: ProcStart { -; EMPTY-NEXT: Kind: S_GPROC32 (0x1110) -; EMPTY-NEXT: PtrParent: 0x0 -; EMPTY-NEXT: PtrEnd: 0xC4 -; EMPTY-NEXT: PtrNext: 0x0 -; EMPTY-NEXT: CodeSize: 0xA -; EMPTY-NEXT: DbgStart: 0x3 -; EMPTY-NEXT: DbgEnd: 0x8 -; EMPTY-NEXT: FunctionType: int () (0x1001) -; EMPTY-NEXT: Segment: 0x1 -; EMPTY-NEXT: Flags [ (0x1) -; EMPTY-NEXT: HasFP (0x1) -; EMPTY-NEXT: ] -; EMPTY-NEXT: DisplayName: main -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 C4000000 00000000 0A000000 |................| -; EMPTY-NEXT: 0010: 03000000 08000000 01100000 10000000 |................| -; EMPTY-NEXT: 0020: 0100016D 61696E00 |...main.| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: FrameProc { -; EMPTY-NEXT: TotalFrameBytes: 0x0 -; EMPTY-NEXT: PaddingFrameBytes: 0x0 -; EMPTY-NEXT: OffsetToPadding: 0x0 -; EMPTY-NEXT: BytesOfCalleeSavedRegisters: 0x0 -; EMPTY-NEXT: OffsetOfExceptionHandler: 0x0 -; EMPTY-NEXT: SectionIdOfExceptionHandler: 0x0 -; EMPTY-NEXT: Flags [ (0x128200) -; EMPTY-NEXT: AsynchronousExceptionHandling (0x200) -; EMPTY-NEXT: OptimizedForSpeed (0x100000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| -; EMPTY-NEXT: 0010: 00000000 00000082 12000000 |............| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: BlockEnd { -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: BuildInfo { -; EMPTY-NEXT: BuildId: 4110 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 0E100000 |....| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: ] -; EMPTY-NEXT: Subsections [ -; EMPTY-NEXT: Lines { -; EMPTY-NEXT: RelocSegment: 1 -; EMPTY-NEXT: RelocOffset: 16 -; EMPTY-NEXT: CodeSize: 10 -; EMPTY-NEXT: HasColumns: No -; EMPTY-NEXT: FileEntry { -; EMPTY-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp -; EMPTY-NEXT: Line { -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: LineNumberStart: 5 -; EMPTY-NEXT: EndDelta: 0 -; EMPTY-NEXT: IsStatement: Yes -; EMPTY-NEXT: } -; EMPTY-NEXT: Line { -; EMPTY-NEXT: Offset: 3 -; EMPTY-NEXT: LineNumberStart: 6 -; EMPTY-NEXT: EndDelta: 0 -; EMPTY-NEXT: IsStatement: Yes -; EMPTY-NEXT: } -; EMPTY-NEXT: Line { -; EMPTY-NEXT: Offset: 8 -; EMPTY-NEXT: LineNumberStart: 7 -; EMPTY-NEXT: EndDelta: 0 -; EMPTY-NEXT: IsStatement: Yes -; EMPTY-NEXT: } -; EMPTY-NEXT: } -; EMPTY-NEXT: } -; EMPTY-NEXT: FileChecksums { -; EMPTY-NEXT: Checksum { -; EMPTY-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp -; EMPTY-NEXT: Kind: MD5 (0x1) -; EMPTY-NEXT: Checksum ( -; EMPTY-NEXT: 0000: A0A5BD0D 3ECD93FC 29D19DE8 26FBF4BC |....>...)...&...| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: } -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Name: * Linker * -; EMPTY-NEXT: Debug Stream Index: 14 -; EMPTY-NEXT: Object File Name: -; EMPTY-NEXT: Num Files: 0 -; EMPTY-NEXT: Source File Name Idx: 0 -; EMPTY-NEXT: Pdb File Name Idx: 1 -; EMPTY-NEXT: Line Info Byte Size: 0 -; EMPTY-NEXT: C13 Line Info Byte Size: 0 -; EMPTY-NEXT: Symbol Byte Size: 516 -; EMPTY-NEXT: Type Server Index: 0 -; EMPTY-NEXT: Has EC Info: No -; EMPTY-NEXT: 0 Contributing Source Files [ -; EMPTY-NEXT: ] -; EMPTY-NEXT: Symbols [ -; EMPTY-NEXT: { -; EMPTY-NEXT: ObjectName { -; EMPTY-NEXT: Signature: 0x0 -; EMPTY-NEXT: ObjectName: * Linker * -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 2A204C69 6E6B6572 202A0000 |....* Linker *..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: CompilerFlags3 { -; EMPTY-NEXT: Language: Link (0x7) -; EMPTY-NEXT: Flags [ (0x0) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Machine: Intel80386 (0x3) -; EMPTY-NEXT: FrontendVersion: 0.0.0.0 -; EMPTY-NEXT: BackendVersion: 12.0.31101.0 -; EMPTY-NEXT: VersionName: Microsoft (R) LINK -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 07000000 03000000 00000000 00000C00 |................| -; EMPTY-NEXT: 0010: 00007D79 00004D69 63726F73 6F667420 |..}y..Microsoft | -; EMPTY-NEXT: 0020: 28522920 4C494E4B 00000000 |(R) LINK....| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: EnvBlock { -; EMPTY-NEXT: Entries [ -; EMPTY-NEXT: cwd -; EMPTY-NEXT: d:\src\llvm\test\DebugInfo\PDB\Inputs -; EMPTY-NEXT: exe -; EMPTY-NEXT: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\link.exe -; EMPTY-NEXT: pdb -; EMPTY-NEXT: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.pdb -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00637764 00643A5C 7372635C 6C6C766D |.cwd.d:\src\llvm| -; EMPTY-NEXT: 0010: 5C746573 745C4465 62756749 6E666F5C |\test\DebugInfo\| -; EMPTY-NEXT: 0020: 5044425C 496E7075 74730065 78650043 |PDB\Inputs.exe.C| -; EMPTY-NEXT: 0030: 3A5C5072 6F677261 6D204669 6C657320 |:\Program Files | -; EMPTY-NEXT: 0040: 28783836 295C4D69 63726F73 6F667420 |(x86)\Microsoft | -; EMPTY-NEXT: 0050: 56697375 616C2053 74756469 6F203132 |Visual Studio 12| -; EMPTY-NEXT: 0060: 2E305C56 435C4249 4E5C6C69 6E6B2E65 |.0\VC\BIN\link.e| -; EMPTY-NEXT: 0070: 78650070 64620064 3A5C7372 635C6C6C |xe.pdb.d:\src\ll| -; EMPTY-NEXT: 0080: 766D5C74 6573745C 44656275 67496E66 |vm\test\DebugInf| -; EMPTY-NEXT: 0090: 6F5C5044 425C496E 70757473 5C656D70 |o\PDB\Inputs\emp| -; EMPTY-NEXT: 00A0: 74792E70 64620000 |ty.pdb..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Trampoline { -; EMPTY-NEXT: Type: TrampIncremental (0x0) -; EMPTY-NEXT: Size: 5 -; EMPTY-NEXT: ThunkOff: 5 -; EMPTY-NEXT: TargetOff: 16 -; EMPTY-NEXT: ThunkSection: 1 -; EMPTY-NEXT: TargetSection: 1 -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000500 05000000 10000000 01000100 |................| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Section { -; EMPTY-NEXT: SectionNumber: 1 -; EMPTY-NEXT: Alignment: 12 -; EMPTY-NEXT: Rva: 4096 -; EMPTY-NEXT: Length: 4122 -; EMPTY-NEXT: Characteristics [ (0x60000020) -; EMPTY-NEXT: IMAGE_SCN_CNT_CODE (0x20) -; EMPTY-NEXT: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Name: .text -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 01000C00 00100000 1A100000 20000060 |............ ..`| -; EMPTY-NEXT: 0010: 2E746578 74000000 |.text...| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: COFF Group { -; EMPTY-NEXT: Size: 4122 -; EMPTY-NEXT: Characteristics [ (0x60000020) -; EMPTY-NEXT: IMAGE_SCN_CNT_CODE (0x20) -; EMPTY-NEXT: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: Segment: 1 -; EMPTY-NEXT: Name: .text$mn -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 1A100000 20000060 00000000 01002E74 |.... ..`.......t| -; EMPTY-NEXT: 0010: 65787424 6D6E0000 |ext$mn..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Section { -; EMPTY-NEXT: SectionNumber: 2 -; EMPTY-NEXT: Alignment: 12 -; EMPTY-NEXT: Rva: 12288 -; EMPTY-NEXT: Length: 690 -; EMPTY-NEXT: Characteristics [ (0x40000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Name: .rdata -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 02000C00 00300000 B2020000 40000040 |.....0......@..@| -; EMPTY-NEXT: 0010: 2E726461 74610000 |.rdata..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: COFF Group { -; EMPTY-NEXT: Size: 323 -; EMPTY-NEXT: Characteristics [ (0x40000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: Segment: 2 -; EMPTY-NEXT: Name: .rdata -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 43010000 40000040 00000000 02002E72 |C...@..@.......r| -; EMPTY-NEXT: 0010: 64617461 00000000 |data....| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: COFF Group { -; EMPTY-NEXT: Size: 0 -; EMPTY-NEXT: Characteristics [ (0x40000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Offset: 323 -; EMPTY-NEXT: Segment: 2 -; EMPTY-NEXT: Name: .edata -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 40000040 43010000 02002E65 |....@..@C......e| -; EMPTY-NEXT: 0010: 64617461 00000000 |data....| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: COFF Group { -; EMPTY-NEXT: Size: 366 -; EMPTY-NEXT: Characteristics [ (0x40000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Offset: 324 -; EMPTY-NEXT: Segment: 2 -; EMPTY-NEXT: Name: .rdata$debug -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 6E010000 40000040 44010000 02002E72 |n...@..@D......r| -; EMPTY-NEXT: 0010: 64617461 24646562 75670000 |data$debug..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Section { -; EMPTY-NEXT: SectionNumber: 3 -; EMPTY-NEXT: Alignment: 12 -; EMPTY-NEXT: Rva: 16384 -; EMPTY-NEXT: Length: 4 -; EMPTY-NEXT: Characteristics [ (0xC0000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Name: .data -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 03000C00 00400000 04000000 400000C0 |.....@......@...| -; EMPTY-NEXT: 0010: 2E646174 61000000 |.data...| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: COFF Group { -; EMPTY-NEXT: Size: 4 -; EMPTY-NEXT: Characteristics [ (0xC0000080) -; EMPTY-NEXT: IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: Segment: 3 -; EMPTY-NEXT: Name: .bss -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 04000000 800000C0 00000000 03002E62 |...............b| -; EMPTY-NEXT: 0010: 73730000 |ss..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Section { -; EMPTY-NEXT: SectionNumber: 4 -; EMPTY-NEXT: Alignment: 12 -; EMPTY-NEXT: Rva: 20480 -; EMPTY-NEXT: Length: 8 -; EMPTY-NEXT: Characteristics [ (0x42000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_DISCARDABLE (0x2000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Name: .reloc -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 04000C00 00500000 08000000 40000042 |.....P......@..B| -; EMPTY-NEXT: 0010: 2E72656C 6F630000 |.reloc..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: ] -; EMPTY-NEXT: Subsections [ -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: Section Contributions [ -; EMPTY-NEXT: Contribution { -; EMPTY-NEXT: ISect: 1 -; EMPTY-NEXT: Off: 0 -; EMPTY-NEXT: Size: 10 -; EMPTY-NEXT: Characteristics [ (0x60000020) -; EMPTY-NEXT: IMAGE_SCN_CNT_CODE (0x20) -; EMPTY-NEXT: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Module { -; EMPTY-NEXT: Index: 1 -; EMPTY-NEXT: Name: * Linker * -; EMPTY-NEXT: } -; EMPTY-NEXT: Data CRC: 0 -; EMPTY-NEXT: Reloc CRC: 0 -; EMPTY-NEXT: } -; EMPTY-NEXT: Contribution { -; EMPTY-NEXT: ISect: 1 -; EMPTY-NEXT: Off: 16 -; EMPTY-NEXT: Size: 10 -; EMPTY-NEXT: Characteristics [ (0x60500020) -; EMPTY-NEXT: IMAGE_SCN_ALIGN_16BYTES (0x500000) -; EMPTY-NEXT: IMAGE_SCN_CNT_CODE (0x20) -; EMPTY-NEXT: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Module { -; EMPTY-NEXT: Index: 0 -; EMPTY-NEXT: Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; EMPTY-NEXT: } -; EMPTY-NEXT: Data CRC: 3617027124 -; EMPTY-NEXT: Reloc CRC: 0 -; EMPTY-NEXT: } -; EMPTY-NEXT: Contribution { -; EMPTY-NEXT: ISect: 2 -; EMPTY-NEXT: Off: 0 -; EMPTY-NEXT: Size: 56 -; EMPTY-NEXT: Characteristics [ (0x40000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Module { -; EMPTY-NEXT: Index: 1 -; EMPTY-NEXT: Name: * Linker * -; EMPTY-NEXT: } -; EMPTY-NEXT: Data CRC: 0 -; EMPTY-NEXT: Reloc CRC: 0 -; EMPTY-NEXT: } -; EMPTY-NEXT: Contribution { -; EMPTY-NEXT: ISect: 2 -; EMPTY-NEXT: Off: 324 -; EMPTY-NEXT: Size: 72 -; EMPTY-NEXT: Characteristics [ (0x40300040) -; EMPTY-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Module { -; EMPTY-NEXT: Index: 1 -; EMPTY-NEXT: Name: * Linker * -; EMPTY-NEXT: } -; EMPTY-NEXT: Data CRC: 0 -; EMPTY-NEXT: Reloc CRC: 0 -; EMPTY-NEXT: } -; EMPTY-NEXT: Contribution { -; EMPTY-NEXT: ISect: 2 -; EMPTY-NEXT: Off: 396 -; EMPTY-NEXT: Size: 20 -; EMPTY-NEXT: Characteristics [ (0x40300040) -; EMPTY-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Module { -; EMPTY-NEXT: Index: 1 -; EMPTY-NEXT: Name: * Linker * -; EMPTY-NEXT: } -; EMPTY-NEXT: Data CRC: 0 -; EMPTY-NEXT: Reloc CRC: 0 -; EMPTY-NEXT: } -; EMPTY-NEXT: Contribution { -; EMPTY-NEXT: ISect: 3 -; EMPTY-NEXT: Off: 0 -; EMPTY-NEXT: Size: 4 -; EMPTY-NEXT: Characteristics [ (0xC0300080) -; EMPTY-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000) -; EMPTY-NEXT: IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Module { -; EMPTY-NEXT: Index: 0 -; EMPTY-NEXT: Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; EMPTY-NEXT: } -; EMPTY-NEXT: Data CRC: 0 -; EMPTY-NEXT: Reloc CRC: 0 -; EMPTY-NEXT: } -; EMPTY-NEXT: ] -; EMPTY-NEXT: Section Map [ -; EMPTY-NEXT: Entry { -; EMPTY-NEXT: Flags [ (0x10D) -; EMPTY-NEXT: AddressIs32Bit (0x8) -; EMPTY-NEXT: Execute (0x4) -; EMPTY-NEXT: IsSelector (0x100) -; EMPTY-NEXT: Read (0x1) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Ovl: 0 -; EMPTY-NEXT: Group: 0 -; EMPTY-NEXT: Frame: 1 -; EMPTY-NEXT: SecName: 65535 -; EMPTY-NEXT: ClassName: 65535 -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: SecByteLength: 4122 -; EMPTY-NEXT: } -; EMPTY-NEXT: Entry { -; EMPTY-NEXT: Flags [ (0x109) -; EMPTY-NEXT: AddressIs32Bit (0x8) -; EMPTY-NEXT: IsSelector (0x100) -; EMPTY-NEXT: Read (0x1) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Ovl: 0 -; EMPTY-NEXT: Group: 0 -; EMPTY-NEXT: Frame: 2 -; EMPTY-NEXT: SecName: 65535 -; EMPTY-NEXT: ClassName: 65535 -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: SecByteLength: 690 -; EMPTY-NEXT: } -; EMPTY-NEXT: Entry { -; EMPTY-NEXT: Flags [ (0x10B) -; EMPTY-NEXT: AddressIs32Bit (0x8) -; EMPTY-NEXT: IsSelector (0x100) -; EMPTY-NEXT: Read (0x1) -; EMPTY-NEXT: Write (0x2) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Ovl: 0 -; EMPTY-NEXT: Group: 0 -; EMPTY-NEXT: Frame: 3 -; EMPTY-NEXT: SecName: 65535 -; EMPTY-NEXT: ClassName: 65535 -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: SecByteLength: 4 -; EMPTY-NEXT: } -; EMPTY-NEXT: Entry { -; EMPTY-NEXT: Flags [ (0x109) -; EMPTY-NEXT: AddressIs32Bit (0x8) -; EMPTY-NEXT: IsSelector (0x100) -; EMPTY-NEXT: Read (0x1) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Ovl: 0 -; EMPTY-NEXT: Group: 0 -; EMPTY-NEXT: Frame: 4 -; EMPTY-NEXT: SecName: 65535 -; EMPTY-NEXT: ClassName: 65535 -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: SecByteLength: 8 -; EMPTY-NEXT: } -; EMPTY-NEXT: Entry { -; EMPTY-NEXT: Flags [ (0x208) -; EMPTY-NEXT: AddressIs32Bit (0x8) -; EMPTY-NEXT: IsAbsoluteAddress (0x200) -; EMPTY-NEXT: ] -; EMPTY-NEXT: Ovl: 0 -; EMPTY-NEXT: Group: 0 -; EMPTY-NEXT: Frame: 0 -; EMPTY-NEXT: SecName: 65535 -; EMPTY-NEXT: ClassName: 65535 -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: SecByteLength: 4294967295 -; EMPTY-NEXT: } -; EMPTY-NEXT: ] -; EMPTY-NEXT: Globals Stream { -; EMPTY-NEXT: Stream number: 6 -; EMPTY-NEXT: Number of buckets: 2 -; EMPTY-NEXT: Hash Buckets: [0, 12] -; EMPTY-NEXT: } -; EMPTY-NEXT: Publics Stream { -; EMPTY-NEXT: Stream number: 7 -; EMPTY-NEXT: SymHash: 556 -; EMPTY-NEXT: AddrMap: 8 -; EMPTY-NEXT: Number of buckets: 2 -; EMPTY-NEXT: Hash Buckets: [0, 12] -; EMPTY-NEXT: Address Map: [36, 0] -; EMPTY-NEXT: Thunk Map: [4112] -; EMPTY-NEXT: Section Offsets: [4096, 1] -; EMPTY-NEXT: Symbols [ -; EMPTY-NEXT: { -; EMPTY-NEXT: PublicSym { -; EMPTY-NEXT: Type: 0 -; EMPTY-NEXT: Seg: 3 -; EMPTY-NEXT: Off: 0 -; EMPTY-NEXT: Name: ?__purecall@@3PAXA -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 00000000 03003F5F 5F707572 |..........?__pur| -; EMPTY-NEXT: 0010: 6563616C 6C404033 50415841 00000000 |ecall@@3PAXA....| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: PublicSym { -; EMPTY-NEXT: Type: 2 -; EMPTY-NEXT: Seg: 1 -; EMPTY-NEXT: Off: 16 -; EMPTY-NEXT: Name: _main -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 02000000 10000000 01005F6D 61696E00 |.........._main.| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: ProcRef { -; EMPTY-NEXT: SumName: 0 -; EMPTY-NEXT: SymOffset: 120 -; EMPTY-NEXT: Mod: 1 -; EMPTY-NEXT: Name: main -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 78000000 01006D61 696E0000 |....x.....main..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: DataSym { -; EMPTY-NEXT: Kind: S_GDATA32 (0x110D) -; EMPTY-NEXT: Type: void* (0x403) -; EMPTY-NEXT: DisplayName: __purecall -; EMPTY-NEXT: } -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 03040000 00000000 03005F5F 70757265 |..........__pure| -; EMPTY-NEXT: 0010: 63616C6C 00000000 |call....| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: Section Headers [ -; EMPTY-NEXT: { -; EMPTY-NEXT: Name: .text -; EMPTY-NEXT: Virtual Size: 4122 -; EMPTY-NEXT: Virtual Address: 4096 -; EMPTY-NEXT: Size of Raw Data: 4608 -; EMPTY-NEXT: File Pointer to Raw Data: 1024 -; EMPTY-NEXT: File Pointer to Relocations: 0 -; EMPTY-NEXT: File Pointer to Linenumbers: 0 -; EMPTY-NEXT: Number of Relocations: 0 -; EMPTY-NEXT: Number of Linenumbers: 0 -; EMPTY-NEXT: Characteristics [ (0x60000020) -; EMPTY-NEXT: IMAGE_SCN_CNT_CODE (0x20) -; EMPTY-NEXT: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Name: .rdata -; EMPTY-NEXT: Virtual Size: 690 -; EMPTY-NEXT: Virtual Address: 12288 -; EMPTY-NEXT: Size of Raw Data: 1024 -; EMPTY-NEXT: File Pointer to Raw Data: 5632 -; EMPTY-NEXT: File Pointer to Relocations: 0 -; EMPTY-NEXT: File Pointer to Linenumbers: 0 -; EMPTY-NEXT: Number of Relocations: 0 -; EMPTY-NEXT: Number of Linenumbers: 0 -; EMPTY-NEXT: Characteristics [ (0x40000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Name: .data -; EMPTY-NEXT: Virtual Size: 4 -; EMPTY-NEXT: Virtual Address: 16384 -; EMPTY-NEXT: Size of Raw Data: 0 -; EMPTY-NEXT: File Pointer to Raw Data: 0 -; EMPTY-NEXT: File Pointer to Relocations: 0 -; EMPTY-NEXT: File Pointer to Linenumbers: 0 -; EMPTY-NEXT: Number of Relocations: 0 -; EMPTY-NEXT: Number of Linenumbers: 0 -; EMPTY-NEXT: Characteristics [ (0xC0000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Name: .reloc -; EMPTY-NEXT: Virtual Size: 8 -; EMPTY-NEXT: Virtual Address: 20480 -; EMPTY-NEXT: Size of Raw Data: 512 -; EMPTY-NEXT: File Pointer to Raw Data: 6656 -; EMPTY-NEXT: File Pointer to Relocations: 0 -; EMPTY-NEXT: File Pointer to Linenumbers: 0 -; EMPTY-NEXT: Number of Relocations: 0 -; EMPTY-NEXT: Number of Linenumbers: 0 -; EMPTY-NEXT: Characteristics [ (0x42000040) -; EMPTY-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; EMPTY-NEXT: IMAGE_SCN_MEM_DISCARDABLE (0x2000000) -; EMPTY-NEXT: IMAGE_SCN_MEM_READ (0x40000000) -; EMPTY-NEXT: ] -; EMPTY-NEXT: } -; EMPTY-NEXT: ] -; EMPTY: New FPO [ -; EMPTY-NEXT: { -; EMPTY-NEXT: Offset: 4112 -; EMPTY-NEXT: Size: 10 -; EMPTY-NEXT: Number of locals: 0 -; EMPTY-NEXT: Number of params: 0 -; EMPTY-NEXT: Size of Prolog: 0 -; EMPTY-NEXT: Number of Saved Registers: 0 -; EMPTY-NEXT: Has SEH: No -; EMPTY-NEXT: Use BP: No -; EMPTY-NEXT: Frame Pointer: 0 -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: Size: 134 -; EMPTY-NEXT: Number of locals: 3 -; EMPTY-NEXT: Number of params: 4 -; EMPTY-NEXT: Size of Prolog: 0 -; EMPTY-NEXT: Number of Saved Registers: 0 -; EMPTY-NEXT: Has SEH: No -; EMPTY-NEXT: Use BP: No -; EMPTY-NEXT: Frame Pointer: 0 -; EMPTY-NEXT: } -; EMPTY-NEXT: ] +ALL: Summary +ALL-NEXT: ============================================================ +ALL-NEXT: Block Size: 4096 +ALL-NEXT: Number of blocks: 25 +ALL-NEXT: Number of streams: 17 +ALL-NEXT: Signature: 1424295906 +ALL-NEXT: Age: 1 +ALL-NEXT: GUID: {0B355641-86A0-A249-896F-9988FAE52FF0} +ALL-NEXT: Features: 0x1 +ALL-NEXT: Has Debug Info: true +ALL-NEXT: Has Types: true +ALL-NEXT: Has IDs: true +ALL-NEXT: Has Globals: true +ALL-NEXT: Has Publics: true +ALL-NEXT: Is incrementally linked: true +ALL-NEXT: Has conflicting types: false +ALL-NEXT: Is stripped: false +ALL: Streams +ALL-NEXT: ============================================================ +ALL-NEXT: Stream 0: [Old MSF Directory] (40 bytes) +ALL-NEXT: Stream 1: [PDB Stream] (118 bytes) +ALL-NEXT: Stream 2: [TPI Stream] (5392 bytes) +ALL-NEXT: Stream 3: [DBI Stream] (739 bytes) +ALL-NEXT: Stream 4: [IPI Stream] (784 bytes) +ALL-NEXT: Stream 5: [Named Stream "/LinkInfo"] (0 bytes) +ALL-NEXT: Stream 6: [Global Symbol Hash] (556 bytes) +ALL-NEXT: Stream 7: [Public Symbol Hash] (604 bytes) +ALL-NEXT: Stream 8: [Public Symbol Records] (104 bytes) +ALL-NEXT: Stream 9: [Named Stream "/src/headerblock"] (0 bytes) +ALL-NEXT: Stream 10: [Section Header Data] (160 bytes) +ALL-NEXT: Stream 11: [New FPO Data] (32 bytes) +ALL-NEXT: Stream 12: [Module "d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj"] (308 bytes) +ALL-NEXT: Stream 13: [Named Stream "/names"] (239 bytes) +ALL-NEXT: Stream 14: [Module "* Linker *"] (520 bytes) +ALL-NEXT: Stream 15: [TPI Hash] (308 bytes) +ALL-NEXT: Stream 16: [IPI Hash] (68 bytes) +ALL: String Table +ALL-NEXT: ============================================================ +ALL-NEXT: ID | String +ALL-NEXT: 1 | 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)' +ALL-NEXT: 86 | 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' +ALL-NEXT: 134 | '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = ' +ALL: Modules +ALL-NEXT: ============================================================ +ALL-NEXT: Mod 0000 | Name: `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`: +ALL-NEXT: Obj: `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`: +ALL-NEXT: debug stream: 12, # files: 1, has ec info: false +ALL-NEXT: Mod 0001 | Name: `* Linker *`: +ALL-NEXT: Obj: ``: +ALL-NEXT: debug stream: 14, # files: 0, has ec info: false +ALL: Files +ALL-NEXT: ============================================================ +ALL-NEXT: Mod 0000 | `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`: +ALL-NEXT: - (MD5: A0A5BD0D3ECD93FC29D19DE826FBF4BC) d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp +ALL-NEXT: Mod 0001 | `* Linker *`: +ALL: Lines +ALL-NEXT: ============================================================ +ALL-NEXT: Mod 0000 | `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`: +ALL-NEXT: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp (MD5: A0A5BD0D3ECD93FC29D19DE826FBF4BC) +ALL-NEXT: 0001:00000010-0000001A, line/addr entries = 3 +ALL-NEXT: 5 00000010 6 00000013 7 00000018 +ALL: Mod 0001 | `* Linker *`: +ALL: Inlinee Lines +ALL-NEXT: ============================================================ +ALL-NEXT: Mod 0000 | `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`: +ALL-NEXT: Mod 0001 | `* Linker *`: +ALL: Types (TPI Stream) +ALL-NEXT: ============================================================ +ALL-NEXT: Showing 75 records +ALL-NEXT: 0x1000 | LF_ARGLIST [size = 8, hash = 205956] +ALL-NEXT: 0x1001 | LF_PROCEDURE [size = 16, hash = 163561] +ALL-NEXT: return type = 0x0074 (int), # args = 0, param list = 0x1000 +ALL-NEXT: calling conv = cdecl, options = None +ALL-NEXT: 0x1002 | LF_FIELDLIST [size = 76, hash = 59811] +ALL-NEXT: - LF_ENUMERATE [apartment = 1] +ALL-NEXT: - LF_ENUMERATE [single = 2] +ALL-NEXT: - LF_ENUMERATE [free = 3] +ALL-NEXT: - LF_ENUMERATE [neutral = 4] +ALL-NEXT: - LF_ENUMERATE [both = 5] +ALL-NEXT: 0x1003 | LF_ENUM [size = 120, hash = 208239] +ALL-NEXT: name: `__vc_attributes::threadingAttribute::threading_e` +ALL-NEXT: unique name: `.?AW4threading_e@threadingAttribute@__vc_attributes@@` +ALL-NEXT: field list: 0x1002, underlying type: 0x0074 (int) +ALL-NEXT: options: has unique name | is nested +ALL-NEXT: 0x1004 | LF_STRUCTURE [size = 100, hash = 16377] +ALL-NEXT: class name: `__vc_attributes::threadingAttribute` +ALL-NEXT: unique name: `.?AUthreadingAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: +ALL-NEXT: options: forward ref | has unique name +ALL-NEXT: 0x1005 | LF_POINTER [size = 12, hash = 247078] +ALL-NEXT: referent = 0x1004, mode = pointer, opts = const, kind = ptr32 +ALL-NEXT: 0x1006 | LF_ARGLIST [size = 12, hash = 194342] +ALL-NEXT: 0x1003: `__vc_attributes::threadingAttribute::threading_e` +ALL-NEXT: 0x1007 | LF_MFUNCTION [size = 28, hash = 254156] +ALL-NEXT: return type = 1, # args = 0x1006, param list = 0x0003 (void) +ALL-NEXT: class type = 0x1004, this type = 0x1005, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1008 | LF_MFUNCTION [size = 28, hash = 194536] +ALL-NEXT: return type = 0, # args = 0x1000, param list = 0x0003 (void) +ALL-NEXT: class type = 0x1004, this type = 0x1005, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1009 | LF_METHODLIST [size = 20, hash = 167492] +ALL-NEXT: - Method [type = 0x1007, vftable offset = -1, attrs = public] +ALL-NEXT: - Method [type = 0x1008, vftable offset = -1, attrs = public] +ALL-NEXT: 0x100A | LF_FIELDLIST [size = 68, hash = 185421] +ALL-NEXT: - LF_NESTTYPE [name = `threading_e`, parent = 0x1003] +ALL-NEXT: - LF_METHOD [name = `threadingAttribute`, # overloads = 2, overload list = 0x1009] +ALL-NEXT: - LF_MEMBER [name = `value`, Type = 0x1003, offset = 0, attrs = public] +ALL-NEXT: 0x100B | LF_STRUCTURE [size = 100, hash = 119540] +ALL-NEXT: class name: `__vc_attributes::threadingAttribute` +ALL-NEXT: unique name: `.?AUthreadingAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: 0x100A +ALL-NEXT: options: has ctor / dtor | contains nested class | has unique name +ALL-NEXT: 0x100C | LF_FIELDLIST [size = 48, hash = 261871] +ALL-NEXT: - LF_ENUMERATE [native = 0] +ALL-NEXT: - LF_ENUMERATE [com = 1] +ALL-NEXT: - LF_ENUMERATE [managed = 2] +ALL-NEXT: 0x100D | LF_ENUM [size = 120, hash = 198119] +ALL-NEXT: name: `__vc_attributes::event_receiverAttribute::type_e` +ALL-NEXT: unique name: `.?AW4type_e@event_receiverAttribute@__vc_attributes@@` +ALL-NEXT: field list: 0x100C, underlying type: 0x0074 (int) +ALL-NEXT: options: has unique name | is nested +ALL-NEXT: 0x100E | LF_STRUCTURE [size = 112, hash = 48056] +ALL-NEXT: class name: `__vc_attributes::event_receiverAttribute` +ALL-NEXT: unique name: `.?AUevent_receiverAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: +ALL-NEXT: options: forward ref | has unique name +ALL-NEXT: 0x100F | LF_POINTER [size = 12, hash = 251486] +ALL-NEXT: referent = 0x100E, mode = pointer, opts = const, kind = ptr32 +ALL-NEXT: 0x1010 | LF_ARGLIST [size = 16, hash = 134580] +ALL-NEXT: 0x100D: `__vc_attributes::event_receiverAttribute::type_e` +ALL-NEXT: 0x0030 (bool): `bool` +ALL-NEXT: 0x1011 | LF_MFUNCTION [size = 28, hash = 148190] +ALL-NEXT: return type = 2, # args = 0x1010, param list = 0x0003 (void) +ALL-NEXT: class type = 0x100E, this type = 0x100F, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1012 | LF_ARGLIST [size = 12, hash = 113636] +ALL-NEXT: 0x100D: `__vc_attributes::event_receiverAttribute::type_e` +ALL-NEXT: 0x1013 | LF_MFUNCTION [size = 28, hash = 53336] +ALL-NEXT: return type = 1, # args = 0x1012, param list = 0x0003 (void) +ALL-NEXT: class type = 0x100E, this type = 0x100F, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1014 | LF_MFUNCTION [size = 28, hash = 55779] +ALL-NEXT: return type = 0, # args = 0x1000, param list = 0x0003 (void) +ALL-NEXT: class type = 0x100E, this type = 0x100F, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1015 | LF_METHODLIST [size = 28, hash = 220695] +ALL-NEXT: - Method [type = 0x1011, vftable offset = -1, attrs = public] +ALL-NEXT: - Method [type = 0x1013, vftable offset = -1, attrs = public] +ALL-NEXT: - Method [type = 0x1014, vftable offset = -1, attrs = public] +ALL-NEXT: 0x1016 | LF_FIELDLIST [size = 96, hash = 198114] +ALL-NEXT: - LF_NESTTYPE [name = `type_e`, parent = 0x100D] +ALL-NEXT: - LF_METHOD [name = `event_receiverAttribute`, # overloads = 3, overload list = 0x1015] +ALL-NEXT: - LF_MEMBER [name = `type`, Type = 0x100D, offset = 0, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `layout_dependent`, Type = 0x0030 (bool), offset = 4, attrs = public] +ALL-NEXT: 0x1017 | LF_STRUCTURE [size = 112, hash = 148734] +ALL-NEXT: class name: `__vc_attributes::event_receiverAttribute` +ALL-NEXT: unique name: `.?AUevent_receiverAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: 0x1016 +ALL-NEXT: options: has ctor / dtor | contains nested class | has unique name +ALL-NEXT: 0x1018 | LF_FIELDLIST [size = 48, hash = 81128] +ALL-NEXT: - LF_ENUMERATE [never = 0] +ALL-NEXT: - LF_ENUMERATE [allowed = 1] +ALL-NEXT: - LF_ENUMERATE [always = 2] +ALL-NEXT: 0x1019 | LF_ENUM [size = 116, hash = 60158] +ALL-NEXT: name: `__vc_attributes::aggregatableAttribute::type_e` +ALL-NEXT: unique name: `.?AW4type_e@aggregatableAttribute@__vc_attributes@@` +ALL-NEXT: field list: 0x1018, underlying type: 0x0074 (int) +ALL-NEXT: options: has unique name | is nested +ALL-NEXT: 0x101A | LF_STRUCTURE [size = 108, hash = 217249] +ALL-NEXT: class name: `__vc_attributes::aggregatableAttribute` +ALL-NEXT: unique name: `.?AUaggregatableAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: +ALL-NEXT: options: forward ref | has unique name +ALL-NEXT: 0x101B | LF_POINTER [size = 12, hash = 174209] +ALL-NEXT: referent = 0x101A, mode = pointer, opts = const, kind = ptr32 +ALL-NEXT: 0x101C | LF_ARGLIST [size = 12, hash = 159978] +ALL-NEXT: 0x1019: `__vc_attributes::aggregatableAttribute::type_e` +ALL-NEXT: 0x101D | LF_MFUNCTION [size = 28, hash = 249504] +ALL-NEXT: return type = 1, # args = 0x101C, param list = 0x0003 (void) +ALL-NEXT: class type = 0x101A, this type = 0x101B, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x101E | LF_MFUNCTION [size = 28, hash = 141941] +ALL-NEXT: return type = 0, # args = 0x1000, param list = 0x0003 (void) +ALL-NEXT: class type = 0x101A, this type = 0x101B, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x101F | LF_METHODLIST [size = 20, hash = 238785] +ALL-NEXT: - Method [type = 0x101D, vftable offset = -1, attrs = public] +ALL-NEXT: - Method [type = 0x101E, vftable offset = -1, attrs = public] +ALL-NEXT: 0x1020 | LF_FIELDLIST [size = 68, hash = 6214] +ALL-NEXT: - LF_NESTTYPE [name = `type_e`, parent = 0x1019] +ALL-NEXT: - LF_METHOD [name = `aggregatableAttribute`, # overloads = 2, overload list = 0x101F] +ALL-NEXT: - LF_MEMBER [name = `type`, Type = 0x1019, offset = 0, attrs = public] +ALL-NEXT: 0x1021 | LF_STRUCTURE [size = 108, hash = 94935] +ALL-NEXT: class name: `__vc_attributes::aggregatableAttribute` +ALL-NEXT: unique name: `.?AUaggregatableAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: 0x1020 +ALL-NEXT: options: has ctor / dtor | contains nested class | has unique name +ALL-NEXT: 0x1022 | LF_ENUM [size = 116, hash = 151449] +ALL-NEXT: name: `__vc_attributes::event_sourceAttribute::type_e` +ALL-NEXT: unique name: `.?AW4type_e@event_sourceAttribute@__vc_attributes@@` +ALL-NEXT: field list: 0x100C, underlying type: 0x0074 (int) +ALL-NEXT: options: has unique name | is nested +ALL-NEXT: 0x1023 | LF_FIELDLIST [size = 28, hash = 135589] +ALL-NEXT: - LF_ENUMERATE [speed = 0] +ALL-NEXT: - LF_ENUMERATE [size = 1] +ALL-NEXT: 0x1024 | LF_ENUM [size = 124, hash = 73373] +ALL-NEXT: name: `__vc_attributes::event_sourceAttribute::optimize_e` +ALL-NEXT: unique name: `.?AW4optimize_e@event_sourceAttribute@__vc_attributes@@` +ALL-NEXT: field list: 0x1023, underlying type: 0x0074 (int) +ALL-NEXT: options: has unique name | is nested +ALL-NEXT: 0x1025 | LF_STRUCTURE [size = 108, hash = 96512] +ALL-NEXT: class name: `__vc_attributes::event_sourceAttribute` +ALL-NEXT: unique name: `.?AUevent_sourceAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: +ALL-NEXT: options: forward ref | has unique name +ALL-NEXT: 0x1026 | LF_POINTER [size = 12, hash = 254299] +ALL-NEXT: referent = 0x1025, mode = pointer, opts = const, kind = ptr32 +ALL-NEXT: 0x1027 | LF_ARGLIST [size = 12, hash = 17744] +ALL-NEXT: 0x1022: `__vc_attributes::event_sourceAttribute::type_e` +ALL-NEXT: 0x1028 | LF_MFUNCTION [size = 28, hash = 239514] +ALL-NEXT: return type = 1, # args = 0x1027, param list = 0x0003 (void) +ALL-NEXT: class type = 0x1025, this type = 0x1026, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1029 | LF_MFUNCTION [size = 28, hash = 173189] +ALL-NEXT: return type = 0, # args = 0x1000, param list = 0x0003 (void) +ALL-NEXT: class type = 0x1025, this type = 0x1026, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x102A | LF_METHODLIST [size = 20, hash = 130544] +ALL-NEXT: - Method [type = 0x1028, vftable offset = -1, attrs = public] +ALL-NEXT: - Method [type = 0x1029, vftable offset = -1, attrs = public] +ALL-NEXT: 0x102B | LF_FIELDLIST [size = 128, hash = 204437] +ALL-NEXT: - LF_NESTTYPE [name = `type_e`, parent = 0x1022] +ALL-NEXT: - LF_NESTTYPE [name = `optimize_e`, parent = 0x1024] +ALL-NEXT: - LF_METHOD [name = `event_sourceAttribute`, # overloads = 2, overload list = 0x102A] +ALL-NEXT: - LF_MEMBER [name = `type`, Type = 0x1022, offset = 0, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `optimize`, Type = 0x1024, offset = 4, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `decorate`, Type = 0x0030 (bool), offset = 8, attrs = public] +ALL-NEXT: 0x102C | LF_STRUCTURE [size = 108, hash = 238560] +ALL-NEXT: class name: `__vc_attributes::event_sourceAttribute` +ALL-NEXT: unique name: `.?AUevent_sourceAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: 0x102B +ALL-NEXT: options: has ctor / dtor | contains nested class | has unique name +ALL-NEXT: 0x102D | LF_FIELDLIST [size = 92, hash = 144673] +ALL-NEXT: - LF_ENUMERATE [dll = 1] +ALL-NEXT: - LF_ENUMERATE [exe = 2] +ALL-NEXT: - LF_ENUMERATE [service = 3] +ALL-NEXT: - LF_ENUMERATE [unspecified = 4] +ALL-NEXT: - LF_ENUMERATE [EXE = 2] +ALL-NEXT: - LF_ENUMERATE [SERVICE = 3] +ALL-NEXT: 0x102E | LF_ENUM [size = 104, hash = 115151] +ALL-NEXT: name: `__vc_attributes::moduleAttribute::type_e` +ALL-NEXT: unique name: `.?AW4type_e@moduleAttribute@__vc_attributes@@` +ALL-NEXT: field list: 0x102D, underlying type: 0x0074 (int) +ALL-NEXT: options: has unique name | is nested +ALL-NEXT: 0x102F | LF_STRUCTURE [size = 96, hash = 197306] +ALL-NEXT: class name: `__vc_attributes::moduleAttribute` +ALL-NEXT: unique name: `.?AUmoduleAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: +ALL-NEXT: options: forward ref | has unique name +ALL-NEXT: 0x1030 | LF_POINTER [size = 12, hash = 256035] +ALL-NEXT: referent = 0x102F, mode = pointer, opts = const, kind = ptr32 +ALL-NEXT: 0x1031 | LF_MODIFIER [size = 12, hash = 101096] +ALL-NEXT: referent = 0x0070 (char), modifiers = const +ALL-NEXT: 0x1032 | LF_POINTER [size = 12, hash = 231280] +ALL-NEXT: referent = 0x1031, mode = pointer, opts = None, kind = ptr32 +ALL-NEXT: 0x1033 | LF_ARGLIST [size = 68, hash = 52156] +ALL-NEXT: 0x102E: `__vc_attributes::moduleAttribute::type_e` +ALL-NEXT: 0x1032: `const char*` +ALL-NEXT: 0x1032: `const char*` +ALL-NEXT: 0x1032: `const char*` +ALL-NEXT: 0x0074 (int): `int` +ALL-NEXT: 0x0030 (bool): `bool` +ALL-NEXT: 0x1032: `const char*` +ALL-NEXT: 0x0074 (int): `int` +ALL-NEXT: 0x1032: `const char*` +ALL-NEXT: 0x1032: `const char*` +ALL-NEXT: 0x0074 (int): `int` +ALL-NEXT: 0x0030 (bool): `bool` +ALL-NEXT: 0x0030 (bool): `bool` +ALL-NEXT: 0x1032: `const char*` +ALL-NEXT: 0x1032: `const char*` +ALL-NEXT: 0x1034 | LF_MFUNCTION [size = 28, hash = 48854] +ALL-NEXT: return type = 15, # args = 0x1033, param list = 0x0003 (void) +ALL-NEXT: class type = 0x102F, this type = 0x1030, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1035 | LF_ARGLIST [size = 12, hash = 170035] +ALL-NEXT: 0x102E: `__vc_attributes::moduleAttribute::type_e` +ALL-NEXT: 0x1036 | LF_MFUNCTION [size = 28, hash = 177041] +ALL-NEXT: return type = 1, # args = 0x1035, param list = 0x0003 (void) +ALL-NEXT: class type = 0x102F, this type = 0x1030, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1037 | LF_MFUNCTION [size = 28, hash = 102745] +ALL-NEXT: return type = 0, # args = 0x1000, param list = 0x0003 (void) +ALL-NEXT: class type = 0x102F, this type = 0x1030, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1038 | LF_METHODLIST [size = 28, hash = 16947] +ALL-NEXT: - Method [type = 0x1034, vftable offset = -1, attrs = public] +ALL-NEXT: - Method [type = 0x1036, vftable offset = -1, attrs = public] +ALL-NEXT: - Method [type = 0x1037, vftable offset = -1, attrs = public] +ALL-NEXT: 0x1039 | LF_FIELDLIST [size = 356, hash = 183703] +ALL-NEXT: - LF_NESTTYPE [name = `type_e`, parent = 0x102E] +ALL-NEXT: - LF_METHOD [name = `moduleAttribute`, # overloads = 3, overload list = 0x1038] +ALL-NEXT: - LF_MEMBER [name = `type`, Type = 0x102E, offset = 0, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `name`, Type = 0x1032, offset = 4, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `version`, Type = 0x1032, offset = 8, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `uuid`, Type = 0x1032, offset = 12, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `lcid`, Type = 0x0074 (int), offset = 16, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `control`, Type = 0x0030 (bool), offset = 20, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `helpstring`, Type = 0x1032, offset = 24, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `helpstringcontext`, Type = 0x0074 (int), offset = 28, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `helpstringdll`, Type = 0x1032, offset = 32, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `helpfile`, Type = 0x1032, offset = 36, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `helpcontext`, Type = 0x0074 (int), offset = 40, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `hidden`, Type = 0x0030 (bool), offset = 44, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `restricted`, Type = 0x0030 (bool), offset = 45, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `custom`, Type = 0x1032, offset = 48, attrs = public] +ALL-NEXT: - LF_MEMBER [name = `resource_name`, Type = 0x1032, offset = 52, attrs = public] +ALL-NEXT: 0x103A | LF_STRUCTURE [size = 96, hash = 98548] +ALL-NEXT: class name: `__vc_attributes::moduleAttribute` +ALL-NEXT: unique name: `.?AUmoduleAttribute@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: 0x1039 +ALL-NEXT: options: has ctor / dtor | contains nested class | has unique name +ALL-NEXT: 0x103B | LF_FIELDLIST [size = 756, hash = 35693] +ALL-NEXT: - LF_ENUMERATE [eAnyUsage = 0] +ALL-NEXT: - LF_ENUMERATE [eCoClassUsage = 1] +ALL-NEXT: - LF_ENUMERATE [eCOMInterfaceUsage = 2] +ALL-NEXT: - LF_ENUMERATE [eInterfaceUsage = 6] +ALL-NEXT: - LF_ENUMERATE [eMemberUsage = 8] +ALL-NEXT: - LF_ENUMERATE [eMethodUsage = 16] +ALL-NEXT: - LF_ENUMERATE [eInterfaceMethodUsage = 32] +ALL-NEXT: - LF_ENUMERATE [eInterfaceMemberUsage = 64] +ALL-NEXT: - LF_ENUMERATE [eCoClassMemberUsage = 128] +ALL-NEXT: - LF_ENUMERATE [eCoClassMethodUsage = 256] +ALL-NEXT: - LF_ENUMERATE [eGlobalMethodUsage = 768] +ALL-NEXT: - LF_ENUMERATE [eGlobalDataUsage = 1024] +ALL-NEXT: - LF_ENUMERATE [eClassUsage = 2048] +ALL-NEXT: - LF_ENUMERATE [eInterfaceParameterUsage = 4096] +ALL-NEXT: - LF_ENUMERATE [eMethodParameterUsage = 12288] +ALL-NEXT: - LF_ENUMERATE [eIDLModuleUsage = 16384] +ALL-NEXT: - LF_ENUMERATE [eAnonymousUsage = 32768] +ALL-NEXT: - LF_ENUMERATE [eTypedefUsage = 65536] +ALL-NEXT: - LF_ENUMERATE [eUnionUsage = 131072] +ALL-NEXT: - LF_ENUMERATE [eEnumUsage = 262144] +ALL-NEXT: - LF_ENUMERATE [eDefineTagUsage = 524288] +ALL-NEXT: - LF_ENUMERATE [eStructUsage = 1048576] +ALL-NEXT: - LF_ENUMERATE [eLocalUsage = 2097152] +ALL-NEXT: - LF_ENUMERATE [ePropertyUsage = 4194304] +ALL-NEXT: - LF_ENUMERATE [eEventUsage = 8388608] +ALL-NEXT: - LF_ENUMERATE [eTemplateUsage = 16777216] +ALL-NEXT: - LF_ENUMERATE [eModuleUsage = 16777216] +ALL-NEXT: - LF_ENUMERATE [eIllegalUsage = 33554432] +ALL-NEXT: - LF_ENUMERATE [eAsynchronousUsage = 67108864] +ALL-NEXT: - LF_ENUMERATE [eAnyIDLUsage = 4161535] +ALL-NEXT: 0x103C | LF_ENUM [size = 140, hash = 171328] +ALL-NEXT: name: `__vc_attributes::helper_attributes::usageAttribute::usage_e` +ALL-NEXT: unique name: `.?AW4usage_e@usageAttribute@helper_attributes@__vc_attributes@@` +ALL-NEXT: field list: 0x103B, underlying type: 0x0074 (int) +ALL-NEXT: options: has unique name | is nested +ALL-NEXT: 0x103D | LF_STRUCTURE [size = 128, hash = 203640] +ALL-NEXT: class name: `__vc_attributes::helper_attributes::usageAttribute` +ALL-NEXT: unique name: `.?AUusageAttribute@helper_attributes@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: +ALL-NEXT: options: forward ref | has unique name +ALL-NEXT: 0x103E | LF_POINTER [size = 12, hash = 139292] +ALL-NEXT: referent = 0x103D, mode = pointer, opts = const, kind = ptr32 +ALL-NEXT: 0x103F | LF_ARGLIST [size = 12, hash = 49018] +ALL-NEXT: 0x0075 (unsigned): `unsigned` +ALL-NEXT: 0x1040 | LF_MFUNCTION [size = 28, hash = 43821] +ALL-NEXT: return type = 1, # args = 0x103F, param list = 0x0003 (void) +ALL-NEXT: class type = 0x103D, this type = 0x103E, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1041 | LF_FIELDLIST [size = 60, hash = 202555] +ALL-NEXT: - LF_NESTTYPE [name = `usage_e`, parent = 0x103C] +ALL-NEXT: - LF_ONEMETHOD [name = `usageAttribute`] +ALL-NEXT: type = 0x1040, vftable offset = -1, attrs = public +ALL-NEXT: - LF_MEMBER [name = `value`, Type = 0x0075 (unsigned), offset = 0, attrs = public] +ALL-NEXT: 0x1042 | LF_STRUCTURE [size = 128, hash = 165040] +ALL-NEXT: class name: `__vc_attributes::helper_attributes::usageAttribute` +ALL-NEXT: unique name: `.?AUusageAttribute@helper_attributes@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: 0x1041 +ALL-NEXT: options: has ctor / dtor | contains nested class | has unique name +ALL-NEXT: 0x1043 | LF_FIELDLIST [size = 68, hash = 215835] +ALL-NEXT: - LF_ENUMERATE [eBoolean = 0] +ALL-NEXT: - LF_ENUMERATE [eInteger = 1] +ALL-NEXT: - LF_ENUMERATE [eFloat = 2] +ALL-NEXT: - LF_ENUMERATE [eDouble = 3] +ALL-NEXT: 0x1044 | LF_ENUM [size = 148, hash = 142625] +ALL-NEXT: name: `__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e` +ALL-NEXT: unique name: `.?AW4type_e@v1_alttypeAttribute@helper_attributes@__vc_attributes@@` +ALL-NEXT: field list: 0x1043, underlying type: 0x0074 (int) +ALL-NEXT: options: has unique name | is nested +ALL-NEXT: 0x1045 | LF_STRUCTURE [size = 140, hash = 52534] +ALL-NEXT: class name: `__vc_attributes::helper_attributes::v1_alttypeAttribute` +ALL-NEXT: unique name: `.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: +ALL-NEXT: options: forward ref | has unique name +ALL-NEXT: 0x1046 | LF_POINTER [size = 12, hash = 44186] +ALL-NEXT: referent = 0x1045, mode = pointer, opts = const, kind = ptr32 +ALL-NEXT: 0x1047 | LF_ARGLIST [size = 12, hash = 103930] +ALL-NEXT: 0x1044: `__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e` +ALL-NEXT: 0x1048 | LF_MFUNCTION [size = 28, hash = 110942] +ALL-NEXT: return type = 1, # args = 0x1047, param list = 0x0003 (void) +ALL-NEXT: class type = 0x1045, this type = 0x1046, this adjust = 0 +ALL-NEXT: calling conv = thiscall, options = constructor +ALL-NEXT: 0x1049 | LF_FIELDLIST [size = 64, hash = 17991] +ALL-NEXT: - LF_NESTTYPE [name = `type_e`, parent = 0x1044] +ALL-NEXT: - LF_ONEMETHOD [name = `v1_alttypeAttribute`] +ALL-NEXT: type = 0x1048, vftable offset = -1, attrs = public +ALL-NEXT: - LF_MEMBER [name = `type`, Type = 0x1044, offset = 0, attrs = public] +ALL-NEXT: 0x104A | LF_STRUCTURE [size = 140, hash = 213215] +ALL-NEXT: class name: `__vc_attributes::helper_attributes::v1_alttypeAttribute` +ALL-NEXT: unique name: `.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@` +ALL-NEXT: vtable: , base list: , field list: 0x1049 +ALL-NEXT: options: has ctor / dtor | contains nested class | has unique name +ALL: Type Index Offsets: +ALL-NEXT: TI: 0x1000, Offset: 0 +ALL: Hash Adjusters: +ALL: Types (IPI Stream) +ALL-NEXT: ============================================================ +ALL-NEXT: Showing 15 records +ALL-NEXT: 0x1000 | LF_UDT_MOD_SRC_LINE [size = 20, hash = 7186] +ALL-NEXT: udt = 0x100B, mod = 1, file = 1, line = 481 +ALL-NEXT: 0x1001 | LF_UDT_MOD_SRC_LINE [size = 20, hash = 7198] +ALL-NEXT: udt = 0x1017, mod = 1, file = 1, line = 194 +ALL-NEXT: 0x1002 | LF_UDT_MOD_SRC_LINE [size = 20, hash = 7180] +ALL-NEXT: udt = 0x1021, mod = 1, file = 1, line = 603 +ALL-NEXT: 0x1003 | LF_UDT_MOD_SRC_LINE [size = 20, hash = 7191] +ALL-NEXT: udt = 0x102C, mod = 1, file = 1, line = 1200 +ALL-NEXT: 0x1004 | LF_UDT_MOD_SRC_LINE [size = 20, hash = 7201] +ALL-NEXT: udt = 0x103A, mod = 1, file = 1, line = 540 +ALL-NEXT: 0x1005 | LF_UDT_MOD_SRC_LINE [size = 20, hash = 7241] +ALL-NEXT: udt = 0x1042, mod = 1, file = 1, line = 108 +ALL-NEXT: 0x1006 | LF_UDT_MOD_SRC_LINE [size = 20, hash = 7249] +ALL-NEXT: udt = 0x104A, mod = 1, file = 1, line = 96 +ALL-NEXT: 0x1007 | LF_STRING_ID [size = 48, hash = 80727] ID: , String: d:\src\llvm\test\DebugInfo\PDB\Inputs +ALL-NEXT: 0x1008 | LF_STRING_ID [size = 76, hash = 154177] ID: , String: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe +ALL-NEXT: 0x1009 | LF_STRING_ID [size = 20, hash = 75189] ID: , String: empty.cpp +ALL-NEXT: 0x100A | LF_STRING_ID [size = 56, hash = 253662] ID: , String: d:\src\llvm\test\DebugInfo\PDB\Inputs\vc120.pdb +ALL-NEXT: 0x100B | LF_STRING_ID [size = 252, hash = 193467] ID: , String: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows +ALL-NEXT: 0x100C | LF_SUBSTR_LIST [size = 12, hash = 222705] +ALL-NEXT: 0x100B: `-Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows` +ALL-NEXT: 0x100D | LF_STRING_ID [size = 96, hash = 186099] ID: 0x100C, String: Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TP -X +ALL-NEXT: 0x100E | LF_BUILDINFO [size = 28, hash = 257108] +ALL-NEXT: 0x1007: `d:\src\llvm\test\DebugInfo\PDB\Inputs` +ALL-NEXT: 0x1008: `C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe` +ALL-NEXT: 0x1009: `empty.cpp` +ALL-NEXT: 0x100A: `d:\src\llvm\test\DebugInfo\PDB\Inputs\vc120.pdb` +ALL-NEXT: 0x100D: ` Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TP -X` +ALL: Type Index Offsets: +ALL-NEXT: TI: 0x1000, Offset: 0 +ALL: Hash Adjusters: +ALL: Public Symbols +ALL-NEXT: ============================================================ +ALL-NEXT: - S_PUB32 [size = 36] `?__purecall@@3PAXA` +ALL-NEXT: type = , addr = 0003:0000 +ALL-NEXT: - S_PUB32 [size = 20] `_main` +ALL-NEXT: type = 0x0002 (), addr = 0001:0016 +ALL-NEXT: - S_PROCREF [size = 20] `main` +ALL-NEXT: module = 1, sum name = 0, offset = 120 +ALL-NEXT: - S_GDATA32 [size = 28] `__purecall` +ALL-NEXT: type = 0x0403 (void*), addr = 0003:0000 +ALL: Symbols +ALL-NEXT: ============================================================ +ALL-NEXT: Mod 0000 | `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`: +ALL-NEXT: - S_OBJNAME [size = 56] sig=0, `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj` +ALL-NEXT: - S_COMPILE3 [size = 60] +ALL-NEXT: machine = intel pentium 3, Ver = Microsoft (R) Optimizing Compiler, language = c++ +ALL-NEXT: frontend = 18.0.31101.0, backend = 18.0.31101.0 +ALL-NEXT: flags = security checks +ALL-NEXT: - S_GPROC32 [size = 44] `main` +ALL-NEXT: parent = 0, addr = 0001:0016, code size = 10, end = 196 +ALL-NEXT: debug start = 3, debug end = 8, flags = has fp +ALL-NEXT: - S_FRAMEPROC [size = 32] +ALL-NEXT: size = 0, padding size = 0, offset to padding = 0 +ALL-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +ALL-NEXT: flags = has async eh | opt speed +ALL-NEXT: - S_END [size = 4] +ALL-NEXT: - S_BUILDINFO [size = 8] BuildId = `4110` +ALL-NEXT: Mod 0001 | `* Linker *`: +ALL-NEXT: - S_OBJNAME [size = 20] sig=0, `* Linker *` +ALL-NEXT: - S_COMPILE3 [size = 48] +ALL-NEXT: machine = intel 80386, Ver = Microsoft (R) LINK, language = link +ALL-NEXT: frontend = 0.0.0.0, backend = 12.0.31101.0 +ALL-NEXT: flags = none +ALL-NEXT: - S_ENVBLOCK [size = 172] +ALL-NEXT: - cwd +ALL-NEXT: - d:\src\llvm\test\DebugInfo\PDB\Inputs +ALL-NEXT: - exe +ALL-NEXT: - C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\link.exe +ALL-NEXT: - pdb +ALL-NEXT: - d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.pdb +ALL-NEXT: - S_TRAMPOLINE [size = 20] +ALL-NEXT: type = tramp incremental, size = 5, source = 0001:0005, target = 0001:0005 +ALL-NEXT: - S_SECTION [size = 28] `.text` +ALL-NEXT: length = 4122, alignment = 12, rva = 4096, section # = 1, characteristics = 1610612768 +ALL-NEXT: - S_COFFGROUP [size = 28] `.text$mn` +ALL-NEXT: length = 4122, addr = 0001:0000, characteristics = 1610612768 +ALL-NEXT: - S_SECTION [size = 28] `.rdata` +ALL-NEXT: length = 690, alignment = 12, rva = 12288, section # = 2, characteristics = 1073741888 +ALL-NEXT: - S_COFFGROUP [size = 28] `.rdata` +ALL-NEXT: length = 323, addr = 0002:0000, characteristics = 1073741888 +ALL-NEXT: - S_COFFGROUP [size = 28] `.edata` +ALL-NEXT: length = 0, addr = 0002:0323, characteristics = 1073741888 +ALL-NEXT: - S_COFFGROUP [size = 32] `.rdata$debug` +ALL-NEXT: length = 366, addr = 0002:0324, characteristics = 1073741888 +ALL-NEXT: - S_SECTION [size = 28] `.data` +ALL-NEXT: length = 4, alignment = 12, rva = 16384, section # = 3, characteristics = 3221225536 +ALL-NEXT: - S_COFFGROUP [size = 24] `.bss` +ALL-NEXT: length = 4, addr = 0003:0000, characteristics = 3221225600 +ALL-NEXT: - S_SECTION [size = 28] `.reloc` +ALL-NEXT: length = 8, alignment = 12, rva = 20480, section # = 4, characteristics = 1107296320 +ALL: Section Contributions +ALL-NEXT: ============================================================ +ALL-NEXT: SC | mod = 1, 0001:0000, size = 10, data crc = 0, reloc crc = 0 +ALL-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ +ALL-NEXT: SC | mod = 0, 0001:0016, size = 10, data crc = 3617027124, reloc crc = 0 +ALL-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | +ALL-NEXT: IMAGE_SCN_MEM_READ +ALL-NEXT: SC | mod = 1, 0002:0000, size = 56, data crc = 0, reloc crc = 0 +ALL-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +ALL-NEXT: SC | mod = 1, 0002:0324, size = 72, data crc = 0, reloc crc = 0 +ALL-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ +ALL-NEXT: SC | mod = 1, 0002:0396, size = 20, data crc = 0, reloc crc = 0 +ALL-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ +ALL-NEXT: SC | mod = 0, 0003:0000, size = 4, data crc = 0, reloc crc = 0 +ALL-NEXT: IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ | +ALL-NEXT: IMAGE_SCN_MEM_WRITE +ALL: Section Map +ALL-NEXT: ============================================================ +ALL-NEXT: Section 0000 | ovl = 0, group = 0, frame = 0, name = 1 +ALL-NEXT: class = 65535, offset = 0, size = 4122 +ALL-NEXT: flags = read | execute | 32 bit addr | selector +ALL-NEXT: Section 0001 | ovl = 1, group = 0, frame = 0, name = 2 +ALL-NEXT: class = 65535, offset = 0, size = 690 +ALL-NEXT: flags = read | 32 bit addr | selector +ALL-NEXT: Section 0002 | ovl = 2, group = 0, frame = 0, name = 3 +ALL-NEXT: class = 65535, offset = 0, size = 4 +ALL-NEXT: flags = read | write | 32 bit addr | selector +ALL-NEXT: Section 0003 | ovl = 3, group = 0, frame = 0, name = 4 +ALL-NEXT: class = 65535, offset = 0, size = 8 +ALL-NEXT: flags = read | 32 bit addr | selector +ALL-NEXT: Section 0004 | ovl = 4, group = 0, frame = 0, name = 0 +ALL-NEXT: class = 65535, offset = 0, size = 4294967295 +ALL-NEXT: flags = 32 bit addr | absolute addr -; ALL: FileHeaders { -; ALL: BlockSize: 4096 -; ALL: FreeBlockMap: 2 -; ALL: NumBlocks: 25 -; ALL: NumDirectoryBytes: 136 -; ALL: Unknown1: 0 -; ALL: BlockMapAddr: 24 -; ALL: NumDirectoryBlocks: 1 -; ALL: DirectoryBlocks: [23] -; ALL: NumStreams: 17 -; ALL: } -; ALL: Streams [ -; ALL: Stream 0: [Old MSF Directory] (40 bytes) -; ALL: Stream 1: [PDB Stream] (118 bytes) -; ALL: Stream 2: [TPI Stream] (5392 bytes) -; ALL: Stream 3: [DBI Stream] (739 bytes) -; ALL: Stream 4: [IPI Stream] (784 bytes) -; ALL: Stream 5: [Named Stream "/LinkInfo"] (0 bytes) -; ALL: Stream 6: [Global Symbol Hash] (556 bytes) -; ALL: Stream 7: [Public Symbol Hash] (604 bytes) -; ALL: Stream 8: [Public Symbol Records] (104 bytes) -; ALL: Stream 9: [Named Stream "/src/headerblock"] (0 bytes) -; ALL: Stream 10: [Section Header Data] (160 bytes) -; ALL: Stream 11: [New FPO Data] (32 bytes) -; ALL: Stream 12: [Module "d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj"] (308 bytes) -; ALL: Stream 13: [Named Stream "/names"] (239 bytes) -; ALL: Stream 14: [Module "* Linker *"] (520 bytes) -; ALL: Stream 15: [TPI Hash] (308 bytes) -; ALL: Stream 16: [IPI Hash] (68 bytes) -; ALL: ] -; ALL: Msf Free Pages: [3, 4, 5, 8, 9] -; ALL: Orphaned Pages: [] -; ALL: Multiply Used Pages: [] -; ALL: Use After Free Pages: [] -; ALL: StreamBlocks [ -; ALL: Stream 0: [8] -; ALL: Stream 1: [19] -; ALL: Stream 2: [18, 17] -; ALL: Stream 3: [14] -; ALL: Stream 4: [20] -; ALL: Stream 5: [] -; ALL: Stream 6: [11] -; ALL: Stream 7: [13] -; ALL: Stream 8: [12] -; ALL: Stream 9: [] -; ALL: Stream 10: [10] -; ALL: Stream 11: [15] -; ALL: Stream 12: [6] -; ALL: Stream 13: [16] -; ALL: Stream 14: [7] -; ALL: Stream 15: [21] -; ALL: Stream 16: [22] -; ALL: ] -; ALL: PDB Stream { -; ALL: Version: 20000404 -; ALL: Signature: 0x54E507E2 -; ALL: Age: 1 -; ALL: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} -; ALL: Features: 0x1 -; ALL: } -; ALL: Type Info Stream (IPI) { -; ALL: IPI Version: 20040203 -; ALL: Record count: 15 -; ALL: Records [ -; ALL: { -; ALL: UdtModSourceLine (0x1000) { -; ALL: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; ALL: UDT: __vc_attributes::threadingAttribute (0x100B) -; ALL: SourceFile: (0x1) -; ALL: LineNumber: 481 -; ALL: Module: 1 -; ALL: } -; ALL: } -; ALL: { -; ALL: UdtModSourceLine (0x1001) { -; ALL: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; ALL: UDT: __vc_attributes::event_receiverAttribute (0x1017) -; ALL: SourceFile: (0x1) -; ALL: LineNumber: 194 -; ALL: Module: 1 -; ALL: } -; ALL: } -; ALL: { -; ALL: UdtModSourceLine (0x1002) { -; ALL: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; ALL: UDT: __vc_attributes::aggregatableAttribute (0x1021) -; ALL: SourceFile: (0x1) -; ALL: LineNumber: 603 -; ALL: Module: 1 -; ALL: } -; ALL: } -; ALL: { -; ALL: UdtModSourceLine (0x1003) { -; ALL: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; ALL: UDT: __vc_attributes::event_sourceAttribute (0x102C) -; ALL: SourceFile: (0x1) -; ALL: LineNumber: 1200 -; ALL: Module: 1 -; ALL: } -; ALL: } -; ALL: { -; ALL: UdtModSourceLine (0x1004) { -; ALL: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; ALL: UDT: __vc_attributes::moduleAttribute (0x103A) -; ALL: SourceFile: (0x1) -; ALL: LineNumber: 540 -; ALL: Module: 1 -; ALL: } -; ALL: } -; ALL: { -; ALL: UdtModSourceLine (0x1005) { -; ALL: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; ALL: UDT: __vc_attributes::helper_attributes::usageAttribute (0x1042) -; ALL: SourceFile: (0x1) -; ALL: LineNumber: 108 -; ALL: Module: 1 -; ALL: } -; ALL: } -; ALL: { -; ALL: UdtModSourceLine (0x1006) { -; ALL: TypeLeafKind: LF_UDT_MOD_SRC_LINE (0x1607) -; ALL: UDT: __vc_attributes::helper_attributes::v1_alttypeAttribute (0x104A) -; ALL: SourceFile: (0x1) -; ALL: LineNumber: 96 -; ALL: Module: 1 -; ALL: } -; ALL: } -; ALL: { -; ALL: StringId (0x1007) { -; ALL: TypeLeafKind: LF_STRING_ID (0x1605) -; ALL: Id: 0x0 -; ALL: StringData: d:\src\llvm\test\DebugInfo\PDB\Inputs -; ALL: } -; ALL: } -; ALL: { -; ALL: StringId (0x1008) { -; ALL: TypeLeafKind: LF_STRING_ID (0x1605) -; ALL: Id: 0x0 -; ALL: StringData: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe -; ALL: } -; ALL: } -; ALL: { -; ALL: StringId (0x1009) { -; ALL: TypeLeafKind: LF_STRING_ID (0x1605) -; ALL: Id: 0x0 -; ALL: StringData: empty.cpp -; ALL: } -; ALL: } -; ALL: { -; ALL: StringId (0x100A) { -; ALL: TypeLeafKind: LF_STRING_ID (0x1605) -; ALL: Id: 0x0 -; ALL: StringData: d:\src\llvm\test\DebugInfo\PDB\Inputs\vc120.pdb -; ALL: } -; ALL: } -; ALL: { -; ALL: StringId (0x100B) { -; ALL: TypeLeafKind: LF_STRING_ID (0x1605) -; ALL: Id: 0x0 -; ALL: StringData: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows -; ALL: } -; ALL: } -; ALL: { -; ALL: StringList (0x100C) { -; ALL: TypeLeafKind: LF_SUBSTR_LIST (0x1604) -; ALL: NumStrings: 1 -; ALL: Strings [ -; ALL: String: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows (0x100B) -; ALL: ] -; ALL: } -; ALL: } -; ALL: { -; ALL: StringId (0x100D) { -; ALL: TypeLeafKind: LF_STRING_ID (0x1605) -; ALL: Id: "-Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows" (0x100C) -; ALL: StringData: Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TP -X -; ALL: } -; ALL: } -; ALL: { -; ALL: BuildInfo (0x100E) { -; ALL: TypeLeafKind: LF_BUILDINFO (0x1603) -; ALL: NumArgs: 5 -; ALL: Arguments [ -; ALL: ArgType: d:\src\llvm\test\DebugInfo\PDB\Inputs (0x1007) -; ALL: ArgType: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\cl.exe (0x1008) -; ALL: ArgType: empty.cpp (0x1009) -; ALL: ArgType: d:\src\llvm\test\DebugInfo\PDB\Inputs\vc120.pdb (0x100A) -; ALL: ArgType: Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TP -X (0x100D) -; ALL: ] -; ALL: } -; ALL: } -; ALL: ] -; ALL: } -; ALL: DBI Stream { -; ALL: Dbi Version: 19990903 -; ALL: Age: 1 -; ALL: Incremental Linking: Yes -; ALL: Has CTypes: No -; ALL: Is Stripped: No -; ALL: Machine Type: x86 -; ALL: Symbol Record Stream Index: 8 -; ALL: Public Symbol Stream Index: 7 -; ALL: Global Symbol Stream Index: 6 -; ALL: Toolchain Version: 12.0 -; ALL: mspdb120.dll version: 12.0.31101 -; ALL: Modules [ -; ALL: { -; ALL: Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; ALL: Debug Stream Index: 12 -; ALL: Object File Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; ALL: Num Files: 1 -; ALL: Source File Name Idx: 0 -; ALL: Pdb File Name Idx: 0 -; ALL: Line Info Byte Size: 0 -; ALL: C13 Line Info Byte Size: 88 -; ALL: Symbol Byte Size: 208 -; ALL: Type Server Index: 0 -; ALL: Has EC Info: No -; ALL: 1 Contributing Source Files [ -; ALL: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp -; ALL: ] -; ALL: Symbols [ -; ALL: { -; ALL: ObjectName { -; ALL: Signature: 0x0 -; ALL: ObjectName: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; ALL: } -; ALL: } -; ALL: { -; ALL: CompilerFlags3 { -; ALL: Language: Cpp (0x1) -; ALL: Flags [ (0x2000) -; ALL: SecurityChecks (0x2000) -; ALL: ] -; ALL: Machine: Pentium3 (0x7) -; ALL: FrontendVersion: 18.0.31101.0 -; ALL: BackendVersion: 18.0.31101.0 -; ALL: VersionName: Microsoft (R) Optimizing Compiler -; ALL: } -; ALL: } -; ALL: { -; ALL: ProcStart { -; ALL: PtrParent: 0x0 -; ALL: PtrEnd: 0xC4 -; ALL: PtrNext: 0x0 -; ALL: CodeSize: 0xA -; ALL: DbgStart: 0x3 -; ALL: DbgEnd: 0x8 -; ALL: FunctionType: int () (0x1001) -; ALL: Segment: 0x1 -; ALL: Flags [ (0x1) -; ALL: HasFP (0x1) -; ALL: ] -; ALL: DisplayName: main -; ALL: } -; ALL: } -; ALL: { -; ALL: FrameProc { -; ALL: TotalFrameBytes: 0x0 -; ALL: PaddingFrameBytes: 0x0 -; ALL: OffsetToPadding: 0x0 -; ALL: BytesOfCalleeSavedRegisters: 0x0 -; ALL: OffsetOfExceptionHandler: 0x0 -; ALL: SectionIdOfExceptionHandler: 0x0 -; ALL: Flags [ (0x128200) -; ALL: AsynchronousExceptionHandling (0x200) -; ALL: OptimizedForSpeed (0x100000) -; ALL: ] -; ALL: } -; ALL: } -; ALL: { -; ALL: BlockEnd { -; ALL: } -; ALL: } -; ALL: { -; ALL: BuildInfo { -; ALL: BuildId: 4110 -; ALL: } -; ALL: } -; ALL: ] -; ALL: } -; ALL: { -; ALL: Name: * Linker * -; ALL: Debug Stream Index: 14 -; ALL: Object File Name: -; ALL: Num Files: 0 -; ALL: Source File Name Idx: 0 -; ALL: Pdb File Name Idx: 1 -; ALL: Line Info Byte Size: 0 -; ALL: C13 Line Info Byte Size: 0 -; ALL: Symbol Byte Size: 516 -; ALL: Type Server Index: 0 -; ALL: Has EC Info: No -; ALL: 0 Contributing Source Files [ -; ALL: ] -; ALL: Symbols [ -; ALL: { -; ALL: ObjectName { -; ALL: Signature: 0x0 -; ALL: ObjectName: * Linker * -; ALL: } -; ALL: } -; ALL: { -; ALL: CompilerFlags3 { -; ALL: Language: Link (0x7) -; ALL: Flags [ (0x0) -; ALL: ] -; ALL: Machine: Intel80386 (0x3) -; ALL: FrontendVersion: 0.0.0.0 -; ALL: BackendVersion: 12.0.31101.0 -; ALL: VersionName: Microsoft (R) LINK -; ALL: } -; ALL: } -; ALL: { -; ALL: EnvBlock { -; ALL: Entries [ -; ALL: cwd -; ALL: d:\src\llvm\test\DebugInfo\PDB\Inputs -; ALL: exe -; ALL: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\BIN\link.exe -; ALL: pdb -; ALL: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.pdb -; ALL: ] -; ALL: } -; ALL: } -; ALL: { -; ALL: Trampoline { -; ALL: Type: TrampIncremental (0x0) -; ALL: Size: 5 -; ALL: ThunkOff: 5 -; ALL: TargetOff: 16 -; ALL: ThunkSection: 1 -; ALL: TargetSection: 1 -; ALL: } -; ALL: } -; ALL: { -; ALL: Section { -; ALL: SectionNumber: 1 -; ALL: Alignment: 12 -; ALL: Rva: 4096 -; ALL: Length: 4122 -; ALL: Characteristics [ (0x60000020) -; ALL: IMAGE_SCN_CNT_CODE (0x20) -; ALL: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Name: .text -; ALL: } -; ALL: } -; ALL: { -; ALL: COFF Group { -; ALL: Size: 4122 -; ALL: Characteristics [ (0x60000020) -; ALL: IMAGE_SCN_CNT_CODE (0x20) -; ALL: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Offset: 0 -; ALL: Segment: 1 -; ALL: Name: .text$mn -; ALL: } -; ALL: } -; ALL: { -; ALL: Section { -; ALL: SectionNumber: 2 -; ALL: Alignment: 12 -; ALL: Rva: 12288 -; ALL: Length: 690 -; ALL: Characteristics [ (0x40000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Name: .rdata -; ALL: } -; ALL: } -; ALL: { -; ALL: COFF Group { -; ALL: Size: 323 -; ALL: Characteristics [ (0x40000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Offset: 0 -; ALL: Segment: 2 -; ALL: Name: .rdata -; ALL: } -; ALL: } -; ALL: { -; ALL: COFF Group { -; ALL: Size: 0 -; ALL: Characteristics [ (0x40000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Offset: 323 -; ALL: Segment: 2 -; ALL: Name: .edata -; ALL: } -; ALL: } -; ALL: { -; ALL: COFF Group { -; ALL: Size: 366 -; ALL: Characteristics [ (0x40000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Offset: 324 -; ALL: Segment: 2 -; ALL: Name: .rdata$debug -; ALL: } -; ALL: } -; ALL: { -; ALL: Section { -; ALL: SectionNumber: 3 -; ALL: Alignment: 12 -; ALL: Rva: 16384 -; ALL: Length: 4 -; ALL: Characteristics [ (0xC0000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: IMAGE_SCN_MEM_WRITE (0x80000000) -; ALL: ] -; ALL: Name: .data -; ALL: } -; ALL: } -; ALL: { -; ALL: COFF Group { -; ALL: Size: 4 -; ALL: Characteristics [ (0xC0000080) -; ALL: IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: IMAGE_SCN_MEM_WRITE (0x80000000) -; ALL: ] -; ALL: Offset: 0 -; ALL: Segment: 3 -; ALL: Name: .bss -; ALL: } -; ALL: } -; ALL: { -; ALL: Section { -; ALL: SectionNumber: 4 -; ALL: Alignment: 12 -; ALL: Rva: 20480 -; ALL: Length: 8 -; ALL: Characteristics [ (0x42000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_DISCARDABLE (0x2000000) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Name: .reloc -; ALL: } -; ALL: } -; ALL: ] -; ALL: } -; ALL: ] -; ALL: } -; ALL: Section Contributions [ -; ALL: Contribution { -; ALL: ISect: 1 -; ALL: Off: 0 -; ALL: Size: 10 -; ALL: Characteristics [ (0x60000020) -; ALL: IMAGE_SCN_CNT_CODE (0x20) -; ALL: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Module { -; ALL: Index: 1 -; ALL: Name: * Linker * -; ALL: } -; ALL: Data CRC: 0 -; ALL: Reloc CRC: 0 -; ALL: } -; ALL: Contribution { -; ALL: ISect: 1 -; ALL: Off: 16 -; ALL: Size: 10 -; ALL: Characteristics [ (0x60500020) -; ALL: IMAGE_SCN_ALIGN_16BYTES (0x500000) -; ALL: IMAGE_SCN_CNT_CODE (0x20) -; ALL: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Module { -; ALL: Index: 0 -; ALL: Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; ALL: } -; ALL: Data CRC: 3617027124 -; ALL: Reloc CRC: 0 -; ALL: } -; ALL: Contribution { -; ALL: ISect: 2 -; ALL: Off: 0 -; ALL: Size: 56 -; ALL: Characteristics [ (0x40000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Module { -; ALL: Index: 1 -; ALL: Name: * Linker * -; ALL: } -; ALL: Data CRC: 0 -; ALL: Reloc CRC: 0 -; ALL: } -; ALL: Contribution { -; ALL: ISect: 2 -; ALL: Off: 324 -; ALL: Size: 72 -; ALL: Characteristics [ (0x40300040) -; ALL: IMAGE_SCN_ALIGN_4BYTES (0x300000) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Module { -; ALL: Index: 1 -; ALL: Name: * Linker * -; ALL: } -; ALL: Data CRC: 0 -; ALL: Reloc CRC: 0 -; ALL: } -; ALL: Contribution { -; ALL: ISect: 2 -; ALL: Off: 396 -; ALL: Size: 20 -; ALL: Characteristics [ (0x40300040) -; ALL: IMAGE_SCN_ALIGN_4BYTES (0x300000) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: Module { -; ALL: Index: 1 -; ALL: Name: * Linker * -; ALL: } -; ALL: Data CRC: 0 -; ALL: Reloc CRC: 0 -; ALL: } -; ALL: Contribution { -; ALL: ISect: 3 -; ALL: Off: 0 -; ALL: Size: 4 -; ALL: Characteristics [ (0xC0300080) -; ALL: IMAGE_SCN_ALIGN_4BYTES (0x300000) -; ALL: IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: IMAGE_SCN_MEM_WRITE (0x80000000) -; ALL: ] -; ALL: Module { -; ALL: Index: 0 -; ALL: Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj -; ALL: } -; ALL: Data CRC: 0 -; ALL: Reloc CRC: 0 -; ALL: } -; ALL: ] -; ALL: Section Map [ -; ALL: Entry { -; ALL: Flags [ (0x10D) -; ALL: AddressIs32Bit (0x8) -; ALL: Execute (0x4) -; ALL: IsSelector (0x100) -; ALL: Read (0x1) -; ALL: ] -; ALL: Ovl: 0 -; ALL: Group: 0 -; ALL: Frame: 1 -; ALL: SecName: 65535 -; ALL: ClassName: 65535 -; ALL: Offset: 0 -; ALL: SecByteLength: 4122 -; ALL: } -; ALL: Entry { -; ALL: Flags [ (0x109) -; ALL: AddressIs32Bit (0x8) -; ALL: IsSelector (0x100) -; ALL: Read (0x1) -; ALL: ] -; ALL: Ovl: 0 -; ALL: Group: 0 -; ALL: Frame: 2 -; ALL: SecName: 65535 -; ALL: ClassName: 65535 -; ALL: Offset: 0 -; ALL: SecByteLength: 690 -; ALL: } -; ALL: Entry { -; ALL: Flags [ (0x10B) -; ALL: AddressIs32Bit (0x8) -; ALL: IsSelector (0x100) -; ALL: Read (0x1) -; ALL: Write (0x2) -; ALL: ] -; ALL: Ovl: 0 -; ALL: Group: 0 -; ALL: Frame: 3 -; ALL: SecName: 65535 -; ALL: ClassName: 65535 -; ALL: Offset: 0 -; ALL: SecByteLength: 4 -; ALL: } -; ALL: Entry { -; ALL: Flags [ (0x109) -; ALL: AddressIs32Bit (0x8) -; ALL: IsSelector (0x100) -; ALL: Read (0x1) -; ALL: ] -; ALL: Ovl: 0 -; ALL: Group: 0 -; ALL: Frame: 4 -; ALL: SecName: 65535 -; ALL: ClassName: 65535 -; ALL: Offset: 0 -; ALL: SecByteLength: 8 -; ALL: } -; ALL: Entry { -; ALL: Flags [ (0x208) -; ALL: AddressIs32Bit (0x8) -; ALL: IsAbsoluteAddress (0x200) -; ALL: ] -; ALL: Ovl: 0 -; ALL: Group: 0 -; ALL: Frame: 0 -; ALL: SecName: 65535 -; ALL: ClassName: 65535 -; ALL: Offset: 0 -; ALL: SecByteLength: 4294967295 -; ALL: } -; ALL: ] -; ALL: Globals Stream { -; ALL: Stream number: 6 -; ALL: Number of buckets: 2 -; ALL: Hash Buckets: [0, 12] -; ALL: } -; ALL: Publics Stream { -; ALL: Stream number: 7 -; ALL: SymHash: 556 -; ALL: AddrMap: 8 -; ALL: Number of buckets: 2 -; ALL: Hash Buckets: [0, 12] -; ALL: Address Map: [36, 0] -; ALL: Thunk Map: [4112] -; ALL: Section Offsets: [4096, 1] -; ALL: Symbols [ -; ALL: { -; ALL: PublicSym { -; ALL: Type: 0 -; ALL: Seg: 3 -; ALL: Off: 0 -; ALL: Name: ?__purecall@@3PAXA -; ALL: } -; ALL: } -; ALL: { -; ALL: PublicSym { -; ALL: Type: 2 -; ALL: Seg: 1 -; ALL: Off: 16 -; ALL: Name: _main -; ALL: } -; ALL: } -; ALL: { -; ALL: ProcRef { -; ALL: SumName: 0 -; ALL: SymOffset: 120 -; ALL: Mod: 1 -; ALL: Name: main -; ALL: } -; ALL: } -; ALL: { -; ALL: DataSym { -; ALL: Type: void* (0x403) -; ALL: DisplayName: __purecall -; ALL: } -; ALL: } -; ALL: ] -; ALL: } -; ALL: Section Headers [ -; ALL: { -; ALL: Name: .text -; ALL: Virtual Size: 4122 -; ALL: Virtual Address: 4096 -; ALL: Size of Raw Data: 4608 -; ALL: File Pointer to Raw Data: 1024 -; ALL: File Pointer to Relocations: 0 -; ALL: File Pointer to Linenumbers: 0 -; ALL: Number of Relocations: 0 -; ALL: Number of Linenumbers: 0 -; ALL: Characteristics [ (0x60000020) -; ALL: IMAGE_SCN_CNT_CODE (0x20) -; ALL: IMAGE_SCN_MEM_EXECUTE (0x20000000) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: } -; ALL: { -; ALL: Name: .rdata -; ALL: Virtual Size: 690 -; ALL: Virtual Address: 12288 -; ALL: Size of Raw Data: 1024 -; ALL: File Pointer to Raw Data: 5632 -; ALL: File Pointer to Relocations: 0 -; ALL: File Pointer to Linenumbers: 0 -; ALL: Number of Relocations: 0 -; ALL: Number of Linenumbers: 0 -; ALL: Characteristics [ (0x40000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: } -; ALL: { -; ALL: Name: .data -; ALL: Virtual Size: 4 -; ALL: Virtual Address: 16384 -; ALL: Size of Raw Data: 0 -; ALL: File Pointer to Raw Data: 0 -; ALL: File Pointer to Relocations: 0 -; ALL: File Pointer to Linenumbers: 0 -; ALL: Number of Relocations: 0 -; ALL: Number of Linenumbers: 0 -; ALL: Characteristics [ (0xC0000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: IMAGE_SCN_MEM_WRITE (0x80000000) -; ALL: ] -; ALL: } -; ALL: { -; ALL: Name: .reloc -; ALL: Virtual Size: 8 -; ALL: Virtual Address: 20480 -; ALL: Size of Raw Data: 512 -; ALL: File Pointer to Raw Data: 6656 -; ALL: File Pointer to Relocations: 0 -; ALL: File Pointer to Linenumbers: 0 -; ALL: Number of Relocations: 0 -; ALL: Number of Linenumbers: 0 -; ALL: Characteristics [ (0x42000040) -; ALL: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) -; ALL: IMAGE_SCN_MEM_DISCARDABLE (0x2000000) -; ALL: IMAGE_SCN_MEM_READ (0x40000000) -; ALL: ] -; ALL: } -; ALL: ] -; BIG: FileHeaders { -; BIG-NEXT: BlockSize: 4096 -; BIG-NEXT: FreeBlockMap: 2 -; BIG-NEXT: NumBlocks: 99 -; BIG-NEXT: NumDirectoryBytes: 616 -; BIG-NEXT: Unknown1: 0 -; BIG-NEXT: BlockMapAddr: 97 -; BIG-NEXT: NumDirectoryBlocks: 1 -; BIG-NEXT: DirectoryBlocks: [96] -; BIG-NEXT: NumStreams: 64 -; BIG-NEXT: } -; BIG-NEXT: PDB Stream { -; BIG-NEXT: Version: 20000404 -; BIG-NEXT: Signature: 0x571FFE67 -; BIG-NEXT: Age: 1 -; BIG-NEXT: Guid: {880ECC89-DF81-0B4F-839C-58CBD052E937} -; BIG-NEXT: Features: 0x1 -; BIG-NEXT: Named Streams { -; BIG-NEXT: /names: 13 -; BIG-NEXT: /LinkInfo: 5 -; BIG-NEXT: /src/headerblock: 61 -; BIG-NEXT: } -; BIG-NEXT: } -; BIG-NEXT: DBI Stream { -; BIG-NEXT: Dbi Version: 19990903 -; BIG-NEXT: Age: 1 -; BIG-NEXT: Incremental Linking: Yes -; BIG-NEXT: Has CTypes: No -; BIG-NEXT: Is Stripped: No -; BIG-NEXT: Machine Type: x86 -; BIG-NEXT: Symbol Record Stream Index: 9 -; BIG-NEXT: Public Symbol Stream Index: 8 -; BIG-NEXT: Global Symbol Stream Index: 7 -; BIG-NEXT: Toolchain Version: 14.0 -; BIG-NEXT: mspdb140.dll version: 14.0.23918 -; BIG-NEXT: Modules [ -; BIG-NEXT: { -; BIG-NEXT: Name: D:\src\llvm\test\tools\llvm-symbolizer\pdb\Inputs\test.obj -; BIG-NEXT: Debug Stream Index: 12 -; BIG-NEXT: Object File Name: D:\src\llvm\test\tools\llvm-symbolizer\pdb\Inputs\test.obj -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 400 -; BIG-NEXT: Symbol Byte Size: 872 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: d:\src\llvm\test\tools\llvm-symbolizer\pdb\inputs\test.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_cpu_disp_.obj -; BIG-NEXT: Debug Stream Index: 14 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 14 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 344 -; BIG-NEXT: Symbol Byte Size: 720 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 14 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\misc\i386\cpu_disp.c -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_initsect_.obj -; BIG-NEXT: Debug Stream Index: 15 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 19 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 464 -; BIG-NEXT: Symbol Byte Size: 464 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 19 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\rtc\initsect.cpp -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdlib.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_sehprolg4_.obj -; BIG-NEXT: Debug Stream Index: 16 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 1 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 32 -; BIG-NEXT: Symbol Byte Size: 444 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\eh\i386\sehprolg4.asm -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_chandler4gs_.obj -; BIG-NEXT: Debug Stream Index: 17 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 14 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 344 -; BIG-NEXT: Symbol Byte Size: 604 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 14 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\eh\i386\chandler4gs.c -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_secchk_.obj -; BIG-NEXT: Debug Stream Index: 18 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 14 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 344 -; BIG-NEXT: Symbol Byte Size: 344 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 14 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\eh\i386\secchk.c -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_cookie.obj -; BIG-NEXT: Debug Stream Index: 19 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 9 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 224 -; BIG-NEXT: Symbol Byte Size: 160 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 9 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_report.obj -; BIG-NEXT: Debug Stream Index: 20 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 14 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 1392 -; BIG-NEXT: Symbol Byte Size: 1144 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 14 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\gs\gs_report.c -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_support.obj -; BIG-NEXT: Debug Stream Index: 21 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 10 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 432 -; BIG-NEXT: Symbol Byte Size: 552 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 10 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\gs\gs_support.c -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\checkcfg.obj -; BIG-NEXT: Debug Stream Index: 22 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 14 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 392 -; BIG-NEXT: Symbol Byte Size: 328 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 14 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\misc\checkcfg.c -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\guard_support.obj -; BIG-NEXT: Debug Stream Index: 23 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 10 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 352 -; BIG-NEXT: Symbol Byte Size: 424 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 10 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\misc\guard_support.c -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\loadcfg.obj -; BIG-NEXT: Debug Stream Index: 24 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 9 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 224 -; BIG-NEXT: Symbol Byte Size: 156 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 9 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\dyn_tls_dtor.obj -; BIG-NEXT: Debug Stream Index: 25 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 11 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 328 -; BIG-NEXT: Symbol Byte Size: 272 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 11 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\math.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\utility\dyn_tls_dtor.c -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\dyn_tls_init.obj -; BIG-NEXT: Debug Stream Index: 26 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 10 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 304 -; BIG-NEXT: Symbol Byte Size: 272 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 10 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\utility\dyn_tls_init.c -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\matherr_detection.obj -; BIG-NEXT: Debug Stream Index: 27 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 88 -; BIG-NEXT: Symbol Byte Size: 276 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\utility\matherr_detection.c -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\ucrt_detection.obj -; BIG-NEXT: Debug Stream Index: 28 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 88 -; BIG-NEXT: Symbol Byte Size: 268 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\utility\ucrt_detection.c -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\argv_mode.obj -; BIG-NEXT: Debug Stream Index: 29 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 88 -; BIG-NEXT: Symbol Byte Size: 260 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\argv_mode.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\commit_mode.obj -; BIG-NEXT: Debug Stream Index: 30 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 88 -; BIG-NEXT: Symbol Byte Size: 260 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\commit_mode.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\default_local_stdio_options.obj -; BIG-NEXT: Debug Stream Index: 31 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 24 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 760 -; BIG-NEXT: Symbol Byte Size: 620 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 24 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\default_local_stdio_options.cpp -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\math.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdlib.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdio.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstdio.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_stdio_config.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vadefs.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\denormal_control.obj -; BIG-NEXT: Debug Stream Index: 32 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 80 -; BIG-NEXT: Symbol Byte Size: 272 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\denormal_control.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\env_mode.obj -; BIG-NEXT: Debug Stream Index: 33 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 88 -; BIG-NEXT: Symbol Byte Size: 268 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\env_mode.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\file_mode.obj -; BIG-NEXT: Debug Stream Index: 34 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 88 -; BIG-NEXT: Symbol Byte Size: 260 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\file_mode.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\invalid_parameter_handler.obj -; BIG-NEXT: Debug Stream Index: 35 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 80 -; BIG-NEXT: Symbol Byte Size: 292 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\invalid_parameter_handler.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\matherr.obj -; BIG-NEXT: Debug Stream Index: 36 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 2 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 112 -; BIG-NEXT: Symbol Byte Size: 312 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 2 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\matherr.cpp -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\math.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\new_mode.obj -; BIG-NEXT: Debug Stream Index: 37 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 88 -; BIG-NEXT: Symbol Byte Size: 260 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\new_mode.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\thread_locale.obj -; BIG-NEXT: Debug Stream Index: 38 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 88 -; BIG-NEXT: Symbol Byte Size: 272 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\thread_locale.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\tncleanup.obj -; BIG-NEXT: Debug Stream Index: 39 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 21 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 624 -; BIG-NEXT: Symbol Byte Size: 432 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 21 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\eh\tncleanup.cpp -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_typeinfo.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_exception.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdlib.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\exe_main.obj -; BIG-NEXT: Debug Stream Index: 40 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 26 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 1668 -; BIG-NEXT: Symbol Byte Size: 2364 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 26 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\startup\exe_main.cpp -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\math.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdio.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstdio.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_stdio_config.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdlib.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vadefs.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\initializers.obj -; BIG-NEXT: Debug Stream Index: 41 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 20 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 488 -; BIG-NEXT: Symbol Byte Size: 196 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 20 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\math.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdlib.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\utility.obj -; BIG-NEXT: Debug Stream Index: 42 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 20 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 2500 -; BIG-NEXT: Symbol Byte Size: 6020 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 20 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\utility\utility.cpp -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\math.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdlib.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\ucrt_stubs.obj -; BIG-NEXT: Debug Stream Index: 43 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 1 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 368 -; BIG-NEXT: Symbol Byte Size: 988 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 1 Contributing Source Files [ -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\utility\ucrt_stubs.cpp -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\utility_desktop.obj -; BIG-NEXT: Debug Stream Index: 44 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 20 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 1240 -; BIG-NEXT: Symbol Byte Size: 1844 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 20 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\utility\utility_desktop.cpp -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\math.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdlib.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\default_precision.obj -; BIG-NEXT: Debug Stream Index: 45 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib -; BIG-NEXT: Num Files: 20 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 552 -; BIG-NEXT: Symbol Byte Size: 356 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 20 Contributing Source Files [ -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\string.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\src\defaults\default_precision.cpp -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\internal_shared.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\malloc.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h -; BIG-NEXT: f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h -; BIG-NEXT: f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\math.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\stdlib.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\ctype.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h -; BIG-NEXT: f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h -; BIG-NEXT: f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: Import:KERNEL32.dll -; BIG-NEXT: Debug Stream Index: 47 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\um\x86\kernel32.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 1616 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: KERNEL32.dll -; BIG-NEXT: Debug Stream Index: 46 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\um\x86\kernel32.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 208 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: Import:VCRUNTIME140.dll -; BIG-NEXT: Debug Stream Index: 49 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\vcruntime.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 664 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: VCRUNTIME140.dll -; BIG-NEXT: Debug Stream Index: 48 -; BIG-NEXT: Object File Name: C:\PROGRA~2\MI0E91~1.0\VC\LIB\vcruntime.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 148 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: Import:api-ms-win-crt-stdio-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 59 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 264 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: api-ms-win-crt-stdio-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 58 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 180 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: Import:api-ms-win-crt-runtime-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 57 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 3068 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: api-ms-win-crt-runtime-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 56 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 188 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: Import:api-ms-win-crt-math-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 55 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 140 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: api-ms-win-crt-math-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 54 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 180 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: Import:api-ms-win-crt-locale-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 53 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 148 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: api-ms-win-crt-locale-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 52 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 188 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: Import:api-ms-win-crt-heap-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 51 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 136 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: api-ms-win-crt-heap-l1-1-0.dll -; BIG-NEXT: Debug Stream Index: 50 -; BIG-NEXT: Object File Name: C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 0 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 180 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: { -; BIG-NEXT: Name: * Linker * -; BIG-NEXT: Debug Stream Index: 60 -; BIG-NEXT: Object File Name: -; BIG-NEXT: Num Files: 0 -; BIG-NEXT: Source File Name Idx: 0 -; BIG-NEXT: Pdb File Name Idx: 55 -; BIG-NEXT: Line Info Byte Size: 0 -; BIG-NEXT: C13 Line Info Byte Size: 0 -; BIG-NEXT: Symbol Byte Size: 3080 -; BIG-NEXT: Type Server Index: 0 -; BIG-NEXT: Has EC Info: No -; BIG-NEXT: 0 Contributing Source Files [ -; BIG-NEXT: ] -; BIG-NEXT: } -; BIG-NEXT: ] -; BIG-NEXT: } -; BAD-BLOCK-SIZE: Native PDB Error: The PDB file is corrupt. Does not contain superblock +BIG: Summary +BIG-NEXT: ============================================================ +BIG-NEXT: Block Size: 4096 +BIG-NEXT: Number of blocks: 99 +BIG-NEXT: Number of streams: 64 +BIG-NEXT: Signature: 1461714535 +BIG-NEXT: Age: 1 +BIG-NEXT: GUID: {880ECC89-DF81-0B4F-839C-58CBD052E937} +BIG-NEXT: Features: 0x1 +BIG-NEXT: Has Debug Info: true +BIG-NEXT: Has Types: true +BIG-NEXT: Has IDs: true +BIG-NEXT: Has Globals: true +BIG-NEXT: Has Publics: true +BIG-NEXT: Is incrementally linked: true +BIG-NEXT: Has conflicting types: false +BIG-NEXT: Is stripped: false +BIG: Modules +BIG-NEXT: ============================================================ +BIG-NEXT: Mod 0000 | Name: `D:\src\llvm\test\tools\llvm-symbolizer\pdb\Inputs\test.obj`: +BIG-NEXT: Obj: `D:\src\llvm\test\tools\llvm-symbolizer\pdb\Inputs\test.obj`: +BIG-NEXT: debug stream: 12, # files: 1, has ec info: false +BIG-NEXT: Mod 0001 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_cpu_disp_.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 14, # files: 14, has ec info: false +BIG-NEXT: Mod 0002 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_initsect_.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 15, # files: 19, has ec info: false +BIG-NEXT: Mod 0003 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_sehprolg4_.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 16, # files: 1, has ec info: false +BIG-NEXT: Mod 0004 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_chandler4gs_.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 17, # files: 14, has ec info: false +BIG-NEXT: Mod 0005 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_secchk_.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 18, # files: 14, has ec info: false +BIG-NEXT: Mod 0006 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_cookie.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 19, # files: 9, has ec info: false +BIG-NEXT: Mod 0007 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_report.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 20, # files: 14, has ec info: false +BIG-NEXT: Mod 0008 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_support.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 21, # files: 10, has ec info: false +BIG-NEXT: Mod 0009 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\checkcfg.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 22, # files: 14, has ec info: false +BIG-NEXT: Mod 0010 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\guard_support.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 23, # files: 10, has ec info: false +BIG-NEXT: Mod 0011 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\loadcfg.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 24, # files: 9, has ec info: false +BIG-NEXT: Mod 0012 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\dyn_tls_dtor.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 25, # files: 11, has ec info: false +BIG-NEXT: Mod 0013 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\dyn_tls_init.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 26, # files: 10, has ec info: false +BIG-NEXT: Mod 0014 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\matherr_detection.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 27, # files: 1, has ec info: false +BIG-NEXT: Mod 0015 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\ucrt_detection.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 28, # files: 1, has ec info: false +BIG-NEXT: Mod 0016 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\argv_mode.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 29, # files: 1, has ec info: false +BIG-NEXT: Mod 0017 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\commit_mode.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 30, # files: 1, has ec info: false +BIG-NEXT: Mod 0018 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\default_local_stdio_options.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 31, # files: 24, has ec info: false +BIG-NEXT: Mod 0019 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\denormal_control.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 32, # files: 1, has ec info: false +BIG-NEXT: Mod 0020 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\env_mode.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 33, # files: 1, has ec info: false +BIG-NEXT: Mod 0021 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\file_mode.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 34, # files: 1, has ec info: false +BIG-NEXT: Mod 0022 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\invalid_parameter_handler.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 35, # files: 1, has ec info: false +BIG-NEXT: Mod 0023 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\matherr.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 36, # files: 2, has ec info: false +BIG-NEXT: Mod 0024 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\new_mode.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 37, # files: 1, has ec info: false +BIG-NEXT: Mod 0025 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\thread_locale.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 38, # files: 1, has ec info: false +BIG-NEXT: Mod 0026 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\tncleanup.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 39, # files: 21, has ec info: false +BIG-NEXT: Mod 0027 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\exe_main.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 40, # files: 26, has ec info: false +BIG-NEXT: Mod 0028 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\initializers.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 41, # files: 20, has ec info: false +BIG-NEXT: Mod 0029 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\utility.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 42, # files: 20, has ec info: false +BIG-NEXT: Mod 0030 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\ucrt_stubs.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 43, # files: 1, has ec info: false +BIG-NEXT: Mod 0031 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\utility_desktop.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 44, # files: 20, has ec info: false +BIG-NEXT: Mod 0032 | Name: `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\default_precision.obj`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\MSVCRT.lib`: +BIG-NEXT: debug stream: 45, # files: 20, has ec info: false +BIG-NEXT: Mod 0033 | Name: `Import:KERNEL32.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\um\x86\kernel32.lib`: +BIG-NEXT: debug stream: 47, # files: 0, has ec info: false +BIG-NEXT: Mod 0034 | Name: `KERNEL32.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\um\x86\kernel32.lib`: +BIG-NEXT: debug stream: 46, # files: 0, has ec info: false +BIG-NEXT: Mod 0035 | Name: `Import:VCRUNTIME140.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\vcruntime.lib`: +BIG-NEXT: debug stream: 49, # files: 0, has ec info: false +BIG-NEXT: Mod 0036 | Name: `VCRUNTIME140.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\MI0E91~1.0\VC\LIB\vcruntime.lib`: +BIG-NEXT: debug stream: 48, # files: 0, has ec info: false +BIG-NEXT: Mod 0037 | Name: `Import:api-ms-win-crt-stdio-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 59, # files: 0, has ec info: false +BIG-NEXT: Mod 0038 | Name: `api-ms-win-crt-stdio-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 58, # files: 0, has ec info: false +BIG-NEXT: Mod 0039 | Name: `Import:api-ms-win-crt-runtime-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 57, # files: 0, has ec info: false +BIG-NEXT: Mod 0040 | Name: `api-ms-win-crt-runtime-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 56, # files: 0, has ec info: false +BIG-NEXT: Mod 0041 | Name: `Import:api-ms-win-crt-math-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 55, # files: 0, has ec info: false +BIG-NEXT: Mod 0042 | Name: `api-ms-win-crt-math-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 54, # files: 0, has ec info: false +BIG-NEXT: Mod 0043 | Name: `Import:api-ms-win-crt-locale-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 53, # files: 0, has ec info: false +BIG-NEXT: Mod 0044 | Name: `api-ms-win-crt-locale-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 52, # files: 0, has ec info: false +BIG-NEXT: Mod 0045 | Name: `Import:api-ms-win-crt-heap-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 51, # files: 0, has ec info: false +BIG-NEXT: Mod 0046 | Name: `api-ms-win-crt-heap-l1-1-0.dll`: +BIG-NEXT: Obj: `C:\PROGRA~2\WI3CF2~1\10\Lib\10.0.10586.0\ucrt\x86\ucrt.lib`: +BIG-NEXT: debug stream: 50, # files: 0, has ec info: false +BIG-NEXT: Mod 0047 | Name: `* Linker *`: +BIG-NEXT: Obj: ``: +BIG-NEXT: debug stream: 60, # files: 0, has ec info: false +BIG: Files +BIG-NEXT: ============================================================ +BIG-NEXT: Mod 0000 | `D:\src\llvm\test\tools\llvm-symbolizer\pdb\Inputs\test.obj`: +BIG-NEXT: - (MD5: A20261917ADC01A12CBDBF778BC6CCC8) d:\src\llvm\test\tools\llvm-symbolizer\pdb\inputs\test.cpp +BIG-NEXT: Mod 0001 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_cpu_disp_.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: 884E12AC852D3B4E1E625A0F01595A68) f:\dd\vctools\crt\vcstartup\src\misc\i386\cpu_disp.c +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: Mod 0002 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_initsect_.obj`: +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: DD3FFC8C4284997F6762C449313244B2) f:\dd\vctools\crt\vcstartup\src\rtc\initsect.cpp +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: C44C7E39EE3B3A4EF6B3211EC0110AA8) f:\dd\externalapis\unifiedcrt\inc\stdlib.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: CA7D066706A198EA5999B084AAB0CE58) f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h +BIG-NEXT: - (MD5: F9FC1E83CBE1A51209ED1C05BB0F70B2) f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h +BIG-NEXT: - (MD5: A40485987BE01BAF5F57569A41DAB837) f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: 96C01EE8E4C01B90601D93353838EBF8) f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: Mod 0003 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_sehprolg4_.obj`: +BIG-NEXT: - (MD5: E562BB073C88A6A3791CE9FBDC64E7A7) f:\dd\vctools\crt\vcstartup\src\eh\i386\sehprolg4.asm +BIG-NEXT: Mod 0004 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_chandler4gs_.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: D014BFD91FD6D4163AF92452CBC9EEA0) f:\dd\vctools\crt\vcstartup\src\eh\i386\chandler4gs.c +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: Mod 0005 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\_secchk_.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: 6C34B4E5ACA82CB0D6BD6CB8C059C9C9) f:\dd\vctools\crt\vcstartup\src\eh\i386\secchk.c +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: Mod 0006 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_cookie.obj`: +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: Mod 0007 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_report.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: 87566AA39C18DD3CEAC021002D34B63D) f:\dd\vctools\crt\vcstartup\src\gs\gs_report.c +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: Mod 0008 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\gs_support.obj`: +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: 57AC84319EF78F67DAA9372FDA8CBFCC) f:\dd\vctools\crt\vcstartup\src\gs\gs_support.c +BIG-NEXT: Mod 0009 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\checkcfg.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: 9552C4FC4125F9D7D3A8B5FD18B7BCCF) f:\dd\vctools\crt\vcstartup\src\misc\checkcfg.c +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: Mod 0010 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\guard_support.obj`: +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: 8BFBA3D0672A148A9FB0E9F0A6BC256D) f:\dd\vctools\crt\vcstartup\src\misc\guard_support.c +BIG-NEXT: Mod 0011 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\loadcfg.obj`: +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: Mod 0012 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\dyn_tls_dtor.obj`: +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: 23CC88BD1D9451C2CE5F824306E16E4D) f:\dd\externalapis\unifiedcrt\inc\math.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: EE3858E06B118BDBAAE53F5E55B0BB0C) f:\dd\vctools\crt\vcstartup\src\utility\dyn_tls_dtor.c +BIG-NEXT: Mod 0013 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\dyn_tls_init.obj`: +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: 9DA48F59075BBAAAB4F7FC4575F34405) f:\dd\vctools\crt\vcstartup\src\utility\dyn_tls_init.c +BIG-NEXT: Mod 0014 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\matherr_detection.obj`: +BIG-NEXT: - (MD5: 2DF28D8BA8B7AAAA67C94719B214B060) f:\dd\vctools\crt\vcstartup\src\utility\matherr_detection.c +BIG-NEXT: Mod 0015 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\ucrt_detection.obj`: +BIG-NEXT: - (MD5: 737902C62D7458629D0DDD52E122C033) f:\dd\vctools\crt\vcstartup\src\utility\ucrt_detection.c +BIG-NEXT: Mod 0016 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\argv_mode.obj`: +BIG-NEXT: - (MD5: 634D3D57BDE292817F77F8DBF366E2D2) f:\dd\vctools\crt\vcstartup\src\defaults\argv_mode.cpp +BIG-NEXT: Mod 0017 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\commit_mode.obj`: +BIG-NEXT: - (MD5: CF5B0F6243121A3F5E206E07CA457128) f:\dd\vctools\crt\vcstartup\src\defaults\commit_mode.cpp +BIG-NEXT: Mod 0018 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\default_local_stdio_options.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: E6391682D136711F96E730F4D6162E0C) f:\dd\vctools\crt\vcstartup\src\defaults\default_local_stdio_options.cpp +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 23CC88BD1D9451C2CE5F824306E16E4D) f:\dd\externalapis\unifiedcrt\inc\math.h +BIG-NEXT: - (MD5: C44C7E39EE3B3A4EF6B3211EC0110AA8) f:\dd\externalapis\unifiedcrt\inc\stdlib.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: CA7D066706A198EA5999B084AAB0CE58) f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2D5E699DF1BED89FCCCCCF0DCFC49050) f:\dd\externalapis\unifiedcrt\inc\stdio.h +BIG-NEXT: - (MD5: 2443DB19DCC585E308F60DAFEF1D4C4C) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstdio.h +BIG-NEXT: - (MD5: 79921ECB03C5C56E28D771ADF8910FD8) f:\dd\externalapis\unifiedcrt\inc\corecrt_stdio_config.h +BIG-NEXT: - (MD5: 7C388EF80868D8301B5A908485637FEE) f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: 96C01EE8E4C01B90601D93353838EBF8) f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: A40485987BE01BAF5F57569A41DAB837) f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h +BIG-NEXT: - (MD5: 303C50A7BC924CD426BAA20C7F16192C) f:\dd\vctools\crt\vcruntime\inc\vadefs.h +BIG-NEXT: - (MD5: F9FC1E83CBE1A51209ED1C05BB0F70B2) f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h +BIG-NEXT: Mod 0019 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\denormal_control.obj`: +BIG-NEXT: - (MD5: 0513001DBCB8CB8F8561DC117FD943BA) f:\dd\vctools\crt\vcstartup\src\defaults\denormal_control.cpp +BIG-NEXT: Mod 0020 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\env_mode.obj`: +BIG-NEXT: - (MD5: 5B7121FC3210A120D7B70CB668D8EF0C) f:\dd\vctools\crt\vcstartup\src\defaults\env_mode.cpp +BIG-NEXT: Mod 0021 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\file_mode.obj`: +BIG-NEXT: - (MD5: 749603C05EB2FB5024819A3107DA9A7D) f:\dd\vctools\crt\vcstartup\src\defaults\file_mode.cpp +BIG-NEXT: Mod 0022 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\invalid_parameter_handler.obj`: +BIG-NEXT: - (MD5: 0C385FD7C6DB91E0BA7C72C1AB680BE6) f:\dd\vctools\crt\vcstartup\src\defaults\invalid_parameter_handler.cpp +BIG-NEXT: Mod 0023 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\matherr.obj`: +BIG-NEXT: - (MD5: F8B3DAD79F14E4169CCBA611203C89CD) f:\dd\vctools\crt\vcstartup\src\defaults\matherr.cpp +BIG-NEXT: - (MD5: 23CC88BD1D9451C2CE5F824306E16E4D) f:\dd\externalapis\unifiedcrt\inc\math.h +BIG-NEXT: Mod 0024 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\new_mode.obj`: +BIG-NEXT: - (MD5: 4F22B6A5E4E0D01E8C000B17F2B2640D) f:\dd\vctools\crt\vcstartup\src\defaults\new_mode.cpp +BIG-NEXT: Mod 0025 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\thread_locale.obj`: +BIG-NEXT: - (MD5: 435F5F51541F7D6565DF6BE20F8AC8A3) f:\dd\vctools\crt\vcstartup\src\defaults\thread_locale.cpp +BIG-NEXT: Mod 0026 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\tncleanup.obj`: +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 984A18787250F7F6D0506E6BC1FD7991) f:\dd\vctools\crt\vcstartup\src\eh\tncleanup.cpp +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 2465A06B1F50CD26AD5EC7D20DA6DB3D) f:\dd\vctools\crt\vcruntime\inc\vcruntime_typeinfo.h +BIG-NEXT: - (MD5: 385CF08DA92F72075026067CE03F8402) f:\dd\vctools\crt\vcruntime\inc\vcruntime_exception.h +BIG-NEXT: - (MD5: C44C7E39EE3B3A4EF6B3211EC0110AA8) f:\dd\externalapis\unifiedcrt\inc\stdlib.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: CA7D066706A198EA5999B084AAB0CE58) f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h +BIG-NEXT: - (MD5: F9FC1E83CBE1A51209ED1C05BB0F70B2) f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h +BIG-NEXT: - (MD5: A40485987BE01BAF5F57569A41DAB837) f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: 96C01EE8E4C01B90601D93353838EBF8) f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: Mod 0027 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\exe_main.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: B71A807A307A52C400179EF5D3FAA1A7) f:\dd\vctools\crt\vcstartup\src\startup\exe_main.cpp +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 23CC88BD1D9451C2CE5F824306E16E4D) f:\dd\externalapis\unifiedcrt\inc\math.h +BIG-NEXT: - (MD5: 2D5E699DF1BED89FCCCCCF0DCFC49050) f:\dd\externalapis\unifiedcrt\inc\stdio.h +BIG-NEXT: - (MD5: 2443DB19DCC585E308F60DAFEF1D4C4C) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstdio.h +BIG-NEXT: - (MD5: 79921ECB03C5C56E28D771ADF8910FD8) f:\dd\externalapis\unifiedcrt\inc\corecrt_stdio_config.h +BIG-NEXT: - (MD5: C44C7E39EE3B3A4EF6B3211EC0110AA8) f:\dd\externalapis\unifiedcrt\inc\stdlib.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: CA7D066706A198EA5999B084AAB0CE58) f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 36A3069CD09EC9F92668000F200D5545) f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl +BIG-NEXT: - (MD5: 7C388EF80868D8301B5A908485637FEE) f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: 96C01EE8E4C01B90601D93353838EBF8) f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: A40485987BE01BAF5F57569A41DAB837) f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: 303C50A7BC924CD426BAA20C7F16192C) f:\dd\vctools\crt\vcruntime\inc\vadefs.h +BIG-NEXT: - (MD5: F9FC1E83CBE1A51209ED1C05BB0F70B2) f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h +BIG-NEXT: Mod 0028 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\initializers.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 23CC88BD1D9451C2CE5F824306E16E4D) f:\dd\externalapis\unifiedcrt\inc\math.h +BIG-NEXT: - (MD5: C44C7E39EE3B3A4EF6B3211EC0110AA8) f:\dd\externalapis\unifiedcrt\inc\stdlib.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: CA7D066706A198EA5999B084AAB0CE58) f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 7C388EF80868D8301B5A908485637FEE) f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: 96C01EE8E4C01B90601D93353838EBF8) f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: A40485987BE01BAF5F57569A41DAB837) f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h +BIG-NEXT: - (MD5: 8A16383C445FDABF21BDBAC3825E8133) f:\dd\externalapis\windows\8.1\sdk\inc\evntprov.h +BIG-NEXT: - (MD5: F9FC1E83CBE1A51209ED1C05BB0F70B2) f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h +BIG-NEXT: Mod 0029 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\utility.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: 2D42DDF1AAE9B3491E4BB346255346D5) f:\dd\vctools\crt\vcstartup\src\utility\utility.cpp +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 23CC88BD1D9451C2CE5F824306E16E4D) f:\dd\externalapis\unifiedcrt\inc\math.h +BIG-NEXT: - (MD5: C44C7E39EE3B3A4EF6B3211EC0110AA8) f:\dd\externalapis\unifiedcrt\inc\stdlib.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: CA7D066706A198EA5999B084AAB0CE58) f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 7C388EF80868D8301B5A908485637FEE) f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: 96C01EE8E4C01B90601D93353838EBF8) f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: A40485987BE01BAF5F57569A41DAB837) f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h +BIG-NEXT: - (MD5: F9FC1E83CBE1A51209ED1C05BB0F70B2) f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h +BIG-NEXT: Mod 0030 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\ucrt_stubs.obj`: +BIG-NEXT: - (MD5: 20976B3B6CD70F2DF77312D18D9C8D32) f:\dd\vctools\crt\vcstartup\src\utility\ucrt_stubs.cpp +BIG-NEXT: Mod 0031 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\utility_desktop.obj`: +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: CC9AAE4BAA114C08FFC7F1515EC09E4C) f:\dd\vctools\crt\vcstartup\src\utility\utility_desktop.cpp +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 23CC88BD1D9451C2CE5F824306E16E4D) f:\dd\externalapis\unifiedcrt\inc\math.h +BIG-NEXT: - (MD5: C44C7E39EE3B3A4EF6B3211EC0110AA8) f:\dd\externalapis\unifiedcrt\inc\stdlib.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: CA7D066706A198EA5999B084AAB0CE58) f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: - (MD5: 7C388EF80868D8301B5A908485637FEE) f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: 96C01EE8E4C01B90601D93353838EBF8) f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: A40485987BE01BAF5F57569A41DAB837) f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h +BIG-NEXT: - (MD5: F9FC1E83CBE1A51209ED1C05BB0F70B2) f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h +BIG-NEXT: Mod 0032 | `f:\dd\vctools\crt\vcstartup\build\md\msvcrt_kernel32\obj1r\i386\default_precision.obj`: +BIG-NEXT: - (MD5: 377E41F4DAE6F93EA819B4EFCF229F08) f:\dd\externalapis\unifiedcrt\inc\string.h +BIG-NEXT: - (MD5: 96C01EE8E4C01B90601D93353838EBF8) f:\dd\externalapis\unifiedcrt\inc\corecrt_memory.h +BIG-NEXT: - (MD5: A5976652B404EDDDBDA326FF9A9488A3) f:\dd\externalapis\unifiedcrt\inc\corecrt_memcpy_s.h +BIG-NEXT: - (MD5: 9621B7E7C6A138B5185711F98CCC568E) f:\dd\vctools\crt\vcstartup\src\defaults\default_precision.cpp +BIG-NEXT: - (MD5: 9393435BC7FDE9F624E309D56629171A) f:\dd\vctools\crt\vcruntime\inc\internal_shared.h +BIG-NEXT: - (MD5: A40485987BE01BAF5F57569A41DAB837) f:\dd\vctools\crt\vcruntime\inc\vcruntime_new.h +BIG-NEXT: - (MD5: F9FC1E83CBE1A51209ED1C05BB0F70B2) f:\dd\externalapis\windows\8.1\sdk\inc\winuser.h +BIG-NEXT: - (MD5: 928553F8BA198C9030B65FA10B6B3DD2) f:\dd\externalapis\unifiedcrt\inc\malloc.h +BIG-NEXT: - (MD5: 493F2CAB7A6BE4175748A9FC6C4A38FB) f:\dd\externalapis\windows\8.1\sdk\inc\basetsd.h +BIG-NEXT: - (MD5: E4963431577926D9BA190CD6C10F8743) f:\dd\vctools\crt\vcruntime\inc\i386\xmmintrin.h +BIG-NEXT: - (MD5: C3412F163DF064CCDEF8CFBE0A387550) f:\dd\externalapis\windows\8.1\sdk\inc\winbase.h +BIG-NEXT: - (MD5: 7C388EF80868D8301B5A908485637FEE) f:\dd\vctools\crt\vcstartup\inc\vcstartup_internal.h +BIG-NEXT: - (MD5: 23CC88BD1D9451C2CE5F824306E16E4D) f:\dd\externalapis\unifiedcrt\inc\math.h +BIG-NEXT: - (MD5: C44C7E39EE3B3A4EF6B3211EC0110AA8) f:\dd\externalapis\unifiedcrt\inc\stdlib.h +BIG-NEXT: - (MD5: DCC558DEFD73C17745F94CC5A98632D9) f:\dd\externalapis\windows\8.1\sdk\inc\stralign.h +BIG-NEXT: - (MD5: ADDFD8BEB612E9A30D5FB7C44F9F3D37) f:\dd\externalapis\windows\8.1\sdk\inc\winnt.h +BIG-NEXT: - (MD5: 386A22AB644E999820C7C22FCE5DB574) f:\dd\externalapis\unifiedcrt\inc\ctype.h +BIG-NEXT: - (MD5: CA7D066706A198EA5999B084AAB0CE58) f:\dd\externalapis\windows\8.1\sdk\inc\guiddef.h +BIG-NEXT: - (MD5: 2D923CBDE24BB8F217FE09A5F7D88929) f:\dd\externalapis\unifiedcrt\inc\corecrt_wstring.h +BIG-NEXT: - (MD5: B38ACA278420B7C5F25A50AD159CACA0) f:\dd\externalapis\windows\8.1\sdk\inc\winerror.h +BIG-NEXT: Mod 0033 | `Import:KERNEL32.dll`: +BIG-NEXT: Mod 0034 | `KERNEL32.dll`: +BIG-NEXT: Mod 0035 | `Import:VCRUNTIME140.dll`: +BIG-NEXT: Mod 0036 | `VCRUNTIME140.dll`: +BIG-NEXT: Mod 0037 | `Import:api-ms-win-crt-stdio-l1-1-0.dll`: +BIG-NEXT: Mod 0038 | `api-ms-win-crt-stdio-l1-1-0.dll`: +BIG-NEXT: Mod 0039 | `Import:api-ms-win-crt-runtime-l1-1-0.dll`: +BIG-NEXT: Mod 0040 | `api-ms-win-crt-runtime-l1-1-0.dll`: +BIG-NEXT: Mod 0041 | `Import:api-ms-win-crt-math-l1-1-0.dll`: +BIG-NEXT: Mod 0042 | `api-ms-win-crt-math-l1-1-0.dll`: +BIG-NEXT: Mod 0043 | `Import:api-ms-win-crt-locale-l1-1-0.dll`: +BIG-NEXT: Mod 0044 | `api-ms-win-crt-locale-l1-1-0.dll`: +BIG-NEXT: Mod 0045 | `Import:api-ms-win-crt-heap-l1-1-0.dll`: +BIG-NEXT: Mod 0046 | `api-ms-win-crt-heap-l1-1-0.dll`: +BIG-NEXT: Mod 0047 | `* Linker *`: + +BAD-BLOCK-SIZE: Native PDB Error: The PDB file is corrupt. Does not contain superblock diff --git a/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test b/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test index 2639490f542a..f25e9024453b 100644 --- a/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test +++ b/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test @@ -1,65 +1,51 @@ ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-and-types-1.yaml ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-and-types-2.yaml ; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb -; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s -; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=INTMAIN %s -; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=VOIDMAIN %s -; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s -; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-NAMES %s -; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-UDT %s +; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s +; RUN: llvm-pdbutil raw -ids %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s -TPI-TYPES: Type Info Stream (TPI) -TPI-TYPES: Record count: 9 -TPI-TYPES-DAG: TypeLeafKind: LF_POINTER -TPI-TYPES-DAG: TypeLeafKind: LF_FIELDLIST -TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST -TPI-TYPES-DAG: TypeLeafKind: LF_STRUCTURE -TPI-TYPES-DAG: TypeLeafKind: LF_MEMBER -TPI-TYPES-DAG: TypeLeafKind: LF_POINTER -TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST -TPI-TYPES-DAG: TypeLeafKind: LF_MFUNCTION -TPI-TYPES-DAG: TypeLeafKind: LF_PROCEDURE -TPI-TYPES-DAG: TypeLeafKind: LF_PROCEDURE -TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST +TPI-TYPES: Types (TPI Stream) +TPI-TYPES-NEXT: ============================================================ +TPI-TYPES-NEXT: Showing 9 records +TPI-TYPES-NEXT: 0x1000 | LF_POINTER [size = 12] +TPI-TYPES-NEXT: referent = 0x0470 (char*), mode = pointer, opts = None, kind = ptr32 +TPI-TYPES-NEXT: 0x1001 | LF_FIELDLIST [size = 24] +TPI-TYPES-NEXT: - LF_MEMBER [name = `FooMember`, Type = 0x0403 (void*), offset = 0, attrs = public] +TPI-TYPES-NEXT: 0x1002 | LF_ARGLIST [size = 16] +TPI-TYPES-NEXT: 0x0074 (int): `int` +TPI-TYPES-NEXT: 0x1000: `char**` +TPI-TYPES-NEXT: 0x1003 | LF_STRUCTURE [size = 36] +TPI-TYPES-NEXT: class name: `FooBar` +TPI-TYPES-NEXT: unique name: `FooBar` +TPI-TYPES-NEXT: vtable: , base list: , field list: 0x1001 +TPI-TYPES-NEXT: options: has unique name +TPI-TYPES-NEXT: 0x1004 | LF_POINTER [size = 12] +TPI-TYPES-NEXT: referent = 0x1003, mode = pointer, opts = None, kind = ptr32 +TPI-TYPES-NEXT: 0x1005 | LF_ARGLIST [size = 12] +TPI-TYPES-NEXT: 0x0074 (int): `int` +TPI-TYPES-NEXT: 0x1006 | LF_MFUNCTION [size = 28] +TPI-TYPES-NEXT: return type = 1, # args = 0x1005, param list = 0x0003 (void) +TPI-TYPES-NEXT: class type = 0x1003, this type = 0x1004, this adjust = 0 +TPI-TYPES-NEXT: calling conv = thiscall, options = constructor +TPI-TYPES-NEXT: 0x1007 | LF_PROCEDURE [size = 16] +TPI-TYPES-NEXT: return type = 0x0074 (int), # args = 2, param list = 0x1002 +TPI-TYPES-NEXT: calling conv = cdecl, options = None +TPI-TYPES-NEXT: 0x1008 | LF_PROCEDURE [size = 16] +TPI-TYPES-NEXT: return type = 0x0003 (void), # args = 2, param list = 0x1002 +TPI-TYPES-NEXT: calling conv = cdecl, options = None -; Both procedures should use the same arglist even though they have a different -; return type. -INTMAIN: ArgList ([[ID:.*]]) -INTMAIN-NEXT: TypeLeafKind: LF_ARGLIST -INTMAIN-NEXT: NumArgs: 2 -INTMAIN-NEXT: Arguments [ -INTMAIN-NEXT: ArgType: int -INTMAIN-NEXT: ArgType: char** -INTMAIN: TypeLeafKind: LF_PROCEDURE -INTMAIN: ReturnType: int -INTMAIN: NumParameters: 2 -INTMAIN-NEXT: ArgListType: (int, char**) ([[ID]]) - -VOIDMAIN: ArgList ([[ID:.*]]) -VOIDMAIN-NEXT: TypeLeafKind: LF_ARGLIST -VOIDMAIN-NEXT: NumArgs: 2 -VOIDMAIN-NEXT: Arguments [ -VOIDMAIN-NEXT: ArgType: int -VOIDMAIN-NEXT: ArgType: char** -VOIDMAIN: TypeLeafKind: LF_PROCEDURE -VOIDMAIN: ReturnType: void -VOIDMAIN: NumParameters: 2 -VOIDMAIN-NEXT: ArgListType: (int, char**) ([[ID]]) - -IPI-TYPES: Type Info Stream (IPI) -IPI-TYPES: Record count: 6 -IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID -IPI-TYPES-DAG: TypeLeafKind: LF_MFUNC_ID -IPI-TYPES-DAG: TypeLeafKind: LF_UDT_MOD_SRC_LINE -IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID -IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID -IPI-TYPES-DAG: TypeLeafKind: LF_MFUNC_ID - -IPI-NAMES-DAG: Name: main -IPI-NAMES-DAG: Name: FooMethod -IPI-NAMES-DAG: Name: main2 -IPI-NAMES-DAG: Name: foo -IPI-NAMES-DAG: Name: FooMethod2 - -IPI-UDT: TypeLeafKind: LF_UDT_MOD_SRC_LINE -IPI-UDT-NEXT: UDT: FooBar +IPI-TYPES: Types (IPI Stream) +IPI-TYPES-NEXT: ============================================================ +IPI-TYPES-NEXT: Showing 6 records +IPI-TYPES-NEXT: 0x1000 | LF_FUNC_ID [size = 20] +IPI-TYPES-NEXT: name = main, type = 0x1007, parent scope = +IPI-TYPES-NEXT: 0x1001 | LF_MFUNC_ID [size = 24] +IPI-TYPES-NEXT: name = FooMethod, type = 0x1006, class type = 0x1003 +IPI-TYPES-NEXT: 0x1002 | LF_UDT_MOD_SRC_LINE [size = 20] +IPI-TYPES-NEXT: udt = 0x1003, mod = 0, file = 0, line = 0 +IPI-TYPES-NEXT: 0x1003 | LF_FUNC_ID [size = 20] +IPI-TYPES-NEXT: name = main2, type = 0x1007, parent scope = +IPI-TYPES-NEXT: 0x1004 | LF_FUNC_ID [size = 16] +IPI-TYPES-NEXT: name = foo, type = 0x1008, parent scope = +IPI-TYPES-NEXT: 0x1005 | LF_MFUNC_ID [size = 24] +IPI-TYPES-NEXT: name = FooMethod2, type = 0x1006, class type = 0x1003 diff --git a/test/DebugInfo/PDB/pdbdump-mergeids.test b/test/DebugInfo/PDB/pdbdump-mergeids.test index 1c0a8704af2a..441ce4d8dbc8 100644 --- a/test/DebugInfo/PDB/pdbdump-mergeids.test +++ b/test/DebugInfo/PDB/pdbdump-mergeids.test @@ -1,31 +1,24 @@ ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-1.yaml ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-2.yaml ; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb -; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s -; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=SUBSTRS %s -; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s +; RUN: llvm-pdbutil raw -ids %t.3.pdb | FileCheck -check-prefix=MERGED %s +; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s -MERGED: Type Info Stream (IPI) -MERGED: Record count: 8 -MERGED-DAG: StringData: One -MERGED-DAG: StringData: Two -MERGED-DAG: StringData: SubOne -MERGED-DAG: StringData: SubTwo -MERGED-DAG: StringData: Main -MERGED-DAG: TypeLeafKind: LF_SUBSTR_LIST -MERGED-DAG: StringData: OnlyInFirst -MERGED-DAG: StringData: OnlyInSecond +MERGED: Types (IPI Stream) +MERGED-NEXT: ============================================================ +MERGED-NEXT: Showing 8 records +MERGED-NEXT: 0x1000 | LF_STRING_ID [size = 12] ID: , String: One +MERGED-NEXT: 0x1001 | LF_STRING_ID [size = 12] ID: , String: Two +MERGED-NEXT: 0x1002 | LF_STRING_ID [size = 20] ID: , String: OnlyInFirst +MERGED-NEXT: 0x1003 | LF_STRING_ID [size = 16] ID: , String: SubOne +MERGED-NEXT: 0x1004 | LF_STRING_ID [size = 16] ID: , String: SubTwo +MERGED-NEXT: 0x1005 | LF_SUBSTR_LIST [size = 16] +MERGED-NEXT: 0x1003: `SubOne` +MERGED-NEXT: 0x1004: `SubTwo` +MERGED-NEXT: 0x1006 | LF_STRING_ID [size = 16] ID: 0x1005, String: Main +MERGED-NEXT: 0x1007 | LF_STRING_ID [size = 24] ID: , String: OnlyInSecond -SUBSTRS: StringList -SUBSTRS: TypeLeafKind: LF_SUBSTR_LIST -SUBSTRS-NEXT: NumStrings: 2 -SUBSTRS-NEXT: Strings [ -SUBSTRS-NEXT: SubOne -SUBSTRS-NEXT: SubTwo -SUBSTRS: StringId -SUBSTRS-NEXT: TypeLeafKind: LF_STRING_ID -SUBSTRS-NEXT: Id: "SubOne" "SubTwo" -SUBSTRS-NEXT: StringData: Main - -TPI-EMPTY: Record count: 0 +TPI-EMPTY: Types (TPI Stream) +TPI-EMPTY-NEXT: ============================================================ +TPI-EMPTY-NEXT: Showing 0 records diff --git a/test/DebugInfo/PDB/pdbdump-mergetypes.test b/test/DebugInfo/PDB/pdbdump-mergetypes.test index 8d32b4d176f2..9aae40543697 100644 --- a/test/DebugInfo/PDB/pdbdump-mergetypes.test +++ b/test/DebugInfo/PDB/pdbdump-mergetypes.test @@ -1,24 +1,36 @@ -; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml -; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml -; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb -; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s -; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=ARGLIST %s - - -MERGED: Type Info Stream (TPI) -MERGED: Record count: 9 -MERGED-DAG: PointeeType: unsigned -MERGED-DAG: PointeeType: unsigned* -MERGED-DAG: PointeeType: unsigned** -MERGED-DAG: PointeeType: __int64 -MERGED-DAG: PointeeType: __int64* -MERGED-DAG: Name: OnlyInMerge1 -MERGED-DAG: Name: OnlyInMerge2 -MERGED-DAG: TypeLeafKind: LF_ARGLIST - -ARGLIST: TypeLeafKind: LF_ARGLIST -ARGLIST-NEXT: NumArgs: 3 -ARGLIST-NEXT: Arguments [ -ARGLIST-NEXT: ArgType: unsigned -ARGLIST-NEXT: ArgType: unsigned* -ARGLIST-NEXT: ArgType: unsigned** ++; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml +; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb +; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=MERGED %s + + +MERGED: Types (TPI Stream) +MERGED-NEXT: ============================================================ +MERGED-NEXT: Showing 9 records +MERGED-NEXT: 0x1000 | LF_POINTER [size = 12] +MERGED-NEXT: referent = 0x0075 (unsigned), mode = pointer, opts = None, kind = ptr32 +MERGED-NEXT: 0x1001 | LF_POINTER [size = 12] +MERGED-NEXT: referent = 0x0076 (__int64), mode = pointer, opts = None, kind = ptr32 +MERGED-NEXT: 0x1002 | LF_STRUCTURE [size = 48] +MERGED-NEXT: class name: `OnlyInMerge1` +MERGED-NEXT: unique name: `OnlyInMerge1` +MERGED-NEXT: vtable: , base list: , field list: +MERGED-NEXT: options: forward ref | has unique name +MERGED-NEXT: 0x1003 | LF_POINTER [size = 12] +MERGED-NEXT: referent = 0x1000, mode = pointer, opts = None, kind = ptr32 +MERGED-NEXT: 0x1004 | LF_POINTER [size = 12] +MERGED-NEXT: referent = 0x1003, mode = pointer, opts = None, kind = ptr32 +MERGED-NEXT: 0x1005 | LF_POINTER [size = 12] +MERGED-NEXT: referent = 0x1001, mode = pointer, opts = None, kind = ptr32 +MERGED-NEXT: 0x1006 | LF_ARGLIST [size = 20] +MERGED-NEXT: 0x0075 (unsigned): `unsigned` +MERGED-NEXT: 0x1000: `unsigned*` +MERGED-NEXT: 0x1003: `unsigned**` +MERGED-NEXT: 0x1007 | LF_PROCEDURE [size = 16] +MERGED-NEXT: return type = 0x0075 (unsigned), # args = 0, param list = 0x1006 +MERGED-NEXT: calling conv = cdecl, options = None +MERGED-NEXT: 0x1008 | LF_STRUCTURE [size = 48] +MERGED-NEXT: class name: `OnlyInMerge2` +MERGED-NEXT: unique name: `OnlyInMerge2` +MERGED-NEXT: vtable: , base list: , field list: +MERGED-NEXT: options: forward ref | has unique name diff --git a/test/DebugInfo/PDB/pdbdump-raw-blocks.test b/test/DebugInfo/PDB/pdbdump-raw-blocks.test index 14e1f86fc029..b695d5a1c4cd 100644 --- a/test/DebugInfo/PDB/pdbdump-raw-blocks.test +++ b/test/DebugInfo/PDB/pdbdump-raw-blocks.test @@ -1,35 +1,29 @@ -; RUN: llvm-pdbutil raw -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s -; RUN: llvm-pdbutil raw -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s -; RUN: not llvm-pdbutil raw -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s -; RUN: not llvm-pdbutil raw -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s -; RUN: not llvm-pdbutil raw -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s - -BLOCK0: Block Data { -BLOCK0-NEXT: Block 0 ( -BLOCK0-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 |Microsoft C/C++ | -BLOCK0-NEXT: 0010: 4D534620 372E3030 0D0A1A44 53000000 |MSF 7.00...DS...| -BLOCK0-NEXT: 0020: 00100000 02000000 19000000 88000000 |................| -BLOCK0-NEXT: 0030: 00000000 18000000 00000000 00000000 |................| -BLOCK0: 0FE0: 00000000 00000000 00000000 00000000 |................| -BLOCK0-NEXT: 0FF0: 00000000 00000000 00000000 00000000 |................| -BLOCK0-NEXT: ) -BLOCK0-NEXT: } - -BLOCK01: Block Data { -BLOCK01-NEXT: Block 0 ( -BLOCK01-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 |Microsoft C/C++ | -BLOCK01-NEXT: 0010: 4D534620 372E3030 0D0A1A44 53000000 |MSF 7.00...DS...| -BLOCK01-NEXT: 0020: 00100000 02000000 19000000 88000000 |................| -BLOCK01-NEXT: 0030: 00000000 18000000 00000000 00000000 |................| -BLOCK01: 0FE0: 00000000 00000000 00000000 00000000 |................| -BLOCK01-NEXT: 0FF0: 00000000 00000000 00000000 00000000 |................| -BLOCK01-NEXT: ) -BLOCK01-NEXT: Block 1 ( -BLOCK01-NEXT: 0000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -BLOCK01-NEXT: 0010: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -BLOCK01: 0FE0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -BLOCK01-NEXT: 0FF0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -BLOCK01-NEXT: ) -BLOCK01-NEXT: } - -BADSYNTAX: Argument '{{.*}}' invalid format. +; RUN: llvm-pdbutil raw -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s +; RUN: llvm-pdbutil raw -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s +; RUN: not llvm-pdbutil raw -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s +; RUN: not llvm-pdbutil raw -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s +; RUN: not llvm-pdbutil raw -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s + +BLOCK0: MSF Blocks +BLOCK0-NEXT: ============================================================ +BLOCK0-NEXT: Block 0 ( +BLOCK0-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 4D534620 372E3030 0D0A1A44 53000000 |Microsoft C/C++ MSF 7.00...DS...| +BLOCK0-NEXT: 0020: 00100000 02000000 19000000 88000000 00000000 18000000 00000000 00000000 |................................| +BLOCK0-NEXT: 0040: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +BLOCK0-NEXT: 0060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +BLOCK0-NOT: Block 1 ( + +BLOCK01: MSF Blocks +BLOCK01-NEXT: ============================================================ +BLOCK01-NEXT: Block 0 ( +BLOCK01-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 4D534620 372E3030 0D0A1A44 53000000 |Microsoft C/C++ MSF 7.00...DS...| +BLOCK01-NEXT: 0020: 00100000 02000000 19000000 88000000 00000000 18000000 00000000 00000000 |................................| +BLOCK01-NEXT: 0040: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +BLOCK01-NEXT: 0060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +BLOCK01: Block 1 ( +BLOCK01-NEXT: 0000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................| +BLOCK01-NEXT: 0020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................| +BLOCK01-NEXT: 0040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................| +BLOCK01-NOT: Block 2 ( + +BADSYNTAX: Argument '{{.*}}' invalid format. diff --git a/test/DebugInfo/PDB/pdbdump-raw-stream.test b/test/DebugInfo/PDB/pdbdump-raw-stream.test index 846960a0964a..2f8e05ad0583 100644 --- a/test/DebugInfo/PDB/pdbdump-raw-stream.test +++ b/test/DebugInfo/PDB/pdbdump-raw-stream.test @@ -1,23 +1,28 @@ -; RUN: llvm-pdbutil raw -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM1 %s -; RUN: not llvm-pdbutil raw -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s - -STREAM1: Stream Data { -STREAM1-NEXT: Stream { -STREAM1-NEXT: Index: 1 -STREAM1-NEXT: Type: PDB Stream -STREAM1-NEXT: Size: 118 -STREAM1-NEXT: Blocks: [19] -STREAM1-NEXT: Data ( -STREAM1-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 |..1....T.....5VA| -STREAM1-NEXT: 0010: 86A0A249 896F9988 FAE52FF0 22000000 |...I.o..../."...| -STREAM1-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 |/LinkInfo./names| -STREAM1-NEXT: 0030: 002F7372 632F6865 61646572 626C6F63 |./src/headerbloc| -STREAM1-NEXT: 0040: 6B000300 00000600 00000100 00001A00 |k...............| -STREAM1-NEXT: 0050: 00000000 00001100 00000900 00000A00 |................| -STREAM1-NEXT: 0060: 00000D00 00000000 00000500 00000000 |................| -STREAM1-NEXT: 0070: 00004191 3201 |..A.2.| -STREAM1-NEXT: ) -STREAM1-NEXT: } -STREAM1-NEXT: } - -INVALIDSTREAM: Native PDB Error: The specified stream could not be loaded. +; RUN: llvm-pdbutil raw -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s +; RUN: llvm-pdbutil raw -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s +; RUN: llvm-pdbutil raw -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s + +STREAM: Stream Data +STREAM-NEXT: ============================================================ +STREAM-NEXT: Stream 1 (118 bytes): PDB Stream +STREAM-NEXT: Data ( +STREAM-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...| +STREAM-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc| +STREAM-NEXT: 0040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................| +STREAM-NEXT: 0060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.| +STREAM-NEXT: ) + +INVALIDSTREAM: Stream Data +INVALIDSTREAM-NEXT: ============================================================ +INVALIDSTREAM-NEXT: Stream 100: Not present + +BOTH: Stream Data +BOTH-NEXT: ============================================================ +BOTH-NEXT: Stream 1 (118 bytes): PDB Stream +BOTH-NEXT: Data ( +BOTH-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...| +BOTH-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc| +BOTH-NEXT: 0040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................| +BOTH-NEXT: 0060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.| +BOTH-NEXT: ) +BOTH-NEXT: Stream 100: Not present diff --git a/test/DebugInfo/PDB/pdbdump-readwrite.test b/test/DebugInfo/PDB/pdbdump-readwrite.test index ee53f3b4cd2a..51ebd754545f 100644 --- a/test/DebugInfo/PDB/pdbdump-readwrite.test +++ b/test/DebugInfo/PDB/pdbdump-readwrite.test @@ -3,48 +3,33 @@ RUN: -pdb-stream -string-table -tpi-stream -stream-directory \ RUN: -stream-metadata %p/Inputs/empty.pdb > %t.1 RUN: llvm-pdbutil yaml2pdb -pdb=%t.2 %t.1 -RUN: llvm-pdbutil raw -headers -string-table -tpi-records %p/Inputs/empty.pdb | FileCheck %s -RUN: llvm-pdbutil raw -headers -string-table -tpi-records %t.2 | FileCheck %s +RUN: llvm-pdbutil raw -summary -string-table -types %p/Inputs/empty.pdb | FileCheck %s +RUN: llvm-pdbutil raw -summary -string-table -types %t.2 | FileCheck %s -CHECK: FileHeaders { -CHECK-NEXT: BlockSize: 4096 -CHECK-NEXT: FreeBlockMap: -CHECK-NEXT: NumBlocks: -CHECK-NEXT: NumDirectoryBytes: -CHECK-NEXT: Unknown1: 0 -CHECK-NEXT: BlockMapAddr: -CHECK-NEXT: NumDirectoryBlocks: 1 -CHECK-NEXT: DirectoryBlocks: -CHECK-NEXT: NumStreams: -CHECK-NEXT: } -CHECK: String Table { -CHECK-DAG: 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)' -CHECK-DAG: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' -CHECK-DAG: '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = ' -CHECK-NEXT: } -CHECK: PDB Stream { -CHECK-NEXT: Version: 20000404 -CHECK-NEXT: Signature: 0x54E507E2 -CHECK-NEXT: Age: 1 -CHECK-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} -CHECK-NEXT: Features: 0x1 -CHECK-NEXT: Named Streams { -CHECK: /names: -CHECK: } -CHECK-NEXT: } -CHECK: Type Info Stream (TPI) { -CHECK-NEXT: TPI Version: 20040203 -CHECK-NEXT: Record count: 75 -CHECK: DBI Stream { -CHECK-NEXT: Dbi Version: 19990903 -CHECK-NEXT: Age: 1 -CHECK-NEXT: Incremental Linking: Yes -CHECK-NEXT: Has CTypes: No -CHECK-NEXT: Is Stripped: No -CHECK-NEXT: Machine Type: x86 -CHECK-NEXT: Symbol Record Stream Index: -CHECK-NEXT: Public Symbol Stream Index: -CHECK-NEXT: Global Symbol Stream Index: -CHECK-NEXT: Toolchain Version: 12.0 -CHECK-NEXT: mspdb120.dll version: 12.0.31101 -CHECK-NEXT: } + +CHECK: Summary +CHECK-NEXT: ============================================================ +CHECK-NEXT: Block Size: 4096 +CHECK-NEXT: Number of blocks: +CHECK-NEXT: Number of streams: +CHECK-NEXT: Signature: 1424295906 +CHECK-NEXT: Age: 1 +CHECK-NEXT: GUID: {0B355641-86A0-A249-896F-9988FAE52FF0} +CHECK-NEXT: Features: 0x1 +CHECK-NEXT: Has Debug Info: true +CHECK-NEXT: Has Types: true +CHECK-NEXT: Has IDs: true +CHECK-NEXT: Has Globals: +CHECK-NEXT: Has Publics: +CHECK-NEXT: Is incrementally linked: true +CHECK-NEXT: Has conflicting types: false +CHECK-NEXT: Is stripped: false +CHECK: String Table +CHECK-NEXT: ============================================================ +CHECK-NEXT: ID | String +CHECK-NEXT: {{.*}} | 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)' +CHECK-NEXT: {{.*}} | 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' +CHECK-NEXT: {{.*}} | '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = ' +CHECK: Types (TPI Stream) +CHECK-NEXT: ============================================================ +CHECK-NEXT: Showing 75 records diff --git a/test/DebugInfo/X86/block-capture.ll b/test/DebugInfo/X86/block-capture.ll index 168040507eef..14927eef59d4 100644 --- a/test/DebugInfo/X86/block-capture.ll +++ b/test/DebugInfo/X86/block-capture.ll @@ -123,7 +123,7 @@ attributes #3 = { nounwind } !66 = !DILocation(line: 2, column: 20, scope: !8) !67 = !DILocation(line: 2, column: 21, scope: !8) !68 = !DILocalVariable(name: "block", line: 2, scope: !8, file: !5, type: !25) -!69 = !DIExpression(DW_OP_deref, DW_OP_plus, 32) +!69 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 32) !70 = !DILocation(line: 2, column: 9, scope: !8) !71 = !DILocation(line: 2, column: 23, scope: !72) !72 = distinct !DILexicalBlock(line: 2, column: 21, file: !1, scope: !8) diff --git a/test/DebugInfo/X86/debug-info-block-captured-self.ll b/test/DebugInfo/X86/debug-info-block-captured-self.ll index 1085eaef0d4e..e1620af50255 100644 --- a/test/DebugInfo/X86/debug-info-block-captured-self.ll +++ b/test/DebugInfo/X86/debug-info-block-captured-self.ll @@ -107,5 +107,5 @@ define internal void @"__24-[Main initWithContext:]_block_invoke_2"(i8* %.block_ !106 = !DILocation(line: 40, scope: !42) !107 = !DIFile(filename: "llvm/tools/clang/test/CodeGenObjC/debug-info-block-captured-self.m", directory: "") !108 = !{i32 1, !"Debug Info Version", i32 3} -!109 = !DIExpression(DW_OP_plus, 32, DW_OP_deref) -!110 = !DIExpression(DW_OP_plus, 32, DW_OP_deref) +!109 = !DIExpression(DW_OP_plus_uconst, 32, DW_OP_deref) +!110 = !DIExpression(DW_OP_plus_uconst, 32, DW_OP_deref) diff --git a/test/DebugInfo/X86/debug-info-blocks.ll b/test/DebugInfo/X86/debug-info-blocks.ll index 859eef804bb1..b79ad89be27d 100644 --- a/test/DebugInfo/X86/debug-info-blocks.ll +++ b/test/DebugInfo/X86/debug-info-blocks.ll @@ -380,4 +380,4 @@ attributes #3 = { nounwind } !108 = !DILocation(line: 61, scope: !36) !109 = !DILocation(line: 62, scope: !36) !110 = !{i32 1, !"Debug Info Version", i32 3} -!111 = !DIExpression(DW_OP_deref, DW_OP_plus, 32) +!111 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 32) diff --git a/test/DebugInfo/X86/double-declare.ll b/test/DebugInfo/X86/double-declare.ll new file mode 100644 index 000000000000..8ed4319b323a --- /dev/null +++ b/test/DebugInfo/X86/double-declare.ll @@ -0,0 +1,44 @@ +; RUN: llc -mtriple=x86_64-apple-darwin -O0 -filetype=obj -o - < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s +; PR33157. Don't crash on duplicate dbg.declare. +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_AT_location [DW_FORM_exprloc] +; CHECK-NOT: DW_AT_location +@g = external global i32 +@h = external global i32 + +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +define void @f(i32* byval %p, i1 %c) !dbg !5 { + br i1 %c, label %x, label %y + +x: + call void @llvm.dbg.declare(metadata i32* %p, metadata !10, metadata !DIExpression()), !dbg !12 + store i32 42, i32* @g, !dbg !12 + br label %done + +y: + call void @llvm.dbg.declare(metadata i32* %p, metadata !10, metadata !DIExpression()), !dbg !12 + store i32 42, i32* @h, !dbg !12 + br label %done + +done: + ret void +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!22, !23} + +!0 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !1, producer: "clang version 5.0.0 ", isOptimized: true, runtimeVersion: 2, emissionKind: FullDebug) +!1 = !DIFile(filename: "", directory: "C:\5Csrc\5Cllvm-project\5Cbuild") +!5 = distinct !DISubprogram(name: "f", isLocal: true, isDefinition: true, scopeLine: 37, flags: DIFlagPrototyped, isOptimized: true, unit: !0, type: !99, scope: !1) +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DILocalVariable(name: "aRect", arg: 1, scope: !11, file: !1, line: 38, type: !6) +!11 = distinct !DILexicalBlock(scope: !98, file: !1, line: 38) +!12 = !DILocation(line: 43, scope: !11, inlinedAt: !13) +!13 = distinct !DILocation(line: 43, scope: !5) +!22 = !{i32 2, !"Dwarf Version", i32 4} +!23 = !{i32 2, !"Debug Info Version", i32 3} +!62 = !{!10} +!98 = distinct !DISubprogram(name: "NSMaxX", scope: !1, file: !1, line: 27, isLocal: true, isDefinition: true, scopeLine: 27, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !62, type: !99) +!99 = !DISubroutineType(types: !100) +!100 = !{null} diff --git a/test/DebugInfo/X86/dw_op_minus.ll b/test/DebugInfo/X86/dw_op_minus.ll index 8e65b489c27b..30bf58378005 100644 --- a/test/DebugInfo/X86/dw_op_minus.ll +++ b/test/DebugInfo/X86/dw_op_minus.ll @@ -10,7 +10,7 @@ ; Capture(buf); ; } ; } -; The interesting part is !DIExpression(DW_OP_minus, 400) +; The interesting part is !DIExpression(DW_OP_constu, 400, DW_OP_minus) target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -56,7 +56,7 @@ declare void @Capture(i32*) !14 = !{i32 2, !"Debug Info Version", i32 3} !15 = !{!"clang version 3.8.0 (trunk 248518) (llvm/trunk 248512)"} !16 = !DILocation(line: 5, column: 3, scope: !4) -!17 = !DIExpression(DW_OP_minus, 400) +!17 = !DIExpression(DW_OP_constu, 400, DW_OP_minus) !18 = !DILocation(line: 5, column: 7, scope: !4) !19 = !DILocation(line: 6, column: 11, scope: !4) !20 = !DILocation(line: 6, column: 3, scope: !4) diff --git a/test/DebugInfo/X86/dw_op_minus_direct.ll b/test/DebugInfo/X86/dw_op_minus_direct.ll index 8d346be532e8..69f4b2c3ef6a 100644 --- a/test/DebugInfo/X86/dw_op_minus_direct.ll +++ b/test/DebugInfo/X86/dw_op_minus_direct.ll @@ -51,7 +51,7 @@ attributes #1 = { nounwind readnone } !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !11 = !{!12} !12 = !DILocalVariable(name: "i", arg: 1, scope: !7, file: !1, line: 1, type: !10) -!13 = !DIExpression(DW_OP_minus, 1, DW_OP_stack_value) +!13 = !DIExpression(DW_OP_constu, 1, DW_OP_minus, DW_OP_stack_value) !14 = !DILocation(line: 1, column: 13, scope: !7) !15 = !DILocation(line: 2, column: 11, scope: !7) !16 = !DILocation(line: 2, column: 3, scope: !7) diff --git a/test/DebugInfo/X86/safestack-byval.ll b/test/DebugInfo/X86/safestack-byval.ll index 42e94698818c..8742c90bc298 100644 --- a/test/DebugInfo/X86/safestack-byval.ll +++ b/test/DebugInfo/X86/safestack-byval.ll @@ -14,7 +14,7 @@ ; } ; CHECK: ![[ZZZ:.*]] = !DILocalVariable(name: "zzz", -; CHECK: ![[ZZZ_EXPR:.*]] = !DIExpression(DW_OP_deref, DW_OP_minus, 400) +; CHECK: ![[ZZZ_EXPR:.*]] = !DIExpression(DW_OP_deref, DW_OP_constu, 400, DW_OP_minus) ; CHECK: DBG_VALUE {{.*}} ![[ZZZ]], ![[ZZZ_EXPR]] %struct.S = type { [100 x i32] } @@ -79,7 +79,7 @@ attributes #2 = { argmemonly nounwind } !20 = !{i32 2, !"Debug Info Version", i32 3} !21 = !{!"clang version 3.8.0 (trunk 254107) (llvm/trunk 254109)"} !22 = !DILocation(line: 8, column: 9, scope: !12) -!23 = !DIExpression(DW_OP_deref, DW_OP_minus, 400) +!23 = !DIExpression(DW_OP_deref, DW_OP_constu, 400, DW_OP_minus) !24 = !DILocation(line: 8, column: 28, scope: !12) !25 = !DIExpression() !26 = !DILocation(line: 9, column: 10, scope: !12) diff --git a/test/DebugInfo/X86/stack-value-dwarf2.ll b/test/DebugInfo/X86/stack-value-dwarf2.ll index 61595f7861fe..b653784ec668 100644 --- a/test/DebugInfo/X86/stack-value-dwarf2.ll +++ b/test/DebugInfo/X86/stack-value-dwarf2.ll @@ -93,4 +93,4 @@ attributes #1 = { nounwind readnone } !15 = !DISubprogram(name: "<(lambda at test.ii:87:58)>", scope: !0, file: !1, line: 27, type: !6, isLocal: false, isDefinition: false, scopeLine: 27, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true, templateParams: !2) !16 = distinct !DILocation(line: 99, column: 21, scope: !17) !17 = !DILexicalBlockFile(scope: !5, file: !1, discriminator: 2) -!18 = !DIExpression(DW_OP_plus, 4, DW_OP_stack_value, DW_OP_LLVM_fragment, 64, 32) +!18 = !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value, DW_OP_LLVM_fragment, 64, 32) diff --git a/test/DebugInfo/X86/unattached-global.ll b/test/DebugInfo/X86/unattached-global.ll index 5d4be7377ef4..5e9af695c8dc 100644 --- a/test/DebugInfo/X86/unattached-global.ll +++ b/test/DebugInfo/X86/unattached-global.ll @@ -12,7 +12,7 @@ target triple = "x86_64-unknown-linux-gnu" !1 = !{!2} !2 = !DIGlobalVariableExpression(var: !3, expr: !4) !3 = distinct !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true, type: !6) -!4 = !DIExpression(DW_OP_plus, 4) +!4 = !DIExpression(DW_OP_plus_uconst, 4) !5 = !DIFile(filename: "", directory: "/") !6 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) diff --git a/test/DebugInfo/dwarfdump-str-offsets-dwp.test b/test/DebugInfo/dwarfdump-str-offsets-dwp.test new file mode 100644 index 000000000000..ceca3225f075 --- /dev/null +++ b/test/DebugInfo/dwarfdump-str-offsets-dwp.test @@ -0,0 +1,56 @@ +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-str-offsets-dwp.x86_64.o | FileCheck %s + +; Verify that the correct strings from each unit are displayed and that the +; index for the .debug_str_offsets section has the right values. + +; CHECK: Compile Unit +; CHECK-NOT: NULL +; CHECK: DW_TAG_compile_unit +; CHECK-NEXT: DW_AT_producer [DW_FORM_strx] ( indexed (00000000) string = "Handmade DWARF producer") +; CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "Compile_Unit_1") +; CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +; CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000002) string = "/home/test/CU1") +; CHECK-NOT: NULL + +; CHECK: Compile Unit +; CHECK-NOT: NULL +; CHECK: DW_TAG_compile_unit +; CHECK-NEXT: DW_AT_producer [DW_FORM_strx] ( indexed (00000000) string = "Handmade DWARF producer") +; CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "Compile_Unit_2") +; CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +; CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000002) string = "/home/test/CU2") +; +; CHECK: Type Unit +; CHECK-NOT: NULL +; CHECK: DW_TAG_type_unit +; CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000000) string = "Type_Unit_1") +; CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x0000001c) +; CHECK-NOT: NULL +; CHECK: DW_TAG_structure_type +; CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "MyStruct_1") +; +; CHECK: Type Unit +; CHECK-NOT: NULL +; CHECK: DW_TAG_type_unit +; CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000000) string = "Type_Unit_2") +; CHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x0000001c) +; CHECK-NOT: NULL +; CHECK: DW_TAG_structure_type +; CHECK-NEXT: DW_AT_name [DW_FORM_strx] ( indexed (00000001) string = "MyStruct_2") + +; Verify the correct offets of the compile and type units contributions in the +; index tables. + +; CHECK: .debug_cu_index contents: +; CHECK-NOT: contents: +; CHECK: 1 0xddeeaaddbbaabbee [{{0x[0-9a-f]*, 0x[0-9a-f]*}}) [{{0x[0-9a-f]*, 0x[0-9a-f]*}}) +; CHECK-SAME: [0x00000000 +; CHECK-NEXT: 2 0xff00ffeeffaaff00 [{{0x[0-9a-f]*, 0x[0-9a-f]*}}) [{{0x[0-9a-f]*, 0x[0-9a-f]*}}) +; CHECK-SAME: [0x00000024 + +; CHECK: .debug_tu_index contents: +; CHECK-NOT: contents: +; CHECK: 1 0xeeaaddbbaabbeedd [{{0x[0-9a-f]*, 0x[0-9a-f]*}}) [{{0x[0-9a-f]*, 0x[0-9a-f]*}}) +; CHECK-SAME: [0x00000000 +; CHECK-NEXT: 2 0x00ffeeffaaff00ff [{{0x[0-9a-f]*, 0x[0-9a-f]*}}) [{{0x[0-9a-f]*, 0x[0-9a-f]*}}) +; CHECK: [0x00000024 diff --git a/test/DebugInfo/dwarfdump-zlib.test b/test/DebugInfo/dwarfdump-zlib.test index d3ef806f3f87..82f29afdebde 100644 --- a/test/DebugInfo/dwarfdump-zlib.test +++ b/test/DebugInfo/dwarfdump-zlib.test @@ -1,6 +1,7 @@ REQUIRES: zlib RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test-zlib.elf-x86-64 | FileCheck %s +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test-zlib.o.elf-x86-64 | FileCheck %s RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test-zlibgnu.elf-x86-64 | FileCheck %s CHECK: .debug_abbrev contents @@ -10,3 +11,7 @@ CHECK: .debug_abbrev contents // that sections names are properly shown in zlib-gnu style (without additional 'z' prefix). CHECK: .debug_info contents CHECK: 0x00000000: Compile Unit: length = 0x00000144 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000148) + +// Also check that relocations in the .zdebug sections are handled correctly: +CHECK: DW_AT_ranges {{.*}} (0x00000000{{$}} +CHECK-NEXT: [0x diff --git a/test/Instrumentation/InstrProfiling/always_inline.ll b/test/Instrumentation/InstrProfiling/always_inline.ll new file mode 100644 index 000000000000..4be7848c9b6f --- /dev/null +++ b/test/Instrumentation/InstrProfiling/always_inline.ll @@ -0,0 +1,28 @@ +; Check that '__attribute__((always_inline)) inline' functions are inlined. + +; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -inline -S | FileCheck %s + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.13.0" + +@__profn_foo = linkonce_odr hidden constant [3 x i8] c"foo" + +; CHECK-LABEL: @main +; CHECK-NOT: call +define i32 @main() { +entry: + %call = call i32 @foo() + ret i32 %call +} + +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #0 + +; CHECK-NOT: define available_externally i32 @foo +define available_externally i32 @foo() #1 { +entry: + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 0, i32 1, i32 0) + ret i32 0 +} + +attributes #0 = { nounwind } +attributes #1 = { alwaysinline } diff --git a/test/Instrumentation/SanitizerCoverage/inline-8bit-counters.ll b/test/Instrumentation/SanitizerCoverage/inline-8bit-counters.ll index 4df6ffeb5a8c..5b5b75117fb5 100644 --- a/test/Instrumentation/SanitizerCoverage/inline-8bit-counters.ll +++ b/test/Instrumentation/SanitizerCoverage/inline-8bit-counters.ll @@ -10,4 +10,4 @@ entry: ; CHECK: store i8 %1, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @__sancov_gen_, i64 0, i64 0), !nosanitize ret void } -; CHECK: call void @__sanitizer_cov_8bit_counters_init(i8* bitcast (i8** @__start___sancov_counters to i8*), i8* bitcast (i8** @__stop___sancov_counters to i8*)) +; CHECK: call void @__sanitizer_cov_8bit_counters_init(i8* bitcast (i8** @__start___sancov_cntrs to i8*), i8* bitcast (i8** @__stop___sancov_cntrs to i8*)) diff --git a/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll b/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll new file mode 100644 index 000000000000..66754889f8ba --- /dev/null +++ b/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll @@ -0,0 +1,16 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @live1() { + call void @live2() + ret void +} + +declare void @live2() + +define void @dead1() { + call void @dead2() + ret void +} + +declare void @dead2() diff --git a/test/LTO/Resolution/X86/dead-strip-fulllto.ll b/test/LTO/Resolution/X86/dead-strip-fulllto.ll new file mode 100644 index 000000000000..a9be2751c81f --- /dev/null +++ b/test/LTO/Resolution/X86/dead-strip-fulllto.ll @@ -0,0 +1,37 @@ +; RUN: opt -module-summary -o %t %s +; RUN: opt -module-summary -o %t2 %S/Inputs/dead-strip-fulllto.ll +; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1,p -r %t,live2,p -r %t,dead2,p \ +; RUN: %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, \ +; RUN: -save-temps -o %t3 +; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s +; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s + +; FULL-NOT: dead +; FULL: U live1 +; FULL: T live2 +; FULL: T main + +; THIN-NOT: dead +; THIN: T live1 +; THIN: U live2 + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @main() { + call void @live1() + ret void +} + +declare void @live1() + +define void @live2() { + ret void +} + +define void @dead2() { + ret void +} + +!0 = !{i32 1, !"ThinLTO", i32 0} +!llvm.module.flags = !{ !0 } diff --git a/test/LTO/Resolution/X86/symtab-elf.ll b/test/LTO/Resolution/X86/symtab-elf.ll index 1683b061c6d6..d5f0fbe3700d 100644 --- a/test/LTO/Resolution/X86/symtab-elf.ll +++ b/test/LTO/Resolution/X86/symtab-elf.ll @@ -6,8 +6,8 @@ target triple = "x86_64-unknown-linux-gnu" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ; CHECK-NOT: linker opts: -!0 = !{i32 6, !"Linker Options", !{!{!"/include:foo"}}} -!llvm.module.flags = !{ !0 } +!0 = !{!"/include:foo"} +!llvm.linker.options = !{ !0 } @g1 = global i32 0 diff --git a/test/LTO/Resolution/X86/symtab.ll b/test/LTO/Resolution/X86/symtab.ll index b7bc11749016..fecea0a1e7b4 100644 --- a/test/LTO/Resolution/X86/symtab.ll +++ b/test/LTO/Resolution/X86/symtab.ll @@ -9,8 +9,8 @@ target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" source_filename = "src.c" ; CHECK: linker opts: /include:foo -!0 = !{i32 6, !"Linker Options", !{!{!"/include:foo"}}} -!llvm.module.flags = !{ !0 } +!0 = !{!"/include:foo"} +!llvm.linker.options = !{ !0 } ; CHECK: D------X _fun define i32 @fun() { diff --git a/test/LibDriver/use-paths.test b/test/LibDriver/use-paths.test new file mode 100644 index 000000000000..971c216127e6 --- /dev/null +++ b/test/LibDriver/use-paths.test @@ -0,0 +1,24 @@ +llvm-lib should behave like "link.exe /lib" and use relative paths to describe +archive members. + +First, get in a clean working directory. +RUN: rm -rf %t && mkdir -p %t && cd %t + +Make foo/a.obj and foo/b.obj. +RUN: mkdir foo +RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o foo/a.obj %S/Inputs/a.s +RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o foo/b.obj %S/Inputs/b.s + +RUN: llvm-lib -out:foo.lib foo/a.obj foo/b.obj +RUN: llvm-ar t foo.lib | FileCheck %s + +FIXME: We should probably use backslashes on Windows to better match MSVC tools. +CHECK: foo/a.obj +CHECK: foo/b.obj + +Do it again with absolute paths and see that we get something. +RUN: llvm-lib -out:foo.lib %t/foo/a.obj %t/foo/b.obj +RUN: llvm-ar t foo.lib | FileCheck %s --check-prefix=ABS + +ABS: {{.*}}/foo/a.obj +ABS: {{.*}}/foo/b.obj diff --git a/test/MC/AMDGPU/flat-gfx9.s b/test/MC/AMDGPU/flat-gfx9.s new file mode 100644 index 000000000000..5f93a7371b8b --- /dev/null +++ b/test/MC/AMDGPU/flat-gfx9.s @@ -0,0 +1,40 @@ +// RUN: not llvm-mc -arch=amdgcn -mcpu=gfx900 -show-encoding %s | FileCheck -check-prefix=GFX9 -check-prefix=GCN %s +// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s | FileCheck -check-prefix=VI -check-prefix=GCN %s + +// RUN: not llvm-mc -arch=amdgcn -mcpu=gfx900 -show-encoding 2>&1 %s | FileCheck -check-prefix=GFX9-ERR -check-prefix=GCNERR %s +// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding 2>&1 %s | FileCheck -check-prefix=VI-ERR -check-prefix=GCNERR %s + + +flat_load_dword v1, v[3:4] offset:0 +// GCN: flat_load_dword v1, v[3:4] ; encoding: [0x00,0x00,0x50,0xdc,0x03,0x00,0x00,0x01] + +flat_load_dword v1, v[3:4] offset:-1 +// GCN-ERR: :35: error: failed parsing operand. + +// FIXME: Error on VI in wrong column +flat_load_dword v1, v[3:4] offset:4095 +// GFX9: flat_load_dword v1, v[3:4] offset:4095 ; encoding: [0xff,0x0f,0x50,0xdc,0x03,0x00,0x00,0x01] +// VIERR: :1: error: invalid operand for instruction + +flat_load_dword v1, v[3:4] offset:4096 +// GCNERR: :28: error: invalid operand for instruction + +flat_load_dword v1, v[3:4] offset:4 glc +// GFX9: flat_load_dword v1, v[3:4] offset:4 glc ; encoding: [0x04,0x00,0x51,0xdc,0x03,0x00,0x00,0x01] +// VIERR: :1: error: invalid operand for instruction + +flat_load_dword v1, v[3:4] offset:4 glc slc +// GFX9: flat_load_dword v1, v[3:4] offset:4 glc slc ; encoding: [0x04,0x00,0x53,0xdc,0x03,0x00,0x00,0x01] +// VIERR: :1: error: invalid operand for instruction + +flat_atomic_add v[3:4], v5 offset:8 slc +// GFX9: flat_atomic_add v[3:4], v5 offset:8 slc ; encoding: [0x08,0x00,0x0a,0xdd,0x03,0x05,0x00,0x00] +// VIERR: :1: error: invalid operand for instruction + +flat_atomic_swap v[3:4], v5 offset:16 +// GFX9: flat_atomic_swap v[3:4], v5 offset:16 ; encoding: [0x10,0x00,0x00,0xdd,0x03,0x05,0x00,0x00] +// VIERR: :1: error: invalid operand for instruction + +flat_store_dword v[3:4], v1 offset:16 +// GFX9: flat_store_dword v[3:4], v1 offset:16 ; encoding: [0x10,0x00,0x70,0xdc,0x03,0x01,0x00,0x00] +// VIERR: :1: error: invalid operand for instruction diff --git a/test/MC/AMDGPU/flat.s b/test/MC/AMDGPU/flat.s index 4e81799fe9f9..d8cad131d1e4 100644 --- a/test/MC/AMDGPU/flat.s +++ b/test/MC/AMDGPU/flat.s @@ -49,9 +49,10 @@ flat_store_dword v[3:4], v1 slc // FIXME: For atomic instructions, glc must be placed immediately following // the data regiser. These forms aren't currently supported: +// FIXME: offset:0 required // flat_atomic_add v1, v[3:4], v5 slc glc -flat_atomic_add v1 v[3:4], v5 glc slc +flat_atomic_add v1, v[3:4], v5 offset:0 glc slc // NOSI: error: // CI: flat_atomic_add v1, v[3:4], v5 glc slc ; encoding: [0x00,0x00,0xcb,0xdc,0x03,0x05,0x00,0x01] // VI: flat_atomic_add v1, v[3:4], v5 glc slc ; encoding: [0x00,0x00,0x0b,0xdd,0x03,0x05,0x00,0x01] diff --git a/test/MC/COFF/cv-compiler-info.ll b/test/MC/COFF/cv-compiler-info.ll index 6c33a25c1f46..f7cd17397d61 100644 --- a/test/MC/COFF/cv-compiler-info.ll +++ b/test/MC/COFF/cv-compiler-info.ll @@ -13,7 +13,7 @@ entry: attributes #0 = { nounwind sspstrong "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!3, !7, !8} +!llvm.module.flags = !{!7, !8} !llvm.ident = !{!9} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 4.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) @@ -35,10 +35,6 @@ attributes #0 = { nounwind sspstrong "correctly-rounded-divide-sqrt-fp-math"="fa ; CHECK-NOT: .short 4412 # Record kind: S_COMPILE3 !1 = !DIFile(filename: "D:\5Csrc\5Cscopes\5Cfoo.cpp", directory: "D:\5Csrc\5Cscopes\5Cclang") !2 = !{} -!3 = !{i32 6, !"Linker Options", !4} -!4 = !{!5, !6} -!5 = !{!"/DEFAULTLIB:libcmtd.lib"} -!6 = !{!"/DEFAULTLIB:oldnames.lib"} !7 = !{i32 2, !"CodeView", i32 1} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{!"clang version 4.0.0 "} diff --git a/test/MC/COFF/linker-options.ll b/test/MC/COFF/linker-options.ll index afc55af692d2..24ac84da1e2d 100755 --- a/test/MC/COFF/linker-options.ll +++ b/test/MC/COFF/linker-options.ll @@ -1,8 +1,10 @@ ; RUN: llc -O0 -mtriple=i386-pc-win32 -filetype=asm -o - %s | FileCheck %s -!0 = !{i32 6, !"Linker Options", !{!{!"/DEFAULTLIB:msvcrt.lib"}, !{!"/DEFAULTLIB:msvcrt.lib", !"/DEFAULTLIB:secur32.lib"}, !{!"/DEFAULTLIB:\22C:\5Cpath to\5Casan_rt.lib\22"}, !{!"\22/with spaces\22"}}} - -!llvm.module.flags = !{ !0 } +!0 = !{!"/DEFAULTLIB:msvcrt.lib"} +!1 = !{!"/DEFAULTLIB:msvcrt.lib", !"/DEFAULTLIB:secur32.lib"} +!2 = !{!"/DEFAULTLIB:\22C:\5Cpath to\5Casan_rt.lib\22"} +!3 = !{!"\22/with spaces\22"} +!llvm.linker.options = !{!0, !1, !2, !3} define dllexport void @foo() { ret void diff --git a/test/MC/Disassembler/PowerPC/ppc64-encoding.txt b/test/MC/Disassembler/PowerPC/ppc64-encoding.txt index a6d079297bcf..25ed35fcb1c0 100644 --- a/test/MC/Disassembler/PowerPC/ppc64-encoding.txt +++ b/test/MC/Disassembler/PowerPC/ppc64-encoding.txt @@ -352,6 +352,18 @@ # CHECK: divweu. 2, 3, 4 0x7c 0x43 0x23 0x17 +# CHECK: modsw 2, 3, 4 +0x7c 0x43 0x26 0x16 + +# CHECK: moduw 2, 3, 4 +0x7c 0x43 0x22 0x16 + +# CHECK: modsd 2, 3, 4 +0x7c 0x43 0x26 0x12 + +# CHECK: modud 2, 3, 4 +0x7c 0x43 0x22 0x12 + # CHECK: mulld 2, 3, 4 0x7c 0x43 0x21 0xd2 diff --git a/test/MC/Disassembler/PowerPC/ppc64le-encoding.txt b/test/MC/Disassembler/PowerPC/ppc64le-encoding.txt index 9ddc286d8aaa..9dc994010551 100644 --- a/test/MC/Disassembler/PowerPC/ppc64le-encoding.txt +++ b/test/MC/Disassembler/PowerPC/ppc64le-encoding.txt @@ -349,6 +349,18 @@ # CHECK: divweu. 2, 3, 4 0x17 0x23 0x43 0x7c +# CHECK: modsw 2, 3, 4 +0x16 0x26 0x43 0x7c + +# CHECK: moduw 2, 3, 4 +0x16 0x22 0x43 0x7c + +# CHECK: modsd 2, 3, 4 +0x12 0x26 0x43 0x7c + +# CHECK: modud 2, 3, 4 +0x12 0x22 0x43 0x7c + # CHECK: mulld 2, 3, 4 0xd2 0x21 0x43 0x7c diff --git a/test/MC/ELF/section.s b/test/MC/ELF/section.s index 03a0f22e580b..c3f7d426ba56 100644 --- a/test/MC/ELF/section.s +++ b/test/MC/ELF/section.s @@ -267,3 +267,15 @@ bar: // CHECK-NEXT: SHF_TLS // CHECK-NEXT: SHF_WRITE // CHECK-NEXT: ] + +// Test SHT_LLVM_ODRTAB + +.section .odrtab,"e",@llvm_odrtab +// ASM: .section .odrtab,"e",@llvm_odrtab + +// CHECK: Section { +// CHECK: Name: .odrtab +// CHECK-NEXT: Type: SHT_LLVM_ODRTAB +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_EXCLUDE +// CHECK-NEXT: ] diff --git a/test/MC/MachO/linker-options.ll b/test/MC/MachO/linker-options.ll index 09ebd0f91567..d9d7a4a46d8f 100644 --- a/test/MC/MachO/linker-options.ll +++ b/test/MC/MachO/linker-options.ll @@ -27,6 +27,7 @@ ; CHECK-OBJ: ] ; CHECK-OBJ: } -!0 = !{i32 6, !"Linker Options", !{!{!"-lz"}, !{!"-framework", !"Cocoa"}, !{!"-lmath"}}} - -!llvm.module.flags = !{ !0 } +!0 = !{!"-lz"} +!1 = !{!"-framework", !"Cocoa"} +!2 = !{!"-lmath"} +!llvm.linker.options = !{!0, !1, !2} diff --git a/test/MC/PowerPC/ppc64-encoding.s b/test/MC/PowerPC/ppc64-encoding.s index a772ca44986c..237dd5cfd727 100644 --- a/test/MC/PowerPC/ppc64-encoding.s +++ b/test/MC/PowerPC/ppc64-encoding.s @@ -493,6 +493,19 @@ # FIXME: divweuo 2, 3, 4 # FIXME: divweuo. 2, 3, 4 +# CHECK-BE: modsw 2, 3, 4 # encoding: [0x7c,0x43,0x26,0x16] +# CHECK-LE: modsw 2, 3, 4 # encoding: [0x16,0x26,0x43,0x7c] + modsw 2, 3, 4 +# CHECK-BE: moduw 2, 3, 4 # encoding: [0x7c,0x43,0x22,0x16] +# CHECK-LE: moduw 2, 3, 4 # encoding: [0x16,0x22,0x43,0x7c] + moduw 2, 3, 4 +# CHECK-BE: modsd 2, 3, 4 # encoding: [0x7c,0x43,0x26,0x12] +# CHECK-LE: modsd 2, 3, 4 # encoding: [0x12,0x26,0x43,0x7c] + modsd 2, 3, 4 +# CHECK-BE: modud 2, 3, 4 # encoding: [0x7c,0x43,0x22,0x12] +# CHECK-LE: modud 2, 3, 4 # encoding: [0x12,0x22,0x43,0x7c] + modud 2, 3, 4 + # CHECK-BE: mulld 2, 3, 4 # encoding: [0x7c,0x43,0x21,0xd2] # CHECK-LE: mulld 2, 3, 4 # encoding: [0xd2,0x21,0x43,0x7c] mulld 2, 3, 4 diff --git a/test/MC/WebAssembly/external-data.ll b/test/MC/WebAssembly/external-data.ll index 91e05b3f13a6..6914736ac671 100644 --- a/test/MC/WebAssembly/external-data.ll +++ b/test/MC/WebAssembly/external-data.ll @@ -2,10 +2,10 @@ ; Verify relocations are correctly generated for addresses of externals ; in the data section. -declare i32 @f1(...) +@myimport = external global i32, align 4 @foo = global i64 7, align 4 -@far = local_unnamed_addr global i32 (...)* @f1, align 4 +@bar = hidden global i32* @myimport, align 4 ; CHECK: - Type: DATA ; CHECK: Relocations: diff --git a/test/MC/WebAssembly/external-func-address.ll b/test/MC/WebAssembly/external-func-address.ll new file mode 100644 index 000000000000..4022b2c9bae9 --- /dev/null +++ b/test/MC/WebAssembly/external-func-address.ll @@ -0,0 +1,25 @@ +; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o - | obj2yaml | FileCheck %s +; Verify that addresses of external functions generate correctly typed +; imports and relocations or type R_TABLE_INDEX_I32. + +declare void @f1() #1 +@ptr_to_f1 = hidden global void ()* @f1, align 4 + + +; CHECK: - Type: IMPORT +; CHECK: Imports: +; CHECK: - Module: env +; CHECK: Field: f1 +; CHECK: Kind: FUNCTION +; CHECK: SigIndex: 0 +; CHECK: - Type: ELEM +; CHECK: Segments: +; CHECK: - Offset: +; CHECK: Opcode: I32_CONST +; CHECK: Value: 0 +; CHECK: Functions: [ 0 ] +; CHECK: - Type: DATA +; CHECK: Relocations: +; CHECK: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 +; CHECK: Index: 0 +; CHECK: Offset: 0x00000006 diff --git a/test/MC/WebAssembly/func-address.ll b/test/MC/WebAssembly/func-address.ll new file mode 100644 index 000000000000..c0a9d9a801ff --- /dev/null +++ b/test/MC/WebAssembly/func-address.ll @@ -0,0 +1,48 @@ +; RUN: llc -mtriple wasm32-unknown-unknown-wasm -O2 -filetype=obj %s -o - | llvm-readobj -r -s -expand-relocs | FileCheck %s + +declare i32 @import1() +declare i32 @import2() +declare i32 @import3() + +; call the imports to make sure they are included in the imports section +define hidden void @call_imports() #0 { +entry: + %call = call i32 @import1() + %call1 = call i32 @import2() + ret void +} + +; take the address of the third import. This should generate a TABLE_INDEX +; relocation with index of 0 since its the first and only address taken +; function. +define hidden void @call_indirect() #0 { +entry: + %adr = alloca i32 ()*, align 4 + store i32 ()* @import3, i32 ()** %adr, align 4 + ret void +} + +; CHECK: Section { +; CHECK: Type: ELEM (0x9) +; CHECK: Size: 7 +; CHECK: Offset: 165 +; CHECK: } + +; CHECK: Relocations [ +; CHECK: Section (9) CODE { +; CHECK: Relocation { +; CHECK: Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB (0) +; CHECK: Offset: 0x4 +; CHECK: Index: 0x0 +; CHECK: } +; CHECK: Relocation { +; CHECK: Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB (0) +; CHECK: Offset: 0xB +; CHECK: Index: 0x1 +; CHECK: } +; CHECK: Relocation { +; CHECK: Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB (1) +; CHECK: Offset: 0x1A +; CHECK: Index: 0x0 +; CHECK: } +; CHECK: } diff --git a/test/ThinLTO/X86/cfi-icall.ll b/test/ThinLTO/X86/cfi-icall.ll new file mode 100644 index 000000000000..ef5d33c8a5a0 --- /dev/null +++ b/test/ThinLTO/X86/cfi-icall.ll @@ -0,0 +1,29 @@ +; RUN: opt -thinlto-bc %s -o %t1.bc +; RUN: llvm-lto2 run -thinlto-distributed-indexes %t1.bc -o %t.out -save-temps \ +; RUN: -r %t1.bc,foo,plx \ +; RUN: -r %t1.bc,bar,x +; RUN: llvm-bcanalyzer -dump %t.out.index.bc | FileCheck %s --check-prefix=COMBINED + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i1 @foo(i8* %p) !type !0 { +entry: + %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") + ret i1 %x +} + +declare !type !0 void @bar() + +declare i1 @llvm.type.test(i8* %ptr, metadata %type) nounwind readnone + +!0 = !{i64 0, !"typeid1"} + +; COMBINED: +; COMBINED: +; COMBINED: + +; COMBINED: blob data = 'foobar' +; COMBINED-NEXT: diff --git a/test/Transforms/CodeExtractor/live_shrink.ll b/test/Transforms/CodeExtractor/live_shrink.ll new file mode 100644 index 000000000000..c25ed2b622cd --- /dev/null +++ b/test/Transforms/CodeExtractor/live_shrink.ll @@ -0,0 +1,67 @@ +; RUN: opt -S -partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i32 } +@cond = local_unnamed_addr global i32 0, align 4 + +; Function Attrs: uwtable +define void @_Z3foov() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) + %tmp2 = load i32, i32* @cond, align 4, !tbaa !2 + %tmp3 = icmp eq i32 %tmp2, 0 + br i1 %tmp3, label %bb4, label %bb5 + +bb4: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb5 + +bb5: ; preds = %bb4, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) + +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; Function Attrs: uwtable +define void @_Z3goov() local_unnamed_addr { +; CHECK-LABEL: @_Z3goov() +bb: +; CHECK: bb: +; CHECK-NOT: alloca +; CHECK-NOT: bitcast +; CHECK-NOT: llvm.lifetime +; CHECK: br i1 +; CHECK: codeRepl.i: +; CHECK: call void @_Z3foov.1_ + + tail call void @_Z3foov() + ret void +} + +; CHECK-LABEL: define internal void @_Z3foov.1_ +; CHECK: newFuncRoot: +; CHECK-NEXT: %tmp = alloca %class.A +; CHECK-NEXT: %tmp1 = bitcast %class.A* %tmp to i8* +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) +; CHECK-NEXT: br label %bb5.exitStub + + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} diff --git a/test/Transforms/CodeExtractor/live_shrink_gep.ll b/test/Transforms/CodeExtractor/live_shrink_gep.ll new file mode 100644 index 000000000000..ac6aa4fbda43 --- /dev/null +++ b/test/Transforms/CodeExtractor/live_shrink_gep.ll @@ -0,0 +1,66 @@ +; RUN: opt -S -partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i8 } + +@cond = local_unnamed_addr global i32 0, align 4 + +; Function Attrs: uwtable +define void @_Z3foov() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 1 + %tmp1 = getelementptr inbounds %class.A, %class.A* %tmp, i64 0, i32 0 + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %tmp1) + %tmp2 = load i32, i32* @cond, align 4, !tbaa !2 + %tmp3 = icmp eq i32 %tmp2, 0 + br i1 %tmp3, label %bb4, label %bb5 + +bb4: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb5 + +bb5: ; preds = %bb4, %bb + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %tmp1) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) + +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; Function Attrs: uwtable +define void @_Z3goov() local_unnamed_addr { +; CHECK-LABEL: @_Z3goov() +bb: +; CHECK: bb: +; CHECK-NOT: alloca +; CHECK-NOT: getelementptr +; CHECK-NOT: llvm.lifetime +; CHECK: br i1 +; CHECK: codeRepl.i: +; CHECK: call void @_Z3foov.1_ + tail call void @_Z3foov() + ret void +} + +; CHECK-LABEL: define internal void @_Z3foov.1_ +; CHECK: newFuncRoot: +; CHECK-NEXT: %tmp = alloca %class.A +; CHECK-NEXT: %tmp1 = getelementptr +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8 +; CHECK: call void @llvm.lifetime.end.p0i8 +; CHECK-NEXT: br label %bb5.exitStub + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} diff --git a/test/Transforms/CodeExtractor/live_shrink_hoist.ll b/test/Transforms/CodeExtractor/live_shrink_hoist.ll new file mode 100644 index 000000000000..d1b310f01769 --- /dev/null +++ b/test/Transforms/CodeExtractor/live_shrink_hoist.ll @@ -0,0 +1,66 @@ +; RUN: opt -S -partial-inliner -max-num-inline-blocks=2 -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -max-num-inline-blocks=2 -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i32 } + +@cond = local_unnamed_addr global i32 0, align 4 + +; Function Attrs: uwtable +define void @_Z3foov() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) + %tmp2 = load i32, i32* @cond, align 4, !tbaa !2 + %tmp3 = icmp eq i32 %tmp2, 0 + br i1 %tmp3, label %bb4, label %bb9 + +bb4: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + %tmp5 = getelementptr inbounds %class.A, %class.A* %tmp, i64 0, i32 0 + %tmp6 = load i32, i32* %tmp5, align 4, !tbaa !6 + %tmp7 = icmp sgt i32 %tmp6, 0 + br i1 %tmp7, label %bb9, label %bb8 + +bb8: ; preds = %bb4 + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb9 + +bb9: ; preds = %bb8, %bb4, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) + +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; Function Attrs: uwtable +define void @_Z3goov() local_unnamed_addr { +bb: + tail call void @_Z3foov() + ret void +} + +; CHECK-LABEL: define internal void @_Z3foov.1_ +; CHECK: bb9: +; CHECK: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) +; CHECK: br label %.exitStub + + + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} +!6 = !{!7, !3, i64 0} +!7 = !{!"_ZTS1A", !3, i64 0} diff --git a/test/Transforms/CodeExtractor/live_shrink_multiple.ll b/test/Transforms/CodeExtractor/live_shrink_multiple.ll new file mode 100644 index 000000000000..8d9045c7267b --- /dev/null +++ b/test/Transforms/CodeExtractor/live_shrink_multiple.ll @@ -0,0 +1,66 @@ +; RUN: opt -S -partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i32 } +@cond = local_unnamed_addr global i32 0, align 4 + +; Function Attrs: uwtable +define void @_Z3foov() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = alloca %class.A, align 4 + %tmp2 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp2) + %tmp3 = bitcast %class.A* %tmp1 to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp3) + %tmp4 = load i32, i32* @cond, align 4, !tbaa !2 + %tmp5 = icmp eq i32 %tmp4, 0 + br i1 %tmp5, label %bb6, label %bb7 + +bb6: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb7 + +bb7: ; preds = %bb6, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp3) + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp2) + ret void +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) + +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; Function Attrs: uwtable +define void @_Z3goov() local_unnamed_addr { +bb: + tail call void @_Z3foov() + ret void +} + +; CHECK-LABEL: define internal void @_Z3foov.1_ +; CHECK: newFuncRoot: +; CHECK-NEXT: alloca +; CHECK-NEXT: bitcast +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8 +; CHECK-NEXT: alloca +; CHECK-NEXT: bitcast +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8 +; CHECK: call void @llvm.lifetime.end.p0i8 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8 +; CHECK-NEXT: br label {{.*}}exitStub + + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} diff --git a/test/Transforms/CodeExtractor/live_shrink_unsafe.ll b/test/Transforms/CodeExtractor/live_shrink_unsafe.ll new file mode 100644 index 000000000000..ea6458cc46ec --- /dev/null +++ b/test/Transforms/CodeExtractor/live_shrink_unsafe.ll @@ -0,0 +1,94 @@ +; The expected behavior of this file is expected to change when partial +; inlining legality check is enhanced. + +; RUN: opt -S -partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s +; RUN: opt -S -passes=partial-inliner -skip-partial-inlining-cost-analysis < %s | FileCheck %s + +%class.A = type { i32 } + +@cond = local_unnamed_addr global i32 0, align 4 +@condptr = external local_unnamed_addr global i32*, align 8 + +; Function Attrs: uwtable +define void @_Z3foo_unknown_mem_accessv() local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = alloca %class.A, align 4 + %tmp2 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp2) + %tmp3 = bitcast %class.A* %tmp1 to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp3) + %tmp4 = load i32*, i32** @condptr, align 8, !tbaa !2 + %tmp5 = load i32, i32* %tmp4, align 4, !tbaa !6 + %tmp6 = icmp eq i32 %tmp5, 0 + br i1 %tmp6, label %bb7, label %bb8 + +bb7: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb8 + +bb8: ; preds = %bb7, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp3) + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp2) + ret void +} + +declare void @_Z3barv() local_unnamed_addr +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +declare void @_ZN1A7memfuncEv(%class.A*) local_unnamed_addr +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +define void @_Z3foo_unknown_calli(i32 %arg) local_unnamed_addr { +bb: + %tmp = alloca %class.A, align 4 + %tmp1 = bitcast %class.A* %tmp to i8* + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %tmp1) + tail call void @_Z3barv() + %tmp2 = icmp eq i32 %arg, 0 + br i1 %tmp2, label %bb3, label %bb4 + +bb3: ; preds = %bb + call void @_ZN1A7memfuncEv(%class.A* nonnull %tmp) + br label %bb4 + +bb4: ; preds = %bb3, %bb + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %tmp1) + ret void +} + +define void @_Z3goov() local_unnamed_addr { +; CHECK-LABEL: @_Z3goov +; CHECK-NEXT: bb: +; CHECK: alloca +; CHECK: lifetime +bb: + call void @_Z3foo_unknown_mem_accessv() + %tmp = load i32, i32* @cond, align 4, !tbaa !2 + tail call void @_Z3foo_unknown_calli(i32 %tmp) + ret void +} + +; CHECK-LABEL define internal void @_Z3foo_unknown_calli.1_bb3 +; CHECK: newFuncRoot: +; CHECK-NEXT: br label %bb3 + +; CHECK: bb4.exitStub: +; CHECK-NEXT: ret void + +; CHECK: bb3: +; CHECK-NOT: lifetime.ed +; CHECK: br label %bb4.exitStub + + + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 5.0.0 (trunk 304489)"} +!2 = !{!3, !3, i64 0} +!3 = !{!"any pointer", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C++ TBAA"} +!6 = !{!7, !7, i64 0} +!7 = !{!"int", !4, i64 0} diff --git a/test/Transforms/CrossDSOCFI/cfi_functions.ll b/test/Transforms/CrossDSOCFI/cfi_functions.ll new file mode 100644 index 000000000000..ccbde51b2115 --- /dev/null +++ b/test/Transforms/CrossDSOCFI/cfi_functions.ll @@ -0,0 +1,23 @@ +; Test that types referenced in ThinLTO-style !cfi.functions are known to __cfi_check. +; RUN: opt -S -cross-dso-cfi < %s | FileCheck %s +; RUN: opt -S -passes=cross-dso-cfi < %s | FileCheck %s + +; CHECK: define void @__cfi_check( +; CHECK: switch i64 +; CHECK-NEXT: i64 1234, label +; CHECK-NEXT: i64 5678, label +; CHECK-NEXT: ] + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +!cfi.functions = !{!0, !1} +!llvm.module.flags = !{!6} + +!0 = !{!"f", i8 0, !2, !4} +!1 = !{!"g", i8 1, !3, !5} +!2 = !{i64 0, !"typeid1"} +!3 = !{i64 0, !"typeid2"} +!4 = !{i64 0, i64 1234} +!5 = !{i64 0, i64 5678} +!6 = !{i32 4, !"Cross-DSO CFI", i32 1} diff --git a/test/Transforms/EarlyCSE/pr33406.ll b/test/Transforms/EarlyCSE/pr33406.ll new file mode 100644 index 000000000000..4d3312e1f0ac --- /dev/null +++ b/test/Transforms/EarlyCSE/pr33406.ll @@ -0,0 +1,26 @@ +; RUN: opt -early-cse-memssa -S %s | FileCheck %s + +; CHECK: define void @patatino() { +; CHECK: for.cond: +; CHECK-NEXT: br i1 true, label %if.end, label %for.inc +; CHECK: if.end: +; CHECK-NEXT: %tinkywinky = load i32, i32* @b +; CHECK-NEXT: br i1 true, label %for.inc, label %for.inc +; CHECK: for.inc: +; CHECK-NEXT: ret void + + +@b = external global i32 + +define void @patatino() { +for.cond: + br i1 true, label %if.end, label %for.inc + +if.end: + %tinkywinky = load i32, i32* @b + store i32 %tinkywinky, i32* @b + br i1 true, label %for.inc, label %for.inc + +for.inc: + ret void +} diff --git a/test/Transforms/GVN/pr32314.ll b/test/Transforms/GVN/pr32314.ll new file mode 100644 index 000000000000..90d14f6fc49c --- /dev/null +++ b/test/Transforms/GVN/pr32314.ll @@ -0,0 +1,53 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -gvn < %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; The load in the loop can not bypass the data from the previous loop. The store above it in the loop aliases. +define void @foo() { +; CHECK-LABEL: @foo( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A:%.*]] = alloca [3 x i32], align 4 +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.cond.cleanup: +; CHECK-NEXT: ret void +; CHECK: for.body: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 1, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[P_017:%.*]] = phi i32* [ undef, [[ENTRY]] ], [ [[ARRAYIDX3:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[TMP0:%.*]] = add nsw i64 [[INDVARS_IV]], -1 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x i32], [3 x i32]* [[A]], i64 0, i64 [[TMP0]] +; CHECK-NEXT: store i32 50, i32* [[ARRAYIDX]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[P_017]], align 4 +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP1]] to i32 +; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[TMP2]], [[TMP3]] +; CHECK-NEXT: [[ARRAYIDX3]] = getelementptr inbounds [3 x i32], [3 x i32]* [[A]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: store i32 60, i32* [[ARRAYIDX3]], align 4 +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], 3 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]] +; +entry: + %a = alloca [3 x i32], align 4 + br label %for.body + +for.cond.cleanup: ; preds = %for.body + ret void + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 1, %entry ], [ %indvars.iv.next, %for.body ] + %p.017 = phi i32* [ undef, %entry ], [ %arrayidx3, %for.body ] + %0 = add nsw i64 %indvars.iv, -1 + %arrayidx = getelementptr inbounds [3 x i32], [3 x i32]* %a, i64 0, i64 %0 + store i32 50, i32* %arrayidx, align 4 + %1 = shl i64 %indvars.iv, 1 + %2 = load i32, i32* %p.017, align 4 + %3 = trunc i64 %1 to i32 + %add1 = add nsw i32 %2, %3 + %arrayidx3 = getelementptr inbounds [3 x i32], [3 x i32]* %a, i64 0, i64 %indvars.iv + store i32 60, i32* %arrayidx3, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp ne i64 %indvars.iv.next, 3 + br i1 %exitcond, label %for.body, label %for.cond.cleanup +} diff --git a/test/Transforms/GlobalMerge/debug-info.ll b/test/Transforms/GlobalMerge/debug-info.ll index 97e0bb2148e9..8d60f3662431 100644 --- a/test/Transforms/GlobalMerge/debug-info.ll +++ b/test/Transforms/GlobalMerge/debug-info.ll @@ -17,7 +17,7 @@ define void @use1() { ; CHECK: [[AVAR]] = !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true) ; CHECK: [[B]] = !DIGlobalVariableExpression(var: [[BVAR:![0-9]+]], expr: [[EXPR:![0-9]+]]) ; CHECK: [[BVAR]] = !DIGlobalVariable(name: "b", scope: null, isLocal: false, isDefinition: true) -; CHECK: [[EXPR]] = !DIExpression(DW_OP_plus, 4) +; CHECK: [[EXPR]] = !DIExpression(DW_OP_plus_uconst, 4) !llvm.module.flags = !{!4, !5} diff --git a/test/Transforms/Inline/always-inline.ll b/test/Transforms/Inline/always-inline.ll index 5366b5a16cc7..791eb94779b7 100644 --- a/test/Transforms/Inline/always-inline.ll +++ b/test/Transforms/Inline/always-inline.ll @@ -305,3 +305,14 @@ entry: ret void ; CHECK: ret void } + +define void @inner14() readnone nounwind { +; CHECK: define void @inner14 + ret void +} + +define void @outer14() { +; CHECK: call void @inner14 + call void @inner14() + ret void +} diff --git a/test/Transforms/InstCombine/debuginfo-dce.ll b/test/Transforms/InstCombine/debuginfo-dce.ll index 086743e80820..50b8f1c6068e 100644 --- a/test/Transforms/InstCombine/debuginfo-dce.ll +++ b/test/Transforms/InstCombine/debuginfo-dce.ll @@ -93,12 +93,12 @@ entry: ret void, !dbg !32 } -; CHECK: ![[LOAD_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_plus, 0) -; CHECK: ![[BITCAST_EXPR]] = !DIExpression(DW_OP_plus, 0) -; CHECK: ![[GEP0_EXPR]] = !DIExpression(DW_OP_minus, 8, DW_OP_plus, 0, DW_OP_stack_value) -; CHECK: ![[GEP1_EXPR]] = !DIExpression(DW_OP_minus, 8, DW_OP_stack_value, +; CHECK: ![[LOAD_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 0) +; CHECK: ![[BITCAST_EXPR]] = !DIExpression(DW_OP_plus_uconst, 0) +; CHECK: ![[GEP0_EXPR]] = !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_plus_uconst, 0, DW_OP_stack_value) +; CHECK: ![[GEP1_EXPR]] = !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_stack_value, ; CHECK-SAME: DW_OP_LLVM_fragment, 0, 32) -; CHECK: ![[GEP2_EXPR]] = !DIExpression(DW_OP_minus, 8, DW_OP_stack_value) +; CHECK: ![[GEP2_EXPR]] = !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_stack_value) ; Function Attrs: nounwind readnone declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1 @@ -130,7 +130,7 @@ attributes #1 = { nounwind readnone } !17 = !{!18} !18 = !DILocalVariable(name: "entry", scope: !14, file: !1, line: 6, type: !4) !19 = !DILocation(line: 6, column: 17, scope: !14) -!20 = !DIExpression(DW_OP_plus, 0) +!20 = !DIExpression(DW_OP_plus_uconst, 0) !21 = !DILocation(line: 11, column: 1, scope: !14) !22 = distinct !DISubprogram(name: "scan", scope: !1, file: !1, line: 4, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !17) !23 = !DILocation(line: 6, column: 17, scope: !22) diff --git a/test/Transforms/InstCombine/element-atomic-memcpy-to-loads.ll b/test/Transforms/InstCombine/element-atomic-memcpy-to-loads.ll index 107440f10a5a..230ac1796671 100644 --- a/test/Transforms/InstCombine/element-atomic-memcpy-to-loads.ll +++ b/test/Transforms/InstCombine/element-atomic-memcpy-to-loads.ll @@ -1,10 +1,11 @@ ; RUN: opt -instcombine -unfold-element-atomic-memcpy-max-elements=8 -S < %s | FileCheck %s +; Temporarily an expected failure until inst combine is updated in the next patch target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -; Test basic unfolding -define void @test1(i8* %Src, i8* %Dst) { -; CHECK-LABEL: test1 -; CHECK-NOT: llvm.memcpy.element.atomic +; Test basic unfolding -- unordered load & store +define void @test1a(i8* %Src, i8* %Dst) { +; CHECK-LABEL: test1a +; CHECK-NOT: llvm.memcpy.element.unordered.atomic ; CHECK-DAG: %memcpy_unfold.src_casted = bitcast i8* %Src to i32* ; CHECK-DAG: %memcpy_unfold.dst_casted = bitcast i8* %Dst to i32* @@ -21,7 +22,7 @@ define void @test1(i8* %Src, i8* %Dst) { ; CHECK-DAG: [[VAL4:%[^\s]+]] = load atomic i32, i32* %{{[^\s]+}} unordered, align 4 ; CHECK-DAG: store atomic i32 [[VAL4]], i32* %{{[^\s]+}} unordered, align 4 entry: - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 4 %Dst, i8* align 8 %Src, i64 4, i32 4) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %Dst, i8* align 4 %Src, i32 16, i32 4) ret void } @@ -31,9 +32,9 @@ define void @test2(i8* %Src, i8* %Dst) { ; CHECK-NOT: load ; CHECK-NOT: store -; CHECK: llvm.memcpy.element.atomic +; CHECK: llvm.memcpy.element.unordered.atomic entry: - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 4 %Dst, i8* align 4 %Src, i64 1000, i32 4) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 8 %Dst, i8* align 4 %Src, i32 256, i32 4) ret void } @@ -43,16 +44,16 @@ define void @test3(i8* %Src, i8* %Dst) { ; CHECK-NOT: load ; CHECK-NOT: store -; CHECK: llvm.memcpy.element.atomic +; CHECK: llvm.memcpy.element.unordered.atomic entry: - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 64 %Dst, i8* align 64 %Src, i64 4, i32 64) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 64 %Dst, i8* align 64 %Src, i32 64, i32 64) ret void } ; Test that we will eliminate redundant bitcasts define void @test4(i64* %Src, i64* %Dst) { ; CHECK-LABEL: test4 -; CHECK-NOT: llvm.memcpy.element.atomic +; CHECK-NOT: llvm.memcpy.element.unordered.atomic ; CHECK-NOT: bitcast @@ -76,17 +77,18 @@ define void @test4(i64* %Src, i64* %Dst) { entry: %Src.casted = bitcast i64* %Src to i8* %Dst.casted = bitcast i64* %Dst to i8* - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 16 %Dst.casted, i8* align 16 %Src.casted, i64 4, i32 8) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 16 %Dst.casted, i8* align 16 %Src.casted, i32 32, i32 8) ret void } +; Test that 0-length unordered atomic memcpy gets removed. define void @test5(i8* %Src, i8* %Dst) { ; CHECK-LABEL: test5 -; CHECK-NOT: llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 64 %Dst, i8* align 64 %Src, i64 0, i32 64) +; CHECK-NOT: llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 64 %Dst, i8* align 64 %Src, i32 0, i32 8) entry: - call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 64 %Dst, i8* align 64 %Src, i64 0, i32 64) + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* align 64 %Dst, i8* align 64 %Src, i32 0, i32 8) ret void } -declare void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* nocapture, i8* nocapture, i64, i32) +declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32) nounwind diff --git a/test/Transforms/InstCombine/ffs-1.ll b/test/Transforms/InstCombine/ffs-1.ll index d27fb5d89f09..af4ee85216ef 100644 --- a/test/Transforms/InstCombine/ffs-1.ll +++ b/test/Transforms/InstCombine/ffs-1.ll @@ -1,12 +1,12 @@ ; Test that the ffs* library call simplifier works correctly. ; -; RUN: opt < %s -instcombine -S | FileCheck %s -; RUN: opt < %s -mtriple i386-pc-linux -instcombine -S | FileCheck %s -check-prefix=CHECK-FFS -; RUN: opt -instcombine -mtriple=arm64-apple-ios9.0 -S %s | FileCheck --check-prefix=CHECK-FFS %s -; RUN: opt -instcombine -mtriple=arm64-apple-tvos9.0 -S %s | FileCheck --check-prefix=CHECK-FFS %s -; RUN: opt -instcombine -mtriple=thumbv7k-apple-watchos2.0 -S %s | FileCheck --check-prefix=CHECK-FFS %s -; RUN: opt -instcombine -mtriple=x86_64-apple-macosx10.11 -S %s | FileCheck --check-prefix=CHECK-FFS %s -; RUN: opt -instcombine -mtriple=x86_64-freebsd-gnu -S %s | FileCheck --check-prefix=CHECK-FFS %s +; RUN: opt < %s -instcombine -S | FileCheck %s --check-prefix=ALL --check-prefix=GENERIC +; RUN: opt < %s -instcombine -mtriple i386-pc-linux -S | FileCheck %s --check-prefix=ALL --check-prefix=TARGET +; RUN: opt < %s -instcombine -mtriple=arm64-apple-ios9.0 -S | FileCheck %s --check-prefix=ALL --check-prefix=TARGET +; RUN: opt < %s -instcombine -mtriple=arm64-apple-tvos9.0 -S | FileCheck %s --check-prefix=ALL --check-prefix=TARGET +; RUN: opt < %s -instcombine -mtriple=thumbv7k-apple-watchos2.0 -S | FileCheck %s --check-prefix=ALL --check-prefix=TARGET +; RUN: opt < %s -instcombine -mtriple=x86_64-apple-macosx10.11 -S | FileCheck %s --check-prefix=ALL --check-prefix=TARGET +; RUN: opt < %s -instcombine -mtriple=x86_64-freebsd-gnu -S | FileCheck %s --check-prefix=ALL --check-prefix=TARGET declare i32 @ffs(i32) declare i32 @ffsl(i32) @@ -15,123 +15,179 @@ declare i32 @ffsll(i64) ; Check ffs(0) -> 0. define i32 @test_simplify1() { -; CHECK-LABEL: @test_simplify1( +; ALL-LABEL: @test_simplify1( +; ALL-NEXT: ret i32 0 +; %ret = call i32 @ffs(i32 0) ret i32 %ret -; CHECK-NEXT: ret i32 0 } define i32 @test_simplify2() { -; CHECK-FFS-LABEL: @test_simplify2( +; GENERIC-LABEL: @test_simplify2( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsl(i32 0) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify2( +; TARGET-NEXT: ret i32 0 +; %ret = call i32 @ffsl(i32 0) ret i32 %ret -; CHECK-FFS-NEXT: ret i32 0 } define i32 @test_simplify3() { -; CHECK-FFS-LABEL: @test_simplify3( +; GENERIC-LABEL: @test_simplify3( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsll(i64 0) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify3( +; TARGET-NEXT: ret i32 0 +; %ret = call i32 @ffsll(i64 0) ret i32 %ret -; CHECK-FFS-NEXT: ret i32 0 } ; Check ffs(c) -> cttz(c) + 1, where 'c' is a constant. define i32 @test_simplify4() { -; CHECK-LABEL: @test_simplify4( +; ALL-LABEL: @test_simplify4( +; ALL-NEXT: ret i32 1 +; %ret = call i32 @ffs(i32 1) ret i32 %ret -; CHECK-NEXT: ret i32 1 } define i32 @test_simplify5() { -; CHECK-LABEL: @test_simplify5( +; ALL-LABEL: @test_simplify5( +; ALL-NEXT: ret i32 12 +; %ret = call i32 @ffs(i32 2048) ret i32 %ret -; CHECK-NEXT: ret i32 12 } define i32 @test_simplify6() { -; CHECK-LABEL: @test_simplify6( +; ALL-LABEL: @test_simplify6( +; ALL-NEXT: ret i32 17 +; %ret = call i32 @ffs(i32 65536) ret i32 %ret -; CHECK-NEXT: ret i32 17 } define i32 @test_simplify7() { -; CHECK-FFS-LABEL: @test_simplify7( +; GENERIC-LABEL: @test_simplify7( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsl(i32 65536) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify7( +; TARGET-NEXT: ret i32 17 +; %ret = call i32 @ffsl(i32 65536) ret i32 %ret -; CHECK-FFS-NEXT: ret i32 17 } define i32 @test_simplify8() { -; CHECK-FFS-LABEL: @test_simplify8( +; GENERIC-LABEL: @test_simplify8( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsll(i64 1024) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify8( +; TARGET-NEXT: ret i32 11 +; %ret = call i32 @ffsll(i64 1024) ret i32 %ret -; CHECK-FFS-NEXT: ret i32 11 } define i32 @test_simplify9() { -; CHECK-FFS-LABEL: @test_simplify9( +; GENERIC-LABEL: @test_simplify9( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsll(i64 65536) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify9( +; TARGET-NEXT: ret i32 17 +; %ret = call i32 @ffsll(i64 65536) ret i32 %ret -; CHECK-FFS-NEXT: ret i32 17 } define i32 @test_simplify10() { -; CHECK-FFS-LABEL: @test_simplify10( +; GENERIC-LABEL: @test_simplify10( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsll(i64 17179869184) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify10( +; TARGET-NEXT: ret i32 35 +; %ret = call i32 @ffsll(i64 17179869184) ret i32 %ret -; CHECK-FFS-NEXT: ret i32 35 } define i32 @test_simplify11() { -; CHECK-FFS-LABEL: @test_simplify11( +; GENERIC-LABEL: @test_simplify11( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsll(i64 281474976710656) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify11( +; TARGET-NEXT: ret i32 49 +; %ret = call i32 @ffsll(i64 281474976710656) ret i32 %ret -; CHECK-FFS-NEXT: ret i32 49 } define i32 @test_simplify12() { -; CHECK-FFS-LABEL: @test_simplify12( +; GENERIC-LABEL: @test_simplify12( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsll(i64 1152921504606846976) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify12( +; TARGET-NEXT: ret i32 61 +; %ret = call i32 @ffsll(i64 1152921504606846976) ret i32 %ret -; CHECK-FFS-NEXT: ret i32 61 } ; Check ffs(x) -> x != 0 ? (i32)llvm.cttz(x) + 1 : 0. define i32 @test_simplify13(i32 %x) { -; CHECK-LABEL: @test_simplify13( +; ALL-LABEL: @test_simplify13( +; ALL-NEXT: [[CTTZ:%.*]] = call i32 @llvm.cttz.i32(i32 %x, i1 true) +; ALL-NEXT: [[TMP1:%.*]] = add nuw nsw i32 [[CTTZ]], 1 +; ALL-NEXT: [[TMP2:%.*]] = icmp ne i32 %x, 0 +; ALL-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 0 +; ALL-NEXT: ret i32 [[TMP3]] +; %ret = call i32 @ffs(i32 %x) -; CHECK-NEXT: [[CTTZ:%[a-z0-9]+]] = call i32 @llvm.cttz.i32(i32 %x, i1 true) -; CHECK-NEXT: [[INC:%[a-z0-9]+]] = add nuw nsw i32 [[CTTZ]], 1 -; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp ne i32 %x, 0 -; CHECK-NEXT: [[RET:%[a-z0-9]+]] = select i1 [[CMP]], i32 [[INC]], i32 0 ret i32 %ret -; CHECK-NEXT: ret i32 [[RET]] } define i32 @test_simplify14(i32 %x) { -; CHECK-FFS-LABEL: @test_simplify14( +; GENERIC-LABEL: @test_simplify14( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsl(i32 %x) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify14( +; TARGET-NEXT: [[CTTZ:%.*]] = call i32 @llvm.cttz.i32(i32 %x, i1 true) +; TARGET-NEXT: [[TMP1:%.*]] = add nuw nsw i32 [[CTTZ]], 1 +; TARGET-NEXT: [[TMP2:%.*]] = icmp ne i32 %x, 0 +; TARGET-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 [[TMP1]], i32 0 +; TARGET-NEXT: ret i32 [[TMP3]] +; %ret = call i32 @ffsl(i32 %x) -; CHECK-FFS-NEXT: [[CTTZ:%[a-z0-9]+]] = call i32 @llvm.cttz.i32(i32 %x, i1 true) -; CHECK-FFS-NEXT: [[INC:%[a-z0-9]+]] = add nuw nsw i32 [[CTTZ]], 1 -; CHECK-FFS-NEXT: [[CMP:%[a-z0-9]+]] = icmp ne i32 %x, 0 -; CHECK-FFS-NEXT: [[RET:%[a-z0-9]+]] = select i1 [[CMP]], i32 [[INC]], i32 0 ret i32 %ret -; CHECK-FFS-NEXT: ret i32 [[RET]] } define i32 @test_simplify15(i64 %x) { -; CHECK-FFS-LABEL: @test_simplify15( +; GENERIC-LABEL: @test_simplify15( +; GENERIC-NEXT: [[RET:%.*]] = call i32 @ffsll(i64 %x) +; GENERIC-NEXT: ret i32 [[RET]] +; +; TARGET-LABEL: @test_simplify15( +; TARGET-NEXT: [[CTTZ:%.*]] = call i64 @llvm.cttz.i64(i64 %x, i1 true) +; TARGET-NEXT: [[TMP1:%.*]] = add nuw nsw i64 [[CTTZ]], 1 +; TARGET-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32 +; TARGET-NEXT: [[TMP3:%.*]] = icmp ne i64 %x, 0 +; TARGET-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 0 +; TARGET-NEXT: ret i32 [[TMP4]] +; %ret = call i32 @ffsll(i64 %x) -; CHECK-FFS-NEXT: [[CTTZ:%[a-z0-9]+]] = call i64 @llvm.cttz.i64(i64 %x, i1 true) -; CHECK-FFS-NEXT: [[INC:%[a-z0-9]+]] = add nuw nsw i64 [[CTTZ]], 1 -; CHECK-FFS-NEXT: [[TRUNC:%[a-z0-9]+]] = trunc i64 [[INC]] to i32 -; CHECK-FFS-NEXT: [[CMP:%[a-z0-9]+]] = icmp ne i64 %x, 0 -; CHECK-FFS-NEXT: [[RET:%[a-z0-9]+]] = select i1 [[CMP]], i32 [[TRUNC]], i32 0 ret i32 %ret -; CHECK-FFS-NEXT: ret i32 [[RET]] } + diff --git a/test/Transforms/InstCombine/lshr.ll b/test/Transforms/InstCombine/lshr.ll index 71b25177162b..4cdcb98f730c 100644 --- a/test/Transforms/InstCombine/lshr.ll +++ b/test/Transforms/InstCombine/lshr.ll @@ -122,10 +122,19 @@ define <2 x i8> @bool_zext_splat(<2 x i1> %x) { ret <2 x i8> %hibit } -; FIXME: The replicated sign bits are all that's left. This could be ashr+zext. - -define i16 @smear_sign_and_widen(i4 %x) { +define i32 @smear_sign_and_widen(i8 %x) { ; CHECK-LABEL: @smear_sign_and_widen( +; CHECK-NEXT: [[TMP1:%.*]] = ashr i8 %x, 7 +; CHECK-NEXT: [[HIBIT:%.*]] = zext i8 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[HIBIT]] +; + %sext = sext i8 %x to i32 + %hibit = lshr i32 %sext, 24 + ret i32 %hibit +} + +define i16 @smear_sign_and_widen_should_not_change_type(i4 %x) { +; CHECK-LABEL: @smear_sign_and_widen_should_not_change_type( ; CHECK-NEXT: [[SEXT:%.*]] = sext i4 %x to i16 ; CHECK-NEXT: [[HIBIT:%.*]] = lshr i16 [[SEXT]], 12 ; CHECK-NEXT: ret i16 [[HIBIT]] @@ -137,8 +146,8 @@ define i16 @smear_sign_and_widen(i4 %x) { define <2 x i8> @smear_sign_and_widen_splat(<2 x i6> %x) { ; CHECK-LABEL: @smear_sign_and_widen_splat( -; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i6> %x to <2 x i8> -; CHECK-NEXT: [[HIBIT:%.*]] = lshr <2 x i8> [[SEXT]], +; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i6> %x, +; CHECK-NEXT: [[HIBIT:%.*]] = zext <2 x i6> [[TMP1]] to <2 x i8> ; CHECK-NEXT: ret <2 x i8> [[HIBIT]] ; %sext = sext <2 x i6> %x to <2 x i8> diff --git a/test/Transforms/InstCombine/onehot_merge.ll b/test/Transforms/InstCombine/onehot_merge.ll index 496d847b5321..47a4ca4b628b 100644 --- a/test/Transforms/InstCombine/onehot_merge.ll +++ b/test/Transforms/InstCombine/onehot_merge.ll @@ -33,3 +33,79 @@ bb: ret i1 %or } +; Same as above but with operands commuted one of the ands, but not the other. +define i1 @foo1_and_commuted(i32 %k, i32 %c1, i32 %c2) { +; CHECK-LABEL: @foo1_and_commuted( +; CHECK-NEXT: [[K2:%.*]] = mul i32 [[K:%.*]], [[K]] +; CHECK-NEXT: [[TMP:%.*]] = shl i32 1, [[C1:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = lshr i32 -2147483648, [[C2:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = or i32 [[TMP]], [[TMP4]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[K2]], [[TMP0]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP1]], [[TMP0]] +; CHECK-NEXT: ret i1 [[TMP2]] +; + %k2 = mul i32 %k, %k ; to trick the complexity sorting + %tmp = shl i32 1, %c1 + %tmp4 = lshr i32 -2147483648, %c2 + %tmp1 = and i32 %k2, %tmp + %tmp2 = icmp eq i32 %tmp1, 0 + %tmp5 = and i32 %tmp4, %k2 + %tmp6 = icmp eq i32 %tmp5, 0 + %or = or i1 %tmp2, %tmp6 + ret i1 %or +} + +define i1 @or_consts(i32 %k, i32 %c1, i32 %c2) { +; CHECK-LABEL: @or_consts( +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[K:%.*]], 12 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 12 +; CHECK-NEXT: ret i1 [[TMP2]] +; + %tmp1 = and i32 4, %k + %tmp2 = icmp ne i32 %tmp1, 0 + %tmp5 = and i32 8, %k + %tmp6 = icmp ne i32 %tmp5, 0 + %or = and i1 %tmp2, %tmp6 + ret i1 %or +} + +define i1 @foo1_or(i32 %k, i32 %c1, i32 %c2) { +; CHECK-LABEL: @foo1_or( +; CHECK-NEXT: [[TMP:%.*]] = shl i32 1, [[C1:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = lshr i32 -2147483648, [[C2:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[TMP]], [[TMP4]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[K:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], [[TMP1]] +; CHECK-NEXT: ret i1 [[TMP3]] +; + %tmp = shl i32 1, %c1 + %tmp4 = lshr i32 -2147483648, %c2 + %tmp1 = and i32 %tmp, %k + %tmp2 = icmp ne i32 %tmp1, 0 + %tmp5 = and i32 %tmp4, %k + %tmp6 = icmp ne i32 %tmp5, 0 + %or = and i1 %tmp2, %tmp6 + ret i1 %or +} + +; Same as above but with operands commuted one of the ors, but not the other. +define i1 @foo1_or_commuted(i32 %k, i32 %c1, i32 %c2) { +; CHECK-LABEL: @foo1_or_commuted( +; CHECK-NEXT: [[K2:%.*]] = mul i32 [[K:%.*]], [[K]] +; CHECK-NEXT: [[TMP:%.*]] = shl i32 1, [[C1:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = lshr i32 -2147483648, [[C2:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[TMP]], [[TMP4]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[K2]], [[TMP1]] +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], [[TMP1]] +; CHECK-NEXT: ret i1 [[TMP3]] +; + %k2 = mul i32 %k, %k ; to trick the complexity sorting + %tmp = shl i32 1, %c1 + %tmp4 = lshr i32 -2147483648, %c2 + %tmp1 = and i32 %k2, %tmp + %tmp2 = icmp ne i32 %tmp1, 0 + %tmp5 = and i32 %tmp4, %k2 + %tmp6 = icmp ne i32 %tmp5, 0 + %or = and i1 %tmp2, %tmp6 + ret i1 %or +} diff --git a/test/Transforms/InstCombine/or-xor.ll b/test/Transforms/InstCombine/or-xor.ll index f2bc290d79a4..485f9612376a 100644 --- a/test/Transforms/InstCombine/or-xor.ll +++ b/test/Transforms/InstCombine/or-xor.ll @@ -114,6 +114,17 @@ define i32 @test10(i32 %A, i32 %B) { ret i32 %or } +define i32 @test10_commuted(i32 %A, i32 %B) { +; CHECK-LABEL: @test10_commuted( +; CHECK-NEXT: ret i32 -1 +; + %xor1 = xor i32 %B, %A + %not = xor i32 %A, -1 + %xor2 = xor i32 %not, %B + %or = or i32 %xor2, %xor1 + ret i32 %or +} + ; (x | y) & ((~x) ^ y) -> (x & y) define i32 @test11(i32 %x, i32 %y) { ; CHECK-LABEL: @test11( @@ -300,3 +311,36 @@ define i8 @or_xor_or(i8 %x) { ret i8 %or2 } +define i8 @test17(i8 %A, i8 %B) { +; CHECK-LABEL: @test17( +; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A]], 33 +; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[NOT]], [[B]] +; CHECK-NEXT: [[OR:%.*]] = or i8 [[XOR1]], [[XOR2]] +; CHECK-NEXT: [[RES:%.*]] = mul i8 [[OR]], [[XOR2]] +; CHECK-NEXT: ret i8 [[RES]] +; + %xor1 = xor i8 %B, %A + %not = xor i8 %A, 33 + %xor2 = xor i8 %not, %B + %or = or i8 %xor1, %xor2 + %res = mul i8 %or, %xor2 ; to increase the use count for the xor + ret i8 %res +} + +define i8 @test18(i8 %A, i8 %B) { +; CHECK-LABEL: @test18( +; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A]], 33 +; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[NOT]], [[B]] +; CHECK-NEXT: [[OR:%.*]] = or i8 [[XOR2]], [[XOR1]] +; CHECK-NEXT: [[RES:%.*]] = mul i8 [[OR]], [[XOR2]] +; CHECK-NEXT: ret i8 [[RES]] +; + %xor1 = xor i8 %B, %A + %not = xor i8 %A, 33 + %xor2 = xor i8 %not, %B + %or = or i8 %xor2, %xor1 + %res = mul i8 %or, %xor2 ; to increase the use count for the xor + ret i8 %res +} diff --git a/test/Transforms/InstCombine/select-with-bitwise-ops.ll b/test/Transforms/InstCombine/select-with-bitwise-ops.ll index 68b73af21a8d..faeb4e046aca 100644 --- a/test/Transforms/InstCombine/select-with-bitwise-ops.ll +++ b/test/Transforms/InstCombine/select-with-bitwise-ops.ll @@ -1,6 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -instcombine -S | FileCheck %s +target datalayout = "n8:16:32:64" + define i32 @select_icmp_eq_and_1_0_or_2(i32 %x, i32 %y) { ; CHECK-LABEL: @select_icmp_eq_and_1_0_or_2( ; CHECK-NEXT: [[AND:%.*]] = shl i32 %x, 1 @@ -295,3 +297,269 @@ define i32 @test67(i16 %x) { ret i32 %3 } +define i32 @test68(i32 %x, i32 %y) { +; CHECK-LABEL: @test68( +; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8 +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TMP1]], -1 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[OR]] +; CHECK-NEXT: ret i32 [[SELECT]] +; + %and = and i32 %x, 128 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %y, 2 + %select = select i1 %cmp, i32 %y, i32 %or + ret i32 %select +} + +define i32 @test69(i32 %x, i32 %y) { +; CHECK-LABEL: @test69( +; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TMP1]], 0 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[OR]] +; CHECK-NEXT: ret i32 [[SELECT]] +; + %and = and i32 %x, 128 + %cmp = icmp ne i32 %and, 0 + %or = or i32 %y, 2 + %select = select i1 %cmp, i32 %y, i32 %or + ret i32 %select +} + +define i32 @shift_no_xor_multiuse_or(i32 %x, i32 %y) { +; CHECK-LABEL: @shift_no_xor_multiuse_or( +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2 +; CHECK-NEXT: [[AND:%.*]] = shl i32 [[X:%.*]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[Y]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP2]], [[OR]] +; CHECK-NEXT: ret i32 [[RES]] +; + %and = and i32 %x, 1 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %y, 2 + %select = select i1 %cmp, i32 %y, i32 %or + %res = mul i32 %select, %or ; to bump up use count of the Or + ret i32 %res +} + +define i32 @no_shift_no_xor_multiuse_or(i32 %x, i32 %y) { +; CHECK-LABEL: @no_shift_no_xor_multiuse_or( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 4096 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[AND]], [[Y]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP1]], [[OR]] +; CHECK-NEXT: ret i32 [[RES]] +; + %and = and i32 %x, 4096 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %y, 4096 + %select = select i1 %cmp, i32 %y, i32 %or + %res = mul i32 %select, %or ; to bump up use count of the Or + ret i32 %res +} + +define i32 @no_shift_xor_multiuse_or(i32 %x, i32 %y) { +; CHECK-LABEL: @no_shift_xor_multiuse_or( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 4096 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[AND]], 4096 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[Y]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP2]], [[OR]] +; CHECK-NEXT: ret i32 [[RES]] +; + %and = and i32 %x, 4096 + %cmp = icmp ne i32 0, %and + %or = or i32 %y, 4096 + %select = select i1 %cmp, i32 %y, i32 %or + %res = mul i32 %select, %or ; to bump up use count of the Or + ret i32 %res +} + +; TODO this increased the number of instructions +define i32 @shift_xor_multiuse_or(i32 %x, i32 %y) { +; CHECK-LABEL: @shift_xor_multiuse_or( +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2048 +; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[X:%.*]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 2048 +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], 2048 +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP2]], [[Y]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP3]], [[OR]] +; CHECK-NEXT: ret i32 [[RES]] +; + %and = and i32 %x, 4096 + %cmp = icmp ne i32 0, %and + %or = or i32 %y, 2048 + %select = select i1 %cmp, i32 %y, i32 %or + %res = mul i32 %select, %or ; to bump up use count of the Or + ret i32 %res +} + +define i32 @shift_no_xor_multiuse_cmp(i32 %x, i32 %y, i32 %z, i32 %w) { +; CHECK-LABEL: @shift_no_xor_multiuse_cmp( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = shl nuw nsw i32 [[AND]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP2]], [[SELECT2]] +; CHECK-NEXT: ret i32 [[RES]] +; + %and = and i32 %x, 1 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %y, 2 + %select = select i1 %cmp, i32 %y, i32 %or + %select2 = select i1 %cmp, i32 %z, i32 %w ; to bump up use count of the cmp + %res = mul i32 %select, %select2 + ret i32 %res +} + +define i32 @no_shift_no_xor_multiuse_cmp(i32 %x, i32 %y, i32 %z, i32 %w) { +; CHECK-LABEL: @no_shift_no_xor_multiuse_cmp( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[AND]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP1]], [[SELECT2]] +; CHECK-NEXT: ret i32 [[RES]] +; + %and = and i32 %x, 4096 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %y, 4096 + %select = select i1 %cmp, i32 %y, i32 %or + %select2 = select i1 %cmp, i32 %z, i32 %w ; to bump up use count of the cmp + %res = mul i32 %select, %select2 + ret i32 %res +} + +define i32 @no_shift_xor_multiuse_cmp(i32 %x, i32 %y, i32 %z, i32 %w) { +; CHECK-LABEL: @no_shift_xor_multiuse_cmp( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[AND]], 4096 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP2]], [[SELECT2]] +; CHECK-NEXT: ret i32 [[RES]] +; + %and = and i32 %x, 4096 + %cmp = icmp ne i32 0, %and + %or = or i32 %y, 4096 + %select = select i1 %cmp, i32 %y, i32 %or + %select2 = select i1 %cmp, i32 %z, i32 %w ; to bump up use count of the cmp + %res = mul i32 %select, %select2 + ret i32 %res +} + +; TODO this increased the number of instructions +define i32 @shift_xor_multiuse_cmp(i32 %x, i32 %y, i32 %z, i32 %w) { +; CHECK-LABEL: @shift_xor_multiuse_cmp( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[AND]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], 2048 +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP2]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP3]], [[SELECT2]] +; CHECK-NEXT: ret i32 [[RES]] +; + %and = and i32 %x, 4096 + %cmp = icmp ne i32 0, %and + %or = or i32 %y, 2048 + %select = select i1 %cmp, i32 %y, i32 %or + %select2 = select i1 %cmp, i32 %z, i32 %w ; to bump up use count of the cmp + %res = mul i32 %select, %select2 + ret i32 %res +} + +; TODO this increased the number of instructions +define i32 @shift_no_xor_multiuse_cmp_or(i32 %x, i32 %y, i32 %z, i32 %w) { +; CHECK-LABEL: @shift_no_xor_multiuse_cmp_or( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = shl nuw nsw i32 [[AND]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[Y]] +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP2]], [[SELECT2]] +; CHECK-NEXT: [[RES2:%.*]] = mul i32 [[RES]], [[OR]] +; CHECK-NEXT: ret i32 [[RES2]] +; + %and = and i32 %x, 1 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %y, 2 + %select = select i1 %cmp, i32 %y, i32 %or + %select2 = select i1 %cmp, i32 %z, i32 %w ; to bump up use count of the cmp + %res = mul i32 %select, %select2 + %res2 = mul i32 %res, %or ; to bump up the use count of the or + ret i32 %res2 +} + +define i32 @no_shift_no_xor_multiuse_cmp_or(i32 %x, i32 %y, i32 %z, i32 %w) { +; CHECK-LABEL: @no_shift_no_xor_multiuse_cmp_or( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 4096 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[AND]], [[Y]] +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP1]], [[SELECT2]] +; CHECK-NEXT: [[RES2:%.*]] = mul i32 [[RES]], [[OR]] +; CHECK-NEXT: ret i32 [[RES2]] +; + %and = and i32 %x, 4096 + %cmp = icmp eq i32 %and, 0 + %or = or i32 %y, 4096 + %select = select i1 %cmp, i32 %y, i32 %or + %select2 = select i1 %cmp, i32 %z, i32 %w ; to bump up use count of the cmp + %res = mul i32 %select, %select2 + %res2 = mul i32 %res, %or ; to bump up the use count of the or + ret i32 %res2 +} + +; TODO this increased the number of instructions +define i32 @no_shift_xor_multiuse_cmp_or(i32 %x, i32 %y, i32 %z, i32 %w) { +; CHECK-LABEL: @no_shift_xor_multiuse_cmp_or( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 4096 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[AND]], 4096 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[Y]] +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP2]], [[SELECT2]] +; CHECK-NEXT: [[RES2:%.*]] = mul i32 [[RES]], [[OR]] +; CHECK-NEXT: ret i32 [[RES2]] +; + %and = and i32 %x, 4096 + %cmp = icmp ne i32 0, %and + %or = or i32 %y, 4096 + %select = select i1 %cmp, i32 %y, i32 %or + %select2 = select i1 %cmp, i32 %z, i32 %w ; to bump up use count of the cmp + %res = mul i32 %select, %select2 + %res2 = mul i32 %res, %or ; to bump up the use count of the or + ret i32 %res2 +} + +; TODO this increased the number of instructions +define i32 @shift_xor_multiuse_cmp_or(i32 %x, i32 %y, i32 %z, i32 %w) { +; CHECK-LABEL: @shift_xor_multiuse_cmp_or( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2048 +; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[AND]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], 2048 +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP2]], [[Y]] +; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] +; CHECK-NEXT: [[RES:%.*]] = mul i32 [[TMP3]], [[SELECT2]] +; CHECK-NEXT: [[RES2:%.*]] = mul i32 [[RES]], [[OR]] +; CHECK-NEXT: ret i32 [[RES2]] +; + %and = and i32 %x, 4096 + %cmp = icmp ne i32 0, %and + %or = or i32 %y, 2048 + %select = select i1 %cmp, i32 %y, i32 %or + %select2 = select i1 %cmp, i32 %z, i32 %w ; to bump up use count of the cmp + %res = mul i32 %select, %select2 + %res2 = mul i32 %res, %or ; to bump up the use count of the or + ret i32 %res2 +} diff --git a/test/Transforms/InstCombine/shift.ll b/test/Transforms/InstCombine/shift.ll index ce8e2fcd38b9..68bbf35d1e65 100644 --- a/test/Transforms/InstCombine/shift.ll +++ b/test/Transforms/InstCombine/shift.ll @@ -1306,3 +1306,13 @@ define <2 x i8> @lshr_demanded_bits_splat(<2 x i8> %x) { ret <2 x i8> %shr } +; Make sure known bits works correctly with non power of 2 bit widths. +define i7 @test65(i7 %a, i7 %b) { +; CHECK-LABEL: @test65( +; CHECK-NEXT: ret i7 0 +; + %shiftamt = and i7 %b, 6 ; this ensures the shift amount is even and less than the bit width. + %x = lshr i7 42, %shiftamt ; 42 has a zero in every even numbered bit and a one in every odd bit. + %y = and i7 %x, 1 ; this extracts the lsb which should be 0 because we shifted an even number of bits and all even bits of the shift input are 0. + ret i7 %y +} diff --git a/test/Transforms/InstCombine/xor2.ll b/test/Transforms/InstCombine/xor2.ll index 3afbf632f6e1..49e6b999fbce 100644 --- a/test/Transforms/InstCombine/xor2.ll +++ b/test/Transforms/InstCombine/xor2.ll @@ -325,3 +325,36 @@ define i32 @test14(i32 %a, i32 %b, i32 %c) { ret i32 %xor } +define i8 @test15(i8 %A, i8 %B) { +; CHECK-LABEL: @test15( +; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A]], 33 +; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[NOT]], [[B]] +; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR1]], [[XOR2]] +; CHECK-NEXT: [[RES:%.*]] = mul i8 [[AND]], [[XOR2]] +; CHECK-NEXT: ret i8 [[RES]] +; + %xor1 = xor i8 %B, %A + %not = xor i8 %A, 33 + %xor2 = xor i8 %not, %B + %and = and i8 %xor1, %xor2 + %res = mul i8 %and, %xor2 ; to increase the use count for the xor + ret i8 %res +} + +define i8 @test16(i8 %A, i8 %B) { +; CHECK-LABEL: @test16( +; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A]], 33 +; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[NOT]], [[B]] +; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR2]], [[XOR1]] +; CHECK-NEXT: [[RES:%.*]] = mul i8 [[AND]], [[XOR2]] +; CHECK-NEXT: ret i8 [[RES]] +; + %xor1 = xor i8 %B, %A + %not = xor i8 %A, 33 + %xor2 = xor i8 %not, %B + %and = and i8 %xor2, %xor1 + %res = mul i8 %and, %xor2 ; to increase the use count for the xor + ret i8 %res +} diff --git a/test/Transforms/LoopIdiom/X86/unordered-atomic-memcpy.ll b/test/Transforms/LoopIdiom/X86/unordered-atomic-memcpy.ll index ec93847178b5..d52378b864ff 100644 --- a/test/Transforms/LoopIdiom/X86/unordered-atomic-memcpy.ll +++ b/test/Transforms/LoopIdiom/X86/unordered-atomic-memcpy.ll @@ -5,7 +5,7 @@ target triple = "x86_64-unknown-linux-gnu" ;; memcpy.atomic formation (atomic load & store) define void @test1(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test1( -; CHECK: call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 1 %Dest, i8* align 1 %Base, i64 %Size, i32 1) +; CHECK: call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %Dest, i8* align 1 %Base, i64 %Size, i32 1) ; CHECK-NOT: store ; CHECK: ret void bb.nph: @@ -30,7 +30,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation (atomic store, normal load) define void @test2(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test2( -; CHECK: call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 1 %Dest, i8* align 1 %Base, i64 %Size, i32 1) +; CHECK: call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %Dest, i8* align 1 %Base, i64 %Size, i32 1) ; CHECK-NOT: store ; CHECK: ret void bb.nph: @@ -55,7 +55,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (atomic store, normal load w/ no align) define void @test2b(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test2b( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: @@ -80,7 +80,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (atomic store, normal load w/ bad align) define void @test2c(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test2c( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: @@ -105,7 +105,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (atomic store w/ bad align, normal load) define void @test2d(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test2d( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: @@ -131,7 +131,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation (normal store, atomic load) define void @test3(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test3( -; CHECK: call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 1 %Dest, i8* align 1 %Base, i64 %Size, i32 1) +; CHECK: call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %Dest, i8* align 1 %Base, i64 %Size, i32 1) ; CHECK-NOT: store ; CHECK: ret void bb.nph: @@ -156,7 +156,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (normal store w/ no align, atomic load) define void @test3b(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test3b( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: @@ -181,7 +181,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (normal store, atomic load w/ bad align) define void @test3c(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test3c( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: @@ -206,7 +206,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (normal store w/ bad align, atomic load) define void @test3d(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test3d( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: @@ -232,7 +232,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (atomic load, ordered-atomic store) define void @test4(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test4( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: @@ -257,7 +257,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (ordered-atomic load, unordered-atomic store) define void @test5(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test5( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: @@ -282,7 +282,8 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation (atomic load & store) -- element size 2 define void @test6(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test6( -; CHECK: call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 2 %Dest{{[0-9]*}}, i8* align 2 %Base{{[0-9]*}}, i64 %Size, i32 2) +; CHECK: [[Sz:%[0-9]+]] = shl i64 %Size, 1 +; CHECK: call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 2 %Dest{{[0-9]*}}, i8* align 2 %Base{{[0-9]*}}, i64 [[Sz]], i32 2) ; CHECK-NOT: store ; CHECK: ret void bb.nph: @@ -307,7 +308,8 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation (atomic load & store) -- element size 4 define void @test7(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test7( -; CHECK: call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 4 %Dest{{[0-9]*}}, i8* align 4 %Base{{[0-9]*}}, i64 %Size, i32 4) +; CHECK: [[Sz:%[0-9]+]] = shl i64 %Size, 2 +; CHECK: call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 4 %Dest{{[0-9]*}}, i8* align 4 %Base{{[0-9]*}}, i64 [[Sz]], i32 4) ; CHECK-NOT: store ; CHECK: ret void bb.nph: @@ -332,7 +334,8 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation (atomic load & store) -- element size 8 define void @test8(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test8( -; CHECK: call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 8 %Dest{{[0-9]*}}, i8* align 8 %Base{{[0-9]*}}, i64 %Size, i32 8) +; CHECK: [[Sz:%[0-9]+]] = shl i64 %Size, 3 +; CHECK: call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 8 %Dest{{[0-9]*}}, i8* align 8 %Base{{[0-9]*}}, i64 [[Sz]], i32 8) ; CHECK-NOT: store ; CHECK: ret void bb.nph: @@ -357,7 +360,8 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (atomic load & store) -- element size 16 define void @test9(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test9( -; CHECK: call void @llvm.memcpy.element.atomic.p0i8.p0i8(i8* align 16 %Dest{{[0-9]*}}, i8* align 16 %Base{{[0-9]*}}, i64 %Size, i32 16) +; CHECK: [[Sz:%[0-9]+]] = shl i64 %Size, 4 +; CHECK: call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 16 %Dest{{[0-9]*}}, i8* align 16 %Base{{[0-9]*}}, i64 [[Sz]], i32 16) ; CHECK-NOT: store ; CHECK: ret void bb.nph: @@ -382,7 +386,7 @@ for.end: ; preds = %for.body, %entry ;; memcpy.atomic formation rejection (atomic load & store) -- element size 32 define void @test10(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test10( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: diff --git a/test/Transforms/LoopIdiom/unordered-atomic-memcpy-noarch.ll b/test/Transforms/LoopIdiom/unordered-atomic-memcpy-noarch.ll index b2528f1c2457..341a7a0baebf 100644 --- a/test/Transforms/LoopIdiom/unordered-atomic-memcpy-noarch.ll +++ b/test/Transforms/LoopIdiom/unordered-atomic-memcpy-noarch.ll @@ -5,7 +5,7 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3 ;; Will not create call due to a max element size of 0 define void @test1(i64 %Size) nounwind ssp { ; CHECK-LABEL: @test1( -; CHECK-NOT: call void @llvm.memcpy.element.atomic +; CHECK-NOT: call void @llvm.memcpy.element.unordered.atomic ; CHECK: store ; CHECK: ret void bb.nph: diff --git a/test/Transforms/LowerTypeTests/Inputs/import-icall.yaml b/test/Transforms/LowerTypeTests/Inputs/import-icall.yaml new file mode 100644 index 000000000000..17b634acd0e1 --- /dev/null +++ b/test/Transforms/LowerTypeTests/Inputs/import-icall.yaml @@ -0,0 +1,19 @@ +--- +TypeIdMap: + typeid1: + TTRes: + Kind: AllOnes + SizeM1BitWidth: 7 + typeid2: + TTRes: + Kind: Single + SizeM1BitWidth: 0 +WithGlobalValueDeadStripping: false +CfiFunctionDefs: + - local_a + - local_b + - does_not_exist +CfiFunctionDecls: + - external + - external_weak +... diff --git a/test/Transforms/LowerTypeTests/export-icall.ll b/test/Transforms/LowerTypeTests/export-icall.ll new file mode 100644 index 000000000000..ad3604899306 --- /dev/null +++ b/test/Transforms/LowerTypeTests/export-icall.ll @@ -0,0 +1,70 @@ +; RUN: opt -S -lowertypetests -lowertypetests-summary-action=export -lowertypetests-read-summary=%S/Inputs/use-typeid1-typeid2.yaml -lowertypetests-write-summary=%t < %s | FileCheck %s +; RUN: FileCheck --check-prefix=SUMMARY %s < %t + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @h(i8 %x) !type !2 { + ret void +} + +declare !type !8 void @f(i32 %x) + +!cfi.functions = !{!0, !1, !3, !4, !5, !6} + +; declaration of @h with a different type is ignored +!0 = !{!"h", i8 1, !7} + +; extern_weak declaration of @h with a different type is ignored as well +!1 = !{!"h", i8 2, !8} +!2 = !{i64 0, !"typeid1"} + +; definition of @f replaces types on the IR declaration above +!3 = !{!"f", i8 0, !2} +!4 = !{!"external", i8 1, !2} +!5 = !{!"external_weak", i8 2, !2} +!6 = !{!"g", i8 0, !7} +!7 = !{i64 0, !"typeid2"} +!8 = !{i64 0, !"typeid3"} + + +; CHECK-DAG: @__typeid_typeid1_global_addr = hidden alias i8, bitcast (void ()* [[JT1:.*]] to i8*) +; CHECK-DAG: @__typeid_typeid1_align = hidden alias i8, inttoptr (i8 3 to i8*) +; CHECK-DAG: @__typeid_typeid1_size_m1 = hidden alias i8, inttoptr (i64 3 to i8*) + +; CHECK-DAG: @h = alias void (i8), bitcast (void ()* [[JT1]] to void (i8)*) +; CHECK-DAG: @f = alias void (i32), {{.*}}getelementptr {{.*}}void ()* [[JT1]] +; CHECK-DAG: @external.cfi_jt = hidden alias void (), {{.*}}getelementptr {{.*}}void ()* [[JT1]] +; CHECK-DAG: @external_weak.cfi_jt = hidden alias void (), {{.*}}getelementptr {{.*}}void ()* [[JT1]] + +; CHECK-DAG: @__typeid_typeid2_global_addr = hidden alias i8, bitcast (void ()* [[JT2:.*]] to i8*) + +; CHECK-DAG: @g = alias void (), void ()* [[JT2]] + +; CHECK-DAG: define internal void @h.cfi(i8 {{.*}}) !type !{{.*}} +; CHECK-DAG: declare !type !{{.*}} void @external() +; CHECK-DAG: declare !type !{{.*}} void @external_weak() +; CHECK-DAG: declare !type !{{.*}} void @f.cfi(i32) +; CHECK-DAG: declare !type !{{.*}} void @g.cfi() + + +; SUMMARY: TypeIdMap: +; SUMMARY-NEXT: typeid1: +; SUMMARY-NEXT: TTRes: +; SUMMARY-NEXT: Kind: AllOnes +; SUMMARY-NEXT: SizeM1BitWidth: 7 +; SUMMARY-NEXT: WPDRes: +; SUMMARY-NEXT: typeid2: +; SUMMARY-NEXT: TTRes: +; SUMMARY-NEXT: Kind: Single +; SUMMARY-NEXT: SizeM1BitWidth: 0 +; SUMMARY-NEXT: WPDRes: + +; SUMMARY: CfiFunctionDefs: +; SUMMARY-NEXT: - f +; SUMMARY-NEXT: - g +; SUMMARY-NEXT: - h +; SUMMARY-NEXT: CfiFunctionDecls: +; SUMMARY-NEXT: - external +; SUMMARY-NEXT: - external_weak +; SUMMARY-NEXT: ... diff --git a/test/Transforms/LowerTypeTests/import-icall.ll b/test/Transforms/LowerTypeTests/import-icall.ll new file mode 100644 index 000000000000..ddeb7fb5c9a2 --- /dev/null +++ b/test/Transforms/LowerTypeTests/import-icall.ll @@ -0,0 +1,40 @@ +; RUN: opt -S -lowertypetests -lowertypetests-summary-action=import -lowertypetests-read-summary=%S/Inputs/import-icall.yaml < %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i8 @local_a() { + call void @external() + call void @external_weak() + ret i8 1 +} + +define internal i8 @local_b() { + %x = call i8 @local_a() + ret i8 %x +} + +define i8 @use_b() { + %x = call i8 @local_b() + ret i8 %x +} + + +declare void @external() +declare extern_weak void @external_weak() + +; CHECK: define hidden i8 @local_a.cfi() { +; CHECK-NEXT: call void @external.cfi_jt() +; CHECK-NEXT: call void select (i1 icmp ne (void ()* @external_weak, void ()* null), void ()* @external_weak.cfi_jt, void ()* null)() +; CHECK-NEXT: ret i8 1 +; CHECK-NEXT: } + +; internal @local_b is not the same function as "local_b" in the summary. +; CHECK: define internal i8 @local_b() { +; CHECK-NEXT: call i8 @local_a() + +; CHECK: declare void @external() +; CHECK: declare extern_weak void @external_weak() +; CHECK: declare i8 @local_a() +; CHECK: declare hidden void @external.cfi_jt() +; CHECK: declare hidden void @external_weak.cfi_jt() diff --git a/test/Transforms/PGOProfile/memop_size_opt.ll b/test/Transforms/PGOProfile/memop_size_opt.ll index 19a2b7ed293b..e11f235a48e7 100644 --- a/test/Transforms/PGOProfile/memop_size_opt.ll +++ b/test/Transforms/PGOProfile/memop_size_opt.ll @@ -38,7 +38,7 @@ for.body3: ; MEMOP_OPT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i32 1, i1 false) ; MEMOP_OPT: br label %[[MERGE_LABEL:.*]] ; MEMOP_OPT: [[DEFAULT_LABEL]]: -; MEMOP_OPT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %conv, i32 1, i1 false){{[[:space:]]}} +; MEMOP_OPT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %conv, i32 1, i1 false), !prof [[NEWVP:![0-9]+]] ; MEMOP_OPT: br label %[[MERGE_LABEL]] ; MEMOP_OPT: [[MERGE_LABEL]]: ; MEMOP_OPT: switch i64 %conv, label %[[DEFAULT_LABEL2:.*]] [ @@ -48,11 +48,16 @@ for.body3: ; MEMOP_OPT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst2, i8* %src2, i64 1, i32 1, i1 false) ; MEMOP_OPT: br label %[[MERGE_LABEL2:.*]] ; MEMOP_OPT: [[DEFAULT_LABEL2]]: -; MEMOP_OPT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst2, i8* %src2, i64 %conv, i32 1, i1 false){{[[:space:]]}} +; MEMOP_OPT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst2, i8* %src2, i64 %conv, i32 1, i1 false), !prof [[NEWVP]] ; MEMOP_OPT: br label %[[MERGE_LABEL2]] ; MEMOP_OPT: [[MERGE_LABEL2]]: ; MEMOP_OPT: br label %for.inc ; MEMOP_OPT: [[SWITCH_BW]] = !{!"branch_weights", i32 457, i32 99} +; Should be 457 total left (original total count 556, minus 99 from specialized +; value 1, which is removed from VP array. Also, we only end up with 5 total +; values, since the default max number of promotions is 5 and therefore +; the rest of the values are ignored when extracting the VP metadata. +; MEMOP_OPT: [[NEWVP]] = !{!"VP", i32 1, i64 457, i64 2, i64 88, i64 3, i64 77, i64 9, i64 72, i64 4, i64 66} for.inc: %inc = add nsw i32 %j.0, 1 diff --git a/test/Transforms/RewriteStatepointsForGC/drop-invalid-metadata.ll b/test/Transforms/RewriteStatepointsForGC/drop-invalid-metadata.ll new file mode 100644 index 000000000000..105afa9def5c --- /dev/null +++ b/test/Transforms/RewriteStatepointsForGC/drop-invalid-metadata.ll @@ -0,0 +1,92 @@ +; RUN: opt -S -rewrite-statepoints-for-gc < %s | FileCheck %s + +; This test checks that metadata that's invalid after RS4GC is dropped. +; We can miscompile if optimizations scheduled after RS4GC uses the +; metadata that's infact invalid. + +declare void @bar() + +declare void @baz(i32) +; Confirm that loadedval instruction does not contain invariant.load metadata. +; but contains the range metadata. +; Since loadedval is not marked invariant, it will prevent incorrectly sinking +; %loadedval in LICM and avoid creation of an unrelocated use of %baseaddr. +define void @test_invariant_load() gc "statepoint-example" { +; CHECK-LABEL: @test_invariant_load +; CHECK: %loadedval = load i32, i32 addrspace(1)* %baseaddr, align 8, !range !0 +bb: + br label %outerloopHdr + +outerloopHdr: ; preds = %bb6, %bb + %baseaddr = phi i32 addrspace(1)* [ undef, %bb ], [ %tmp4, %bb6 ] +; LICM may sink this load to exit block after RS4GC because it's tagged invariant. + %loadedval = load i32, i32 addrspace(1)* %baseaddr, align 8, !range !0, !invariant.load !1 + br label %innerloopHdr + +innerloopHdr: ; preds = %innerlooplatch, %outerloopHdr + %tmp4 = phi i32 addrspace(1)* [ %baseaddr, %outerloopHdr ], [ %gep, %innerlooplatch ] + br label %innermostloophdr + +innermostloophdr: ; preds = %bb6, %innerloopHdr + br i1 undef, label %exitblock, label %bb6 + +bb6: ; preds = %innermostloophdr + switch i32 undef, label %innermostloophdr [ + i32 0, label %outerloopHdr + i32 1, label %innerlooplatch + ] + +innerlooplatch: ; preds = %bb6 + call void @bar() + %gep = getelementptr inbounds i32, i32 addrspace(1)* %tmp4, i64 8 + br label %innerloopHdr + +exitblock: ; preds = %innermostloophdr + %tmp13 = add i32 42, %loadedval + call void @baz(i32 %tmp13) + unreachable +} + +; drop the noalias metadata. +define void @test_noalias(i32 %x, i32 addrspace(1)* %p, i32 addrspace(1)* %q) gc "statepoint-example" { +; CHECK-LABEL: test_noalias +; CHECK: %y = load i32, i32 addrspace(1)* %q, align 16 +; CHECK: gc.statepoint +; CHECK: %p.relocated +; CHECK-NEXT: %p.relocated.casted = bitcast i8 addrspace(1)* %p.relocated to i32 addrspace(1)* +; CHECK-NEXT: store i32 %x, i32 addrspace(1)* %p.relocated.casted, align 16 +entry: + %y = load i32, i32 addrspace(1)* %q, align 16, !noalias !3 + call void @baz(i32 %x) + store i32 %x, i32 addrspace(1)* %p, align 16, !noalias !4 + ret void +} + +; drop the dereferenceable metadata +define void @test_dereferenceable(i32 addrspace(1)* addrspace(1)* %p, i32 %x, i32 addrspace(1)* %q) gc "statepoint-example" { +; CHECK-LABEL: test_dereferenceable +; CHECK: %v1 = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* %p +; CHECK-NEXT: %v2 = load i32, i32 addrspace(1)* %v1 +; CHECK: gc.statepoint + %v1 = load i32 addrspace(1)*, i32 addrspace(1)* addrspace(1)* %p, !dereferenceable !5 + %v2 = load i32, i32 addrspace(1)* %v1 + call void @baz(i32 %x) + store i32 %v2, i32 addrspace(1)* %q, align 16 + ret void +} + +declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64, i32, void (i32)*, i32, i32, ...) + +; Function Attrs: nounwind readonly +declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32) #0 + +declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) + +attributes #0 = { nounwind readonly } + +!0 = !{i32 0, i32 2147483647} +!1 = !{} +!2 = !{i32 10, i32 1} +!3 = !{!3} +!4 = !{!4} +!5 = !{i64 8} diff --git a/test/Transforms/SLPVectorizer/X86/arith-add.ll b/test/Transforms/SLPVectorizer/X86/arith-add.ll index 0266758b27d2..22b2c7422933 100644 --- a/test/Transforms/SLPVectorizer/X86/arith-add.ll +++ b/test/Transforms/SLPVectorizer/X86/arith-add.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -mtriple=x86_64-unknown -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=SSE +; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=slm -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=SLM ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=corei7-avx -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX --check-prefix=AVX1 ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=core-avx2 -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX --check-prefix=AVX2 ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=knl -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX512 --check-prefix=AVX512F @@ -38,6 +39,25 @@ define void @add_v8i64() { ; SSE-NEXT: store <2 x i64> [[TMP12]], <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 6) to <2 x i64>*), align 8 ; SSE-NEXT: ret void ; +; SLM-LABEL: @add_v8i64( +; SLM-NEXT: [[TMP1:%.*]] = load <2 x i64>, <2 x i64>* bitcast ([8 x i64]* @a64 to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP2:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 2) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP3:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 4) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP4:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 6) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP5:%.*]] = load <2 x i64>, <2 x i64>* bitcast ([8 x i64]* @b64 to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP6:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 2) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP7:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 4) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP8:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 6) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP9:%.*]] = add <2 x i64> [[TMP1]], [[TMP5]] +; SLM-NEXT: [[TMP10:%.*]] = add <2 x i64> [[TMP2]], [[TMP6]] +; SLM-NEXT: [[TMP11:%.*]] = add <2 x i64> [[TMP3]], [[TMP7]] +; SLM-NEXT: [[TMP12:%.*]] = add <2 x i64> [[TMP4]], [[TMP8]] +; SLM-NEXT: store <2 x i64> [[TMP9]], <2 x i64>* bitcast ([8 x i64]* @c64 to <2 x i64>*), align 8 +; SLM-NEXT: store <2 x i64> [[TMP10]], <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 2) to <2 x i64>*), align 8 +; SLM-NEXT: store <2 x i64> [[TMP11]], <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 4) to <2 x i64>*), align 8 +; SLM-NEXT: store <2 x i64> [[TMP12]], <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 6) to <2 x i64>*), align 8 +; SLM-NEXT: ret void +; ; AVX-LABEL: @add_v8i64( ; AVX-NEXT: [[TMP1:%.*]] = load <4 x i64>, <4 x i64>* bitcast ([8 x i64]* @a64 to <4 x i64>*), align 8 ; AVX-NEXT: [[TMP2:%.*]] = load <4 x i64>, <4 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 4) to <4 x i64>*), align 8 @@ -111,6 +131,25 @@ define void @add_v16i32() { ; SSE-NEXT: store <4 x i32> [[TMP12]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 12) to <4 x i32>*), align 4 ; SSE-NEXT: ret void ; +; SLM-LABEL: @add_v16i32( +; SLM-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* bitcast ([16 x i32]* @a32 to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP2:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP3:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP4:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP5:%.*]] = load <4 x i32>, <4 x i32>* bitcast ([16 x i32]* @b32 to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP6:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP7:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP8:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP9:%.*]] = add <4 x i32> [[TMP1]], [[TMP5]] +; SLM-NEXT: [[TMP10:%.*]] = add <4 x i32> [[TMP2]], [[TMP6]] +; SLM-NEXT: [[TMP11:%.*]] = add <4 x i32> [[TMP3]], [[TMP7]] +; SLM-NEXT: [[TMP12:%.*]] = add <4 x i32> [[TMP4]], [[TMP8]] +; SLM-NEXT: store <4 x i32> [[TMP9]], <4 x i32>* bitcast ([16 x i32]* @c32 to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP10]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP11]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP12]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: ret void +; ; AVX-LABEL: @add_v16i32( ; AVX-NEXT: [[TMP1:%.*]] = load <8 x i32>, <8 x i32>* bitcast ([16 x i32]* @a32 to <8 x i32>*), align 4 ; AVX-NEXT: [[TMP2:%.*]] = load <8 x i32>, <8 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 8) to <8 x i32>*), align 4 @@ -216,6 +255,25 @@ define void @add_v32i16() { ; SSE-NEXT: store <8 x i16> [[TMP12]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 24) to <8 x i16>*), align 2 ; SSE-NEXT: ret void ; +; SLM-LABEL: @add_v32i16( +; SLM-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* bitcast ([32 x i16]* @a16 to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP2:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP3:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP4:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP5:%.*]] = load <8 x i16>, <8 x i16>* bitcast ([32 x i16]* @b16 to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP6:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP7:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP8:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP9:%.*]] = add <8 x i16> [[TMP1]], [[TMP5]] +; SLM-NEXT: [[TMP10:%.*]] = add <8 x i16> [[TMP2]], [[TMP6]] +; SLM-NEXT: [[TMP11:%.*]] = add <8 x i16> [[TMP3]], [[TMP7]] +; SLM-NEXT: [[TMP12:%.*]] = add <8 x i16> [[TMP4]], [[TMP8]] +; SLM-NEXT: store <8 x i16> [[TMP9]], <8 x i16>* bitcast ([32 x i16]* @c16 to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP10]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP11]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP12]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: ret void +; ; AVX-LABEL: @add_v32i16( ; AVX-NEXT: [[TMP1:%.*]] = load <16 x i16>, <16 x i16>* bitcast ([32 x i16]* @a16 to <16 x i16>*), align 2 ; AVX-NEXT: [[TMP2:%.*]] = load <16 x i16>, <16 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 16) to <16 x i16>*), align 2 diff --git a/test/Transforms/SLPVectorizer/X86/arith-fp.ll b/test/Transforms/SLPVectorizer/X86/arith-fp.ll index e00ed849ee4b..119cf594c905 100644 --- a/test/Transforms/SLPVectorizer/X86/arith-fp.ll +++ b/test/Transforms/SLPVectorizer/X86/arith-fp.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -mtriple=x86_64-unknown -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=SSE +; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=slm -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=SLM ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=corei7-avx -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=core-avx2 -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=skx -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX @@ -69,13 +70,32 @@ define <2 x double> @buildvector_mul_2f64(<2 x double> %a, <2 x double> %b) { } define <2 x double> @buildvector_div_2f64(<2 x double> %a, <2 x double> %b) { -; CHECK-LABEL: @buildvector_div_2f64( -; CHECK-NEXT: [[TMP1:%.*]] = fdiv <2 x double> [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x double> [[TMP1]], i32 0 -; CHECK-NEXT: [[R0:%.*]] = insertelement <2 x double> undef, double [[TMP2]], i32 0 -; CHECK-NEXT: [[TMP3:%.*]] = extractelement <2 x double> [[TMP1]], i32 1 -; CHECK-NEXT: [[R1:%.*]] = insertelement <2 x double> [[R0]], double [[TMP3]], i32 1 -; CHECK-NEXT: ret <2 x double> [[R1]] +; SSE-LABEL: @buildvector_div_2f64( +; SSE-NEXT: [[TMP1:%.*]] = fdiv <2 x double> [[A:%.*]], [[B:%.*]] +; SSE-NEXT: [[TMP2:%.*]] = extractelement <2 x double> [[TMP1]], i32 0 +; SSE-NEXT: [[R0:%.*]] = insertelement <2 x double> undef, double [[TMP2]], i32 0 +; SSE-NEXT: [[TMP3:%.*]] = extractelement <2 x double> [[TMP1]], i32 1 +; SSE-NEXT: [[R1:%.*]] = insertelement <2 x double> [[R0]], double [[TMP3]], i32 1 +; SSE-NEXT: ret <2 x double> [[R1]] +; +; SLM-LABEL: @buildvector_div_2f64( +; SLM-NEXT: [[A0:%.*]] = extractelement <2 x double> [[A:%.*]], i32 0 +; SLM-NEXT: [[A1:%.*]] = extractelement <2 x double> [[A]], i32 1 +; SLM-NEXT: [[B0:%.*]] = extractelement <2 x double> [[B:%.*]], i32 0 +; SLM-NEXT: [[B1:%.*]] = extractelement <2 x double> [[B]], i32 1 +; SLM-NEXT: [[C0:%.*]] = fdiv double [[A0]], [[B0]] +; SLM-NEXT: [[C1:%.*]] = fdiv double [[A1]], [[B1]] +; SLM-NEXT: [[R0:%.*]] = insertelement <2 x double> undef, double [[C0]], i32 0 +; SLM-NEXT: [[R1:%.*]] = insertelement <2 x double> [[R0]], double [[C1]], i32 1 +; SLM-NEXT: ret <2 x double> [[R1]] +; +; AVX-LABEL: @buildvector_div_2f64( +; AVX-NEXT: [[TMP1:%.*]] = fdiv <2 x double> [[A:%.*]], [[B:%.*]] +; AVX-NEXT: [[TMP2:%.*]] = extractelement <2 x double> [[TMP1]], i32 0 +; AVX-NEXT: [[R0:%.*]] = insertelement <2 x double> undef, double [[TMP2]], i32 0 +; AVX-NEXT: [[TMP3:%.*]] = extractelement <2 x double> [[TMP1]], i32 1 +; AVX-NEXT: [[R1:%.*]] = insertelement <2 x double> [[R0]], double [[TMP3]], i32 1 +; AVX-NEXT: ret <2 x double> [[R1]] ; %a0 = extractelement <2 x double> %a, i32 0 %a1 = extractelement <2 x double> %a, i32 1 @@ -317,17 +337,48 @@ define <4 x double> @buildvector_mul_4f64(<4 x double> %a, <4 x double> %b) { } define <4 x double> @buildvector_div_4f64(<4 x double> %a, <4 x double> %b) { -; CHECK-LABEL: @buildvector_div_4f64( -; CHECK-NEXT: [[TMP1:%.*]] = fdiv <4 x double> [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = extractelement <4 x double> [[TMP1]], i32 0 -; CHECK-NEXT: [[R0:%.*]] = insertelement <4 x double> undef, double [[TMP2]], i32 0 -; CHECK-NEXT: [[TMP3:%.*]] = extractelement <4 x double> [[TMP1]], i32 1 -; CHECK-NEXT: [[R1:%.*]] = insertelement <4 x double> [[R0]], double [[TMP3]], i32 1 -; CHECK-NEXT: [[TMP4:%.*]] = extractelement <4 x double> [[TMP1]], i32 2 -; CHECK-NEXT: [[R2:%.*]] = insertelement <4 x double> [[R1]], double [[TMP4]], i32 2 -; CHECK-NEXT: [[TMP5:%.*]] = extractelement <4 x double> [[TMP1]], i32 3 -; CHECK-NEXT: [[R3:%.*]] = insertelement <4 x double> [[R2]], double [[TMP5]], i32 3 -; CHECK-NEXT: ret <4 x double> [[R3]] +; SSE-LABEL: @buildvector_div_4f64( +; SSE-NEXT: [[TMP1:%.*]] = fdiv <4 x double> [[A:%.*]], [[B:%.*]] +; SSE-NEXT: [[TMP2:%.*]] = extractelement <4 x double> [[TMP1]], i32 0 +; SSE-NEXT: [[R0:%.*]] = insertelement <4 x double> undef, double [[TMP2]], i32 0 +; SSE-NEXT: [[TMP3:%.*]] = extractelement <4 x double> [[TMP1]], i32 1 +; SSE-NEXT: [[R1:%.*]] = insertelement <4 x double> [[R0]], double [[TMP3]], i32 1 +; SSE-NEXT: [[TMP4:%.*]] = extractelement <4 x double> [[TMP1]], i32 2 +; SSE-NEXT: [[R2:%.*]] = insertelement <4 x double> [[R1]], double [[TMP4]], i32 2 +; SSE-NEXT: [[TMP5:%.*]] = extractelement <4 x double> [[TMP1]], i32 3 +; SSE-NEXT: [[R3:%.*]] = insertelement <4 x double> [[R2]], double [[TMP5]], i32 3 +; SSE-NEXT: ret <4 x double> [[R3]] +; +; SLM-LABEL: @buildvector_div_4f64( +; SLM-NEXT: [[A0:%.*]] = extractelement <4 x double> [[A:%.*]], i32 0 +; SLM-NEXT: [[A1:%.*]] = extractelement <4 x double> [[A]], i32 1 +; SLM-NEXT: [[A2:%.*]] = extractelement <4 x double> [[A]], i32 2 +; SLM-NEXT: [[A3:%.*]] = extractelement <4 x double> [[A]], i32 3 +; SLM-NEXT: [[B0:%.*]] = extractelement <4 x double> [[B:%.*]], i32 0 +; SLM-NEXT: [[B1:%.*]] = extractelement <4 x double> [[B]], i32 1 +; SLM-NEXT: [[B2:%.*]] = extractelement <4 x double> [[B]], i32 2 +; SLM-NEXT: [[B3:%.*]] = extractelement <4 x double> [[B]], i32 3 +; SLM-NEXT: [[C0:%.*]] = fdiv double [[A0]], [[B0]] +; SLM-NEXT: [[C1:%.*]] = fdiv double [[A1]], [[B1]] +; SLM-NEXT: [[C2:%.*]] = fdiv double [[A2]], [[B2]] +; SLM-NEXT: [[C3:%.*]] = fdiv double [[A3]], [[B3]] +; SLM-NEXT: [[R0:%.*]] = insertelement <4 x double> undef, double [[C0]], i32 0 +; SLM-NEXT: [[R1:%.*]] = insertelement <4 x double> [[R0]], double [[C1]], i32 1 +; SLM-NEXT: [[R2:%.*]] = insertelement <4 x double> [[R1]], double [[C2]], i32 2 +; SLM-NEXT: [[R3:%.*]] = insertelement <4 x double> [[R2]], double [[C3]], i32 3 +; SLM-NEXT: ret <4 x double> [[R3]] +; +; AVX-LABEL: @buildvector_div_4f64( +; AVX-NEXT: [[TMP1:%.*]] = fdiv <4 x double> [[A:%.*]], [[B:%.*]] +; AVX-NEXT: [[TMP2:%.*]] = extractelement <4 x double> [[TMP1]], i32 0 +; AVX-NEXT: [[R0:%.*]] = insertelement <4 x double> undef, double [[TMP2]], i32 0 +; AVX-NEXT: [[TMP3:%.*]] = extractelement <4 x double> [[TMP1]], i32 1 +; AVX-NEXT: [[R1:%.*]] = insertelement <4 x double> [[R0]], double [[TMP3]], i32 1 +; AVX-NEXT: [[TMP4:%.*]] = extractelement <4 x double> [[TMP1]], i32 2 +; AVX-NEXT: [[R2:%.*]] = insertelement <4 x double> [[R1]], double [[TMP4]], i32 2 +; AVX-NEXT: [[TMP5:%.*]] = extractelement <4 x double> [[TMP1]], i32 3 +; AVX-NEXT: [[R3:%.*]] = insertelement <4 x double> [[R2]], double [[TMP5]], i32 3 +; AVX-NEXT: ret <4 x double> [[R3]] ; %a0 = extractelement <4 x double> %a, i32 0 %a1 = extractelement <4 x double> %a, i32 1 @@ -745,25 +796,80 @@ define <8 x double> @buildvector_mul_8f64(<8 x double> %a, <8 x double> %b) { } define <8 x double> @buildvector_div_8f64(<8 x double> %a, <8 x double> %b) { -; CHECK-LABEL: @buildvector_div_8f64( -; CHECK-NEXT: [[TMP1:%.*]] = fdiv <8 x double> [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = extractelement <8 x double> [[TMP1]], i32 0 -; CHECK-NEXT: [[R0:%.*]] = insertelement <8 x double> undef, double [[TMP2]], i32 0 -; CHECK-NEXT: [[TMP3:%.*]] = extractelement <8 x double> [[TMP1]], i32 1 -; CHECK-NEXT: [[R1:%.*]] = insertelement <8 x double> [[R0]], double [[TMP3]], i32 1 -; CHECK-NEXT: [[TMP4:%.*]] = extractelement <8 x double> [[TMP1]], i32 2 -; CHECK-NEXT: [[R2:%.*]] = insertelement <8 x double> [[R1]], double [[TMP4]], i32 2 -; CHECK-NEXT: [[TMP5:%.*]] = extractelement <8 x double> [[TMP1]], i32 3 -; CHECK-NEXT: [[R3:%.*]] = insertelement <8 x double> [[R2]], double [[TMP5]], i32 3 -; CHECK-NEXT: [[TMP6:%.*]] = extractelement <8 x double> [[TMP1]], i32 4 -; CHECK-NEXT: [[R4:%.*]] = insertelement <8 x double> [[R3]], double [[TMP6]], i32 4 -; CHECK-NEXT: [[TMP7:%.*]] = extractelement <8 x double> [[TMP1]], i32 5 -; CHECK-NEXT: [[R5:%.*]] = insertelement <8 x double> [[R4]], double [[TMP7]], i32 5 -; CHECK-NEXT: [[TMP8:%.*]] = extractelement <8 x double> [[TMP1]], i32 6 -; CHECK-NEXT: [[R6:%.*]] = insertelement <8 x double> [[R5]], double [[TMP8]], i32 6 -; CHECK-NEXT: [[TMP9:%.*]] = extractelement <8 x double> [[TMP1]], i32 7 -; CHECK-NEXT: [[R7:%.*]] = insertelement <8 x double> [[R6]], double [[TMP9]], i32 7 -; CHECK-NEXT: ret <8 x double> [[R7]] +; SSE-LABEL: @buildvector_div_8f64( +; SSE-NEXT: [[TMP1:%.*]] = fdiv <8 x double> [[A:%.*]], [[B:%.*]] +; SSE-NEXT: [[TMP2:%.*]] = extractelement <8 x double> [[TMP1]], i32 0 +; SSE-NEXT: [[R0:%.*]] = insertelement <8 x double> undef, double [[TMP2]], i32 0 +; SSE-NEXT: [[TMP3:%.*]] = extractelement <8 x double> [[TMP1]], i32 1 +; SSE-NEXT: [[R1:%.*]] = insertelement <8 x double> [[R0]], double [[TMP3]], i32 1 +; SSE-NEXT: [[TMP4:%.*]] = extractelement <8 x double> [[TMP1]], i32 2 +; SSE-NEXT: [[R2:%.*]] = insertelement <8 x double> [[R1]], double [[TMP4]], i32 2 +; SSE-NEXT: [[TMP5:%.*]] = extractelement <8 x double> [[TMP1]], i32 3 +; SSE-NEXT: [[R3:%.*]] = insertelement <8 x double> [[R2]], double [[TMP5]], i32 3 +; SSE-NEXT: [[TMP6:%.*]] = extractelement <8 x double> [[TMP1]], i32 4 +; SSE-NEXT: [[R4:%.*]] = insertelement <8 x double> [[R3]], double [[TMP6]], i32 4 +; SSE-NEXT: [[TMP7:%.*]] = extractelement <8 x double> [[TMP1]], i32 5 +; SSE-NEXT: [[R5:%.*]] = insertelement <8 x double> [[R4]], double [[TMP7]], i32 5 +; SSE-NEXT: [[TMP8:%.*]] = extractelement <8 x double> [[TMP1]], i32 6 +; SSE-NEXT: [[R6:%.*]] = insertelement <8 x double> [[R5]], double [[TMP8]], i32 6 +; SSE-NEXT: [[TMP9:%.*]] = extractelement <8 x double> [[TMP1]], i32 7 +; SSE-NEXT: [[R7:%.*]] = insertelement <8 x double> [[R6]], double [[TMP9]], i32 7 +; SSE-NEXT: ret <8 x double> [[R7]] +; +; SLM-LABEL: @buildvector_div_8f64( +; SLM-NEXT: [[A0:%.*]] = extractelement <8 x double> [[A:%.*]], i32 0 +; SLM-NEXT: [[A1:%.*]] = extractelement <8 x double> [[A]], i32 1 +; SLM-NEXT: [[A2:%.*]] = extractelement <8 x double> [[A]], i32 2 +; SLM-NEXT: [[A3:%.*]] = extractelement <8 x double> [[A]], i32 3 +; SLM-NEXT: [[A4:%.*]] = extractelement <8 x double> [[A]], i32 4 +; SLM-NEXT: [[A5:%.*]] = extractelement <8 x double> [[A]], i32 5 +; SLM-NEXT: [[A6:%.*]] = extractelement <8 x double> [[A]], i32 6 +; SLM-NEXT: [[A7:%.*]] = extractelement <8 x double> [[A]], i32 7 +; SLM-NEXT: [[B0:%.*]] = extractelement <8 x double> [[B:%.*]], i32 0 +; SLM-NEXT: [[B1:%.*]] = extractelement <8 x double> [[B]], i32 1 +; SLM-NEXT: [[B2:%.*]] = extractelement <8 x double> [[B]], i32 2 +; SLM-NEXT: [[B3:%.*]] = extractelement <8 x double> [[B]], i32 3 +; SLM-NEXT: [[B4:%.*]] = extractelement <8 x double> [[B]], i32 4 +; SLM-NEXT: [[B5:%.*]] = extractelement <8 x double> [[B]], i32 5 +; SLM-NEXT: [[B6:%.*]] = extractelement <8 x double> [[B]], i32 6 +; SLM-NEXT: [[B7:%.*]] = extractelement <8 x double> [[B]], i32 7 +; SLM-NEXT: [[C0:%.*]] = fdiv double [[A0]], [[B0]] +; SLM-NEXT: [[C1:%.*]] = fdiv double [[A1]], [[B1]] +; SLM-NEXT: [[C2:%.*]] = fdiv double [[A2]], [[B2]] +; SLM-NEXT: [[C3:%.*]] = fdiv double [[A3]], [[B3]] +; SLM-NEXT: [[C4:%.*]] = fdiv double [[A4]], [[B4]] +; SLM-NEXT: [[C5:%.*]] = fdiv double [[A5]], [[B5]] +; SLM-NEXT: [[C6:%.*]] = fdiv double [[A6]], [[B6]] +; SLM-NEXT: [[C7:%.*]] = fdiv double [[A7]], [[B7]] +; SLM-NEXT: [[R0:%.*]] = insertelement <8 x double> undef, double [[C0]], i32 0 +; SLM-NEXT: [[R1:%.*]] = insertelement <8 x double> [[R0]], double [[C1]], i32 1 +; SLM-NEXT: [[R2:%.*]] = insertelement <8 x double> [[R1]], double [[C2]], i32 2 +; SLM-NEXT: [[R3:%.*]] = insertelement <8 x double> [[R2]], double [[C3]], i32 3 +; SLM-NEXT: [[R4:%.*]] = insertelement <8 x double> [[R3]], double [[C4]], i32 4 +; SLM-NEXT: [[R5:%.*]] = insertelement <8 x double> [[R4]], double [[C5]], i32 5 +; SLM-NEXT: [[R6:%.*]] = insertelement <8 x double> [[R5]], double [[C6]], i32 6 +; SLM-NEXT: [[R7:%.*]] = insertelement <8 x double> [[R6]], double [[C7]], i32 7 +; SLM-NEXT: ret <8 x double> [[R7]] +; +; AVX-LABEL: @buildvector_div_8f64( +; AVX-NEXT: [[TMP1:%.*]] = fdiv <8 x double> [[A:%.*]], [[B:%.*]] +; AVX-NEXT: [[TMP2:%.*]] = extractelement <8 x double> [[TMP1]], i32 0 +; AVX-NEXT: [[R0:%.*]] = insertelement <8 x double> undef, double [[TMP2]], i32 0 +; AVX-NEXT: [[TMP3:%.*]] = extractelement <8 x double> [[TMP1]], i32 1 +; AVX-NEXT: [[R1:%.*]] = insertelement <8 x double> [[R0]], double [[TMP3]], i32 1 +; AVX-NEXT: [[TMP4:%.*]] = extractelement <8 x double> [[TMP1]], i32 2 +; AVX-NEXT: [[R2:%.*]] = insertelement <8 x double> [[R1]], double [[TMP4]], i32 2 +; AVX-NEXT: [[TMP5:%.*]] = extractelement <8 x double> [[TMP1]], i32 3 +; AVX-NEXT: [[R3:%.*]] = insertelement <8 x double> [[R2]], double [[TMP5]], i32 3 +; AVX-NEXT: [[TMP6:%.*]] = extractelement <8 x double> [[TMP1]], i32 4 +; AVX-NEXT: [[R4:%.*]] = insertelement <8 x double> [[R3]], double [[TMP6]], i32 4 +; AVX-NEXT: [[TMP7:%.*]] = extractelement <8 x double> [[TMP1]], i32 5 +; AVX-NEXT: [[R5:%.*]] = insertelement <8 x double> [[R4]], double [[TMP7]], i32 5 +; AVX-NEXT: [[TMP8:%.*]] = extractelement <8 x double> [[TMP1]], i32 6 +; AVX-NEXT: [[R6:%.*]] = insertelement <8 x double> [[R5]], double [[TMP8]], i32 6 +; AVX-NEXT: [[TMP9:%.*]] = extractelement <8 x double> [[TMP1]], i32 7 +; AVX-NEXT: [[R7:%.*]] = insertelement <8 x double> [[R6]], double [[TMP9]], i32 7 +; AVX-NEXT: ret <8 x double> [[R7]] ; %a0 = extractelement <8 x double> %a, i32 0 %a1 = extractelement <8 x double> %a, i32 1 diff --git a/test/Transforms/SLPVectorizer/X86/arith-mul.ll b/test/Transforms/SLPVectorizer/X86/arith-mul.ll index 95875d7f01fd..4763a9a2bf12 100644 --- a/test/Transforms/SLPVectorizer/X86/arith-mul.ll +++ b/test/Transforms/SLPVectorizer/X86/arith-mul.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -mtriple=x86_64-unknown -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=SSE +; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=slm -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=SLM ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=corei7-avx -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX --check-prefix=AVX1 ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=core-avx2 -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX --check-prefix=AVX2 ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=knl -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX512 --check-prefix=AVX512F @@ -54,6 +55,41 @@ define void @mul_v8i64() { ; SSE-NEXT: store i64 [[R7]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 7), align 8 ; SSE-NEXT: ret void ; +; SLM-LABEL: @mul_v8i64( +; SLM-NEXT: [[A0:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 0), align 8 +; SLM-NEXT: [[A1:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 1), align 8 +; SLM-NEXT: [[A2:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 2), align 8 +; SLM-NEXT: [[A3:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 3), align 8 +; SLM-NEXT: [[A4:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 4), align 8 +; SLM-NEXT: [[A5:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 5), align 8 +; SLM-NEXT: [[A6:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 6), align 8 +; SLM-NEXT: [[A7:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 7), align 8 +; SLM-NEXT: [[B0:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 0), align 8 +; SLM-NEXT: [[B1:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 1), align 8 +; SLM-NEXT: [[B2:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 2), align 8 +; SLM-NEXT: [[B3:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 3), align 8 +; SLM-NEXT: [[B4:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 4), align 8 +; SLM-NEXT: [[B5:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 5), align 8 +; SLM-NEXT: [[B6:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 6), align 8 +; SLM-NEXT: [[B7:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 7), align 8 +; SLM-NEXT: [[R0:%.*]] = mul i64 [[A0]], [[B0]] +; SLM-NEXT: [[R1:%.*]] = mul i64 [[A1]], [[B1]] +; SLM-NEXT: [[R2:%.*]] = mul i64 [[A2]], [[B2]] +; SLM-NEXT: [[R3:%.*]] = mul i64 [[A3]], [[B3]] +; SLM-NEXT: [[R4:%.*]] = mul i64 [[A4]], [[B4]] +; SLM-NEXT: [[R5:%.*]] = mul i64 [[A5]], [[B5]] +; SLM-NEXT: [[R6:%.*]] = mul i64 [[A6]], [[B6]] +; SLM-NEXT: [[R7:%.*]] = mul i64 [[A7]], [[B7]] +; SLM-NEXT: store i64 [[R0]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 0), align 8 +; SLM-NEXT: store i64 [[R1]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 1), align 8 +; SLM-NEXT: store i64 [[R2]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 2), align 8 +; SLM-NEXT: store i64 [[R3]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 3), align 8 +; SLM-NEXT: store i64 [[R4]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 4), align 8 +; SLM-NEXT: store i64 [[R5]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 5), align 8 +; SLM-NEXT: store i64 [[R6]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 6), align 8 +; SLM-NEXT: store i64 [[R7]], i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 7), align 8 +; SLM-NEXT: ret void +; ; AVX1-LABEL: @mul_v8i64( ; AVX1-NEXT: [[A0:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 0), align 8 ; AVX1-NEXT: [[A1:%.*]] = load i64, i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 1), align 8 @@ -162,6 +198,25 @@ define void @mul_v16i32() { ; SSE-NEXT: store <4 x i32> [[TMP12]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 12) to <4 x i32>*), align 4 ; SSE-NEXT: ret void ; +; SLM-LABEL: @mul_v16i32( +; SLM-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* bitcast ([16 x i32]* @a32 to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP2:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP3:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP4:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP5:%.*]] = load <4 x i32>, <4 x i32>* bitcast ([16 x i32]* @b32 to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP6:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP7:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP8:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP9:%.*]] = mul <4 x i32> [[TMP1]], [[TMP5]] +; SLM-NEXT: [[TMP10:%.*]] = mul <4 x i32> [[TMP2]], [[TMP6]] +; SLM-NEXT: [[TMP11:%.*]] = mul <4 x i32> [[TMP3]], [[TMP7]] +; SLM-NEXT: [[TMP12:%.*]] = mul <4 x i32> [[TMP4]], [[TMP8]] +; SLM-NEXT: store <4 x i32> [[TMP9]], <4 x i32>* bitcast ([16 x i32]* @c32 to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP10]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP11]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP12]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: ret void +; ; AVX-LABEL: @mul_v16i32( ; AVX-NEXT: [[TMP1:%.*]] = load <8 x i32>, <8 x i32>* bitcast ([16 x i32]* @a32 to <8 x i32>*), align 4 ; AVX-NEXT: [[TMP2:%.*]] = load <8 x i32>, <8 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 8) to <8 x i32>*), align 4 @@ -267,6 +322,25 @@ define void @mul_v32i16() { ; SSE-NEXT: store <8 x i16> [[TMP12]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 24) to <8 x i16>*), align 2 ; SSE-NEXT: ret void ; +; SLM-LABEL: @mul_v32i16( +; SLM-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* bitcast ([32 x i16]* @a16 to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP2:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP3:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP4:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP5:%.*]] = load <8 x i16>, <8 x i16>* bitcast ([32 x i16]* @b16 to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP6:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP7:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP8:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP9:%.*]] = mul <8 x i16> [[TMP1]], [[TMP5]] +; SLM-NEXT: [[TMP10:%.*]] = mul <8 x i16> [[TMP2]], [[TMP6]] +; SLM-NEXT: [[TMP11:%.*]] = mul <8 x i16> [[TMP3]], [[TMP7]] +; SLM-NEXT: [[TMP12:%.*]] = mul <8 x i16> [[TMP4]], [[TMP8]] +; SLM-NEXT: store <8 x i16> [[TMP9]], <8 x i16>* bitcast ([32 x i16]* @c16 to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP10]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP11]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP12]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: ret void +; ; AVX-LABEL: @mul_v32i16( ; AVX-NEXT: [[TMP1:%.*]] = load <16 x i16>, <16 x i16>* bitcast ([32 x i16]* @a16 to <16 x i16>*), align 2 ; AVX-NEXT: [[TMP2:%.*]] = load <16 x i16>, <16 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 16) to <16 x i16>*), align 2 diff --git a/test/Transforms/SLPVectorizer/X86/arith-sub.ll b/test/Transforms/SLPVectorizer/X86/arith-sub.ll index 85838369e226..2bbaaca02d88 100644 --- a/test/Transforms/SLPVectorizer/X86/arith-sub.ll +++ b/test/Transforms/SLPVectorizer/X86/arith-sub.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -mtriple=x86_64-unknown -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=SSE +; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=slm -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=SLM ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=corei7-avx -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX --check-prefix=AVX1 ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=core-avx2 -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX --check-prefix=AVX2 ; RUN: opt < %s -mtriple=x86_64-unknown -mcpu=knl -basicaa -slp-vectorizer -S | FileCheck %s --check-prefix=CHECK --check-prefix=AVX512 --check-prefix=AVX512F @@ -38,6 +39,25 @@ define void @sub_v8i64() { ; SSE-NEXT: store <2 x i64> [[TMP12]], <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 6) to <2 x i64>*), align 8 ; SSE-NEXT: ret void ; +; SLM-LABEL: @sub_v8i64( +; SLM-NEXT: [[TMP1:%.*]] = load <2 x i64>, <2 x i64>* bitcast ([8 x i64]* @a64 to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP2:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 2) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP3:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 4) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP4:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 6) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP5:%.*]] = load <2 x i64>, <2 x i64>* bitcast ([8 x i64]* @b64 to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP6:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 2) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP7:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 4) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP8:%.*]] = load <2 x i64>, <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @b64, i32 0, i64 6) to <2 x i64>*), align 8 +; SLM-NEXT: [[TMP9:%.*]] = sub <2 x i64> [[TMP1]], [[TMP5]] +; SLM-NEXT: [[TMP10:%.*]] = sub <2 x i64> [[TMP2]], [[TMP6]] +; SLM-NEXT: [[TMP11:%.*]] = sub <2 x i64> [[TMP3]], [[TMP7]] +; SLM-NEXT: [[TMP12:%.*]] = sub <2 x i64> [[TMP4]], [[TMP8]] +; SLM-NEXT: store <2 x i64> [[TMP9]], <2 x i64>* bitcast ([8 x i64]* @c64 to <2 x i64>*), align 8 +; SLM-NEXT: store <2 x i64> [[TMP10]], <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 2) to <2 x i64>*), align 8 +; SLM-NEXT: store <2 x i64> [[TMP11]], <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 4) to <2 x i64>*), align 8 +; SLM-NEXT: store <2 x i64> [[TMP12]], <2 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @c64, i32 0, i64 6) to <2 x i64>*), align 8 +; SLM-NEXT: ret void +; ; AVX-LABEL: @sub_v8i64( ; AVX-NEXT: [[TMP1:%.*]] = load <4 x i64>, <4 x i64>* bitcast ([8 x i64]* @a64 to <4 x i64>*), align 8 ; AVX-NEXT: [[TMP2:%.*]] = load <4 x i64>, <4 x i64>* bitcast (i64* getelementptr inbounds ([8 x i64], [8 x i64]* @a64, i32 0, i64 4) to <4 x i64>*), align 8 @@ -111,6 +131,25 @@ define void @sub_v16i32() { ; SSE-NEXT: store <4 x i32> [[TMP12]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 12) to <4 x i32>*), align 4 ; SSE-NEXT: ret void ; +; SLM-LABEL: @sub_v16i32( +; SLM-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* bitcast ([16 x i32]* @a32 to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP2:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP3:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP4:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP5:%.*]] = load <4 x i32>, <4 x i32>* bitcast ([16 x i32]* @b32 to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP6:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP7:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP8:%.*]] = load <4 x i32>, <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @b32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: [[TMP9:%.*]] = sub <4 x i32> [[TMP1]], [[TMP5]] +; SLM-NEXT: [[TMP10:%.*]] = sub <4 x i32> [[TMP2]], [[TMP6]] +; SLM-NEXT: [[TMP11:%.*]] = sub <4 x i32> [[TMP3]], [[TMP7]] +; SLM-NEXT: [[TMP12:%.*]] = sub <4 x i32> [[TMP4]], [[TMP8]] +; SLM-NEXT: store <4 x i32> [[TMP9]], <4 x i32>* bitcast ([16 x i32]* @c32 to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP10]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 4) to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP11]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 8) to <4 x i32>*), align 4 +; SLM-NEXT: store <4 x i32> [[TMP12]], <4 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @c32, i32 0, i64 12) to <4 x i32>*), align 4 +; SLM-NEXT: ret void +; ; AVX-LABEL: @sub_v16i32( ; AVX-NEXT: [[TMP1:%.*]] = load <8 x i32>, <8 x i32>* bitcast ([16 x i32]* @a32 to <8 x i32>*), align 4 ; AVX-NEXT: [[TMP2:%.*]] = load <8 x i32>, <8 x i32>* bitcast (i32* getelementptr inbounds ([16 x i32], [16 x i32]* @a32, i32 0, i64 8) to <8 x i32>*), align 4 @@ -216,6 +255,25 @@ define void @sub_v32i16() { ; SSE-NEXT: store <8 x i16> [[TMP12]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 24) to <8 x i16>*), align 2 ; SSE-NEXT: ret void ; +; SLM-LABEL: @sub_v32i16( +; SLM-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* bitcast ([32 x i16]* @a16 to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP2:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP3:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP4:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP5:%.*]] = load <8 x i16>, <8 x i16>* bitcast ([32 x i16]* @b16 to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP6:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP7:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP8:%.*]] = load <8 x i16>, <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @b16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: [[TMP9:%.*]] = sub <8 x i16> [[TMP1]], [[TMP5]] +; SLM-NEXT: [[TMP10:%.*]] = sub <8 x i16> [[TMP2]], [[TMP6]] +; SLM-NEXT: [[TMP11:%.*]] = sub <8 x i16> [[TMP3]], [[TMP7]] +; SLM-NEXT: [[TMP12:%.*]] = sub <8 x i16> [[TMP4]], [[TMP8]] +; SLM-NEXT: store <8 x i16> [[TMP9]], <8 x i16>* bitcast ([32 x i16]* @c16 to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP10]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 8) to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP11]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 16) to <8 x i16>*), align 2 +; SLM-NEXT: store <8 x i16> [[TMP12]], <8 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @c16, i32 0, i64 24) to <8 x i16>*), align 2 +; SLM-NEXT: ret void +; ; AVX-LABEL: @sub_v32i16( ; AVX-NEXT: [[TMP1:%.*]] = load <16 x i16>, <16 x i16>* bitcast ([32 x i16]* @a16 to <16 x i16>*), align 2 ; AVX-NEXT: [[TMP2:%.*]] = load <16 x i16>, <16 x i16>* bitcast (i16* getelementptr inbounds ([32 x i16], [32 x i16]* @a16, i32 0, i64 16) to <16 x i16>*), align 2 diff --git a/test/Transforms/SafeStack/X86/debug-loc.ll b/test/Transforms/SafeStack/X86/debug-loc.ll index 88cda693b293..d6b217142bfe 100644 --- a/test/Transforms/SafeStack/X86/debug-loc.ll +++ b/test/Transforms/SafeStack/X86/debug-loc.ll @@ -37,10 +37,10 @@ entry: ; CHECK-DAG: ![[VAR_ARG]] = !DILocalVariable(name: "zzz" ; 100 aligned up to 8 -; CHECK-DAG: ![[EXPR_ARG]] = !DIExpression(DW_OP_minus, 104) +; CHECK-DAG: ![[EXPR_ARG]] = !DIExpression(DW_OP_constu, 104, DW_OP_minus ; CHECK-DAG: ![[VAR_LOCAL]] = !DILocalVariable(name: "xxx" -; CHECK-DAG: ![[EXPR_LOCAL]] = !DIExpression(DW_OP_minus, 208) +; CHECK-DAG: ![[EXPR_LOCAL]] = !DIExpression(DW_OP_constu, 208, DW_OP_minus ; Function Attrs: nounwind readnone declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 diff --git a/test/Transforms/SafeStack/X86/debug-loc2.ll b/test/Transforms/SafeStack/X86/debug-loc2.ll index 8059a722fd45..731516c3c65e 100644 --- a/test/Transforms/SafeStack/X86/debug-loc2.ll +++ b/test/Transforms/SafeStack/X86/debug-loc2.ll @@ -84,8 +84,8 @@ attributes #4 = { nounwind } !13 = !DILocation(line: 5, column: 3, scope: !6) !14 = !DILocation(line: 6, column: 3, scope: !6) -; CHECK-DAG: ![[X1_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 4) -; CHECK-DAG: ![[X2_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 8) +; CHECK-DAG: ![[X1_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_constu, 4, DW_OP_minus) +; CHECK-DAG: ![[X2_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_constu, 8, DW_OP_minus) !15 = !DIExpression(DW_OP_deref) !16 = !DILocation(line: 5, column: 7, scope: !6) !17 = !DILocation(line: 8, column: 3, scope: !6) @@ -95,4 +95,4 @@ attributes #4 = { nounwind } !21 = !DILocation(line: 10, column: 1, scope: !22) !22 = !DILexicalBlockFile(scope: !6, file: !1, discriminator: 1) !23 = !DIExpression() -!24 = !DIExpression(DW_OP_minus, 42) +!24 = !DIExpression(DW_OP_constu, 42, DW_OP_minus) diff --git a/test/Transforms/Util/PredicateInfo/pr33456.ll b/test/Transforms/Util/PredicateInfo/pr33456.ll new file mode 100644 index 000000000000..f1cc83a071b9 --- /dev/null +++ b/test/Transforms/Util/PredicateInfo/pr33456.ll @@ -0,0 +1,68 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -print-predicateinfo -analyze < %s 2>&1 | FileCheck %s +; Don't insert predicate info for conditions with a single target. +@a = global i32 1, align 4 +@d = common global i32 0, align 4 +@c = common global i32 0, align 4 +@b = common global i32 0, align 4 +@e = common global i32 0, align 4 + +define i32 @main() { +; CHECK-LABEL: @main( +; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @d, align 4 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0 +; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP13:%.*]] +; CHECK: [[TMP4:%.*]] = load i32, i32* @a, align 4 +; CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* @c, align 4 +; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP5]], 1 +; CHECK-NEXT: br i1 [[TMP6]], label [[TMP7:%.*]], label [[TMP9:%.*]] +; CHECK: [[TMP8:%.*]] = icmp eq i32 [[TMP4]], 0 +; CHECK-NEXT: br i1 [[TMP8]], label [[TMP9]], label [[TMP9]] +; CHECK: [[DOT0:%.*]] = phi i32 [ [[TMP4]], [[TMP7]] ], [ [[TMP4]], [[TMP7]] ], [ [[DOT1:%.*]], [[TMP13]] ], [ [[TMP4]], [[TMP3]] ] +; CHECK-NEXT: [[TMP10:%.*]] = load i32, i32* @b, align 4 +; CHECK-NEXT: [[TMP11:%.*]] = sdiv i32 [[TMP10]], [[DOT0]] +; CHECK-NEXT: [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 0 +; CHECK-NEXT: br i1 [[TMP12]], label [[TMP13]], label [[TMP13]] +; CHECK: [[DOT1]] = phi i32 [ [[DOT0]], [[TMP9]] ], [ [[DOT0]], [[TMP9]] ], [ undef, [[TMP0:%.*]] ] +; CHECK-NEXT: [[TMP14:%.*]] = load i32, i32* @e, align 4 +; CHECK-NEXT: [[TMP15:%.*]] = icmp eq i32 [[TMP14]], 0 +; CHECK-NEXT: br i1 [[TMP15]], label [[TMP16:%.*]], label [[TMP9]] +; CHECK: ret i32 0 +; + %1 = load i32, i32* @d, align 4 + %2 = icmp eq i32 %1, 0 + br i1 %2, label %3, label %13 + +;
    Paper #GroupPaper NameMeetingStatusFirst released version
    2890The definition of 'object state' applies only to class typesKonaComplete
    2900The copy and move constructors of optional are not constexprKonaComplete
    2903The form of initialization for the emplace-constructors is not specifiedKona
    2904Make variant move-assignment more exception safeKona
    2904Make variant move-assignment more exception safeKonaComplete
    2905is_constructible_v<unique_ptr<P, D>, P, D const &> should be false when D is not copy constructibleKonaComplete
    2908The less-than operator for shared pointers could do moreKona
    2911An is_aggregate type trait is neededKonaComplete