From dde26e361f50df4b999ac117222c74f2c100f817 Mon Sep 17 00:00:00 2001 From: Xing Xue Date: Sat, 19 Oct 2024 18:41:06 -0400 Subject: [PATCH 01/12] [libunwind][AIX] Call dlclose only when dlsym() fails (#112768) The personality routine `__xlcxx_personality_v0` in `libc++abi` is hard-coded in the unwinder as the handler for EH in applications generated by the legacy IBM C++ compiler. The symbol is resolved dynamically using `dlopen` to avoid a hard dependency of `libunwind` on `libc++abi` for cases such as non-C++ applications. However, `dlclose` was incorrectly called after `dlsym` succeeded, potentially invalidating the function pointer obtained from `dlsym` when the memory allocated for the `dlopen` is reclaimed. This PR changes to call `dlclose` only when `dlsym` fails. --- libunwind/src/UnwindCursor.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index 2a3aba28fb6ca5..32e6fb43d988ff 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -2150,9 +2150,9 @@ bool UnwindCursor::getInfoFromTBTable(pint_t pc, R ®isters) { dlsym(libHandle, "__xlcxx_personality_v0")); if (xlcPersonalityV0 == NULL) { _LIBUNWIND_TRACE_UNWINDING("dlsym() failed with errno=%d\n", errno); + dlclose(libHandle); assert(0 && "dlsym() failed"); } - dlclose(libHandle); errno = saveErrno; } xlcPersonalityV0InitLock.unlock(); From cd938bf3279b6d2f1c0a8c82b6371a384d744378 Mon Sep 17 00:00:00 2001 From: Felipe de Azevedo Piovezan Date: Sat, 19 Oct 2024 20:53:29 -0300 Subject: [PATCH 02/12] [lldb] Introduce Language::AreEquivalentFunctions (#112720) This allows languages to provide an opinion on whether two symbol contexts are equivalent (i.e. belong to the same function). It is useful to drive the comparisons done by stepping plans that need to ensure symbol contexts obtained from different points in time are actually the same. --- lldb/include/lldb/Target/Language.h | 9 +++++++++ lldb/source/Target/ThreadPlanStepOverRange.cpp | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/lldb/include/lldb/Target/Language.h b/lldb/include/lldb/Target/Language.h index 41d8eeef469eab..c9cddee6baa2da 100644 --- a/lldb/include/lldb/Target/Language.h +++ b/lldb/include/lldb/Target/Language.h @@ -363,6 +363,15 @@ class Language : public PluginInterface { return false; } + /// Returns a boolean indicating whether two symbol contexts are equal for the + /// purposes of frame comparison. If the plugin has no opinion, it should + /// return nullopt. + virtual std::optional + AreEqualForFrameComparison(const SymbolContext &sc1, + const SymbolContext &sc2) const { + return {}; + } + /// Returns true if this Language supports exception breakpoints on throw via /// a corresponding LanguageRuntime plugin. virtual bool SupportsExceptionBreakpointsOnThrow() const { return false; } diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index 934f23b3b21a28..ef5b4b5c434d16 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -11,6 +11,7 @@ #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/LineTable.h" +#include "lldb/Target/Language.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" @@ -103,6 +104,10 @@ void ThreadPlanStepOverRange::SetupAvoidNoDebug( bool ThreadPlanStepOverRange::IsEquivalentContext( const SymbolContext &context) { + if (Language *language = Language::FindPlugin(context.GetLanguage())) + if (std::optional maybe_equivalent = + language->AreEqualForFrameComparison(context, m_addr_context)) + return *maybe_equivalent; // Match as much as is specified in the m_addr_context: This is a fairly // loose sanity check. Note, sometimes the target doesn't get filled in so I // left out the target check. And sometimes the module comes in as the .o From 2deb3a26fa47a4640962489e5473726d7a8bf12b Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Sat, 19 Oct 2024 18:11:06 -0700 Subject: [PATCH 03/12] [LV] Fixup IV users only once during epilogue vectorization. (NFC) Induction users only need to be updated when vectorizing the epilogue. Avoid running fixupIVUsers when vectorizing the main loop during epilogue vectorization. --- llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index ce0903b838aa8a..a95ac032b1ffbc 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -539,10 +539,10 @@ class InnerLoopVectorizer { friend class LoopVectorizationPlanner; /// Set up the values of the IVs correctly when exiting the vector loop. - void fixupIVUsers(PHINode *OrigPhi, const InductionDescriptor &II, - Value *VectorTripCount, Value *EndValue, - BasicBlock *MiddleBlock, VPlan &Plan, - VPTransformState &State); + virtual void fixupIVUsers(PHINode *OrigPhi, const InductionDescriptor &II, + Value *VectorTripCount, Value *EndValue, + BasicBlock *MiddleBlock, VPlan &Plan, + VPTransformState &State); /// Iteratively sink the scalarized operands of a predicated instruction into /// the block that was created for it. @@ -770,6 +770,11 @@ class EpilogueVectorizerMainLoop : public InnerLoopAndEpilogueVectorizer { BasicBlock *emitIterationCountCheck(BasicBlock *Bypass, bool ForEpilogue); void printDebugTracesAtStart() override; void printDebugTracesAtEnd() override; + + void fixupIVUsers(PHINode *OrigPhi, const InductionDescriptor &II, + Value *VectorTripCount, Value *EndValue, + BasicBlock *MiddleBlock, VPlan &Plan, + VPTransformState &State) override {}; }; // A specialized derived class of inner loop vectorizer that performs From fe8af49a1bf73055941d7aba5d1d2f8e894e8022 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 20 Oct 2024 01:38:16 +0000 Subject: [PATCH 04/12] [ELF] Pass Ctx & to Defined & CommonSymbol --- lld/ELF/Arch/ARM.cpp | 6 +++--- lld/ELF/Arch/PPC64.cpp | 2 +- lld/ELF/Driver.cpp | 2 +- lld/ELF/InputFiles.cpp | 25 +++++++++++++------------ lld/ELF/LinkerScript.cpp | 6 +++--- lld/ELF/Relocations.cpp | 10 +++++----- lld/ELF/Symbols.h | 7 ++++--- lld/ELF/SyntheticSections.cpp | 8 ++++---- lld/ELF/Writer.cpp | 18 +++++++++--------- 9 files changed, 43 insertions(+), 41 deletions(-) diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp index 9bb3604ce61cc5..1cc396aa395d3b 100644 --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -1439,8 +1439,8 @@ void ArmCmseSGSection::finalizeContents() { for (size_t i = 0; i < sgVeneers.size(); ++i) { ArmCmseSGVeneer *s = sgVeneers[i]; s->offset = i * s->size; - Defined(file, StringRef(), s->sym->binding, s->sym->stOther, s->sym->type, - s->offset | 1, s->size, this) + Defined(ctx, file, StringRef(), s->sym->binding, s->sym->stOther, + s->sym->type, s->offset | 1, s->size, this) .overwrite(*s->sym); } } @@ -1474,7 +1474,7 @@ template void elf::writeARMCmseImportLib(Ctx &ctx) { for (auto &p : ctx.symtab->cmseSymMap) { Defined *d = cast(p.second.sym); impSymTab->addSymbol(makeDefined( - ctx.internalFile, d->getName(), d->computeBinding(ctx), + ctx, ctx.internalFile, d->getName(), d->computeBinding(ctx), /*stOther=*/0, STT_FUNC, d->getVA(), d->getSize(), nullptr)); } diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp index d937492fe440d7..9f550745f93b2a 100644 --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -254,7 +254,7 @@ static bool addOptional(Ctx &ctx, StringRef name, uint64_t value, Symbol *sym = ctx.symtab->find(name); if (!sym || sym->isDefined()) return false; - sym->resolve(ctx, Defined{ctx.internalFile, StringRef(), STB_GLOBAL, + sym->resolve(ctx, Defined{ctx, ctx.internalFile, StringRef(), STB_GLOBAL, STV_HIDDEN, STT_FUNC, value, /*size=*/0, /*section=*/nullptr}); defined.push_back(cast(sym)); diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index fb77e67e9fc5ca..0d7712f904dab8 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2375,7 +2375,7 @@ static void replaceCommonSymbols(Ctx &ctx) { auto *bss = make(ctx, "COMMON", s->size, s->alignment); bss->file = s->file; ctx.inputSections.push_back(bss); - Defined(s->file, StringRef(), s->binding, s->stOther, s->type, + Defined(ctx, s->file, StringRef(), s->binding, s->stOther, s->type, /*value=*/0, s->size, bss) .overwrite(*s); } diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 3d02ef8b77abaa..0d3db373138874 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1156,14 +1156,14 @@ void ObjFile::initializeSymbols(const object::ELFFile &obj) { fatal(toString(this) + ": common symbol '" + sym->getName() + "' has invalid alignment: " + Twine(value)); hasCommonSyms = true; - sym->resolve(ctx, CommonSymbol{this, StringRef(), binding, stOther, type, - value, size}); + sym->resolve(ctx, CommonSymbol{ctx, this, StringRef(), binding, stOther, + type, value, size}); continue; } // Handle global defined symbols. Defined::section will be set in postParse. - sym->resolve(ctx, Defined{this, StringRef(), binding, stOther, type, value, - size, nullptr}); + sym->resolve(ctx, Defined{ctx, this, StringRef(), binding, stOther, type, + value, size, nullptr}); } // Undefined symbols (excluding those defined relative to non-prevailing @@ -1219,7 +1219,7 @@ void ObjFile::initSectionsAndLocalSyms(bool ignoreComdats) { new (symbols[i]) Undefined(this, name, STB_LOCAL, eSym.st_other, type, /*discardedSecIdx=*/secIdx); else - new (symbols[i]) Defined(this, name, STB_LOCAL, eSym.st_other, type, + new (symbols[i]) Defined(ctx, this, name, STB_LOCAL, eSym.st_other, type, eSym.st_value, eSym.st_size, sec); symbols[i]->partition = 1; symbols[i]->isUsedInRegularObj = true; @@ -1765,11 +1765,12 @@ static void createBitcodeSymbol(Ctx &ctx, Symbol *&sym, } if (objSym.isCommon()) { - sym->resolve(ctx, CommonSymbol{&f, StringRef(), binding, visibility, + sym->resolve(ctx, CommonSymbol{ctx, &f, StringRef(), binding, visibility, STT_OBJECT, objSym.getCommonAlignment(), objSym.getCommonSize()}); } else { - Defined newSym(&f, StringRef(), binding, visibility, type, 0, 0, nullptr); + Defined newSym(ctx, &f, StringRef(), binding, visibility, type, 0, 0, + nullptr); if (objSym.canBeOmittedFromSymbolTable()) newSym.exportDynamic = false; sym->resolve(ctx, newSym); @@ -1849,14 +1850,14 @@ void BinaryFile::parse() { llvm::StringSaver &saver = lld::saver(); - ctx.symtab->addAndCheckDuplicate(ctx, Defined{this, saver.save(s + "_start"), - STB_GLOBAL, STV_DEFAULT, - STT_OBJECT, 0, 0, section}); ctx.symtab->addAndCheckDuplicate( - ctx, Defined{this, saver.save(s + "_end"), STB_GLOBAL, STV_DEFAULT, + ctx, Defined{ctx, this, saver.save(s + "_start"), STB_GLOBAL, STV_DEFAULT, + STT_OBJECT, 0, 0, section}); + ctx.symtab->addAndCheckDuplicate( + ctx, Defined{ctx, this, saver.save(s + "_end"), STB_GLOBAL, STV_DEFAULT, STT_OBJECT, data.size(), 0, section}); ctx.symtab->addAndCheckDuplicate( - ctx, Defined{this, saver.save(s + "_size"), STB_GLOBAL, STV_DEFAULT, + ctx, Defined{ctx, this, saver.save(s + "_size"), STB_GLOBAL, STV_DEFAULT, STT_OBJECT, data.size(), 0, nullptr}); } diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 0560065ffa4780..d2088b4c648180 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -227,8 +227,8 @@ void LinkerScript::addSymbol(SymbolAssignment *cmd) { // write expressions like this: `alignment = 16; . = ALIGN(., alignment)`. uint64_t symValue = value.sec ? 0 : value.getValue(); - Defined newSym(createInternalFile(ctx, cmd->location), cmd->name, STB_GLOBAL, - visibility, value.type, symValue, 0, sec); + Defined newSym(ctx, createInternalFile(ctx, cmd->location), cmd->name, + STB_GLOBAL, visibility, value.type, symValue, 0, sec); Symbol *sym = ctx.symtab->insert(cmd->name); sym->mergeProperties(newSym); @@ -244,7 +244,7 @@ void LinkerScript::declareSymbol(SymbolAssignment *cmd) { return; uint8_t visibility = cmd->hidden ? STV_HIDDEN : STV_DEFAULT; - Defined newSym(ctx.internalFile, cmd->name, STB_GLOBAL, visibility, + Defined newSym(ctx, ctx.internalFile, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE, 0, 0, nullptr); // If the symbol is already defined, its order is 0 (with absence indicating diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 0188d658f9210e..c8dcc276c30a66 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -315,10 +315,10 @@ static SmallSet getSymbolsAt(Ctx &ctx, SharedSymbol &ss) { // in .bss and in the case of a canonical plt entry it is in .plt. This function // replaces the existing symbol with a Defined pointing to the appropriate // location. -static void replaceWithDefined(Symbol &sym, SectionBase &sec, uint64_t value, - uint64_t size) { +static void replaceWithDefined(Ctx &ctx, Symbol &sym, SectionBase &sec, + uint64_t value, uint64_t size) { Symbol old = sym; - Defined(sym.file, StringRef(), sym.binding, sym.stOther, sym.type, value, + Defined(ctx, sym.file, StringRef(), sym.binding, sym.stOther, sym.type, value, size, &sec) .overwrite(sym); @@ -398,7 +398,7 @@ template static void addCopyRelSymbol(Ctx &ctx, SharedSymbol &ss) { // dynamic symbol for each one. This causes the copy relocation to correctly // interpose any aliases. for (SharedSymbol *sym : getSymbolsAt(ctx, ss)) - replaceWithDefined(*sym, *sec, 0, sym->size); + replaceWithDefined(ctx, *sym, *sec, 0, sym->size); ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->copyRel, *sec, 0, ss); } @@ -1807,7 +1807,7 @@ void elf::postScanRelocations(Ctx &ctx) { } else { assert(sym.isFunc() && sym.hasFlag(NEEDS_PLT)); if (!sym.isDefined()) { - replaceWithDefined(sym, *ctx.in.plt, + replaceWithDefined(ctx, sym, *ctx.in.plt, ctx.target->pltHeaderSize + ctx.target->pltEntrySize * sym.getPltIdx(ctx), 0); diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 010ae9742378b9..86abebe79f8db6 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -363,8 +363,9 @@ class Symbol { // Represents a symbol that is defined in the current output file. class Defined : public Symbol { public: - Defined(InputFile *file, StringRef name, uint8_t binding, uint8_t stOther, - uint8_t type, uint64_t value, uint64_t size, SectionBase *section) + Defined(Ctx &ctx, InputFile *file, StringRef name, uint8_t binding, + uint8_t stOther, uint8_t type, uint64_t value, uint64_t size, + SectionBase *section) : Symbol(DefinedKind, file, name, binding, stOther, type), value(value), size(size), section(section) { exportDynamic = ctx.arg.exportDynamic; @@ -401,7 +402,7 @@ class Defined : public Symbol { // section. (Therefore, the later passes don't see any CommonSymbols.) class CommonSymbol : public Symbol { public: - CommonSymbol(InputFile *file, StringRef name, uint8_t binding, + CommonSymbol(Ctx &ctx, InputFile *file, StringRef name, uint8_t binding, uint8_t stOther, uint8_t type, uint64_t alignment, uint64_t size) : Symbol(CommonKind, file, name, binding, stOther, type), alignment(alignment), size(size) { diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index e18e7a32df86c7..f50404ed3016f4 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -276,8 +276,8 @@ InputSection *elf::createInterpSection(Ctx &ctx) { Defined *elf::addSyntheticLocal(Ctx &ctx, StringRef name, uint8_t type, uint64_t value, uint64_t size, InputSectionBase §ion) { - Defined *s = makeDefined(section.file, name, STB_LOCAL, STV_DEFAULT, type, - value, size, §ion); + Defined *s = makeDefined(ctx, section.file, name, STB_LOCAL, STV_DEFAULT, + type, value, size, §ion); if (ctx.in.symTab) ctx.in.symTab->addSymbol(s); @@ -4681,8 +4681,8 @@ static Defined *addOptionalRegular(Ctx &ctx, StringRef name, SectionBase *sec, if (!s || s->isDefined() || s->isCommon()) return nullptr; - s->resolve(ctx, Defined{ctx.internalFile, StringRef(), STB_GLOBAL, stOther, - STT_NOTYPE, val, + s->resolve(ctx, Defined{ctx, ctx.internalFile, StringRef(), STB_GLOBAL, + stOther, STT_NOTYPE, val, /*size=*/0, sec}); s->isUsedInRegularObj = true; return cast(s); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 2cd4478d00cf5d..c237a5f3793a12 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -145,8 +145,8 @@ static Defined *addOptionalRegular(Ctx &ctx, StringRef name, SectionBase *sec, if (!s || s->isDefined() || s->isCommon()) return nullptr; - s->resolve(ctx, Defined{ctx.internalFile, StringRef(), STB_GLOBAL, stOther, - STT_NOTYPE, val, + s->resolve(ctx, Defined{ctx, ctx.internalFile, StringRef(), STB_GLOBAL, + stOther, STT_NOTYPE, val, /*size=*/0, sec}); s->isUsedInRegularObj = true; return cast(s); @@ -158,7 +158,7 @@ void elf::addReservedSymbols(Ctx &ctx) { if (ctx.arg.emachine == EM_MIPS) { auto addAbsolute = [&](StringRef name) { Symbol *sym = - ctx.symtab->addSymbol(Defined{ctx.internalFile, name, STB_GLOBAL, + ctx.symtab->addSymbol(Defined{ctx, ctx.internalFile, name, STB_GLOBAL, STV_HIDDEN, STT_NOTYPE, 0, 0, nullptr}); sym->isUsedInRegularObj = true; return cast(sym); @@ -211,9 +211,9 @@ void elf::addReservedSymbols(Ctx &ctx) { if (ctx.arg.emachine == EM_PPC64) gotOff = 0x8000; - s->resolve(ctx, - Defined{ctx.internalFile, StringRef(), STB_GLOBAL, STV_HIDDEN, - STT_NOTYPE, gotOff, /*size=*/0, ctx.out.elfHeader}); + s->resolve(ctx, Defined{ctx, ctx.internalFile, StringRef(), STB_GLOBAL, + STV_HIDDEN, STT_NOTYPE, gotOff, /*size=*/0, + ctx.out.elfHeader}); ctx.sym.globalOffsetTable = cast(s); } @@ -534,7 +534,7 @@ template void Writer::addSectionSymbols() { // Set the symbol to be relative to the output section so that its st_value // equals the output section address. Note, there may be a gap between the // start of the output section and isec. - ctx.in.symTab->addSymbol(makeDefined(isec->file, "", STB_LOCAL, + ctx.in.symTab->addSymbol(makeDefined(ctx, isec->file, "", STB_LOCAL, /*stOther=*/0, STT_SECTION, /*value=*/0, /*size=*/0, &osec)); } @@ -1734,7 +1734,7 @@ template void Writer::finalizeSections() { // https://sourceware.org/ml/binutils/2002-03/msg00360.html if (ctx.mainPart->dynamic->parent) { Symbol *s = ctx.symtab->addSymbol(Defined{ - ctx.internalFile, "_DYNAMIC", STB_WEAK, STV_HIDDEN, STT_NOTYPE, + ctx, ctx.internalFile, "_DYNAMIC", STB_WEAK, STV_HIDDEN, STT_NOTYPE, /*value=*/0, /*size=*/0, ctx.mainPart->dynamic.get()}); s->isUsedInRegularObj = true; } @@ -1775,7 +1775,7 @@ template void Writer::finalizeSections() { // define _TLS_MODULE_BASE_ relative to the first TLS section. Symbol *s = ctx.symtab->find("_TLS_MODULE_BASE_"); if (s && s->isUndefined()) { - s->resolve(ctx, Defined{ctx.internalFile, StringRef(), STB_GLOBAL, + s->resolve(ctx, Defined{ctx, ctx.internalFile, StringRef(), STB_GLOBAL, STV_HIDDEN, STT_TLS, /*value=*/0, 0, /*section=*/nullptr}); ctx.sym.tlsModuleBase = cast(s); From cba5c77a715cfa5892c69b6c646556825932575b Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Sat, 19 Oct 2024 19:14:21 -0700 Subject: [PATCH 05/12] [VPlan] Mark unreachable code path when retrieving the scalar PH. (NFCI) --- llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index a95ac032b1ffbc..0d35bfb921dc79 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -8866,11 +8866,8 @@ static void addLiveOutsForFirstOrderRecurrences( ScalarPHVPBB = cast(MiddleVPBB->getSuccessors()[1]); } else if (ExitUsersToFix.empty()) { ScalarPHVPBB = cast(MiddleVPBB->getSingleSuccessor()); - } - if (!ScalarPHVPBB) { - assert(ExitUsersToFix.empty() && - "missed inserting extracts for exiting values"); - return; + } else { + llvm_unreachable("unsupported CFG in VPlan"); } VPBuilder ScalarPHBuilder(ScalarPHVPBB); From 1336e3d0b9a361fbbe2d97f225ef6757d20df51a Mon Sep 17 00:00:00 2001 From: c8ef Date: Sun, 20 Oct 2024 10:46:35 +0800 Subject: [PATCH 06/12] [ConstantFold] Fold `ilogb` and `ilogbf` when the input parameter is a constant value. (#113014) This patch adds support for constant folding for the `ilogb` and `ilogbf` libc functions. --- llvm/lib/Analysis/ConstantFolding.cpp | 10 +- llvm/test/Transforms/InstCombine/ilogb.ll | 203 ++++++++++++++++++++++ 2 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Transforms/InstCombine/ilogb.ll diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 74df67a4ff9b43..c0104d2bc26112 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1677,6 +1677,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) { return Name == "fabs" || Name == "fabsf" || Name == "floor" || Name == "floorf" || Name == "fmod" || Name == "fmodf"; + case 'i': + return Name == "ilogb" || Name == "ilogbf"; case 'l': return Name == "log" || Name == "logf" || Name == "logl" || Name == "log2" || Name == "log2f" || Name == "log10" || @@ -2131,7 +2133,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, } #endif - if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy()) + if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy() && + !Ty->isIntegerTy()) return nullptr; // Use internal versions of these intrinsics. @@ -2391,6 +2394,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, // TODO: What about hosts that lack a C99 library? return ConstantFoldFP(log10, APF, Ty); break; + case LibFunc_ilogb: + case LibFunc_ilogbf: + if (!APF.isZero() && TLI->has(Func)) + return ConstantInt::get(Ty, ilogb(APF), true); + break; case LibFunc_logb: case LibFunc_logbf: if (!APF.isZero() && TLI->has(Func)) diff --git a/llvm/test/Transforms/InstCombine/ilogb.ll b/llvm/test/Transforms/InstCombine/ilogb.ll new file mode 100644 index 00000000000000..e30791fe68e7b2 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/ilogb.ll @@ -0,0 +1,203 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +define i32 @ilogbf_const1() { +; CHECK-LABEL: define i32 @ilogbf_const1() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 7.000000e+00) +; CHECK-NEXT: ret i32 2 +; + %r = call i32 @ilogbf(float 7.000000e+00) + ret i32 %r +} + +define i32 @ilogb_const1() { +; CHECK-LABEL: define i32 @ilogb_const1() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double -7.000000e+00) +; CHECK-NEXT: ret i32 2 +; + %r = call i32 @ilogb(double -7.000000e+00) + ret i32 %r +} + +define i32 @ilogbf_const2() { +; CHECK-LABEL: define i32 @ilogbf_const2() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 5.000000e-01) +; CHECK-NEXT: ret i32 -1 +; + %r = call i32 @ilogbf(float 5.000000e-01) + ret i32 %r +} + +define i32 @ilogb_const2() { +; CHECK-LABEL: define i32 @ilogb_const2() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double -5.000000e-01) +; CHECK-NEXT: ret i32 -1 +; + %r = call i32 @ilogb(double -5.000000e-01) + ret i32 %r +} + +define i32 @ilogbf_zero() { +; CHECK-LABEL: define i32 @ilogbf_zero() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0.000000e+00) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0.000000e+00) + ret i32 %r +} + +define i32 @ilogb_zero() { +; CHECK-LABEL: define i32 @ilogb_zero() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0.000000e+00) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0.000000e+00) + ret i32 %r +} + +define i32 @ilogbf_neg_zero() { +; CHECK-LABEL: define i32 @ilogbf_neg_zero() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float -0.000000e+00) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float -0.000000e+00) + ret i32 %r +} + +define i32 @ilogb_neg_zero() { +; CHECK-LABEL: define i32 @ilogb_neg_zero() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double -0.000000e+00) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double -0.000000e+00) + ret i32 %r +} + +define i32 @ilogbf_inf() { +; CHECK-LABEL: define i32 @ilogbf_inf() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0x7FF0000000000000) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0x7FF0000000000000) + ret i32 %r +} + +define i32 @ilogb_inf() { +; CHECK-LABEL: define i32 @ilogb_inf() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0x7FF0000000000000) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0x7FF0000000000000) + ret i32 %r +} + +define i32 @ilogbf_nan() { +; CHECK-LABEL: define i32 @ilogbf_nan() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0x7FF8000000000000) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0x7FF8000000000000) + ret i32 %r +} + +define i32 @ilogb_nan() { +; CHECK-LABEL: define i32 @ilogb_nan() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0x7FF8000000000000) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0x7FF8000000000000) + ret i32 %r +} + +define i32 @ilogbf_zero_readnone() { +; CHECK-LABEL: define i32 @ilogbf_zero_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0.000000e+00) #[[ATTR0:[0-9]+]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0.000000e+00) readnone + ret i32 %r +} + +define i32 @ilogb_zero_readnone() { +; CHECK-LABEL: define i32 @ilogb_zero_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0.000000e+00) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0.000000e+00) readnone + ret i32 %r +} + +define i32 @ilogbf_neg_zero_readnone() { +; CHECK-LABEL: define i32 @ilogbf_neg_zero_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float -0.000000e+00) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float -0.000000e+00) readnone + ret i32 %r +} + +define i32 @ilogb_neg_zero_readnone() { +; CHECK-LABEL: define i32 @ilogb_neg_zero_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double -0.000000e+00) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double -0.000000e+00) readnone + ret i32 %r +} + +define i32 @ilogbf_inf_readnone() { +; CHECK-LABEL: define i32 @ilogbf_inf_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0x7FF0000000000000) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0x7FF0000000000000) readnone + ret i32 %r +} + +define i32 @ilogb_inf_readnone() { +; CHECK-LABEL: define i32 @ilogb_inf_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0x7FF0000000000000) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0x7FF0000000000000) readnone + ret i32 %r +} + +define i32 @ilogbf_nan_readnone() { +; CHECK-LABEL: define i32 @ilogbf_nan_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0x7FF8000000000000) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0x7FF8000000000000) readnone + ret i32 %r +} + +define i32 @ilogb_nan_readnone() { +; CHECK-LABEL: define i32 @ilogb_nan_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0x7FF8000000000000) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0x7FF8000000000000) readnone + ret i32 %r +} + +define i32 @ilogbf_poison() { +; CHECK-LABEL: define i32 @ilogbf_poison() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float poison) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float poison) + ret i32 %r +} + +define i32 @ilogb_poison() { +; CHECK-LABEL: define i32 @ilogb_poison() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double poison) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double poison) + ret i32 %r +} + +declare i32 @ilogbf(float) +declare i32 @ilogb(double) From 4a011ac84fa16f7eed34c309bdac5591d9553da7 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Sun, 20 Oct 2024 12:30:35 +0900 Subject: [PATCH 07/12] [Coverage] Introduce "partial fold" on BranchRegion (#112694) Currently both True/False counts were folded. It lost the information, "It is True or False before folding." It prevented recalling branch counts in merging template instantiations. In `llvm-cov`, a folded branch is shown as: - `[True: n, Folded]` - `[Folded, False n]` In the case If `n` is zero, a branch is reported as "uncovered". This is distinguished from "folded" branch. When folded branches are merged, `Folded` may be dissolved. In the coverage map, either `Counter` is `Zero`. Currently both were `Zero`. Since "partial fold" has been introduced, either case in `switch` is omitted as `Folded`. Each `case:` in `switch` is reported as `[True: n, Folded]`, since `False` count doesn't show meaningful value. When `switch` doesn't have `default:`, `switch (Cond)` is reported as `[Folded, False: n]`, since `True` count was just the sum of `case`(s). `switch` with `default` can be considered as "the statement that doesn't have any `False`(s)". --- clang/lib/CodeGen/CoverageMappingGen.cpp | 46 +++++-------- .../CoverageMapping/branch-constfolded.cpp | 40 ++++++------ clang/test/CoverageMapping/if.cpp | 4 +- clang/test/CoverageMapping/macro-expansion.c | 10 +-- .../test/CoverageMapping/mcdc-scratch-space.c | 4 +- .../CoverageMapping/mcdc-system-headers.cpp | 4 +- clang/test/CoverageMapping/switch.cpp | 64 +++++++++---------- clang/test/CoverageMapping/switchmacro.c | 4 +- .../ProfileData/Coverage/CoverageMapping.h | 15 +++-- .../ProfileData/Coverage/CoverageMapping.cpp | 2 +- .../test/tools/llvm-cov/branch-c-general.test | 14 ++-- llvm/tools/llvm-cov/CoverageExporterJson.cpp | 2 +- llvm/tools/llvm-cov/CoverageExporterLcov.cpp | 2 +- llvm/tools/llvm-cov/CoverageSummaryInfo.cpp | 24 +++---- .../tools/llvm-cov/SourceCoverageViewHTML.cpp | 51 +++++++++------ .../tools/llvm-cov/SourceCoverageViewText.cpp | 47 ++++++++------ 16 files changed, 169 insertions(+), 164 deletions(-) diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 577a0f571e16ea..0a63c50d44f4b7 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1098,12 +1098,6 @@ struct CounterCoverageMappingBuilder return ExitCount; } - /// Determine whether the given condition can be constant folded. - bool ConditionFoldsToBool(const Expr *Cond) { - Expr::EvalResult Result; - return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext())); - } - /// Create a Branch Region around an instrumentable condition for coverage /// and add it to the function's SourceRegions. A branch region tracks a /// "True" counter and a "False" counter for boolean expressions that @@ -1133,13 +1127,15 @@ struct CounterCoverageMappingBuilder // Alternatively, we can prevent any optimization done via // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in // CodeGenFunction.c always returns false, but that is very heavy-handed. - if (ConditionFoldsToBool(C)) - popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C), - Counter::getZero(), BranchParams)); - else - // Otherwise, create a region with the True counter and False counter. - popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, - BranchParams)); + Expr::EvalResult Result; + if (C->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext())) { + if (Result.Val.getInt().getBoolValue()) + FalseCnt = Counter::getZero(); + else + TrueCnt = Counter::getZero(); + } + popRegions( + pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, BranchParams)); } } @@ -1153,12 +1149,12 @@ struct CounterCoverageMappingBuilder /// Create a Branch Region around a SwitchCase for code coverage /// and add it to the function's SourceRegions. - void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt, - Counter FalseCnt) { + void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt) { // Push region onto RegionStack but immediately pop it (which adds it to // the function's SourceRegions) because it doesn't apply to any other // source other than the SwitchCase. - popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt)); + popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), + Counter::getZero())); } /// Check whether a region with bounds \c StartLoc and \c EndLoc @@ -1870,24 +1866,16 @@ struct CounterCoverageMappingBuilder const SwitchCase *Case = S->getSwitchCaseList(); for (; Case; Case = Case->getNextSwitchCase()) { HasDefaultCase = HasDefaultCase || isa(Case); - CaseCountSum = - addCounters(CaseCountSum, getRegionCounter(Case), /*Simplify=*/false); - createSwitchCaseRegion( - Case, getRegionCounter(Case), - subtractCounters(ParentCount, getRegionCounter(Case))); + auto CaseCount = getRegionCounter(Case); + CaseCountSum = addCounters(CaseCountSum, CaseCount, /*Simplify=*/false); + createSwitchCaseRegion(Case, CaseCount); } - // Simplify is skipped while building the counters above: it can get really - // slow on top of switches with thousands of cases. Instead, trigger - // simplification by adding zero to the last counter. - CaseCountSum = addCounters(CaseCountSum, Counter::getZero()); - // If no explicit default case exists, create a branch region to represent // the hidden branch, which will be added later by the CodeGen. This region // will be associated with the switch statement's condition. if (!HasDefaultCase) { - Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum); - Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue); - createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse); + Counter DefaultCount = subtractCounters(ParentCount, CaseCountSum); + createBranchRegion(S->getCond(), Counter::getZero(), DefaultCount); } } diff --git a/clang/test/CoverageMapping/branch-constfolded.cpp b/clang/test/CoverageMapping/branch-constfolded.cpp index 1e7e32808e8382..a2ac1c1eacd28f 100644 --- a/clang/test/CoverageMapping/branch-constfolded.cpp +++ b/clang/test/CoverageMapping/branch-constfolded.cpp @@ -5,94 +5,94 @@ // CHECK-LABEL: _Z6fand_0b: bool fand_0(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2 - return false && a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0 + return false && a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, (#0 - #1) } // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = #2, (#1 - #2) // CHECK-LABEL: _Z6fand_1b: bool fand_1(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2 return a && true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #1, (#0 - #1) -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = #2, 0 // CHECK-LABEL: _Z6fand_2bb: bool fand_2(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3 - return false && a && b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0 + return false && a && b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, (#0 - #3) } // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = #4, (#3 - #4) // CHECK: Branch,File 0, [[@LINE-2]]:24 -> [[@LINE-2]]:25 = #2, (#1 - #2) // CHECK-LABEL: _Z6fand_3bb: bool fand_3(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3 return a && true && b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #3, (#0 - #3) -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = #4, 0 // CHECK: Branch,File 0, [[@LINE-2]]:23 -> [[@LINE-2]]:24 = #2, (#1 - #2) // CHECK-LABEL: _Z6fand_4bb: bool fand_4(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3 return a && b && false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #3, (#0 - #3) } // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:16 = #4, (#3 - #4) - // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:25 = 0, 0 + // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:25 = 0, (#1 - #2) // CHECK-LABEL: _Z6fand_5b: bool fand_5(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:23 = M:3, C:2 - return false && true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0 -} // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:23 = 0, 0 + return false && true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, (#0 - #1) +} // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:23 = #2, 0 // CHECK-LABEL: _Z6fand_6b: bool fand_6(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2 - return true && a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0 + return true && a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = #1, 0 } // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = #2, (#1 - #2) // CHECK-LABEL: _Z6fand_7b: bool fand_7(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2 return a && false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #1, (#0 - #1) -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, (#1 - #2) // CHECK-LABEL: _Z5for_0b: bool for_0(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2 - return true || a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0 + return true || a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = (#0 - #1), 0 } // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = (#1 - #2), #2 // CHECK-LABEL: _Z5for_1b: bool for_1(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2 return a || false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #1), #1 -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, #2 // CHECK-LABEL: _Z5for_2bb: bool for_2(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3 - return true || a || b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0 + return true || a || b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = (#0 - #3), 0 } // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = (#3 - #4), #4 // CHECK: Branch,File 0, [[@LINE-2]]:23 -> [[@LINE-2]]:24 = (#1 - #2), #2 // CHECK-LABEL: _Z5for_3bb: bool for_3(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3 return a || false || b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #3), #3 -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, #4 // CHECK: Branch,File 0, [[@LINE-2]]:24 -> [[@LINE-2]]:25 = (#1 - #2), #2 // CHECK-LABEL: _Z5for_4bb: bool for_4(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3 return a || b || true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #3), #3 } // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:16 = (#3 - #4), #4 - // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:24 = 0, 0 + // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:24 = (#1 - #2), 0 // CHECK-LABEL: _Z5for_5b: bool for_5(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:23 = M:3, C:2 - return true || false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0 -} // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:23 = 0, 0 + return true || false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = (#0 - #1), 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:23 = 0, #2 // CHECK-LABEL: _Z5for_6b: bool for_6(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2 - return false || a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0 + return false || a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, #1 } // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = (#1 - #2), #2 // CHECK-LABEL: _Z5for_7b: bool for_7(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2 return a || true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #1), #1 -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = (#1 - #2), 0 // CHECK-LABEL: _Z5for_8b: bool for_8(bool a) { // MCDC: Decision,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:20 = M:3, C:2 - // CHECK: Branch,File 0, [[@LINE+2]]:7 -> [[@LINE+2]]:11 = 0, 0 - // CHECK: Branch,File 0, [[@LINE+1]]:15 -> [[@LINE+1]]:20 = 0, 0 + // CHECK: Branch,File 0, [[@LINE+2]]:7 -> [[@LINE+2]]:11 = #2, 0 + // CHECK: Branch,File 0, [[@LINE+1]]:15 -> [[@LINE+1]]:20 = 0, (#2 - #3) if (true && false) return true; else diff --git a/clang/test/CoverageMapping/if.cpp b/clang/test/CoverageMapping/if.cpp index 445cdfc20e2aff..b6fd525e930f90 100644 --- a/clang/test/CoverageMapping/if.cpp +++ b/clang/test/CoverageMapping/if.cpp @@ -14,7 +14,7 @@ struct S { // CHECK-LABEL: _Z3foov: // CHECK-NEXT: [[@LINE+3]]:12 -> [[@LINE+8]]:2 = #0 // CHECK-NEXT: [[@LINE+3]]:15 -> [[@LINE+3]]:19 = #0 - // CHECK-NEXT: Branch,File 0, [[@LINE+2]]:15 -> [[@LINE+2]]:19 = 0, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE+2]]:15 -> [[@LINE+2]]:19 = #2, 0 void foo() { // CHECK-NEXT: Gap,File 0, [[@LINE+1]]:21 -> [[@LINE+1]]:22 = #2 if (int j = true ? nop() // CHECK-NEXT: [[@LINE]]:22 -> [[@LINE]]:27 = #2 : nop(); // CHECK-NEXT: [[@LINE]]:22 -> [[@LINE]]:27 = (#0 - #2) @@ -168,7 +168,7 @@ int main() { // CHECK: File 0, [[@LINE]]:12 -> {{[0-9]+}}:2 = // GH-45481 S s; s.the_prop = 0? 1 : 2; // CHECK-NEXT: File 0, [[@LINE]]:16 -> [[@LINE]]:17 = #0 - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:16 -> [[@LINE-1]]:17 = 0, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:16 -> [[@LINE-1]]:17 = 0, (#0 - #7) // CHECK-NEXT: Gap,File 0, [[@LINE-2]]:18 -> [[@LINE-2]]:19 = #7 // CHECK-NEXT: File 0, [[@LINE-3]]:19 -> [[@LINE-3]]:20 = #7 // CHECK-NEXT: File 0, [[@LINE-4]]:23 -> [[@LINE-4]]:24 = (#0 - #7) diff --git a/clang/test/CoverageMapping/macro-expansion.c b/clang/test/CoverageMapping/macro-expansion.c index ad71fb15eda423..4cd2c934371931 100644 --- a/clang/test/CoverageMapping/macro-expansion.c +++ b/clang/test/CoverageMapping/macro-expansion.c @@ -4,29 +4,29 @@ // CHECK: File 1, [[@LINE+7]]:12 -> [[@LINE+7]]:38 = #0 // CHECK-NEXT: File 1, [[@LINE+6]]:15 -> [[@LINE+6]]:28 = (#0 + #2) // CHECK-NEXT: File 1, [[@LINE+5]]:21 -> [[@LINE+5]]:22 = (#0 + #2) -// CHECK: Branch,File 1, [[@LINE+4]]:21 -> [[@LINE+4]]:22 = 0, 0 +// CHECK: Branch,File 1, [[@LINE+4]]:21 -> [[@LINE+4]]:22 = 0, ((#0 + #2) - #3) // CHECK-NEXT: File 1, [[@LINE+3]]:24 -> [[@LINE+3]]:26 = #3 // CHECK-NEXT: File 1, [[@LINE+2]]:36 -> [[@LINE+2]]:37 = (#0 + #2) -// CHECK-NEXT: Branch,File 1, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, 0 +// CHECK-NEXT: Branch,File 1, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, #0 #define M1 do { if (0) {} } while (0) // CHECK-NEXT: File 2, [[@LINE+12]]:15 -> [[@LINE+12]]:41 = #0 // CHECK-NEXT: File 2, [[@LINE+11]]:18 -> [[@LINE+11]]:31 = (#0 + #4) // CHECK-NEXT: File 2, [[@LINE+10]]:24 -> [[@LINE+10]]:25 = (#0 + #4) // CHECK: File 2, [[@LINE+9]]:27 -> [[@LINE+9]]:29 = #5 // CHECK-NEXT: File 2, [[@LINE+8]]:39 -> [[@LINE+8]]:40 = (#0 + #4) -// CHECK-NEXT: Branch,File 2, [[@LINE+7]]:39 -> [[@LINE+7]]:40 = 0, 0 +// CHECK-NEXT: Branch,File 2, [[@LINE+7]]:39 -> [[@LINE+7]]:40 = 0, #0 // CHECK-NEXT: File 3, [[@LINE+6]]:15 -> [[@LINE+6]]:41 = #0 // CHECK-NEXT: File 3, [[@LINE+5]]:18 -> [[@LINE+5]]:31 = (#0 + #6) // CHECK-NEXT: File 3, [[@LINE+4]]:24 -> [[@LINE+4]]:25 = (#0 + #6) // CHECK: File 3, [[@LINE+3]]:27 -> [[@LINE+3]]:29 = #7 // CHECK-NEXT: File 3, [[@LINE+2]]:39 -> [[@LINE+2]]:40 = (#0 + #6) -// CHECK-NEXT: Branch,File 3, [[@LINE+1]]:39 -> [[@LINE+1]]:40 = 0, 0 +// CHECK-NEXT: Branch,File 3, [[@LINE+1]]:39 -> [[@LINE+1]]:40 = 0, #0 #define M2(x) do { if (x) {} } while (0) // CHECK-NEXT: File 4, [[@LINE+5]]:15 -> [[@LINE+5]]:38 = #0 // CHECK-NEXT: File 4, [[@LINE+4]]:18 -> [[@LINE+4]]:28 = (#0 + #8) // CHECK-NEXT: Expansion,File 4, [[@LINE+3]]:20 -> [[@LINE+3]]:22 = (#0 + #8) // CHECK-NEXT: File 4, [[@LINE+2]]:36 -> [[@LINE+2]]:37 = (#0 + #8) -// CHECK-NEXT: Branch,File 4, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, 0 +// CHECK-NEXT: Branch,File 4, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, #0 #define M3(x) do { M2(x); } while (0) // CHECK-NEXT: File 5, [[@LINE+4]]:15 -> [[@LINE+4]]:27 = #0 // CHECK-NEXT: File 5, [[@LINE+3]]:16 -> [[@LINE+3]]:19 = #0 diff --git a/clang/test/CoverageMapping/mcdc-scratch-space.c b/clang/test/CoverageMapping/mcdc-scratch-space.c index a263e9b688faed..60e456948a5182 100644 --- a/clang/test/CoverageMapping/mcdc-scratch-space.c +++ b/clang/test/CoverageMapping/mcdc-scratch-space.c @@ -3,7 +3,7 @@ // CHECK: builtin_macro0: int builtin_macro0(int a) { // CHECK: Decision,File 0, [[@LINE+1]]:11 -> [[@LINE+2]]:15 = M:3, C:2 - return (__LINE__ // CHECK: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:11 = 0, 0 [1,2,0] + return (__LINE__ // CHECK: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:11 = #1, 0 [1,2,0] && a); // CHECK: Branch,File 0, [[@LINE]]:14 -> [[@LINE]]:15 = #2, (#1 - #2) [2,0,0] } @@ -11,7 +11,7 @@ int builtin_macro0(int a) { int builtin_macro1(int a) { // CHECK: Decision,File 0, [[@LINE+1]]:11 -> [[@LINE+2]]:22 = M:3, C:2 return (a // CHECK: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = (#0 - #1), #1 [1,0,2] - || __LINE__); // CHECK: Branch,File 0, [[@LINE]]:14 -> [[@LINE]]:14 = 0, 0 [2,0,0] + || __LINE__); // CHECK: Branch,File 0, [[@LINE]]:14 -> [[@LINE]]:14 = (#1 - #2), 0 [2,0,0] } #define PRE(x) pre_##x diff --git a/clang/test/CoverageMapping/mcdc-system-headers.cpp b/clang/test/CoverageMapping/mcdc-system-headers.cpp index ae26ed5fe469f2..cb1c8743c36e82 100644 --- a/clang/test/CoverageMapping/mcdc-system-headers.cpp +++ b/clang/test/CoverageMapping/mcdc-system-headers.cpp @@ -17,10 +17,10 @@ int func0(int a) { // CHECK: Decision,File 0, [[@LINE+3]]:11 -> [[@LINE+3]]:21 = M:3, C:2 // W_SYS: Expansion,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:16 = #0 (Expanded file = 1) - // X_SYS: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:11 = 0, 0 [1,2,0] + // X_SYS: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:11 = #1, 0 [1,2,0] return (CONST && a); // CHECK: Branch,File 0, [[@LINE-1]]:20 -> [[@LINE-1]]:21 = #2, (#1 - #2) [2,0,0] - // W_SYS: Branch,File 1, [[@LINE-16]]:15 -> [[@LINE-16]]:17 = 0, 0 [1,2,0] + // W_SYS: Branch,File 1, [[@LINE-16]]:15 -> [[@LINE-16]]:17 = #1, 0 [1,2,0] } // CHECK: _Z5func1ii: diff --git a/clang/test/CoverageMapping/switch.cpp b/clang/test/CoverageMapping/switch.cpp index b47c0e80099527..a1fee644faaf0e 100644 --- a/clang/test/CoverageMapping/switch.cpp +++ b/clang/test/CoverageMapping/switch.cpp @@ -2,13 +2,13 @@ // CHECK: foo void foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+11]]:2 = #0 - switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = ((#0 - #2) - #3), (#2 + #3) + switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = 0, ((#0 - #2) - #3) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+5]]:10 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = #2 - return; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) + return; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, 0 // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE+1]]:3 = 0 case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #3 - break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) + break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, 0 } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = #1 int x = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = #1 @@ -18,24 +18,24 @@ int nop() { return 0; } // CHECK: bar void bar(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+21]]:2 = #0 - switch (i) // CHECK-NEXT: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = #0, 0 + switch (i) // CHECK-NEXT: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = 0, #0 ; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:6 = 0 switch (i) { // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+17]]:2 = #1 - } // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = #1, 0 + } // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = 0, #1 switch (i) // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+14]]:2 = #2 - nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = #2, 0 + nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = 0, #2 // CHECK-NEXT: File 0, [[@LINE-1]]:5 -> [[@LINE-1]]:10 = 0 switch (i) // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+11]]:2 = #3 - case 1: // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = (#3 - #5), #5 + case 1: // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = 0, (#3 - #5) // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE+1]]:10 = #5 - nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #5, (#3 - #5) + nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #5, 0 // CHECK-NEXT: File 0, [[@LINE+1]]:3 -> [[@LINE+7]]:2 = #4 - switch (i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = (#4 - #7), #7 + switch (i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = 0, (#4 - #7) nop(); // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+2]]:10 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #7 - nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, (#4 - #7) + nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, 0 } nop(); // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = #6 } @@ -44,7 +44,7 @@ void bar(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+21]]:2 = #0 void baz() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+5]]:2 = #0 switch (int i = true ? nop() // CHECK: [[@LINE]]:26 -> [[@LINE]]:31 = #2 : nop(); // CHECK-NEXT: [[@LINE]]:26 -> [[@LINE]]:31 = (#0 - #2) - i) {} // CHECK-NEXT: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = #0, 0 + i) {} // CHECK-NEXT: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = 0, #0 nop(); // CHECK-NEXT: [[@LINE]]:3 -> [[@LINE+1]]:2 = #1 } @@ -53,35 +53,35 @@ int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+39]]:2 = #0 int i = 0; switch(i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:13 -> [[@LINE+8]]:10 = 0 case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #2 - i = 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) + i = 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, 0 break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #3 - i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) + i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, 0 break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #4 - break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #4, (#0 - #4) + break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #4, 0 } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = #1 switch(i) { // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+27]]:2 = #1 case 0: // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+7]]:10 = 0 i = 1; // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE+1]]:10 = #6 - break; // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #6, (#1 - #6) + break; // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #6, 0 // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:10 = #7 - i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, (#1 - #7) + i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = (#7 + #8) - break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #8, (#1 - #8) + break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #8, 0 } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = #5 // CHECK-NEXT: File 0, [[@LINE+1]]:3 -> [[@LINE+17]]:2 = #5 - switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = ((((#5 - #10) - #11) - #12) - #13), (((#10 + #11) + #12) + #13) + switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = 0, ((((#5 - #10) - #11) - #12) - #13) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+8]]:11 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+7]]:11 = #10 - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #10, (#5 - #10) + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #10, 0 case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+5]]:11 = (#10 + #11) - i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #11, (#5 - #11) + i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #11, 0 case 3: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:11 = ((#10 + #11) + #12) - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #12, (#5 - #12) + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #12, 0 case 4: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = (((#10 + #11) + #12) + #13) - i = 99; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #13, (#5 - #13) + i = 99; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #13, 0 } foo(1); // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:11 = #9 @@ -95,10 +95,10 @@ int pr44011(int i) { // CHECK-NEXT: File 0, [[@LINE]]:20 -> {{.*}}:2 = #0 switch (i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+6]]:13 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 = #2 - return 0; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) + return 0; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, 0 // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 = #3 - return 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #3, (#0 - #3) + return 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #3, 0 } } // A region for counter #1 is missing due to the missing return. @@ -106,17 +106,17 @@ int pr44011(int i) { // CHECK-NEXT: File 0, [[@LINE]]:20 -> {{.*}}:2 = #0 // FIXME: End location for "case 1" shouldn't point at the end of the switch. // CHECK: fallthrough int fallthrough(int i) { // CHECK-NEXT: File 0, [[@LINE]]:24 -> [[@LINE+14]]:2 = #0 - // CHECK-NEXT: Branch,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:11 = ((((#0 - #2) - #3) - #4) - #5), (((#2 + #3) + #4) + #5) + // CHECK-NEXT: Branch,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:11 = 0, ((((#0 - #2) - #3) - #4) - #5) switch(i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:13 -> [[@LINE+10]]:10 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+9]]:10 = #2 - i = 23; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) + i = 23; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, 0 case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = (#2 + #3) - i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) + i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, 0 break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0 case 3: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+4]]:10 = #4 - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4) + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, 0 case 4: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = (#4 + #5) - i = 99; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #5, (#0 - #5) + i = 99; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #5, 0 break; } } @@ -126,12 +126,12 @@ void abort(void) __attribute((noreturn)); int noret(int x) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+11]]:2 switch (x) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+8]]:14 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:12 - abort(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, (#0 - #2) + abort(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, 0 // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:3 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 - return 5; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) + return 5; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, 0 // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = 0 case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:14 - return 10; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4) + return 10; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, 0 } } diff --git a/clang/test/CoverageMapping/switchmacro.c b/clang/test/CoverageMapping/switchmacro.c index 4c98cc7d9403a4..0696e7490cdf99 100644 --- a/clang/test/CoverageMapping/switchmacro.c +++ b/clang/test/CoverageMapping/switchmacro.c @@ -6,7 +6,7 @@ int foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> {{[0-9]+}}:2 = #0 switch (i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> {{[0-9]+}}:11 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> {{[0-9]+}}:11 = #2 - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, (#0 - #2) + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, 0 if (i == 1) // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:15 = #2 // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:9 -> [[@LINE-1]]:15 = #3, (#2 - #3) return 0; // CHECK: File 0, [[@LINE]]:7 -> [[@LINE]]:15 = #3 @@ -15,7 +15,7 @@ int foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> {{[0-9]+}}:2 = #0 // CHECK-NEXT: File 0, [[@LINE+1]]:8 -> {{[0-9]+}}:11 = (#2 - #3) FOO(1); case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:13 = ((#2 + #4) - #3) - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4) + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, 0 return 2; // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+4]]:3 = 0 // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:6 = 0 diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h index fa07b3a9e8b14f..e631e3899fd4de 100644 --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -358,20 +358,21 @@ struct CounterMappingRegion { struct CountedRegion : public CounterMappingRegion { uint64_t ExecutionCount; uint64_t FalseExecutionCount; - bool Folded; + bool TrueFolded; + bool FalseFolded; bool HasSingleByteCoverage; CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount, bool HasSingleByteCoverage) : CounterMappingRegion(R), ExecutionCount(ExecutionCount), - FalseExecutionCount(0), Folded(false), + FalseExecutionCount(0), TrueFolded(false), FalseFolded(true), HasSingleByteCoverage(HasSingleByteCoverage) {} CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount, uint64_t FalseExecutionCount, bool HasSingleByteCoverage) : CounterMappingRegion(R), ExecutionCount(ExecutionCount), - FalseExecutionCount(FalseExecutionCount), Folded(false), - HasSingleByteCoverage(HasSingleByteCoverage) {} + FalseExecutionCount(FalseExecutionCount), TrueFolded(false), + FalseFolded(false), HasSingleByteCoverage(HasSingleByteCoverage) {} }; /// MCDC Record grouping all information together. @@ -719,10 +720,10 @@ struct FunctionRecord { Region.Kind == CounterMappingRegion::MCDCBranchRegion) { CountedBranchRegions.emplace_back(Region, Count, FalseCount, HasSingleByteCoverage); - // If both counters are hard-coded to zero, then this region represents a + // If either counter is hard-coded to zero, then this region represents a // constant-folded branch. - if (Region.Count.isZero() && Region.FalseCount.isZero()) - CountedBranchRegions.back().Folded = true; + CountedBranchRegions.back().TrueFolded = Region.Count.isZero(); + CountedBranchRegions.back().FalseFolded = Region.FalseCount.isZero(); return; } if (CountedRegions.empty()) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index c713371da81e40..119e09187b9080 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -503,7 +503,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder { const auto &BranchParams = B->getBranchParams(); PosToID[I] = BranchParams.ID; CondLoc[I] = B->startLoc(); - Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero()); + Folded[I++] = (B->Count.isZero() || B->FalseCount.isZero()); } // Using Profile Bitmap from runtime, mark the executed test vectors. diff --git a/llvm/test/tools/llvm-cov/branch-c-general.test b/llvm/test/tools/llvm-cov/branch-c-general.test index 9b5889babde366..2fa99dfe61532e 100644 --- a/llvm/test/tools/llvm-cov/branch-c-general.test +++ b/llvm/test/tools/llvm-cov/branch-c-general.test @@ -47,7 +47,7 @@ // CHECK: Branch (103:9): [True: 9, False: 1] // CHECK: switches() -// CHECK: Branch (113:3): [True: 1, False: 0] +// CHECK: Branch (113:3): [True: 1, Folded] // CHECK: Branch (117:63): [True: 15, False: 0] // CHECK: Branch (119:5): [True: 1, False: 14] // CHECK: Branch (120:11): [True: 0, False: 1] @@ -57,7 +57,7 @@ // CHECK: Branch (126:11): [True: 3, False: 0] // CHECK: Branch (128:5): [True: 4, False: 11] // CHECK: Branch (129:11): [True: 4, False: 0] -// CHECK: Branch (131:7): [True: 4, False: 0] +// CHECK: Branch (131:7): [True: 4, Folded] // CHECK: Branch (132:13): [True: 4, False: 0] // CHECK: Branch (136:5): [True: 5, False: 10] // CHECK: Branch (137:11): [True: 1, False: 4] @@ -114,13 +114,13 @@ -// REPORT: Name Regions Miss Cover Lines Miss Cover Branches Miss Cover +// REPORT: Name Regions Miss Cover Lines Miss Cover Branches Miss Cover // REPORT-NEXT: --- // REPORT-NEXT: simple_loops 8 0 100.00% 9 0 100.00% 6 0 100.00% // REPORT-NEXT: conditionals 24 0 100.00% 15 0 100.00% 16 2 87.50% // REPORT-NEXT: early_exits 20 4 80.00% 25 2 92.00% 16 6 62.50% // REPORT-NEXT: jumps 39 12 69.23% 48 2 95.83% 26 9 65.38% -// REPORT-NEXT: switches 28 5 82.14% 38 4 89.47% 30 9 70.00% +// REPORT-NEXT: switches 28 5 82.14% 38 4 89.47% 28 7 75.00% // REPORT-NEXT: big_switch 25 1 96.00% 32 0 100.00% 30 6 80.00% // REPORT-NEXT: boolean_operators 16 0 100.00% 13 0 100.00% 22 2 90.91% // REPORT-NEXT: boolop_loops 19 0 100.00% 14 0 100.00% 16 2 87.50% @@ -129,12 +129,12 @@ // REPORT-NEXT: main 1 0 100.00% 16 0 100.00% 0 0 0.00% // REPORT-NEXT: c-general.c:static_func 4 0 100.00% 4 0 100.00% 2 0 100.00% // REPORT-NEXT: --- -// REPORT-NEXT: TOTAL 197 24 87.82% 234 8 96.58% 174 38 78.16% +// REPORT-NEXT: TOTAL 197 24 87.82% 234 8 96.58% 172 36 79.07% // Test file-level report. // RUN: llvm-profdata merge %S/Inputs/branch-c-general.proftext -o %t.profdata // RUN: llvm-cov report %S/Inputs/branch-c-general.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-c-general.c | FileCheck %s -check-prefix=FILEREPORT -// FILEREPORT: TOTAL{{.*}}174 38 78.16% +// FILEREPORT: TOTAL{{.*}}172 36 79.07% // Test color True/False output. // RUN: llvm-cov show --use-color --show-branches=count %S/Inputs/branch-c-general.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-c-general.c | FileCheck %s -check-prefix=USECOLOR @@ -161,6 +161,6 @@ // HTML-INDEX: // HTML-INDEX: 87.82% (173/197) // HTML-INDEX: -// HTML-INDEX: 78.16% (136/174) +// HTML-INDEX: 79.07% (136/172) // HTML-INDEX: // HTML-INDEX: Totals diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp index 9a8c7c94f06124..4088c1b053aa8d 100644 --- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp +++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp @@ -125,7 +125,7 @@ json::Array renderRegions(ArrayRef Regions) { json::Array renderBranchRegions(ArrayRef Regions) { json::Array RegionArray; for (const auto &Region : Regions) - if (!Region.Folded) + if (!Region.TrueFolded || !Region.FalseFolded) RegionArray.push_back(renderBranch(Region)); return RegionArray; } diff --git a/llvm/tools/llvm-cov/CoverageExporterLcov.cpp b/llvm/tools/llvm-cov/CoverageExporterLcov.cpp index ae8f556edb313b..d6b9367ae4c514 100644 --- a/llvm/tools/llvm-cov/CoverageExporterLcov.cpp +++ b/llvm/tools/llvm-cov/CoverageExporterLcov.cpp @@ -139,7 +139,7 @@ void renderBranchExecutionCounts(raw_ostream &OS, unsigned BranchIndex = 0; while (NextBranch != EndBranch && CurrentLine == NextBranch->LineStart) { - if (!NextBranch->Folded) { + if (!NextBranch->TrueFolded || !NextBranch->FalseFolded) { unsigned BC1 = NextBranch->ExecutionCount; unsigned BC2 = NextBranch->FalseExecutionCount; bool BranchNotExecuted = (BC1 == 0 && BC2 == 0); diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp index 4f150020ee3815..58e7918d392709 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp @@ -19,18 +19,18 @@ using namespace coverage; static void sumBranches(size_t &NumBranches, size_t &CoveredBranches, const ArrayRef &Branches) { for (const auto &BR : Branches) { - // Skip folded branches. - if (BR.Folded) - continue; - - // "True" Condition Branches. - ++NumBranches; - if (BR.ExecutionCount > 0) - ++CoveredBranches; - // "False" Condition Branches. - ++NumBranches; - if (BR.FalseExecutionCount > 0) - ++CoveredBranches; + if (!BR.TrueFolded) { + // "True" Condition Branches. + ++NumBranches; + if (BR.ExecutionCount > 0) + ++CoveredBranches; + } + if (!BR.FalseFolded) { + // "False" Condition Branches. + ++NumBranches; + if (BR.FalseExecutionCount > 0) + ++CoveredBranches; + } } } diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp index 6f4d327679d6b6..7421763dd7a427 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp @@ -1128,36 +1128,45 @@ void SourceCoverageViewHTML::renderBranchView(raw_ostream &OS, BranchView &BRV, "line-number") + "): ["; - if (R.Folded) { + if (R.TrueFolded && R.FalseFolded) { OS << "Folded - Ignored]\n"; continue; } // Display TrueCount or TruePercent. - std::string TrueColor = R.ExecutionCount ? "None" : "red branch"; + std::string TrueColor = + (R.TrueFolded || R.ExecutionCount ? "None" : "red branch"); std::string TrueCovClass = - (R.ExecutionCount > 0) ? "covered-line" : "uncovered-line"; - - OS << tag("span", "True", TrueColor); - OS << ": "; - if (getOptions().ShowBranchCounts) - OS << tag("span", formatCount(R.ExecutionCount), TrueCovClass) << ", "; - else - OS << format("%0.2f", TruePercent) << "%, "; + (R.TrueFolded || R.ExecutionCount > 0 ? "covered-line" + : "uncovered-line"); + + if (R.TrueFolded) + OS << "Folded, "; + else { + OS << tag("span", "True", TrueColor) << ": "; + if (getOptions().ShowBranchCounts) + OS << tag("span", formatCount(R.ExecutionCount), TrueCovClass) << ", "; + else + OS << format("%0.2f", TruePercent) << "%, "; + } // Display FalseCount or FalsePercent. - std::string FalseColor = R.FalseExecutionCount ? "None" : "red branch"; + std::string FalseColor = + (R.FalseFolded || R.FalseExecutionCount ? "None" : "red branch"); std::string FalseCovClass = - (R.FalseExecutionCount > 0) ? "covered-line" : "uncovered-line"; - - OS << tag("span", "False", FalseColor); - OS << ": "; - if (getOptions().ShowBranchCounts) - OS << tag("span", formatCount(R.FalseExecutionCount), FalseCovClass); - else - OS << format("%0.2f", FalsePercent) << "%"; - - OS << "]\n"; + (R.FalseFolded || R.FalseExecutionCount > 0 ? "covered-line" + : "uncovered-line"); + + if (R.FalseFolded) + OS << "Folded]\n"; + else { + OS << tag("span", "False", FalseColor) << ": "; + if (getOptions().ShowBranchCounts) + OS << tag("span", formatCount(R.FalseExecutionCount), FalseCovClass) + << "]\n"; + else + OS << format("%0.2f", FalsePercent) << "%]\n"; + } } OS << EndPre; OS << EndExpansionDiv; diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp index 8b93b592910b3d..444f33dac10837 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp @@ -309,31 +309,38 @@ void SourceCoverageViewText::renderBranchView(raw_ostream &OS, BranchView &BRV, renderLinePrefix(OS, ViewDepth); OS << " Branch (" << R.LineStart << ":" << R.ColumnStart << "): ["; - if (R.Folded) { + if (R.TrueFolded && R.FalseFolded) { OS << "Folded - Ignored]\n"; continue; } - colored_ostream(OS, raw_ostream::RED, - getOptions().Colors && !R.ExecutionCount, - /*Bold=*/false, /*BG=*/true) - << "True"; - - if (getOptions().ShowBranchCounts) - OS << ": " << formatCount(R.ExecutionCount) << ", "; - else - OS << ": " << format("%0.2f", TruePercent) << "%, "; - - colored_ostream(OS, raw_ostream::RED, - getOptions().Colors && !R.FalseExecutionCount, - /*Bold=*/false, /*BG=*/true) - << "False"; + if (R.TrueFolded) + OS << "Folded, "; + else { + colored_ostream(OS, raw_ostream::RED, + getOptions().Colors && !R.ExecutionCount, + /*Bold=*/false, /*BG=*/true) + << "True"; + + if (getOptions().ShowBranchCounts) + OS << ": " << formatCount(R.ExecutionCount) << ", "; + else + OS << ": " << format("%0.2f", TruePercent) << "%, "; + } - if (getOptions().ShowBranchCounts) - OS << ": " << formatCount(R.FalseExecutionCount); - else - OS << ": " << format("%0.2f", FalsePercent) << "%"; - OS << "]\n"; + if (R.FalseFolded) + OS << "Folded]\n"; + else { + colored_ostream(OS, raw_ostream::RED, + getOptions().Colors && !R.FalseExecutionCount, + /*Bold=*/false, /*BG=*/true) + << "False"; + + if (getOptions().ShowBranchCounts) + OS << ": " << formatCount(R.FalseExecutionCount) << "]\n"; + else + OS << ": " << format("%0.2f", FalsePercent) << "%]\n"; + } } } From 861bd36bce3c3e1384b87b0366cf83e2c022c325 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 19 Oct 2024 20:32:58 -0700 Subject: [PATCH 08/12] [ELF] Pass Ctx & to Symbol::getVA --- lld/ELF/AArch64ErrataFix.cpp | 2 +- lld/ELF/ARMErrataFix.cpp | 4 +-- lld/ELF/Arch/AArch64.cpp | 12 +++---- lld/ELF/Arch/ARM.cpp | 25 +++++++------ lld/ELF/Arch/AVR.cpp | 2 +- lld/ELF/Arch/LoongArch.cpp | 4 +-- lld/ELF/Arch/Mips.cpp | 2 +- lld/ELF/Arch/PPC.cpp | 2 +- lld/ELF/Arch/PPC64.cpp | 4 +-- lld/ELF/Arch/RISCV.cpp | 17 ++++----- lld/ELF/Arch/SystemZ.cpp | 2 +- lld/ELF/Arch/X86.cpp | 2 +- lld/ELF/Arch/X86_64.cpp | 2 +- lld/ELF/InputSection.cpp | 44 ++++++++++++----------- lld/ELF/MapFile.cpp | 4 +-- lld/ELF/OutputSections.cpp | 2 +- lld/ELF/Relocations.cpp | 5 +-- lld/ELF/Symbols.cpp | 6 ++-- lld/ELF/Symbols.h | 2 +- lld/ELF/SyntheticSections.cpp | 29 +++++++-------- lld/ELF/Thunks.cpp | 68 +++++++++++++++++------------------ lld/ELF/Writer.cpp | 6 ++-- 22 files changed, 125 insertions(+), 121 deletions(-) diff --git a/lld/ELF/AArch64ErrataFix.cpp b/lld/ELF/AArch64ErrataFix.cpp index cd8fbf16f5b839..f9e03ce5bbe4db 100644 --- a/lld/ELF/AArch64ErrataFix.cpp +++ b/lld/ELF/AArch64ErrataFix.cpp @@ -417,7 +417,7 @@ void Patch843419Section::writeTo(uint8_t *buf) { // Return address is the next instruction after the one we have just copied. uint64_t s = getLDSTAddr() + 4; - uint64_t p = patchSym->getVA() + 4; + uint64_t p = patchSym->getVA(ctx) + 4; ctx.target->relocateNoSym(buf + 4, R_AARCH64_JUMP26, s - p); } diff --git a/lld/ELF/ARMErrataFix.cpp b/lld/ELF/ARMErrataFix.cpp index 630084afd509ce..6d759d7dec1d8a 100644 --- a/lld/ELF/ARMErrataFix.cpp +++ b/lld/ELF/ARMErrataFix.cpp @@ -218,7 +218,7 @@ static bool branchDestInFirstRegion(Ctx &ctx, const InputSection *isec, // or the PLT. if (r) { uint64_t dst = - (r->expr == R_PLT_PC) ? r->sym->getPltVA(ctx) : r->sym->getVA(); + r->expr == R_PLT_PC ? r->sym->getPltVA(ctx) : r->sym->getVA(ctx); // Account for Thumb PC bias, usually cancelled to 0 by addend of -4. destAddr = dst + r->addend + 4; } else { @@ -449,7 +449,7 @@ static void implementPatch(ScanResult sr, InputSection *isec, // Thunk from the patch to the target. uint64_t dstSymAddr = (sr.rel->expr == R_PLT_PC) ? sr.rel->sym->getPltVA(ctx) - : sr.rel->sym->getVA(); + : sr.rel->sym->getVA(ctx); destIsARM = (dstSymAddr & 1) == 0; } psec = make(ctx, isec, sr.off, sr.instr, destIsARM); diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 260307ac4c3dcb..f4f867d019136e 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -360,7 +360,7 @@ void AArch64::writeGotPlt(uint8_t *buf, const Symbol &) const { void AArch64::writeIgotPlt(uint8_t *buf, const Symbol &s) const { if (ctx.arg.writeAddends) - write64(ctx, buf, s.getVA()); + write64(ctx, buf, s.getVA(ctx)); } void AArch64::writePltHeader(uint8_t *buf) const { @@ -416,7 +416,7 @@ bool AArch64::needsThunk(RelExpr expr, RelType type, const InputFile *file, if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 && type != R_AARCH64_PLT32) return false; - uint64_t dst = expr == R_PLT_PC ? s.getPltVA(ctx) : s.getVA(a); + uint64_t dst = expr == R_PLT_PC ? s.getPltVA(ctx) : s.getVA(ctx, a); return !inBranchRange(type, branchAddr, dst); } @@ -808,7 +808,7 @@ bool AArch64Relaxer::tryRelaxAdrpAdd(const Relocation &adrpRel, Symbol &sym = *adrpRel.sym; // Check if the address difference is within 1MiB range. - int64_t val = sym.getVA() - (secAddr + addRel.offset); + int64_t val = sym.getVA(ctx) - (secAddr + addRel.offset); if (val < -1024 * 1024 || val >= 1024 * 1024) return false; @@ -874,7 +874,7 @@ bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel, return false; // Check if the address difference is within 4GB range. int64_t val = - getAArch64Page(sym.getVA()) - getAArch64Page(secAddr + adrpRel.offset); + getAArch64Page(sym.getVA(ctx)) - getAArch64Page(secAddr + adrpRel.offset); if (val != llvm::SignExtend64(val, 33)) return false; @@ -890,11 +890,11 @@ bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel, ctx.target->relocate( buf + adrpSymRel.offset, adrpSymRel, - SignExtend64(getAArch64Page(sym.getVA()) - + SignExtend64(getAArch64Page(sym.getVA(ctx)) - getAArch64Page(secAddr + adrpSymRel.offset), 64)); ctx.target->relocate(buf + addRel.offset, addRel, - SignExtend64(sym.getVA(), 64)); + SignExtend64(sym.getVA(ctx), 64)); tryRelaxAdrpAdd(adrpSymRel, addRel, secAddr, buf); return true; } diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp index 1cc396aa395d3b..be3f80337aae71 100644 --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -213,7 +213,7 @@ void ARM::writeGotPlt(uint8_t *buf, const Symbol &) const { void ARM::writeIgotPlt(uint8_t *buf, const Symbol &s) const { // An ARM entry is the address of the ifunc resolver function. - write32(ctx, buf, s.getVA()); + write32(ctx, buf, s.getVA(ctx)); } // Long form PLT Header that does not have any restrictions on the displacement @@ -404,26 +404,26 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file, // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb). assert(!useThumbPLTs(ctx) && "If the source is ARM, we should not need Thumb PLTs"); - if (s.isFunc() && expr == R_PC && (s.getVA() & 1)) + if (s.isFunc() && expr == R_PC && (s.getVA(ctx) & 1)) return true; [[fallthrough]]; case R_ARM_CALL: { - uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA(ctx) : s.getVA(); + uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA(ctx) : s.getVA(ctx); return !inBranchRange(type, branchAddr, dst + a) || - (!ctx.arg.armHasBlx && (s.getVA() & 1)); + (!ctx.arg.armHasBlx && (s.getVA(ctx) & 1)); } case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, when all PLT entries are ARM interworking is required. // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM). if ((expr == R_PLT_PC && !useThumbPLTs(ctx)) || - (s.isFunc() && (s.getVA() & 1) == 0)) + (s.isFunc() && (s.getVA(ctx) & 1) == 0)) return true; [[fallthrough]]; case R_ARM_THM_CALL: { - uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA(ctx) : s.getVA(); + uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA(ctx) : s.getVA(ctx); return !inBranchRange(type, branchAddr, dst + a) || - (!ctx.arg.armHasBlx && (s.getVA() & 1) == 0);; + (!ctx.arg.armHasBlx && (s.getVA(ctx) & 1) == 0); } } return false; @@ -1399,7 +1399,7 @@ void ArmCmseSGSection::writeTo(uint8_t *buf) { write16(ctx, p + 4, 0xf000); // B.W S write16(ctx, p + 6, 0xb000); ctx.target->relocateNoSym(p + 4, R_ARM_THM_JUMP24, - s->acleSeSym->getVA() - + s->acleSeSym->getVA(ctx) - (getVA() + s->offset + s->size)); } } @@ -1466,16 +1466,15 @@ template void elf::writeARMCmseImportLib(Ctx &ctx) { osIsPairs.emplace_back(make(ctx, shstrtab->name, 0, 0), shstrtab); - std::sort(ctx.symtab->cmseSymMap.begin(), ctx.symtab->cmseSymMap.end(), - [](const auto &a, const auto &b) -> bool { - return a.second.sym->getVA() < b.second.sym->getVA(); - }); + llvm::sort(ctx.symtab->cmseSymMap, [&](const auto &a, const auto &b) { + return a.second.sym->getVA(ctx) < b.second.sym->getVA(ctx); + }); // Copy the secure gateway entry symbols to the import library symbol table. for (auto &p : ctx.symtab->cmseSymMap) { Defined *d = cast(p.second.sym); impSymTab->addSymbol(makeDefined( ctx, ctx.internalFile, d->getName(), d->computeBinding(ctx), - /*stOther=*/0, STT_FUNC, d->getVA(), d->getSize(), nullptr)); + /*stOther=*/0, STT_FUNC, d->getVA(ctx), d->getSize(), nullptr)); } size_t idx = 0; diff --git a/lld/ELF/Arch/AVR.cpp b/lld/ELF/Arch/AVR.cpp index 4dc605c47059c1..64790f1ce83ab3 100644 --- a/lld/ELF/Arch/AVR.cpp +++ b/lld/ELF/Arch/AVR.cpp @@ -110,7 +110,7 @@ bool AVR::needsThunk(RelExpr expr, RelType type, const InputFile *file, case R_AVR_HI8_LDI_GS: // A thunk is needed if the symbol's virtual address is out of range // [0, 0x1ffff]. - return s.getVA() >= 0x20000; + return s.getVA(ctx) >= 0x20000; default: return false; } diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 5923cda2298b4e..876aadcb91511b 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -316,9 +316,9 @@ void LoongArch::writeGotPlt(uint8_t *buf, const Symbol &s) const { void LoongArch::writeIgotPlt(uint8_t *buf, const Symbol &s) const { if (ctx.arg.writeAddends) { if (ctx.arg.is64) - write64le(buf, s.getVA()); + write64le(buf, s.getVA(ctx)); else - write32le(buf, s.getVA()); + write32le(buf, s.getVA(ctx)); } } diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index 1d3000793ca268..d84e85239d2ec2 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -96,7 +96,7 @@ RelExpr MIPS::getRelExpr(RelType type, const Symbol &s, // If the target symbol is not preemptible and is not microMIPS, // it might be possible to replace jalr/jr instruction by bal/b. // It depends on the target symbol's offset. - if (!s.isPreemptible && !(s.getVA() & 0x1)) + if (!s.isPreemptible && !(s.getVA(ctx) & 0x1)) return R_PC; return R_NONE; case R_MICROMIPS_JALR: diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp index 3af4101fff606f..2cd526020f7d35 100644 --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -209,7 +209,7 @@ bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file, return true; if (s.isUndefWeak()) return false; - return !PPC::inBranchRange(type, branchAddr, s.getVA(a)); + return !PPC::inBranchRange(type, branchAddr, s.getVA(ctx, a)); } uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; } diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp index 9f550745f93b2a..d0f59681ccbd3c 100644 --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -404,7 +404,7 @@ static bool tryRelaxPPC64TocIndirection(Ctx &ctx, const Relocation &rel, assert(!d->isGnuIFunc()); // Two instructions can materialize a 32-bit signed offset from the toc base. - uint64_t tocRelative = d->getVA(addend) - getPPC64TocBase(ctx); + uint64_t tocRelative = d->getVA(ctx, addend) - getPPC64TocBase(ctx); if (!isInt<32>(tocRelative)) return false; @@ -1452,7 +1452,7 @@ bool PPC64::needsThunk(RelExpr expr, RelType type, const InputFile *file, // a range-extending thunk. // See the comment in getRelocTargetVA() about R_PPC64_CALL. return !inBranchRange(type, branchAddr, - s.getVA(a) + + s.getVA(ctx, a) + getPPC64GlobalEntryToLocalEntryOffset(s.stOther)); } diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 1ae016e4de01ee..7ebb67c3612311 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -214,9 +214,9 @@ void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const { void RISCV::writeIgotPlt(uint8_t *buf, const Symbol &s) const { if (ctx.arg.writeAddends) { if (ctx.arg.is64) - write64le(buf, s.getVA()); + write64le(buf, s.getVA(ctx)); else - write32le(buf, s.getVA()); + write32le(buf, s.getVA(ctx)); } } @@ -466,7 +466,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { case INTERNAL_R_RISCV_GPREL_I: case INTERNAL_R_RISCV_GPREL_S: { Defined *gp = ctx.sym.riscvGlobalPointer; - int64_t displace = SignExtend64(val - gp->getVA(), bits); + int64_t displace = SignExtend64(val - gp->getVA(ctx), bits); checkInt(ctx, loc, displace, 12, rel); uint32_t insn = (read32le(loc) & ~(31 << 15)) | (X_GP << 15); if (rel.type == INTERNAL_R_RISCV_GPREL_I) @@ -657,7 +657,8 @@ void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { const Relocation &rel1 = relocs[i + 1]; if (rel.type == R_RISCV_SET_ULEB128 && rel1.type == R_RISCV_SUB_ULEB128 && rel.offset == rel1.offset) { - auto val = rel.sym->getVA(rel.addend) - rel1.sym->getVA(rel1.addend); + auto val = rel.sym->getVA(ctx, rel.addend) - + rel1.sym->getVA(ctx, rel1.addend); if (overwriteULEB128(loc, val) >= 0x80) errorOrWarn(sec.getLocation(rel.offset) + ": ULEB128 value " + Twine(val) + " exceeds available space; references '" + @@ -737,7 +738,7 @@ static void relaxCall(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, const uint64_t insnPair = read64le(sec.content().data() + r.offset); const uint32_t rd = extractBits(insnPair, 32 + 11, 32 + 7); const uint64_t dest = - (r.expr == R_PLT_PC ? sym.getPltVA(ctx) : sym.getVA()) + r.addend; + (r.expr == R_PLT_PC ? sym.getPltVA(ctx) : sym.getVA(ctx)) + r.addend; const int64_t displace = dest - loc; if (rvc && isInt<12>(displace) && rd == 0) { @@ -759,7 +760,7 @@ static void relaxCall(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, // Relax local-exec TLS when hi20 is zero. static void relaxTlsLe(const InputSection &sec, size_t i, uint64_t loc, Relocation &r, uint32_t &remove) { - uint64_t val = r.sym->getVA(r.addend); + uint64_t val = r.sym->getVA(ctx, r.addend); if (hi20(val) != 0) return; uint32_t insn = read32le(sec.content().data() + r.offset); @@ -791,7 +792,7 @@ static void relaxHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, if (!gp) return; - if (!isInt<12>(r.sym->getVA(r.addend) - gp->getVA())) + if (!isInt<12>(r.sym->getVA(ctx, r.addend) - gp->getVA(ctx))) return; switch (r.type) { @@ -863,7 +864,7 @@ static bool relax(Ctx &ctx, InputSection &sec) { // For TLSDESC=>LE, we can use the short form if hi20 is zero. tlsdescRelax = relaxable(relocs, i); toLeShortForm = tlsdescRelax && r.expr == R_RELAX_TLS_GD_TO_LE && - !hi20(r.sym->getVA(r.addend)); + !hi20(r.sym->getVA(ctx, r.addend)); [[fallthrough]]; case R_RISCV_TLSDESC_LOAD_LO12: // For TLSDESC=>LE/IE, AUIPC and L[DW] are removed if relaxable. diff --git a/lld/ELF/Arch/SystemZ.cpp b/lld/ELF/Arch/SystemZ.cpp index 584379638ad981..106b530c31b28b 100644 --- a/lld/ELF/Arch/SystemZ.cpp +++ b/lld/ELF/Arch/SystemZ.cpp @@ -188,7 +188,7 @@ void SystemZ::writeGotPlt(uint8_t *buf, const Symbol &s) const { void SystemZ::writeIgotPlt(uint8_t *buf, const Symbol &s) const { if (ctx.arg.writeAddends) - write64be(buf, s.getVA()); + write64be(buf, s.getVA(ctx)); } void SystemZ::writePltHeader(uint8_t *buf) const { diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp index 58199cdb99a284..a36212a5b1690a 100644 --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -181,7 +181,7 @@ void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const { void X86::writeIgotPlt(uint8_t *buf, const Symbol &s) const { // An x86 entry is the address of the ifunc resolver function. - write32le(buf, s.getVA()); + write32le(buf, s.getVA(ctx)); } RelType X86::getDynRel(RelType type) const { diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp index df2983f2022818..d32ba638b740c5 100644 --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -429,7 +429,7 @@ void X86_64::writeGotPlt(uint8_t *buf, const Symbol &s) const { void X86_64::writeIgotPlt(uint8_t *buf, const Symbol &s) const { // An x86 entry is the address of the ifunc resolver function (for -z rel). if (ctx.arg.writeAddends) - write64le(buf, s.getVA()); + write64le(buf, s.getVA(ctx)); } void X86_64::writePltHeader(uint8_t *buf) const { diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 2e9e8a7007bbf8..6c34471a9e5022 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -508,7 +508,8 @@ void InputSection::copyRelocations(Ctx &ctx, uint8_t *buf, } if (RelTy::HasAddend) - p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr; + p->r_addend = + sym.getVA(ctx, addend) - section->getOutputSection()->addr; // For SHF_ALLOC sections relocated by REL, append a relocation to // sec->relocations so that relocateAlloc transitively called by // writeSections will update the implicit addend. Non-SHF_ALLOC sections @@ -701,7 +702,7 @@ static int64_t getTlsTpOffset(Ctx &ctx, const Symbol &s) { // Variant 1. case EM_ARM: case EM_AARCH64: - return s.getVA(0) + ctx.arg.wordsize * 2 + + return s.getVA(ctx, 0) + ctx.arg.wordsize * 2 + ((tls->p_vaddr - ctx.arg.wordsize * 2) & (tls->p_align - 1)); case EM_MIPS: case EM_PPC: @@ -709,7 +710,7 @@ static int64_t getTlsTpOffset(Ctx &ctx, const Symbol &s) { // Adjusted Variant 1. TP is placed with a displacement of 0x7000, which is // to allow a signed 16-bit offset to reach 0x1000 of TCB/thread-library // data and 0xf000 of the program's TLS segment. - return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)) - 0x7000; + return s.getVA(ctx, 0) + (tls->p_vaddr & (tls->p_align - 1)) - 0x7000; case EM_LOONGARCH: case EM_RISCV: // See the comment in handleTlsRelocation. For TLSDESC=>IE, @@ -717,7 +718,7 @@ static int64_t getTlsTpOffset(Ctx &ctx, const Symbol &s) { // `tls` may be null, the return value is ignored. if (s.type != STT_TLS) return 0; - return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)); + return s.getVA(ctx, 0) + (tls->p_vaddr & (tls->p_align - 1)); // Variant 2. case EM_HEXAGON: @@ -725,7 +726,7 @@ static int64_t getTlsTpOffset(Ctx &ctx, const Symbol &s) { case EM_SPARCV9: case EM_386: case EM_X86_64: - return s.getVA(0) - tls->p_memsz - + return s.getVA(ctx, 0) - tls->p_memsz - ((-tls->p_vaddr - tls->p_memsz) & (tls->p_align - 1)); default: llvm_unreachable("unhandled ctx.arg.emachine"); @@ -743,13 +744,13 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, case R_AARCH64_AUTH: case R_RISCV_ADD: case R_RISCV_LEB128: - return r.sym->getVA(a); + return r.sym->getVA(ctx, a); case R_ADDEND: return a; case R_RELAX_HINT: return 0; case R_ARM_SBREL: - return r.sym->getVA(a) - getARMStaticBase(*r.sym); + return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym); case R_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: return r.sym->getGotVA(ctx) + a; @@ -767,9 +768,9 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, return ctx.in.gotPlt->getVA() + a - p; case R_GOTREL: case R_PPC64_RELAX_TOC: - return r.sym->getVA(a) - ctx.in.got->getVA(); + return r.sym->getVA(ctx, a) - ctx.in.got->getVA(); case R_GOTPLTREL: - return r.sym->getVA(a) - ctx.in.gotPlt->getVA(); + return r.sym->getVA(ctx, a) - ctx.in.gotPlt->getVA(); case R_GOTPLT: case R_RELAX_TLS_GD_TO_IE_GOTPLT: return r.sym->getGotVA(ctx) + a - ctx.in.gotPlt->getVA(); @@ -795,7 +796,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, r.type); return getLoongArchPageDelta(r.sym->getGotVA(ctx) + a, p, r.type); case R_MIPS_GOTREL: - return r.sym->getVA(a) - ctx.in.mipsGot->getGp(file); + return r.sym->getVA(ctx, a) - ctx.in.mipsGot->getGp(file); case R_MIPS_GOT_GP: return ctx.in.mipsGot->getGp(file) + a; case R_MIPS_GOT_GP_PC: { @@ -836,16 +837,16 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, return ctx.in.mipsGot->getVA() + ctx.in.mipsGot->getTlsIndexOffset(file) - ctx.in.mipsGot->getGp(file); case R_AARCH64_PAGE_PC: { - uint64_t val = r.sym->isUndefWeak() ? p + a : r.sym->getVA(a); + uint64_t val = r.sym->isUndefWeak() ? p + a : r.sym->getVA(ctx, a); return getAArch64Page(val) - getAArch64Page(p); } case R_RISCV_PC_INDIRECT: { if (const Relocation *hiRel = getRISCVPCRelHi20(this, r)) - return getRelocTargetVA(ctx, *hiRel, r.sym->getVA()); + return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx)); return 0; } case R_LOONGARCH_PAGE_PC: - return getLoongArchPageDelta(r.sym->getVA(a), p, r.type); + return getLoongArchPageDelta(r.sym->getVA(ctx, a), p, r.type); case R_PC: case R_ARM_PCA: { uint64_t dest; @@ -868,9 +869,9 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, else if (ctx.arg.emachine == EM_RISCV) dest = getRISCVUndefinedRelativeWeakVA(r.type, p) + a; else - dest = r.sym->getVA(a); + dest = r.sym->getVA(ctx, a); } else { - dest = r.sym->getVA(a); + dest = r.sym->getVA(ctx, a); } return dest - p; } @@ -891,7 +892,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, // target VA computation. return r.sym->getPltVA(ctx) - p; case R_PPC64_CALL: { - uint64_t symVA = r.sym->getVA(a); + uint64_t symVA = r.sym->getVA(ctx, a); // If we have an undefined weak symbol, we might get here with a symbol // address of zero. That could overflow, but the code must be unreachable, // so don't bother doing anything at all. @@ -910,7 +911,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, return getPPC64TocBase(ctx) + a; case R_RELAX_GOT_PC: case R_PPC64_RELAX_GOT_PC: - return r.sym->getVA(a) - p; + return r.sym->getVA(ctx, a) - p; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_LD_TO_LE: @@ -1016,8 +1017,8 @@ void InputSection::relocateNonAlloc(Ctx &ctx, uint8_t *buf, if (!ds && tombstone) { val = *tombstone; } else { - val = sym.getVA(addend) - - (f->getRelocTargetSym(*it).getVA(0) + getAddend(*it)); + val = sym.getVA(ctx, addend) - + (f->getRelocTargetSym(*it).getVA(ctx) + getAddend(*it)); } if (overwriteULEB128(bufLoc, val) >= 0x80) errorOrWarn(getLocation(offset) + ": ULEB128 value " + Twine(val) + @@ -1083,7 +1084,8 @@ void InputSection::relocateNonAlloc(Ctx &ctx, uint8_t *buf, // sections. if (LLVM_LIKELY(expr == R_ABS) || expr == R_DTPREL || expr == R_GOTPLTREL || expr == R_RISCV_ADD) { - target.relocateNoSym(bufLoc, type, SignExtend64(sym.getVA(addend))); + target.relocateNoSym(bufLoc, type, + SignExtend64(sym.getVA(ctx, addend))); continue; } @@ -1116,7 +1118,7 @@ void InputSection::relocateNonAlloc(Ctx &ctx, uint8_t *buf, warn(msg); target.relocateNoSym( bufLoc, type, - SignExtend64(sym.getVA(addend - offset - outSecOff))); + SignExtend64(sym.getVA(ctx, addend - offset - outSecOff))); } } diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp index 6bbc1ecc646fdd..84bc95f9bd00ce 100644 --- a/lld/ELF/MapFile.cpp +++ b/lld/ELF/MapFile.cpp @@ -68,7 +68,7 @@ static std::vector getSymbols(Ctx &ctx) { static SymbolMapTy getSectionSyms(ArrayRef syms) { SymbolMapTy ret; for (Defined *dr : syms) - ret[dr->section].emplace_back(dr, dr->getVA()); + ret[dr->section].emplace_back(dr, dr->getVA(ctx)); // Sort symbols by address. We want to print out symbols in the // order in the output file rather than the order they appeared @@ -95,7 +95,7 @@ getSymbolStrings(Ctx &ctx, ArrayRef syms) { parallelFor(0, syms.size(), [&](size_t i) { raw_string_ostream os(strs[i]); OutputSection *osec = syms[i]->getOutputSection(); - uint64_t vma = syms[i]->getVA(); + uint64_t vma = syms[i]->getVA(ctx); uint64_t lma = osec ? osec->getLMA() + vma - osec->getVA(0) : 0; writeHeader(ctx, os, vma, lma, syms[i]->getSize(), 1); os << indent16 << toString(*syms[i]); diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 309039fe7e204a..6f76c5d73a5388 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -624,7 +624,7 @@ encodeOneCrel(Ctx &ctx, raw_svector_ostream &os, if (d) { SectionBase *section = d->section; assert(section->isLive()); - addend = sym.getVA(addend) - section->getOutputSection()->addr; + addend = sym.getVA(ctx, addend) - section->getOutputSection()->addr; } else { // Encode R_*_NONE(symidx=0). symidx = type = addend = 0; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index c8dcc276c30a66..d40348a7b30d8f 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -2257,7 +2257,7 @@ std::pair ThunkCreator::getThunk(InputSection *isec, if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) && t->isCompatibleWith(*isec, rel) && ctx.target->inBranchRange(rel.type, src, - t->getThunkTargetSym()->getVA(-pcBias))) + t->getThunkTargetSym()->getVA(ctx, -pcBias))) return std::make_pair(t, false); // No existing compatible Thunk in range, create a new one @@ -2281,7 +2281,8 @@ std::pair ThunkCreator::getSyntheticLandingPad(Defined &d, // relocation back to its original non-Thunk target. bool ThunkCreator::normalizeExistingThunk(Relocation &rel, uint64_t src) { if (Thunk *t = thunks.lookup(rel.sym)) { - if (ctx.target->inBranchRange(rel.type, src, rel.sym->getVA(rel.addend))) + if (ctx.target->inBranchRange(rel.type, src, + rel.sym->getVA(ctx, rel.addend))) return true; rel.sym = &t->destination; rel.addend = t->addend; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 3caa609338e068..6d9b3c839f86ae 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -58,7 +58,7 @@ std::string lld::toString(const elf::Symbol &sym) { return ret; } -static uint64_t getSymVA(const Symbol &sym, int64_t addend) { +static uint64_t getSymVA(Ctx &ctx, const Symbol &sym, int64_t addend) { switch (sym.kind()) { case Symbol::DefinedKind: { auto &d = cast(sym); @@ -141,8 +141,8 @@ static uint64_t getSymVA(const Symbol &sym, int64_t addend) { llvm_unreachable("invalid symbol kind"); } -uint64_t Symbol::getVA(int64_t addend) const { - return getSymVA(*this, addend) + addend; +uint64_t Symbol::getVA(Ctx &ctx, int64_t addend) const { + return getSymVA(ctx, *this, addend) + addend; } uint64_t Symbol::getGotVA(Ctx &ctx) const { diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 86abebe79f8db6..339f32e05f1625 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -210,7 +210,7 @@ class Symbol { bool isInGot(Ctx &ctx) const { return getGotIdx(ctx) != uint32_t(-1); } bool isInPlt(Ctx &ctx) const { return getPltIdx(ctx) != uint32_t(-1); } - uint64_t getVA(int64_t addend = 0) const; + uint64_t getVA(Ctx &, int64_t addend = 0) const; uint64_t getGotOffset(Ctx &) const; uint64_t getGotVA(Ctx &) const; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index f50404ed3016f4..7a344635a1cb53 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -749,7 +749,7 @@ void MipsGotSection::addEntry(InputFile &file, Symbol &sym, int64_t addend, if (const OutputSection *os = sym.getOutputSection()) g.pagesMap.insert({os, {}}); else - g.local16.insert({{nullptr, getMipsPageAddr(sym.getVA(addend))}, 0}); + g.local16.insert({{nullptr, getMipsPageAddr(sym.getVA(ctx, addend))}, 0}); } else if (sym.isTls()) g.tls.insert({&sym, 0}); else if (sym.isPreemptible && expr == R_ABS) @@ -808,10 +808,11 @@ uint64_t MipsGotSection::getPageEntryOffset(const InputFile *f, uint64_t index = 0; if (const OutputSection *outSec = sym.getOutputSection()) { uint64_t secAddr = getMipsPageAddr(outSec->addr); - uint64_t symAddr = getMipsPageAddr(sym.getVA(addend)); + uint64_t symAddr = getMipsPageAddr(sym.getVA(ctx, addend)); index = g.pagesMap.lookup(outSec).firstIndex + (symAddr - secAddr) / 0xffff; } else { - index = g.local16.lookup({nullptr, getMipsPageAddr(sym.getVA(addend))}); + index = + g.local16.lookup({nullptr, getMipsPageAddr(sym.getVA(ctx, addend))}); } return index * ctx.arg.wordsize; } @@ -1099,7 +1100,7 @@ uint64_t MipsGotSection::getGp(const InputFile *f) const { // returns "common" _gp value. For secondary GOTs calculate // individual _gp values. if (!f || f->mipsGotIndex == uint32_t(-1) || f->mipsGotIndex == 0) - return ctx.sym.mipsGp->getVA(0); + return ctx.sym.mipsGp->getVA(ctx, 0); return getVA() + gots[f->mipsGotIndex].startIndex * ctx.arg.wordsize + 0x7ff0; } @@ -1124,7 +1125,7 @@ void MipsGotSection::writeTo(uint8_t *buf) { auto write = [&](size_t i, const Symbol *s, int64_t a) { uint64_t va = a; if (s) - va = s->getVA(a); + va = s->getVA(ctx, a); writeUint(ctx, buf + i * ctx.arg.wordsize, va); }; // Write 'page address' entries to the local part of the GOT. @@ -1522,10 +1523,10 @@ DynamicSection::computeContents() { if (Symbol *b = ctx.symtab->find(ctx.arg.init)) if (b->isDefined()) - addInt(DT_INIT, b->getVA()); + addInt(DT_INIT, b->getVA(ctx)); if (Symbol *b = ctx.symtab->find(ctx.arg.fini)) if (b->isDefined()) - addInt(DT_FINI, b->getVA()); + addInt(DT_FINI, b->getVA(ctx)); } if (part.verSym && part.verSym->isNeeded()) @@ -2288,7 +2289,7 @@ template void SymbolTableSection::writeTo(uint8_t *buf) { const uint32_t shndx = getSymSectionIndex(sym); if (isDefinedHere) { eSym->st_shndx = shndx; - eSym->st_value = sym->getVA(); + eSym->st_value = sym->getVA(ctx); // Copy symbol size if it is a defined symbol. st_size is not // significant for undefined symbols, so whether copying it or not is up // to us if that's the case. We'll leave it as zero because by not @@ -3241,7 +3242,7 @@ void DebugNamesSection::getNameRelocs( Relocs rels) { for (const RelTy &rel : rels) { Symbol &sym = file.getRelocTargetSym(rel); - relocs[rel.r_offset] = sym.getVA(getAddend(rel)); + relocs[rel.r_offset] = sym.getVA(ctx, getAddend(rel)); } } @@ -4356,11 +4357,11 @@ void PPC64LongBranchTargetSection::writeTo(uint8_t *buf) { for (auto entry : entries) { const Symbol *sym = entry.first; int64_t addend = entry.second; - assert(sym->getVA()); + assert(sym->getVA(ctx)); // Need calls to branch to the local entry-point since a long-branch // must be a local-call. write64(ctx, buf, - sym->getVA(addend) + + sym->getVA(ctx, addend) + getPPC64GlobalEntryToLocalEntryOffset(sym->stOther)); buf += 8; } @@ -4616,7 +4617,7 @@ createMemtagGlobalDescriptors(Ctx &ctx, for (const Symbol *sym : symbols) { if (!includeInSymtab(ctx, *sym)) continue; - const uint64_t addr = sym->getVA(); + const uint64_t addr = sym->getVA(ctx); const uint64_t size = sym->getSize(); if (addr <= kMemtagGranuleSize && buf != nullptr) @@ -4653,8 +4654,8 @@ createMemtagGlobalDescriptors(Ctx &ctx, bool MemtagGlobalDescriptors::updateAllocSize(Ctx &ctx) { size_t oldSize = getSize(); std::stable_sort(symbols.begin(), symbols.end(), - [](const Symbol *s1, const Symbol *s2) { - return s1->getVA() < s2->getVA(); + [&ctx = ctx](const Symbol *s1, const Symbol *s2) { + return s1->getVA(ctx) < s2->getVA(ctx); }); return oldSize != getSize(); } diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp index 971b2724b3e26f..94c0b2409c6c7c 100644 --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -464,7 +464,7 @@ class PPC64R2SaveStub final : public Thunk { // This is similar to the handling for ARMThunk. bool mayUseShortThunk = true; int64_t computeOffset() const { - return destination.getVA() - (getThunkTargetSym()->getVA() + 4); + return destination.getVA(ctx) - (getThunkTargetSym()->getVA(ctx) + 4); } }; @@ -550,7 +550,7 @@ void Thunk::setOffset(uint64_t newOffset) { // AArch64 Thunk base class. static uint64_t getAArch64ThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) { - uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(a); + uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, a); return v; } @@ -558,7 +558,7 @@ bool AArch64Thunk::getMayUseShortThunk() { if (!mayUseShortThunk) return false; uint64_t s = getAArch64ThunkDestVA(ctx, destination, addend); - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t p = getThunkTargetSym()->getVA(ctx); mayUseShortThunk = llvm::isInt<28>(s - p); return mayUseShortThunk; } @@ -569,7 +569,7 @@ void AArch64Thunk::writeTo(uint8_t *buf) { return; } uint64_t s = getAArch64ThunkDestVA(ctx, destination, addend); - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t p = getThunkTargetSym()->getVA(ctx); write32(ctx, buf, 0x14000000); // b S ctx.target->relocateNoSym(buf, R_AARCH64_CALL26, s - p); } @@ -592,7 +592,7 @@ void AArch64ABSLongThunk::writeLong(uint8_t *buf) { // AArch64BTILandingPadThunk that defines landingPad. assert(!mayNeedLandingPad || landingPad != nullptr); uint64_t s = mayNeedLandingPad - ? landingPad->getVA(0) + ? landingPad->getVA(ctx, 0) : getAArch64ThunkDestVA(ctx, destination, addend); memcpy(buf, data, sizeof(data)); ctx.target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s); @@ -621,9 +621,9 @@ void AArch64ADRPThunk::writeLong(uint8_t *buf) { // AArch64BTILandingPadThunk that defines landingPad. assert(!mayNeedLandingPad || landingPad != nullptr); uint64_t s = mayNeedLandingPad - ? landingPad->getVA(0) + ? landingPad->getVA(ctx, 0) : getAArch64ThunkDestVA(ctx, destination, addend); - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t p = getThunkTargetSym()->getVA(ctx); memcpy(buf, data, sizeof(data)); ctx.target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(s) - getAArch64Page(p)); @@ -656,8 +656,8 @@ bool AArch64BTILandingPadThunk::getMayUseShortThunk() { return false; // If the target is the following instruction then we can fall // through without the indirect branch. - uint64_t s = destination.getVA(addend); - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t s = destination.getVA(ctx, addend); + uint64_t p = getThunkTargetSym()->getVA(ctx); // This function is called before addresses are stable. We need to // work out the range from the thunk to the next section but the // address of the start of the next section depends on the size of @@ -670,8 +670,8 @@ bool AArch64BTILandingPadThunk::getMayUseShortThunk() { } void AArch64BTILandingPadThunk::writeLong(uint8_t *buf) { - uint64_t s = destination.getVA(addend); - uint64_t p = getThunkTargetSym()->getVA() + 4; + uint64_t s = destination.getVA(ctx, addend); + uint64_t p = getThunkTargetSym()->getVA(ctx) + 4; write32(ctx, buf, 0xd503245f); // BTI c write32(ctx, buf + 4, 0x14000000); // B S ctx.target->relocateNoSym(buf + 4, R_AARCH64_CALL26, s - p); @@ -679,7 +679,7 @@ void AArch64BTILandingPadThunk::writeLong(uint8_t *buf) { // ARM Target Thunks static uint64_t getARMThunkDestVA(Ctx &ctx, const Symbol &s) { - uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(); + uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx); return SignExtend64<32>(v); } @@ -693,7 +693,7 @@ bool ARMThunk::getMayUseShortThunk() { mayUseShortThunk = false; return false; } - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t p = getThunkTargetSym()->getVA(ctx); int64_t offset = s - p - 8; mayUseShortThunk = llvm::isInt<26>(offset); return mayUseShortThunk; @@ -706,7 +706,7 @@ void ARMThunk::writeTo(uint8_t *buf) { } uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t p = getThunkTargetSym()->getVA(ctx); int64_t offset = s - p - 8; write32(ctx, buf, 0xea000000); // b S ctx.target->relocateNoSym(buf, R_ARM_JUMP24, offset); @@ -736,7 +736,7 @@ bool ThumbThunk::getMayUseShortThunk() { mayUseShortThunk = false; return false; } - uint64_t p = getThunkTargetSym()->getVA() & ~1; + uint64_t p = getThunkTargetSym()->getVA(ctx) & ~1; int64_t offset = s - p - 4; mayUseShortThunk = llvm::isInt<25>(offset); return mayUseShortThunk; @@ -749,7 +749,7 @@ void ThumbThunk::writeTo(uint8_t *buf) { } uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t p = getThunkTargetSym()->getVA(ctx); int64_t offset = s - p - 4; write16(ctx, buf + 0, 0xf000); // b.w S write16(ctx, buf + 2, 0xb000); @@ -806,7 +806,7 @@ void ARMV7PILongThunk::writeLong(uint8_t *buf) { write32(ctx, buf + 8, 0xe08cc00f); // L1: add ip, ip, pc write32(ctx, buf + 12, 0xe12fff1c); // bx ip uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t p = getThunkTargetSym()->getVA(ctx); int64_t offset = s - p - 16; ctx.target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset); ctx.target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset); @@ -826,7 +826,7 @@ void ThumbV7PILongThunk::writeLong(uint8_t *buf) { write16(ctx, buf + 8, 0x44fc); // L1: add ip, pc write16(ctx, buf + 10, 0x4760); // bx ip uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA() & ~0x1; + uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1; int64_t offset = s - p - 12; ctx.target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset); ctx.target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset); @@ -904,7 +904,7 @@ void ThumbV6MPILongThunk::writeLong(uint8_t *buf) { 0x46c0); // nop ; pad to 4-byte boundary write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 4) uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA() & ~0x1; + uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1; ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12); } @@ -992,7 +992,7 @@ void ARMV4PILongBXThunk::writeLong(uint8_t *buf) { write32(ctx, buf + 8, 0xe12fff1c); // bx ip write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8) uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA() & ~0x1; + uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1; ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12); } @@ -1009,7 +1009,7 @@ void ARMV4PILongThunk::writeLong(uint8_t *buf) { write32(ctx, buf + 4, 0xe08ff00c); // L1: add pc, pc, r12 write32(ctx, buf + 8, 0x00000000); // L2: .word S - (P + (L1 - P) + 8) uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA() & ~0x1; + uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1; ctx.target->relocateNoSym(buf + 8, R_ARM_REL32, s - p - 12); } @@ -1029,7 +1029,7 @@ void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) { write32(ctx, buf + 8, 0xe08cf00f); // L1: add pc, r12, pc write32(ctx, buf + 12, 0x00000000); // L2: .word S - (P + (L1 - P) + 8) uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA() & ~0x1; + uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1; ctx.target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 16); } @@ -1051,7 +1051,7 @@ void ThumbV4PILongThunk::writeLong(uint8_t *buf) { write32(ctx, buf + 12, 0xe12fff1c); // bx ip write32(ctx, buf + 16, 0x00000000); // L2: .word S - (P + (L1 - P) + 8) uint64_t s = getARMThunkDestVA(ctx, destination); - uint64_t p = getThunkTargetSym()->getVA() & ~0x1; + uint64_t p = getThunkTargetSym()->getVA(ctx) & ~0x1; ctx.target->relocateNoSym(buf + 16, R_ARM_REL32, s - p - 16); } @@ -1067,7 +1067,7 @@ void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) { // Use the long jump which covers a range up to 8MiB. void AVRThunk::writeTo(uint8_t *buf) { write32(ctx, buf, 0x940c); // jmp func - ctx.target->relocateNoSym(buf, R_AVR_CALL, destination.getVA()); + ctx.target->relocateNoSym(buf, R_AVR_CALL, destination.getVA(ctx)); } void AVRThunk::addSymbols(ThunkSection &isec) { @@ -1077,7 +1077,7 @@ void AVRThunk::addSymbols(ThunkSection &isec) { // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. void MipsThunk::writeTo(uint8_t *buf) { - uint64_t s = destination.getVA(); + uint64_t s = destination.getVA(ctx); write32(ctx, buf, 0x3c190000); // lui $25, %hi(func) write32(ctx, buf + 4, 0x08000000 | (s >> 2)); // j func write32(ctx, buf + 8, 0x27390000); // addiu $25, $25, %lo(func) @@ -1099,7 +1099,7 @@ InputSection *MipsThunk::getTargetInputSection() const { // Write microMIPS R2-R5 LA25 thunk code // to call PIC function from the non-PIC one. void MicroMipsThunk::writeTo(uint8_t *buf) { - uint64_t s = destination.getVA(); + uint64_t s = destination.getVA(ctx); write16(ctx, buf, 0x41b9); // lui $25, %hi(func) write16(ctx, buf + 4, 0xd400); // j func write16(ctx, buf + 8, 0x3339); // addiu $25, $25, %lo(func) @@ -1124,8 +1124,8 @@ InputSection *MicroMipsThunk::getTargetInputSection() const { // Write microMIPS R6 LA25 thunk code // to call PIC function from the non-PIC one. void MicroMipsR6Thunk::writeTo(uint8_t *buf) { - uint64_t s = destination.getVA(); - uint64_t p = getThunkTargetSym()->getVA(); + uint64_t s = destination.getVA(ctx); + uint64_t p = getThunkTargetSym()->getVA(ctx); write16(ctx, buf, 0x1320); // lui $25, %hi(func) write16(ctx, buf + 4, 0x3339); // addiu $25, $25, %lo(func) write16(ctx, buf + 8, 0x9400); // bc func @@ -1213,9 +1213,9 @@ void PPC32LongThunk::addSymbols(ThunkSection &isec) { void PPC32LongThunk::writeTo(uint8_t *buf) { auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; }; auto lo = [](uint32_t v) -> uint16_t { return v; }; - uint32_t d = destination.getVA(addend); + uint32_t d = destination.getVA(ctx, addend); if (ctx.arg.isPic) { - uint32_t off = d - (getThunkTargetSym()->getVA() + 8); + uint32_t off = d - (getThunkTargetSym()->getVA(ctx) + 8); write32(ctx, buf + 0, 0x7c0802a6); // mflr r12,0 write32(ctx, buf + 4, 0x429f0005); // bcl r20,r31,.+4 write32(ctx, buf + 8, 0x7d8802a6); // mtctr r12 @@ -1269,7 +1269,7 @@ void PPC64R2SaveStub::writeTo(uint8_t *buf) { write32(ctx, buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b } else if (isInt<34>(offset)) { int nextInstOffset; - uint64_t tocOffset = destination.getVA() - getPPC64TocBase(ctx); + uint64_t tocOffset = destination.getVA(ctx) - getPPC64TocBase(ctx); if (tocOffset >> 16 > 0) { const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff); const uint64_t addis = @@ -1306,8 +1306,8 @@ bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec, void PPC64R12SetupStub::writeTo(uint8_t *buf) { int64_t offset = - (gotPlt ? destination.getGotPltVA(ctx) : destination.getVA()) - - getThunkTargetSym()->getVA(); + (gotPlt ? destination.getGotPltVA(ctx) : destination.getVA(ctx)) - + getThunkTargetSym()->getVA(ctx); if (!isInt<34>(offset)) reportRangeError(ctx, buf, offset, 34, destination, "R12 setup stub offset"); @@ -1393,7 +1393,7 @@ static Thunk *addThunkAArch64(Ctx &ctx, RelType type, Symbol &s, int64_t a) { // TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for // Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state). static Thunk *addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s, int64_t a) { - bool thumb_target = s.getVA(a) & 1; + bool thumb_target = s.getVA(ctx, a) & 1; switch (reloc) { case R_ARM_PC24: diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index c237a5f3793a12..975954991caebe 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1504,9 +1504,9 @@ template void Writer::finalizeAddressDependentContent() { // .rela.dyn. See also AArch64::relocate. if (part.relrAuthDyn) { auto it = llvm::remove_if( - part.relrAuthDyn->relocs, [&part](const RelativeReloc &elem) { + part.relrAuthDyn->relocs, [this, &part](const RelativeReloc &elem) { const Relocation &reloc = elem.inputSec->relocs()[elem.relocIdx]; - if (isInt<32>(reloc.sym->getVA(reloc.addend))) + if (isInt<32>(reloc.sym->getVA(ctx, reloc.addend))) return false; part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec, reloc.offset, @@ -2713,7 +2713,7 @@ template void Writer::checkSections() { static uint64_t getEntryAddr(Ctx &ctx) { // Case 1, 2 or 3 if (Symbol *b = ctx.symtab->find(ctx.arg.entry)) - return b->getVA(); + return b->getVA(ctx); // Case 4 uint64_t addr; From 5d928ffce22d976b6594496f14351e00c2e4dd78 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 19 Oct 2024 21:02:03 -0700 Subject: [PATCH 09/12] [ELF] Remove error-prone RelocationBaseSection::classof --- lld/ELF/OutputSections.cpp | 6 +++++- lld/ELF/SyntheticSections.h | 8 +------- lld/ELF/Writer.cpp | 7 +++---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 6f76c5d73a5388..6cae7cf8f8599d 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -882,7 +882,11 @@ void OutputSection::checkDynRelAddends(Ctx &ctx) { // for input .rel[a]. sections which we simply pass through to the // output. We skip over those and only look at the synthetic relocation // sections created during linking. - const auto *sec = dyn_cast(sections[i]); + if (!SyntheticSection::classof(sections[i]) || + !is_contained({ELF::SHT_REL, ELF::SHT_RELA, ELF::SHT_RELR}, + sections[i]->type)) + return; + const auto *sec = cast(sections[i]); if (!sec) return; for (const DynamicReloc &rel : sec->relocs) { diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index d64c4aad8c552b..3573767671feb1 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -547,13 +547,7 @@ class RelocationBaseSection : public SyntheticSection { void mergeRels(); void partitionRels(); void finalizeContents() override; - static bool classof(const SectionBase *d) { - return SyntheticSection::classof(d) && - (d->type == llvm::ELF::SHT_RELA || d->type == llvm::ELF::SHT_REL || - d->type == llvm::ELF::SHT_RELR || - (d->type == llvm::ELF::SHT_AARCH64_AUTH_RELR && - elf::ctx.arg.emachine == llvm::ELF::EM_AARCH64)); - } + int32_t dynamicTag, sizeDynamicTag; SmallVector relocs; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 975954991caebe..ecd4f5e470833c 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1690,10 +1690,9 @@ static void removeUnusedSyntheticSections(Ctx &ctx) { // finalizeAddressDependentContent, making .rela.dyn no longer empty. // Conservatively keep .rela.dyn. .relr.auth.dyn can be made empty, but // we would fail to remove it here. - if (ctx.arg.emachine == EM_AARCH64 && ctx.arg.relrPackDynRelocs) - if (auto *relSec = dyn_cast(sec)) - if (relSec == ctx.mainPart->relaDyn.get()) - return false; + if (ctx.arg.emachine == EM_AARCH64 && ctx.arg.relrPackDynRelocs && + sec == ctx.mainPart->relaDyn.get()) + return false; unused.insert(sec); return true; }); From e6625a2c106f6af468a98323b08c7ce3cf273485 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 19 Oct 2024 21:08:50 -0700 Subject: [PATCH 10/12] [ELF] Pass Ctx & --- lld/ELF/Arch/RISCV.cpp | 6 +++--- lld/ELF/InputSection.cpp | 4 +++- lld/ELF/MapFile.cpp | 4 ++-- lld/ELF/Symbols.cpp | 8 ++++---- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 7ebb67c3612311..e80dfbd4351b1e 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -758,8 +758,8 @@ static void relaxCall(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, } // Relax local-exec TLS when hi20 is zero. -static void relaxTlsLe(const InputSection &sec, size_t i, uint64_t loc, - Relocation &r, uint32_t &remove) { +static void relaxTlsLe(Ctx &ctx, const InputSection &sec, size_t i, + uint64_t loc, Relocation &r, uint32_t &remove) { uint64_t val = r.sym->getVA(ctx, r.addend); if (hi20(val) != 0) return; @@ -852,7 +852,7 @@ static bool relax(Ctx &ctx, InputSection &sec) { case R_RISCV_TPREL_LO12_I: case R_RISCV_TPREL_LO12_S: if (relaxable(relocs, i)) - relaxTlsLe(sec, i, loc, r, remove); + relaxTlsLe(ctx, sec, i, loc, r, remove); break; case R_RISCV_HI20: case R_RISCV_LO12_I: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 6c34471a9e5022..3b48fbe07bb082 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -70,8 +70,10 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags, // If SHF_COMPRESSED is set, parse the header. The legacy .zdebug format is no // longer supported. - if (flags & SHF_COMPRESSED) + if (flags & SHF_COMPRESSED) { + Ctx &ctx = file->ctx; invokeELFT(parseCompressedHeader,); + } } // SHF_INFO_LINK and SHF_GROUP are normally resolved and not copied to the diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp index 84bc95f9bd00ce..afaf04dc72fe6c 100644 --- a/lld/ELF/MapFile.cpp +++ b/lld/ELF/MapFile.cpp @@ -65,7 +65,7 @@ static std::vector getSymbols(Ctx &ctx) { } // Returns a map from sections to their symbols. -static SymbolMapTy getSectionSyms(ArrayRef syms) { +static SymbolMapTy getSectionSyms(Ctx &ctx, ArrayRef syms) { SymbolMapTy ret; for (Defined *dr : syms) ret[dr->section].emplace_back(dr, dr->getVA(ctx)); @@ -149,7 +149,7 @@ static void printEhFrame(Ctx &ctx, raw_ostream &os, const EhFrameSection *sec) { static void writeMapFile(Ctx &ctx, raw_fd_ostream &os) { // Collect symbol info that we want to print out. std::vector syms = getSymbols(ctx); - SymbolMapTy sectionSyms = getSectionSyms(syms); + SymbolMapTy sectionSyms = getSectionSyms(ctx, syms); DenseMap symStr = getSymbolStrings(ctx, syms); // Print out the header line. diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 6d9b3c839f86ae..da35bf858cb371 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -44,13 +44,13 @@ LLVM_ATTRIBUTE_UNUSED static inline void assertSymbols() { } // Returns a symbol for an error message. -static std::string maybeDemangleSymbol(StringRef symName) { - return elf::ctx.arg.demangle ? demangle(symName.str()) : symName.str(); +static std::string maybeDemangleSymbol(Ctx &ctx, StringRef symName) { + return ctx.arg.demangle ? demangle(symName.str()) : symName.str(); } std::string lld::toString(const elf::Symbol &sym) { StringRef name = sym.getName(); - std::string ret = maybeDemangleSymbol(name); + std::string ret = maybeDemangleSymbol(ctx, name); const char *suffix = sym.getVersionSuffix(); if (*suffix == '@') @@ -617,7 +617,7 @@ void Symbol::resolve(Ctx &ctx, const LazySymbol &other) { // For common objects, we want to look for global or weak definitions that // should be extracted as the canonical definition instead. - if (LLVM_UNLIKELY(isCommon()) && elf::ctx.arg.fortranCommon && + if (LLVM_UNLIKELY(isCommon()) && ctx.arg.fortranCommon && other.file->shouldExtractForCommon(getName())) { ctx.backwardReferences.erase(this); other.overwrite(*this); From 11dad2fa5138a50d60a5a34a2c7e074b976820e2 Mon Sep 17 00:00:00 2001 From: Pranav Bhandarkar Date: Sun, 20 Oct 2024 01:01:39 -0500 Subject: [PATCH 11/12] [flang][OpenMP] - Add `MapInfoOp` instances for target private variables when needed (#109862) This PR adds an OpenMP dialect related pass for FIR/HLFIR which creates `MapInfoOp` instances for certain privatized symbols. For example, if an allocatable variable is used in a private clause attached to a `omp.target` op, then the allocatable variable's descriptor will be needed on the device (e.g. GPU). This descriptor needs to be separately mapped onto the device. This pass creates the necessary `omp.map.info` ops for this. --- .../include/flang/Optimizer/OpenMP/Passes.td | 13 ++ flang/lib/Optimizer/OpenMP/CMakeLists.txt | 1 + .../OpenMP/MapsForPrivatizedSymbols.cpp | 156 ++++++++++++++++++ flang/lib/Optimizer/Passes/Pipelines.cpp | 1 + .../target-private-allocatable.f90 | 20 ++- .../target-private-multiple-variables.f90 | 24 ++- .../omp-maps-for-privatized-symbols.fir | 48 ++++++ mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | 2 +- 8 files changed, 251 insertions(+), 14 deletions(-) create mode 100644 flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp create mode 100644 flang/test/Transforms/omp-maps-for-privatized-symbols.fir diff --git a/flang/include/flang/Optimizer/OpenMP/Passes.td b/flang/include/flang/Optimizer/OpenMP/Passes.td index 1c0ce08f5b4838..c070bc22ff20cc 100644 --- a/flang/include/flang/Optimizer/OpenMP/Passes.td +++ b/flang/include/flang/Optimizer/OpenMP/Passes.td @@ -22,6 +22,19 @@ def MapInfoFinalizationPass let dependentDialects = ["mlir::omp::OpenMPDialect"]; } +def MapsForPrivatizedSymbolsPass + : Pass<"omp-maps-for-privatized-symbols", "mlir::func::FuncOp"> { + let summary = "Creates MapInfoOp instances for privatized symbols when needed"; + let description = [{ + Adds omp.map.info operations for privatized symbols on omp.target ops + In certain situations, such as when an allocatable is privatized, its + descriptor is needed in the alloc region of the privatizer. This results + in the use of the descriptor inside the target region. As such, the + descriptor then needs to be mapped. This pass adds such MapInfoOp operations. + }]; + let dependentDialects = ["mlir::omp::OpenMPDialect"]; +} + def MarkDeclareTargetPass : Pass<"omp-mark-declare-target", "mlir::ModuleOp"> { let summary = "Marks all functions called by an OpenMP declare target function as declare target"; diff --git a/flang/lib/Optimizer/OpenMP/CMakeLists.txt b/flang/lib/Optimizer/OpenMP/CMakeLists.txt index 92051634f0378b..035d0d5ca46c76 100644 --- a/flang/lib/Optimizer/OpenMP/CMakeLists.txt +++ b/flang/lib/Optimizer/OpenMP/CMakeLists.txt @@ -2,6 +2,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) add_flang_library(FlangOpenMPTransforms FunctionFiltering.cpp + MapsForPrivatizedSymbols.cpp MapInfoFinalization.cpp MarkDeclareTarget.cpp diff --git a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp new file mode 100644 index 00000000000000..2fa55844aec7c7 --- /dev/null +++ b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp @@ -0,0 +1,156 @@ +//===- MapsForPrivatizedSymbols.cpp +//-----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +/// \file +/// An OpenMP dialect related pass for FIR/HLFIR which creates MapInfoOp +/// instances for certain privatized symbols. +/// For example, if an allocatable variable is used in a private clause attached +/// to a omp.target op, then the allocatable variable's descriptor will be +/// needed on the device (e.g. GPU). This descriptor needs to be separately +/// mapped onto the device. This pass creates the necessary omp.map.info ops for +/// this. +//===----------------------------------------------------------------------===// +// TODO: +// 1. Before adding omp.map.info, check if we already have an omp.map.info for +// the variable in question. +// 2. Generalize this for more than just omp.target ops. +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Optimizer/Dialect/Support/KindMapping.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" +#include "flang/Optimizer/OpenMP/Passes.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/OpenMP/OpenMPDialect.h" +#include "mlir/IR/BuiltinAttributes.h" +#include "mlir/IR/SymbolTable.h" +#include "mlir/Pass/Pass.h" +#include "llvm/Frontend/OpenMP/OMPConstants.h" +#include "llvm/Support/Debug.h" +#include + +#define DEBUG_TYPE "omp-maps-for-privatized-symbols" + +namespace flangomp { +#define GEN_PASS_DEF_MAPSFORPRIVATIZEDSYMBOLSPASS +#include "flang/Optimizer/OpenMP/Passes.h.inc" +} // namespace flangomp +using namespace mlir; +namespace { +class MapsForPrivatizedSymbolsPass + : public flangomp::impl::MapsForPrivatizedSymbolsPassBase< + MapsForPrivatizedSymbolsPass> { + + bool privatizerNeedsMap(omp::PrivateClauseOp &privatizer) { + Region &allocRegion = privatizer.getAllocRegion(); + Value blockArg0 = allocRegion.getArgument(0); + if (blockArg0.use_empty()) + return false; + return true; + } + omp::MapInfoOp createMapInfo(Location loc, Value var, + fir::FirOpBuilder &builder) { + uint64_t mapTypeTo = static_cast< + std::underlying_type_t>( + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO); + Operation *definingOp = var.getDefiningOp(); + auto declOp = llvm::dyn_cast_or_null(definingOp); + assert(declOp && + "Expected defining Op of privatized var to be hlfir.declare"); + + // We want the first result of the hlfir.declare op because our goal + // is to map the descriptor (fir.box or fir.boxchar) and the first + // result for hlfir.declare is the descriptor if a the symbol being + // decalred needs a descriptor. + Value varPtr = declOp.getBase(); + + // If we do not have a reference to descritor, but the descriptor itself + // then we need to store that on the stack so that we can map the + // address of the descriptor. + if (mlir::isa(varPtr.getType()) || + mlir::isa(varPtr.getType())) { + OpBuilder::InsertPoint savedInsPoint = builder.saveInsertionPoint(); + mlir::Block *allocaBlock = builder.getAllocaBlock(); + assert(allocaBlock && "No allocablock found for a funcOp"); + builder.setInsertionPointToStart(allocaBlock); + auto alloca = builder.create(loc, varPtr.getType()); + builder.restoreInsertionPoint(savedInsPoint); + builder.create(loc, varPtr, alloca); + varPtr = alloca; + } + return builder.create( + loc, varPtr.getType(), varPtr, + TypeAttr::get(llvm::cast(varPtr.getType()) + .getElementType()), + /*varPtrPtr=*/Value{}, + /*members=*/SmallVector{}, + /*member_index=*/DenseIntElementsAttr{}, + /*bounds=*/ValueRange{}, + builder.getIntegerAttr(builder.getIntegerType(64, /*isSigned=*/false), + mapTypeTo), + builder.getAttr( + omp::VariableCaptureKind::ByRef), + StringAttr(), builder.getBoolAttr(false)); + } + void addMapInfoOp(omp::TargetOp targetOp, omp::MapInfoOp mapInfoOp) { + auto argIface = llvm::cast(*targetOp); + unsigned insertIndex = + argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs(); + targetOp.getMapVarsMutable().append(ValueRange{mapInfoOp}); + targetOp.getRegion().insertArgument(insertIndex, mapInfoOp.getType(), + mapInfoOp.getLoc()); + } + void addMapInfoOps(omp::TargetOp targetOp, + llvm::SmallVectorImpl &mapInfoOps) { + for (auto mapInfoOp : mapInfoOps) + addMapInfoOp(targetOp, mapInfoOp); + } + void runOnOperation() override { + ModuleOp module = getOperation()->getParentOfType(); + fir::KindMapping kindMap = fir::getKindMapping(module); + fir::FirOpBuilder builder{module, std::move(kindMap)}; + llvm::DenseMap> + mapInfoOpsForTarget; + + getOperation()->walk([&](omp::TargetOp targetOp) { + if (targetOp.getPrivateVars().empty()) + return; + OperandRange privVars = targetOp.getPrivateVars(); + std::optional privSyms = targetOp.getPrivateSyms(); + SmallVector mapInfoOps; + for (auto [privVar, privSym] : llvm::zip_equal(privVars, *privSyms)) { + + SymbolRefAttr privatizerName = llvm::cast(privSym); + omp::PrivateClauseOp privatizer = + SymbolTable::lookupNearestSymbolFrom( + targetOp, privatizerName); + if (!privatizerNeedsMap(privatizer)) { + continue; + } + builder.setInsertionPoint(targetOp); + Location loc = targetOp.getLoc(); + omp::MapInfoOp mapInfoOp = createMapInfo(loc, privVar, builder); + mapInfoOps.push_back(mapInfoOp); + LLVM_DEBUG(llvm::dbgs() << "MapsForPrivatizedSymbolsPass created ->\n"); + LLVM_DEBUG(mapInfoOp.dump()); + } + if (!mapInfoOps.empty()) { + mapInfoOpsForTarget.insert({targetOp.getOperation(), mapInfoOps}); + } + }); + if (!mapInfoOpsForTarget.empty()) { + for (auto &[targetOp, mapInfoOps] : mapInfoOpsForTarget) { + addMapInfoOps(static_cast(targetOp), mapInfoOps); + } + } + } +}; +} // namespace diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp index 3fa5c54403bd8c..3c139f7e93405c 100644 --- a/flang/lib/Optimizer/Passes/Pipelines.cpp +++ b/flang/lib/Optimizer/Passes/Pipelines.cpp @@ -243,6 +243,7 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm, /// rather than the host device. void createOpenMPFIRPassPipeline(mlir::PassManager &pm, bool isTargetDevice) { pm.addPass(flangomp::createMapInfoFinalizationPass()); + pm.addPass(flangomp::createMapsForPrivatizedSymbolsPass()); pm.addPass(flangomp::createMarkDeclareTargetPass()); if (isTargetDevice) pm.addPass(flangomp::createFunctionFilteringPass()); diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-allocatable.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-allocatable.f90 index a27de1152ce17a..e11525c569ffb8 100644 --- a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-allocatable.f90 +++ b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-allocatable.f90 @@ -18,22 +18,22 @@ end subroutine target_allocatable ! CHECK-SAME: @[[VAR_PRIVATIZER_SYM:.*]] : ! CHECK-SAME: [[TYPE:!fir.ref>>]] alloc { ! CHECK: ^bb0(%[[PRIV_ARG:.*]]: [[TYPE]]): -! CHECK: %[[PRIV_ALLOC:.*]] = fir.alloca !fir.box> {bindc_name = "alloc_var", {{.*}}} +! CHECK: %[[PRIV_ALLOC:.*]] = fir.alloca [[DESC_TYPE:!fir.box>]] {bindc_name = "alloc_var", {{.*}}} -! CHECK-NEXT: %[[PRIV_ARG_VAL:.*]] = fir.load %[[PRIV_ARG]] : !fir.ref>> -! CHECK-NEXT: %[[PRIV_ARG_BOX:.*]] = fir.box_addr %[[PRIV_ARG_VAL]] : (!fir.box>) -> !fir.heap +! CHECK-NEXT: %[[PRIV_ARG_VAL:.*]] = fir.load %[[PRIV_ARG]] : [[TYPE]] +! CHECK-NEXT: %[[PRIV_ARG_BOX:.*]] = fir.box_addr %[[PRIV_ARG_VAL]] : ([[DESC_TYPE]]) -> !fir.heap ! CHECK-NEXT: %[[PRIV_ARG_ADDR:.*]] = fir.convert %[[PRIV_ARG_BOX]] : (!fir.heap) -> i64 ! CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : i64 ! CHECK-NEXT: %[[ALLOC_COND:.*]] = arith.cmpi ne, %[[PRIV_ARG_ADDR]], %[[C0]] : i64 ! CHECK-NEXT: fir.if %[[ALLOC_COND]] { ! CHECK: %[[PRIV_ALLOCMEM:.*]] = fir.allocmem i32 {fir.must_be_heap = true, {{.*}}} -! CHECK-NEXT: %[[PRIV_ALLOCMEM_BOX:.*]] = fir.embox %[[PRIV_ALLOCMEM]] : (!fir.heap) -> !fir.box> -! CHECK-NEXT: fir.store %[[PRIV_ALLOCMEM_BOX]] to %[[PRIV_ALLOC]] : !fir.ref>> +! CHECK-NEXT: %[[PRIV_ALLOCMEM_BOX:.*]] = fir.embox %[[PRIV_ALLOCMEM]] : (!fir.heap) -> [[DESC_TYPE]] +! CHECK-NEXT: fir.store %[[PRIV_ALLOCMEM_BOX]] to %[[PRIV_ALLOC]] : [[TYPE]] ! CHECK-NEXT: } else { ! CHECK-NEXT: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap -! CHECK-NEXT: %[[ZERO_BOX:.*]] = fir.embox %[[ZERO_BITS]] : (!fir.heap) -> !fir.box> -! CHECK-NEXT: fir.store %[[ZERO_BOX]] to %[[PRIV_ALLOC]] : !fir.ref>> +! CHECK-NEXT: %[[ZERO_BOX:.*]] = fir.embox %[[ZERO_BITS]] : (!fir.heap) -> [[DESC_TYPE]] +! CHECK-NEXT: fir.store %[[ZERO_BOX]] to %[[PRIV_ALLOC]] : [[TYPE]] ! CHECK-NEXT: } ! CHECK-NEXT: %[[PRIV_DECL:.*]]:2 = hlfir.declare %[[PRIV_ALLOC]] @@ -63,9 +63,11 @@ end subroutine target_allocatable ! CHECK-LABEL: func.func @_QPtarget_allocatable() { -! CHECK: %[[VAR_ALLOC:.*]] = fir.alloca !fir.box> +! CHECK: %[[VAR_ALLOC:.*]] = fir.alloca [[DESC_TYPE]] ! CHECK-SAME: {bindc_name = "alloc_var", {{.*}}} ! CHECK: %[[VAR_DECL:.*]]:2 = hlfir.declare %[[VAR_ALLOC]] -! CHECK: omp.target private( +! CHECK: %[[MAP_VAR:.*]] = omp.map.info var_ptr(%[[VAR_DECL]]#0 : [[TYPE]], [[DESC_TYPE]]) +! CHECK-SAME: map_clauses(to) capture(ByRef) -> [[TYPE]] +! CHECK: omp.target map_entries(%[[MAP_VAR]] -> %arg0 : [[TYPE]]) private( ! CHECK-SAME: @[[VAR_PRIVATIZER_SYM]] %[[VAR_DECL]]#0 -> %{{.*}} : [[TYPE]]) { diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-multiple-variables.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-multiple-variables.f90 index ce98f518581a45..b0c76ff3845f83 100644 --- a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-multiple-variables.f90 +++ b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-multiple-variables.f90 @@ -147,12 +147,29 @@ end subroutine target_allocatable ! CHECK-NEXT: } ! CHECK: func.func @_QPtarget_allocatable +! CHECK: %[[CHAR_VAR_DESC_ALLOCA:.*]] = fir.alloca !fir.boxchar<1> +! CHECK: %[[REAL_ARR_DESC_ALLOCA:.*]] = fir.alloca !fir.box> +! CHECK: %[[ALLOC_VAR_ALLOCA:.*]] = fir.alloca !fir.box> {bindc_name = "alloc_var", {{.*}}} +! CHECK: %[[ALLOC_VAR_DECL:.*]]:2 = hlfir.declare %[[ALLOC_VAR_ALLOCA]] ! CHECK: %[[MAPPED_ALLOC:.*]] = fir.alloca i32 {bindc_name = "mapped_var", {{.*}}} ! CHECK-NEXT: %[[MAPPED_DECL:.*]]:2 = hlfir.declare %[[MAPPED_ALLOC]] -! CHECK: %[[MAPPED_MI:.*]] = omp.map.info var_ptr(%[[MAPPED_DECL]]#1 : !fir.ref, i32) - +! CHECK: %[[CHAR_VAR_ALLOC:.*]] = fir.alloca !fir.char<1,?>{{.*}} {bindc_name = "char_var", {{.*}}} +! CHECK: %[[CHAR_VAR_DECL:.*]]:2 = hlfir.declare %[[CHAR_VAR_ALLOC]] typeparams +! CHECK: %[[REAL_ARR_ALLOC:.*]] = fir.alloca !fir.array, {{.*}} {bindc_name = "real_arr", {{.*}}} +! CHECK: %[[REAL_ARR_DECL:.*]]:2 = hlfir.declare %[[REAL_ARR_ALLOC]]({{.*}}) +! CHECK: %[[MAPPED_MI0:.*]] = omp.map.info var_ptr(%[[MAPPED_DECL]]#1 : !fir.ref, i32) {{.*}} +! CHECK: %[[ALLOC_VAR_MAP:.*]] = omp.map.info var_ptr(%[[ALLOC_VAR_DECL]]#0 : !fir.ref>>, !fir.box>) +! CHECK: fir.store %[[REAL_ARR_DECL]]#0 to %[[REAL_ARR_DESC_ALLOCA]] : !fir.ref>> +! CHECK: %[[REAL_ARR_DESC_MAP:.*]] = omp.map.info var_ptr(%[[REAL_ARR_DESC_ALLOCA]] : !fir.ref>>, !fir.box>) +! CHECK: fir.store %[[CHAR_VAR_DECL]]#0 to %[[CHAR_VAR_DESC_ALLOCA]] : !fir.ref> +! CHECK: %[[CHAR_VAR_DESC_MAP:.*]] = omp.map.info var_ptr(%[[CHAR_VAR_DESC_ALLOCA]] : !fir.ref>, !fir.boxchar<1>) ! CHECK: omp.target -! CHECK-SAME: map_entries(%[[MAPPED_MI]] -> %[[MAPPED_ARG:.*]] : !fir.ref) +! CHECK-SAME: map_entries( +! CHECK-SAME: %[[MAPPED_MI0]] -> %[[MAPPED_ARG0:[^,]+]], +! CHECK-SAME: %[[ALLOC_VAR_MAP]] -> %[[MAPPED_ARG1:[^,]+]] +! CHECK-SAME %[[REAL_ARR_DESC_MAP]] -> %[[MAPPED_ARG2:[^,]+]] +! CHECK_SAME %[[CHAR_VAR_DESC_MAP]] -> %[[MAPPED_ARG3:.[^,]+]] : +! CHECK-SAME !fir.ref, !fir.ref>>, !fir.ref>>, !fir.ref>) ! CHECK-SAME: private( ! CHECK-SAME: @[[ALLOC_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[ALLOC_ARG:[^,]+]], ! CHECK-SAME: @[[REAL_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[REAL_ARG:[^,]+]], @@ -162,7 +179,6 @@ end subroutine target_allocatable ! CHECK-SAME: @[[CHAR_PRIVATIZER_SYM]] %{{[^[:space:]]+}}#0 -> %[[CHAR_ARG:[^,]+]] : ! CHECK-SAME: !fir.ref>>, !fir.ref, !fir.ref, !fir.box>, !fir.ref>, !fir.boxchar<1>) { ! CHECK-NOT: fir.alloca -! CHECK: hlfir.declare %[[MAPPED_ARG]] ! CHECK: hlfir.declare %[[ALLOC_ARG]] ! CHECK: hlfir.declare %[[REAL_ARG]] ! CHECK: hlfir.declare %[[LB_ARG]] diff --git a/flang/test/Transforms/omp-maps-for-privatized-symbols.fir b/flang/test/Transforms/omp-maps-for-privatized-symbols.fir new file mode 100644 index 00000000000000..d32444aaabf237 --- /dev/null +++ b/flang/test/Transforms/omp-maps-for-privatized-symbols.fir @@ -0,0 +1,48 @@ +// RUN: fir-opt --split-input-file --omp-maps-for-privatized-symbols %s | FileCheck %s +module attributes {omp.is_target_device = false} { + omp.private {type = private} @_QFtarget_simpleEsimple_var_private_ref_box_heap_i32 : !fir.ref>> alloc { + ^bb0(%arg0: !fir.ref>>): + %0 = fir.alloca !fir.box> {bindc_name = "simple_var", pinned, uniq_name = "_QFtarget_simpleEsimple_var"} + %1 = fir.load %arg0 : !fir.ref>> + %5:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtarget_simpleEsimple_var"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + omp.yield(%5#0 : !fir.ref>>) + } + func.func @_QPtarget_simple() { + %0 = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFtarget_simpleEa"} + %1:2 = hlfir.declare %0 {uniq_name = "_QFtarget_simpleEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %2 = fir.alloca !fir.box> {bindc_name = "simple_var", uniq_name = "_QFtarget_simpleEsimple_var"} + %3 = fir.zero_bits !fir.heap + %4 = fir.embox %3 : (!fir.heap) -> !fir.box> + fir.store %4 to %2 : !fir.ref>> + %5:2 = hlfir.declare %2 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtarget_simpleEsimple_var"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + %c2_i32 = arith.constant 2 : i32 + hlfir.assign %c2_i32 to %1#0 : i32, !fir.ref + %6 = omp.map.info var_ptr(%1#1 : !fir.ref, i32) map_clauses(to) capture(ByRef) -> !fir.ref {name = "a"} + omp.target map_entries(%6 -> %arg0 : !fir.ref) private(@_QFtarget_simpleEsimple_var_private_ref_box_heap_i32 %5#0 -> %arg1 : !fir.ref>>) { + %11:2 = hlfir.declare %arg0 {uniq_name = "_QFtarget_simpleEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %12:2 = hlfir.declare %arg1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtarget_simpleEsimple_var"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + %c10_i32 = arith.constant 10 : i32 + %13 = fir.load %11#0 : !fir.ref + %14 = arith.addi %c10_i32, %13 : i32 + hlfir.assign %14 to %12#0 realloc : i32, !fir.ref>> + omp.terminator + } + %7 = fir.load %5#1 : !fir.ref>> + %8 = fir.box_addr %7 : (!fir.box>) -> !fir.heap + %9 = fir.convert %8 : (!fir.heap) -> i64 + %c0_i64 = arith.constant 0 : i64 + %10 = arith.cmpi ne, %9, %c0_i64 : i64 + fir.if %10 { + %11 = fir.load %5#1 : !fir.ref>> + %12 = fir.box_addr %11 : (!fir.box>) -> !fir.heap + fir.freemem %12 : !fir.heap + %13 = fir.zero_bits !fir.heap + %14 = fir.embox %13 : (!fir.heap) -> !fir.box> + fir.store %14 to %5#1 : !fir.ref>> + } + return + } +} +// CHECK: %[[MAP0:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref, i32) map_clauses(to) capture(ByRef) -> !fir.ref {name = "a"} +// CHECK: %[[MAP1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) -> !fir.ref>> +// CHECK: omp.target map_entries(%[[MAP0]] -> %arg0, %[[MAP1]] -> %arg1 : !fir.ref, !fir.ref>>) diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td index 45313200d4f0b9..626539cb7bde42 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -948,7 +948,7 @@ def MapInfoOp : OpenMP_Op<"map.info", [AttrSizedOperandSegments]> { objects (e.g. derived types or classes), indicates the bounds to be copied of the variable. When it's an array slice it is in rank order where rank 0 is the inner-most dimension. - - 'map_clauses': OpenMP map type for this map capture, for example: from, to and + - 'map_type': OpenMP map type for this map capture, for example: from, to and always. It's a bitfield composed of the OpenMP runtime flags stored in OpenMPOffloadMappingFlags. - 'map_capture_type': Capture type for the variable e.g. this, byref, byvalue, byvla From e6c01432b6fb6077e1bdf2e0abf05d2c2dd3fd3e Mon Sep 17 00:00:00 2001 From: OverMighty Date: Sun, 20 Oct 2024 09:49:19 +0200 Subject: [PATCH 12/12] [libc][math][c23] Update newhdrgen for new _Float16 math functions (#113005) --- libc/newhdrgen/yaml/math.yaml | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/libc/newhdrgen/yaml/math.yaml b/libc/newhdrgen/yaml/math.yaml index 98ea1a0d25fbb7..fe07803cff06f8 100644 --- a/libc/newhdrgen/yaml/math.yaml +++ b/libc/newhdrgen/yaml/math.yaml @@ -206,6 +206,13 @@ functions: return_type: float arguments: - type: float + - name: coshf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: ddivl standards: - stdc @@ -266,6 +273,13 @@ functions: return_type: float arguments: - type: float + - name: exp10m1f16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: exp2 standards: - stdc @@ -1557,6 +1571,13 @@ functions: return_type: float arguments: - type: float + - name: log10f16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: log1p standards: - stdc @@ -1581,6 +1602,13 @@ functions: return_type: float arguments: - type: float + - name: log2f16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: logb standards: - stdc @@ -1619,6 +1647,13 @@ functions: return_type: float arguments: - type: float + - name: logf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: lrint standards: - stdc @@ -2297,6 +2332,13 @@ functions: return_type: float arguments: - type: float + - name: sinhf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: sinpif16 standards: - stdc @@ -2323,6 +2365,13 @@ functions: arguments: - type: float128 guard: LIBC_TYPES_HAS_FLOAT128 + - name: sqrtf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: sqrtl standards: - stdc @@ -2347,6 +2396,13 @@ functions: return_type: float arguments: - type: float + - name: tanhf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: totalorder standards: - stdc