diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge index 78a9cb77ff7d90f03179049c069aa9e05af3e66d..e1c66ac18e7ac0abb6b7dbeb29b29e22ed0642b6 100755 --- a/.ci/generate-buildkite-pipeline-premerge +++ b/.ci/generate-buildkite-pipeline-premerge @@ -68,7 +68,7 @@ function compute-projects-to-test() { done ;; clang) - for p in clang-tools-extra compiler-rt flang lldb cross-project-tests; do + for p in clang-tools-extra compiler-rt lldb cross-project-tests; do echo $p done ;; diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index 75765819ac464eb83bec5d5643d50195ee07a88e..edd0f7d2365a4b54430c161a4abe52d45b50ab1c 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -677,6 +677,9 @@ public: /// have an origin file name available. bool HasSymbolsWithFileName{false}; + /// Does the binary have BAT section. + bool HasBATSection{false}; + /// Sum of execution count of all functions uint64_t SumExecutionCount{0}; diff --git a/bolt/include/bolt/Passes/BinaryPasses.h b/bolt/include/bolt/Passes/BinaryPasses.h index 5d7692559eda882b125ee5314117eb5fe65932d0..a07c9130041fdb01947ac3698c078f62f3f6f9d4 100644 --- a/bolt/include/bolt/Passes/BinaryPasses.h +++ b/bolt/include/bolt/Passes/BinaryPasses.h @@ -16,6 +16,7 @@ #include "bolt/Core/BinaryContext.h" #include "bolt/Core/BinaryFunction.h" #include "bolt/Core/DynoStats.h" +#include "bolt/Profile/BoltAddressTranslation.h" #include "llvm/Support/CommandLine.h" #include #include @@ -399,8 +400,11 @@ public: /// Prints a list of the top 100 functions sorted by a set of /// dyno stats categories. class PrintProgramStats : public BinaryFunctionPass { + BoltAddressTranslation *BAT = nullptr; + public: - explicit PrintProgramStats() : BinaryFunctionPass(false) {} + explicit PrintProgramStats(BoltAddressTranslation *BAT = nullptr) + : BinaryFunctionPass(false), BAT(BAT) {} const char *getName() const override { return "print-stats"; } bool shouldPrint(const BinaryFunction &) const override { return false; } diff --git a/bolt/include/bolt/Passes/StokeInfo.h b/bolt/include/bolt/Passes/StokeInfo.h index 76417e6a2c3baa612ff7041142d8bba4933b3f04..a18c2a05d0153eacf04f44f79e1514a5f38ec271 100644 --- a/bolt/include/bolt/Passes/StokeInfo.h +++ b/bolt/include/bolt/Passes/StokeInfo.h @@ -87,10 +87,10 @@ struct StokeFuncInfo { << "," << NumBlocks << "," << IsLoopFree << "," << NumLoops << "," << MaxLoopDepth << "," << HotSize << "," << TotalSize << "," << Score << "," << HasCall << ",\"{ "; - for (std::string S : DefIn) + for (const std::string &S : DefIn) Outfile << "%" << S << " "; Outfile << "}\",\"{ "; - for (std::string S : LiveOut) + for (const std::string &S : LiveOut) Outfile << "%" << S << " "; Outfile << "}\"," << HeapOut << "," << StackOut << "," << HasRipAddr << "," << Omitted << "\n"; diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index c158a9bb3e3f253f5d0e60f4f22c8bb53c42b12b..6453b3070ceb8d23983e09c77c3ef3f5e29764be 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -15,6 +15,7 @@ #define BOLT_PROFILE_DATA_AGGREGATOR_H #include "bolt/Profile/DataReader.h" +#include "bolt/Profile/YAMLProfileWriter.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/Program.h" @@ -248,7 +249,7 @@ private: BinaryFunction *getBATParentFunction(const BinaryFunction &Func) const; /// Retrieve the location name to be used for samples recorded in \p Func. - StringRef getLocationName(const BinaryFunction &Func) const; + static StringRef getLocationName(const BinaryFunction &Func, bool BAT); /// Semantic actions - parser hooks to interpret parsed perf samples /// Register a sample (non-LBR mode), i.e. a new hit at \p Address @@ -490,6 +491,8 @@ public: /// Parse the output generated by "perf buildid-list" to extract build-ids /// and return a file name matching a given \p FileBuildID. std::optional getFileNameForBuildID(StringRef FileBuildID); + + friend class YAMLProfileWriter; }; } // namespace bolt } // namespace llvm diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index ad2eb18caf109b0c987b1e568404649142599c9c..64d160adeee862ab750a77947c6a11501dd3ef97 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -1322,7 +1322,9 @@ void BinaryContext::processInterproceduralReferences() { InterproceduralReferences) { BinaryFunction &Function = *It.first; uint64_t Address = It.second; - if (!Address || Function.isIgnored()) + // Process interprocedural references from ignored functions in BAT mode + // (non-simple in non-relocation mode) to properly register entry points + if (!Address || (Function.isIgnored() && !HasBATSection)) continue; BinaryFunction *TargetFunction = diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 10b93e702984fb180f8d38e652b07340cc5a2846..1bb05f044fc8bbe7cdc06c526eb8e8adcfc49828 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -1666,7 +1666,8 @@ void BinaryFunction::postProcessEntryPoints() { // In non-relocation mode there's potentially an external undetectable // reference to the entry point and hence we cannot move this entry // point. Optimizing without moving could be difficult. - if (!BC.HasRelocations) + // In BAT mode, register any known entry points for CFG construction. + if (!BC.HasRelocations && !BC.HasBATSection) setSimple(false); const uint32_t Offset = KV.first; diff --git a/bolt/lib/Passes/BinaryPasses.cpp b/bolt/lib/Passes/BinaryPasses.cpp index 298ba29ff5b3ff0404a9815f2a17cf95efa23ffc..11e22dea71fb2910df81d3fee82fba81d0e6496f 100644 --- a/bolt/lib/Passes/BinaryPasses.cpp +++ b/bolt/lib/Passes/BinaryPasses.cpp @@ -1390,9 +1390,19 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) { if (Function.isPLTFunction()) continue; + // Adjustment for BAT mode: the profile for BOLT split fragments is combined + // so only count the hot fragment. + const uint64_t Address = Function.getAddress(); + bool IsHotParentOfBOLTSplitFunction = !Function.getFragments().empty() && + BAT && BAT->isBATFunction(Address) && + !BAT->fetchParentAddress(Address); + ++NumRegularFunctions; - if (!Function.isSimple()) { + // In BOLTed binaries split functions are non-simple (due to non-relocation + // mode), but the original function is known to be simple and we have a + // valid profile for it. + if (!Function.isSimple() && !IsHotParentOfBOLTSplitFunction) { if (Function.hasProfile()) ++NumNonSimpleProfiledFunctions; continue; diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index e06debcee741e1270cf5f81d4afcc92e25a516f7..c0fd69b98c82d63f046ef345f3378fd92890c467 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -613,7 +613,8 @@ Error DataAggregator::readProfile(BinaryContext &BC) { if (std::error_code EC = writeBATYAML(BC, opts::SaveProfile)) report_error("cannot create output data file", EC); } - BC.logBOLTErrorsAndQuitOnFatal(PrintProgramStats().runOnFunctions(BC)); + PrintProgramStats PPS(BAT); + BC.logBOLTErrorsAndQuitOnFatal(PPS.runOnFunctions(BC)); } return Error::success(); @@ -673,7 +674,8 @@ DataAggregator::getBATParentFunction(const BinaryFunction &Func) const { return nullptr; } -StringRef DataAggregator::getLocationName(const BinaryFunction &Func) const { +StringRef DataAggregator::getLocationName(const BinaryFunction &Func, + bool BAT) { if (!BAT) return Func.getOneName(); @@ -702,7 +704,7 @@ bool DataAggregator::doSample(BinaryFunction &OrigFunc, uint64_t Address, auto I = NamesToSamples.find(Func.getOneName()); if (I == NamesToSamples.end()) { bool Success; - StringRef LocName = getLocationName(Func); + StringRef LocName = getLocationName(Func, BAT); std::tie(I, Success) = NamesToSamples.insert( std::make_pair(Func.getOneName(), FuncSampleData(LocName, FuncSampleData::ContainerTy()))); @@ -722,7 +724,7 @@ bool DataAggregator::doIntraBranch(BinaryFunction &Func, uint64_t From, FuncBranchData *AggrData = getBranchData(Func); if (!AggrData) { AggrData = &NamesToBranches[Func.getOneName()]; - AggrData->Name = getLocationName(Func); + AggrData->Name = getLocationName(Func, BAT); setBranchData(Func, AggrData); } @@ -741,7 +743,7 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, StringRef SrcFunc; StringRef DstFunc; if (FromFunc) { - SrcFunc = getLocationName(*FromFunc); + SrcFunc = getLocationName(*FromFunc, BAT); FromAggrData = getBranchData(*FromFunc); if (!FromAggrData) { FromAggrData = &NamesToBranches[FromFunc->getOneName()]; @@ -752,7 +754,7 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, recordExit(*FromFunc, From, Mispreds, Count); } if (ToFunc) { - DstFunc = getLocationName(*ToFunc); + DstFunc = getLocationName(*ToFunc, BAT); ToAggrData = getBranchData(*ToFunc); if (!ToAggrData) { ToAggrData = &NamesToBranches[ToFunc->getOneName()]; @@ -1227,7 +1229,7 @@ ErrorOr DataAggregator::parseLocationOrOffset() { if (Sep == StringRef::npos) return parseOffset(); StringRef LookAhead = ParsingBuf.substr(0, Sep); - if (LookAhead.find_first_of(":") == StringRef::npos) + if (!LookAhead.contains(':')) return parseOffset(); ErrorOr BuildID = parseString(':'); @@ -2340,7 +2342,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, continue; BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncAddress); assert(BF); - YamlBF.Name = getLocationName(*BF); + YamlBF.Name = getLocationName(*BF, BAT); YamlBF.Id = BF->getFunctionNumber(); YamlBF.Hash = BAT->getBFHash(FuncAddress); YamlBF.ExecCount = BF->getKnownExecutionCount(); diff --git a/bolt/lib/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp index ef04ba0d21ad75cf29421c24922738e9f0cba1d9..cf6b61ddd603148dc4660db8dee2235567acd699 100644 --- a/bolt/lib/Profile/YAMLProfileWriter.cpp +++ b/bolt/lib/Profile/YAMLProfileWriter.cpp @@ -10,6 +10,7 @@ #include "bolt/Core/BinaryBasicBlock.h" #include "bolt/Core/BinaryFunction.h" #include "bolt/Profile/BoltAddressTranslation.h" +#include "bolt/Profile/DataAggregator.h" #include "bolt/Profile/ProfileReaderBase.h" #include "bolt/Rewrite/RewriteInstance.h" #include "llvm/Support/CommandLine.h" @@ -39,6 +40,10 @@ const BinaryFunction *YAMLProfileWriter::setCSIDestination( BC.getFunctionForSymbol(Symbol, &EntryID)) { if (BAT && BAT->isBATFunction(Callee->getAddress())) std::tie(Callee, EntryID) = BAT->translateSymbol(BC, *Symbol, Offset); + else if (const BinaryBasicBlock *BB = + Callee->getBasicBlockContainingOffset(Offset)) + BC.getFunctionForSymbol(Callee->getSecondaryEntryPointSymbol(*BB), + &EntryID); CSI.DestId = Callee->getFunctionNumber(); CSI.EntryDiscriminator = EntryID; return Callee; @@ -59,7 +64,7 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS, BF.computeHash(UseDFS); BF.computeBlockHashes(); - YamlBF.Name = BF.getPrintName(); + YamlBF.Name = DataAggregator::getLocationName(BF, BAT); YamlBF.Id = BF.getFunctionNumber(); YamlBF.Hash = BF.getHash(); YamlBF.NumBasicBlocks = BF.size(); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 85b39176754b64187b37542f8bb866a22f87cbd1..9cc4c8c8c4fafa7deca4c89782931c488d1b0f19 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -1988,6 +1988,7 @@ Error RewriteInstance::readSpecialSections() { if (ErrorOr BATSec = BC->getUniqueSectionByName(BoltAddressTranslation::SECTION_NAME)) { + BC->HasBATSection = true; // Do not read BAT when plotting a heatmap if (!opts::HeatmapMode) { if (std::error_code EC = BAT->parse(BC->outs(), BATSec->getContents())) { @@ -4808,6 +4809,40 @@ void RewriteInstance::updateELFSymbolTable( // Create a new symbol based on the existing symbol. ELFSymTy NewSymbol = Symbol; + // Handle special symbols based on their name. + Expected SymbolName = Symbol.getName(StringSection); + assert(SymbolName && "cannot get symbol name"); + + auto updateSymbolValue = [&](const StringRef Name, + std::optional Value = std::nullopt) { + NewSymbol.st_value = Value ? *Value : getNewValueForSymbol(Name); + NewSymbol.st_shndx = ELF::SHN_ABS; + BC->outs() << "BOLT-INFO: setting " << Name << " to 0x" + << Twine::utohexstr(NewSymbol.st_value) << '\n'; + }; + + if (*SymbolName == "__hot_start" || *SymbolName == "__hot_end") { + if (opts::HotText) { + updateSymbolValue(*SymbolName); + ++NumHotTextSymsUpdated; + } + goto registerSymbol; + } + + if (*SymbolName == "__hot_data_start" || *SymbolName == "__hot_data_end") { + if (opts::HotData) { + updateSymbolValue(*SymbolName); + ++NumHotDataSymsUpdated; + } + goto registerSymbol; + } + + if (*SymbolName == "_end") { + if (NextAvailableAddress > Symbol.st_value) + updateSymbolValue(*SymbolName, NextAvailableAddress); + goto registerSymbol; + } + if (Function) { // If the symbol matched a function that was not emitted, update the // corresponding section index but otherwise leave it unchanged. @@ -4904,33 +4939,7 @@ void RewriteInstance::updateELFSymbolTable( } } - // Handle special symbols based on their name. - Expected SymbolName = Symbol.getName(StringSection); - assert(SymbolName && "cannot get symbol name"); - - auto updateSymbolValue = [&](const StringRef Name, - std::optional Value = std::nullopt) { - NewSymbol.st_value = Value ? *Value : getNewValueForSymbol(Name); - NewSymbol.st_shndx = ELF::SHN_ABS; - BC->outs() << "BOLT-INFO: setting " << Name << " to 0x" - << Twine::utohexstr(NewSymbol.st_value) << '\n'; - }; - - if (opts::HotText && - (*SymbolName == "__hot_start" || *SymbolName == "__hot_end")) { - updateSymbolValue(*SymbolName); - ++NumHotTextSymsUpdated; - } - - if (opts::HotData && (*SymbolName == "__hot_data_start" || - *SymbolName == "__hot_data_end")) { - updateSymbolValue(*SymbolName); - ++NumHotDataSymsUpdated; - } - - if (*SymbolName == "_end" && NextAvailableAddress > Symbol.st_value) - updateSymbolValue(*SymbolName, NextAvailableAddress); - + registerSymbol: if (IsDynSym) Write((&Symbol - cantFail(Obj.symbols(&SymTabSection)).begin()) * sizeof(ELFSymTy), diff --git a/bolt/runtime/instr.cpp b/bolt/runtime/instr.cpp index 16e0bbd55f90b1ed373b472fc0d70039b27aba93..d1f8a216badcf2713efab082dbed55952e374f19 100644 --- a/bolt/runtime/instr.cpp +++ b/bolt/runtime/instr.cpp @@ -1245,7 +1245,6 @@ void Graph::computeEdgeFrequencies(const uint64_t *Counters, continue; assert(SpanningTreeNodes[Cur].NumInEdges == 1, "must have 1 parent"); - const uint32_t Parent = SpanningTreeNodes[Cur].InEdges[0].Node; const uint32_t ParentEdge = SpanningTreeNodes[Cur].InEdges[0].ID; // Calculate parent edge freq. @@ -1464,9 +1463,8 @@ void visitCallFlowEntry(CallFlowHashTable::MapEntry &Entry, int FD, int openProfile() { // Build the profile name string by appending our PID char Buf[BufSize]; - char *Ptr = Buf; uint64_t PID = __getpid(); - Ptr = strCopy(Buf, __bolt_instr_filename, BufSize); + char *Ptr = strCopy(Buf, __bolt_instr_filename, BufSize); if (__bolt_instr_use_pid) { Ptr = strCopy(Ptr, ".", BufSize - (Ptr - Buf + 1)); Ptr = intToStr(Ptr, PID, 10); diff --git a/bolt/test/X86/bolt-address-translation-yaml.test b/bolt/test/X86/bolt-address-translation-yaml.test index e21513b7dfe592cb5a2bc14f6aab74564440259a..9f2c2ef3ab98723c96a2f138de14436d3edcd6ed 100644 --- a/bolt/test/X86/bolt-address-translation-yaml.test +++ b/bolt/test/X86/bolt-address-translation-yaml.test @@ -31,7 +31,8 @@ RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat.preagg.txt -w %t.yaml -o RUN: 2>&1 | FileCheck --check-prefix READ-BAT-CHECK %s RUN: FileCheck --input-file %t.yaml --check-prefix YAML-BAT-CHECK %s # Check that YAML converted from fdata matches YAML created directly with BAT. -RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o /dev/null +RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o /dev/null \ +RUN: 2>&1 | FileCheck --check-prefix READ-BAT-FDATA-CHECK %s RUN: FileCheck --input-file %t.yaml-fdata --check-prefix YAML-BAT-CHECK %s # Test resulting YAML profile with the original binary (no-stale mode) @@ -45,6 +46,8 @@ WRITE-BAT-CHECK: BOLT-INFO: BAT section size (bytes): 384 READ-BAT-CHECK-NOT: BOLT-ERROR: unable to save profile in YAML format for input file processed by BOLT READ-BAT-CHECK: BOLT-INFO: Parsed 5 BAT entries READ-BAT-CHECK: PERF2BOLT: read 79 aggregated LBR entries +READ-BAT-CHECK: BOLT-INFO: 5 out of 21 functions in the binary (23.8%) have non-empty execution profile +READ-BAT-FDATA-CHECK: BOLT-INFO: 5 out of 16 functions in the binary (31.2%) have non-empty execution profile YAML-BAT-CHECK: functions: # Function not covered by BAT - has insns in basic block diff --git a/bolt/test/X86/ignored-interprocedural-reference.s b/bolt/test/X86/ignored-interprocedural-reference.s new file mode 100644 index 0000000000000000000000000000000000000000..12e4fb92adcc0d0017c874e8d09ec3a38da2e2cf --- /dev/null +++ b/bolt/test/X86/ignored-interprocedural-reference.s @@ -0,0 +1,49 @@ +# This reproduces a bug with not processing interprocedural references from +# ignored functions. + +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -nostdlib -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.out --enable-bat -funcs=main +# RUN: link_fdata %s %t.out %t.preagg PREAGG +# RUN: perf2bolt %t.out -p %t.preagg --pa -o %t.fdata -w %t.yaml +# RUN: FileCheck %s --input-file=%t.fdata --check-prefix=CHECK-FDATA +# RUN: FileCheck %s --input-file=%t.yaml --check-prefix=CHECK-YAML + +# CHECK-FDATA: 1 main 0 1 foo a 1 1 +# CHECK-YAML: name: main +# CHECK-YAML: calls: {{.*}} disc: 1 + +# PREAGG: B #main# #foo_secondary# 1 1 +# main calls foo at valid instruction offset past nops that are to be stripped. + .globl main +main: + .cfi_startproc + call foo_secondary + ret + .cfi_endproc +.size main,.-main + +# Placeholder cold fragment to force main to be ignored in non-relocation mode. + .globl main.cold +main.cold: + .cfi_startproc + ud2 + .cfi_endproc +.size main.cold,.-main.cold + +# foo is set up to contain a valid instruction at called offset, and trapping +# instructions past that. + .globl foo +foo: + .cfi_startproc + .nops 10 + .globl foo_secondary +foo_secondary: + ret + .rept 20 + int3 + .endr + .cfi_endproc +.size foo,.-foo diff --git a/bolt/test/X86/register-fragments-bolt-symbols.s b/bolt/test/X86/register-fragments-bolt-symbols.s index 6478adf19372b2938061dd36389330e4b6ebe79d..90c402b2234d761dd99c1883f76d22ba8435b38d 100644 --- a/bolt/test/X86/register-fragments-bolt-symbols.s +++ b/bolt/test/X86/register-fragments-bolt-symbols.s @@ -18,6 +18,11 @@ # RUN: FileCheck --input-file %t.bat.fdata --check-prefix=CHECK-FDATA %s # RUN: FileCheck --input-file %t.bat.yaml --check-prefix=CHECK-YAML %s +# RUN: link_fdata --no-redefine %s %t.bolt %t.preagg2 PREAGG2 +# PREAGG2: B X:0 #chain# 1 0 +# RUN: perf2bolt %t.bolt -p %t.preagg2 --pa -o %t.bat2.fdata -w %t.bat2.yaml +# RUN: FileCheck %s --input-file %t.bat2.yaml --check-prefix=CHECK-YAML2 + # CHECK-SYMS: l df *ABS* [[#]] chain.s # CHECK-SYMS: l F .bolt.org.text [[#]] chain # CHECK-SYMS: l F .text.cold [[#]] chain.cold.0 @@ -28,6 +33,9 @@ # CHECK-FDATA: 0 [unknown] 0 1 chain/chain.s/2 10 0 1 # CHECK-YAML: - name: 'chain/chain.s/2' +# CHECK-YAML2: - name: 'chain/chain.s/1' +## non-BAT function has non-zero insns: +# CHECK-YAML2: insns: 1 .file "chain.s" .text diff --git a/bolt/test/link_fdata.py b/bolt/test/link_fdata.py index 0232dd3211e9bbcccecd5c37cf2269fa0373dcc2..3837e394ccc87bb6b0c79d9613f0cec8bf8aff9c 100755 --- a/bolt/test/link_fdata.py +++ b/bolt/test/link_fdata.py @@ -19,6 +19,7 @@ parser.add_argument("output") parser.add_argument("prefix", nargs="?", default="FDATA", help="Custom FDATA prefix") parser.add_argument("--nmtool", default="nm", help="Path to nm tool") parser.add_argument("--no-lbr", action="store_true") +parser.add_argument("--no-redefine", action="store_true") args = parser.parse_args() @@ -90,6 +91,8 @@ nm_output = subprocess.run( symbols = {} for symline in nm_output.splitlines(): symval, _, symname = symline.split(maxsplit=2) + if symname in symbols and args.no_redefine: + continue symbols[symname] = symval diff --git a/bolt/test/runtime/X86/hot-end-symbol.s b/bolt/test/runtime/X86/hot-end-symbol.s index e6d83d77167acde60626e0be308fb3f3c716ca39..6ae771cead75682010dbd0739682f00b4f30239a 100755 --- a/bolt/test/runtime/X86/hot-end-symbol.s +++ b/bolt/test/runtime/X86/hot-end-symbol.s @@ -12,6 +12,7 @@ # RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q # RUN: llvm-bolt %t.exe --relocs=1 --hot-text --reorder-functions=hfsort \ +# RUN: --split-functions --split-strategy=all \ # RUN: --data %t.fdata -o %t.out | FileCheck %s # RUN: %t.out 1 @@ -30,12 +31,12 @@ # CHECK-OUTPUT: __hot_start # CHECK-OUTPUT-NEXT: main # CHECK-OUTPUT-NEXT: __hot_end +# CHECK-OUTPUT-NOT: __hot_start.cold .text .globl main .type main, %function .globl __hot_start - .type __hot_start, %object .p2align 4 main: __hot_start: diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp index 36687a8e761e85fce8b52494d2c68fb20051c2e5..c87b3ea7e261632d8f5b954ffff9c88ef445cc2c 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp @@ -54,7 +54,9 @@ AST_MATCHER(QualType, isEnableIf) { AST_MATCHER_P(TemplateTypeParmDecl, hasDefaultArgument, clang::ast_matchers::internal::Matcher, TypeMatcher) { return Node.hasDefaultArgument() && - TypeMatcher.matches(Node.getDefaultArgument(), Finder, Builder); + TypeMatcher.matches( + Node.getDefaultArgument().getArgument().getAsType(), Finder, + Builder); } AST_MATCHER(TemplateDecl, hasAssociatedConstraints) { return Node.hasAssociatedConstraints(); diff --git a/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp index 09aaf3e31d5dd7f4bd57c4465316a1994dae904c..75f1107904fcec9b455588fb0e1e53d66a4f3b95 100644 --- a/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp @@ -19,10 +19,11 @@ namespace { AST_MATCHER_P(TemplateTypeParmDecl, hasUnnamedDefaultArgument, ast_matchers::internal::Matcher, InnerMatcher) { if (Node.getIdentifier() != nullptr || !Node.hasDefaultArgument() || - Node.getDefaultArgumentInfo() == nullptr) + Node.getDefaultArgument().getArgument().isNull()) return false; - TypeLoc DefaultArgTypeLoc = Node.getDefaultArgumentInfo()->getTypeLoc(); + TypeLoc DefaultArgTypeLoc = + Node.getDefaultArgument().getTypeSourceInfo()->getTypeLoc(); return InnerMatcher.matches(DefaultArgTypeLoc, Finder, Builder); } diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp index 7a021fe14436a102037f442433db810ff0ef3366..ea4d99586c71102117a15e53736800e94e1ecb4f 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp @@ -177,9 +177,11 @@ matchTrailingTemplateParam(const FunctionTemplateDecl *FunctionTemplate) { dyn_cast(LastParam)) { if (LastTemplateParam->hasDefaultArgument() && LastTemplateParam->getIdentifier() == nullptr) { - return {matchEnableIfSpecialization( - LastTemplateParam->getDefaultArgumentInfo()->getTypeLoc()), - LastTemplateParam}; + return { + matchEnableIfSpecialization(LastTemplateParam->getDefaultArgument() + .getTypeSourceInfo() + ->getTypeLoc()), + LastTemplateParam}; } } return {}; diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index e811f5519de2c136c2789aeb26fb569f2095832c..88e4886cd0df938923ce0e871fb7bb3827471744 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -123,6 +123,9 @@ static const NamedDecl *getFailureForNamedDecl(const NamedDecl *ND) { if (const auto *Method = dyn_cast(ND)) { if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) Canonical = cast(Overridden->getCanonicalDecl()); + else if (const FunctionTemplateDecl *Primary = Method->getPrimaryTemplate()) + if (const FunctionDecl *TemplatedDecl = Primary->getTemplatedDecl()) + Canonical = cast(TemplatedDecl->getCanonicalDecl()); if (Canonical != ND) return Canonical; diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 06b949bc4a2b552907c5dbe95d0fd7c768096346..2ec0994e846e94ff95b93efbc6927a552018d9cd 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -247,8 +247,12 @@ fetchTemplateParameters(const TemplateParameterList *Params, if (!TTP->getName().empty()) P.Name = TTP->getNameAsString(); - if (TTP->hasDefaultArgument()) - P.Default = TTP->getDefaultArgument().getAsString(PP); + if (TTP->hasDefaultArgument()) { + P.Default.emplace(); + llvm::raw_string_ostream Out(*P.Default); + TTP->getDefaultArgument().getArgument().print(PP, Out, + /*IncludeType=*/false); + } } else if (const auto *NTTP = dyn_cast(Param)) { P.Type = printType(NTTP, PP); diff --git a/clang-tools-extra/clangd/test/infinite-instantiation.test b/clang-tools-extra/clangd/test/infinite-instantiation.test index 85a1b656f49086c7d463be50fdd2af808a0506cf..a9c787c77027c7e06c607a00862410c07193359d 100644 --- a/clang-tools-extra/clangd/test/infinite-instantiation.test +++ b/clang-tools-extra/clangd/test/infinite-instantiation.test @@ -1,5 +1,6 @@ -// RUN: cp %s %t.cpp -// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s +// RUN: rm -rf %t.dir && mkdir -p %t.dir +// RUN: echo '[{"directory": "%/t.dir", "command": "clang -ftemplate-depth=100 -x c++ %/s", "file": "%/s"}]' > %t.dir/compile_commands.json +// RUN: not clangd --compile-commands-dir=%t.dir -check=%s 2>&1 | FileCheck -strict-whitespace %s // CHECK: [template_recursion_depth_exceeded] diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 6a9892bada9155e4ee87ceef384e1937f0e2cfa9..741abc0a199a7730388979b545c1b5560f0de548 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -375,7 +375,8 @@ Changes in existing checks ` check in `GetConfigPerFile` mode by resolving symbolic links to header files. Fixed handling of Hungarian Prefix when configured to `LowerCase`. Added support for renaming designated - initializers. Added support for renaming macro arguments. + initializers. Added support for renaming macro arguments. Fixed renaming + conflicts arising from out-of-line member function template definitions. - Improved :doc:`readability-implicit-bool-conversion ` check to provide diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-no-crash.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-no-crash.cpp index 300fff6cb179bfc00b7e48635af8efbcedaf9891..2e2964dda1dafdd996e1def36fa0463aecb72cb5 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-no-crash.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-no-crash.cpp @@ -5,3 +5,11 @@ struct X { // CHECK-MESSAGES: :[[@LINE-1]]:5: error: field has incomplete type 'X' [clang-diagnostic-error] int a = 10; }; + +template class NoCrash { + // CHECK-MESSAGES: :[[@LINE+2]]:20: error: base class has incomplete type + // CHECK-MESSAGES: :[[@LINE-2]]:29: note: definition of 'NoCrash' is not complete until the closing '}' + class B : public NoCrash { + template B(U u) {} + }; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp index 8d6992afef08a977ee35673db604369ae866927e..eaa73b906ce09289c56f18b8d916b00334954d1c 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp @@ -463,12 +463,6 @@ struct NegativeIncompleteArrayMember { char e[]; }; -template class NoCrash { - class B : public NoCrash { - template B(U u) {} - }; -}; - struct PositiveBitfieldMember { PositiveBitfieldMember() {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-outofline.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-outofline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f807875e27698da28337cb8444c40c8844ef5357 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-outofline.cpp @@ -0,0 +1,30 @@ +// RUN: %check_clang_tidy %s readability-identifier-naming %t -std=c++20 \ +// RUN: --config='{CheckOptions: { \ +// RUN: readability-identifier-naming.MethodCase: CamelCase, \ +// RUN: }}' + +namespace SomeNamespace { +namespace Inner { + +class SomeClass { +public: + template + int someMethod(); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for method 'someMethod' [readability-identifier-naming] +// CHECK-FIXES: {{^}} int SomeMethod(); +}; +template +int SomeClass::someMethod() { +// CHECK-FIXES: {{^}}int SomeClass::SomeMethod() { + return 5; +} + +} // namespace Inner + +void someFunc() { + Inner::SomeClass S; + S.someMethod(); +// CHECK-FIXES: {{^}} S.SomeMethod(); +} + +} // namespace SomeNamespace diff --git a/clang/cmake/caches/HLSL.cmake b/clang/cmake/caches/HLSL.cmake index 27f848fdccf0ca3e24880f85df20f571f7816d94..ed813f60c9c69970e8c93784b39cc3955693a062 100644 --- a/clang/cmake/caches/HLSL.cmake +++ b/clang/cmake/caches/HLSL.cmake @@ -12,7 +12,7 @@ set(LLVM_ENABLE_PROJECTS "clang;clang-tools-extra" CACHE STRING "") set(CLANG_ENABLE_HLSL On CACHE BOOL "") -if (NOT CMAKE_CONFIGURATION_TYPES) +if (HLSL_ENABLE_DISTRIBUTION) set(LLVM_DISTRIBUTION_COMPONENTS "clang;hlsl-resource-headers;clangd" CACHE STRING "") diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5a123b0b86ddacd653f252a24260169709382aa5..81e9d0423f96aecced463f43e5ffadb4efde3288 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -742,6 +742,13 @@ Bug Fixes to C++ Support - Fix a bug with checking constrained non-type template parameters for equivalence. Fixes (#GH77377). - Fix a bug where the last argument was not considered when considering the most viable function for explicit object argument member functions. Fixes (#GH92188). +- Fix a C++11 crash when a non-const non-static member function is defined out-of-line with + the ``constexpr`` specifier. Fixes (#GH61004). +- Clang no longer transforms dependent qualified names into implicit class member access expressions + until it can be determined whether the name is that of a non-static member. +- Clang now correctly diagnoses when the current instantiation is used as an incomplete base class. +- Clang no longer treats ``constexpr`` class scope function template specializations of non-static members + as implicitly ``const`` in language modes after C++11. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index b747adfb6992e3bc75d17e575457ab47fce07115..dee51e402b687fa36f598a6ba22262cdb871e173 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -124,6 +124,7 @@ clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h clang/include/clang/Analysis/FlowSensitive/ASTOps.h +clang/include/clang/Analysis/FlowSensitive/CNFFormula.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -621,6 +622,7 @@ clang/tools/libclang/CXCursor.h clang/tools/scan-build-py/tests/functional/src/include/clean-one.h clang/unittests/Analysis/CFGBuildResult.h clang/unittests/Analysis/MacroExpansionContextTest.cpp +clang/unittests/Analysis/FlowSensitive/CNFFormula.cpp clang/unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/MapLatticeTest.cpp @@ -632,6 +634,7 @@ clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +clang/unittests/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp clang/unittests/Analysis/FlowSensitive/WatchedLiteralsSolverTest.cpp clang/unittests/AST/ASTImporterFixtures.cpp clang/unittests/AST/ASTImporterFixtures.h diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index e03b11219478670277472f41b6c31cc31f2f6961..2ce2b810d3636498cb8f8fe27a427d22cb0ee612 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2611,7 +2611,7 @@ public: /// /// \returns if this is an array type, the completely unqualified array type /// that corresponds to it. Otherwise, returns T.getUnqualifiedType(). - QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals); + QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals) const; /// Determine whether the given types are equivalent after /// cvr-qualifiers have been removed. diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index bf7c204e4ad73ab6408292215d3a839cc495c0ca..98db1cb57899096f636680d0a98d0df05d898b9c 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -695,7 +695,7 @@ public: if (const auto *TC = D->getTypeConstraint()) Visit(TC->getImmediatelyDeclaredConstraint()); if (D->hasDefaultArgument()) - Visit(D->getDefaultArgument(), SourceRange(), + Visit(D->getDefaultArgument().getArgument(), SourceRange(), D->getDefaultArgStorage().getInheritedFrom(), D->defaultArgumentWasInherited() ? "inherited from" : "previous"); } diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index f3d6a321ecf104c279a0b855f4e21c46474e7596..07b08b5ed43ca450f79f65ce01c6c52b672353e3 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1185,7 +1185,7 @@ class TemplateTypeParmDecl final : public TypeDecl, /// The default template argument, if any. using DefArgStorage = - DefaultArgStorage; + DefaultArgStorage; DefArgStorage DefaultArgument; TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc, @@ -1225,13 +1225,9 @@ public: bool hasDefaultArgument() const { return DefaultArgument.isSet(); } /// Retrieve the default argument, if any. - QualType getDefaultArgument() const { - return DefaultArgument.get()->getType(); - } - - /// Retrieves the default argument's source information, if any. - TypeSourceInfo *getDefaultArgumentInfo() const { - return DefaultArgument.get(); + const TemplateArgumentLoc &getDefaultArgument() const { + static const TemplateArgumentLoc NoneLoc; + return DefaultArgument.isSet() ? *DefaultArgument.get() : NoneLoc; } /// Retrieves the location of the default argument declaration. @@ -1244,9 +1240,8 @@ public: } /// Set the default argument for this template parameter. - void setDefaultArgument(TypeSourceInfo *DefArg) { - DefaultArgument.set(DefArg); - } + void setDefaultArgument(const ASTContext &C, + const TemplateArgumentLoc &DefArg); /// Set that this default argument was inherited from another /// parameter. diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index fac65628ffede8329b71c9d850502a743087a47c..dbf693611a7fa56edf7a9345d0613a3a1af71f59 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -4377,15 +4377,21 @@ class PackIndexingExpr final // The pack being indexed, followed by the index Stmt *SubExprs[2]; - size_t TransformedExpressions; + // The size of the trailing expressions. + unsigned TransformedExpressions : 31; + + LLVM_PREFERRED_TYPE(bool) + unsigned ExpandedToEmptyPack : 1; PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc, SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr, - ArrayRef SubstitutedExprs = {}) + ArrayRef SubstitutedExprs = {}, + bool ExpandedToEmptyPack = false) : Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary), EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc), SubExprs{PackIdExpr, IndexExpr}, - TransformedExpressions(SubstitutedExprs.size()) { + TransformedExpressions(SubstitutedExprs.size()), + ExpandedToEmptyPack(ExpandedToEmptyPack) { auto *Exprs = getTrailingObjects(); std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(), @@ -4408,10 +4414,14 @@ public: SourceLocation EllipsisLoc, SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr, std::optional Index, - ArrayRef SubstitutedExprs = {}); + ArrayRef SubstitutedExprs = {}, + bool ExpandedToEmptyPack = false); static PackIndexingExpr *CreateDeserialized(ASTContext &Context, unsigned NumTransformedExprs); + /// Determine if the expression was expanded to empty. + bool expandsToEmptyPack() const { return ExpandedToEmptyPack; } + /// Determine the location of the 'sizeof' keyword. SourceLocation getEllipsisLoc() const { return EllipsisLoc; } @@ -4445,6 +4455,7 @@ public: return getTrailingObjects()[*Index]; } + /// Return the trailing expressions, regardless of the expansion. ArrayRef getExpressions() const { return {getTrailingObjects(), TransformedExpressions}; } diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 607a2b9d653678836264e0742840d24d1dc69ec4..28ff8c44bd25698564251cb69d67e165f95bbd36 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -677,6 +677,35 @@ public: ArrayRef VarList, SourceLocation EndLoc); }; +class OpenACCReductionClause final + : public OpenACCClauseWithVarList, + public llvm::TrailingObjects { + OpenACCReductionOperator Op; + + OpenACCReductionClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + OpenACCReductionOperator Operator, + ArrayRef VarList, SourceLocation EndLoc) + : OpenACCClauseWithVarList(OpenACCClauseKind::Reduction, BeginLoc, + LParenLoc, EndLoc), + Op(Operator) { + std::uninitialized_copy(VarList.begin(), VarList.end(), + getTrailingObjects()); + setExprs(MutableArrayRef(getTrailingObjects(), VarList.size())); + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Reduction; + } + + static OpenACCReductionClause * + Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, + OpenACCReductionOperator Operator, ArrayRef VarList, + SourceLocation EndLoc); + + OpenACCReductionOperator getReductionOp() const { return Op; } +}; + template class OpenACCClauseVisitor { Impl &getDerived() { return static_cast(*this); } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f5cefedb07e0eba340bd950b3c36769b5a39a774..659e4cdd1037b1ef1f77554b9f40ef34637993fa 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1960,7 +1960,7 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, { TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); TRY_TO(TraverseTemplateTypeParamDeclConstraints(D)); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) - TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc())); + TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument())); }) DEF_TRAVERSE_DECL(TypedefDecl, { diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index da3834f19ca04466ab9574c8fdbcfd737539bcfe..9a5c6e8d562c34a8a19cf26f79b1df442e1901fd 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2523,6 +2523,7 @@ public: bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. bool isExtVectorBoolType() const; // Extended vector type with bool element. + bool isSubscriptableVectorType() const; bool isMatrixType() const; // Matrix type. bool isConstantMatrixType() const; // Constant matrix type. bool isDependentAddressSpaceType() const; // value-dependent address space qualifier @@ -7729,6 +7730,10 @@ inline bool Type::isExtVectorBoolType() const { return cast(CanonicalType)->getElementType()->isBooleanType(); } +inline bool Type::isSubscriptableVectorType() const { + return isVectorType() || isSveVLSBuiltinType(); +} + inline bool Type::isMatrixType() const { return isa(CanonicalType); } diff --git a/clang/include/clang/Analysis/FlowSensitive/CNFFormula.h b/clang/include/clang/Analysis/FlowSensitive/CNFFormula.h new file mode 100644 index 0000000000000000000000000000000000000000..fb13e774c67fe798e84ebb3178d7aa589f7af6ef --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/CNFFormula.h @@ -0,0 +1,179 @@ +//===- CNFFormula.h ---------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// A representation of a boolean formula in 3-CNF. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H + +#include +#include + +#include "clang/Analysis/FlowSensitive/Formula.h" + +namespace clang { +namespace dataflow { + +/// Boolean variables are represented as positive integers. +using Variable = uint32_t; + +/// A null boolean variable is used as a placeholder in various data structures +/// and algorithms. +constexpr Variable NullVar = 0; + +/// Literals are represented as positive integers. Specifically, for a boolean +/// variable `V` that is represented as the positive integer `I`, the positive +/// literal `V` is represented as the integer `2*I` and the negative literal +/// `!V` is represented as the integer `2*I+1`. +using Literal = uint32_t; + +/// A null literal is used as a placeholder in various data structures and +/// algorithms. +constexpr Literal NullLit = 0; + +/// Clause identifiers are represented as positive integers. +using ClauseID = uint32_t; + +/// A null clause identifier is used as a placeholder in various data structures +/// and algorithms. +constexpr ClauseID NullClause = 0; + +/// Returns the positive literal `V`. +inline constexpr Literal posLit(Variable V) { return 2 * V; } + +/// Returns the negative literal `!V`. +inline constexpr Literal negLit(Variable V) { return 2 * V + 1; } + +/// Returns whether `L` is a positive literal. +inline constexpr bool isPosLit(Literal L) { return 0 == (L & 1); } + +/// Returns whether `L` is a negative literal. +inline constexpr bool isNegLit(Literal L) { return 1 == (L & 1); } + +/// Returns the negated literal `!L`. +inline constexpr Literal notLit(Literal L) { return L ^ 1; } + +/// Returns the variable of `L`. +inline constexpr Variable var(Literal L) { return L >> 1; } + +/// A boolean formula in 3-CNF (conjunctive normal form with at most 3 literals +/// per clause). +class CNFFormula { + /// `LargestVar` is equal to the largest positive integer that represents a + /// variable in the formula. + const Variable LargestVar; + + /// Literals of all clauses in the formula. + /// + /// The element at index 0 stands for the literal in the null clause. It is + /// set to 0 and isn't used. Literals of clauses in the formula start from the + /// element at index 1. + /// + /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of + /// `Clauses` will be `[0, L1, L2, L2, L3, L4]`. + std::vector Clauses; + + /// Start indices of clauses of the formula in `Clauses`. + /// + /// The element at index 0 stands for the start index of the null clause. It + /// is set to 0 and isn't used. Start indices of clauses in the formula start + /// from the element at index 1. + /// + /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of + /// `ClauseStarts` will be `[0, 1, 3]`. Note that the literals of the first + /// clause always start at index 1. The start index for the literals of the + /// second clause depends on the size of the first clause and so on. + std::vector ClauseStarts; + + /// Indicates that we already know the formula is unsatisfiable. + /// During construction, we catch simple cases of conflicting unit-clauses. + bool KnownContradictory; + +public: + explicit CNFFormula(Variable LargestVar); + + /// Adds the `L1 v ... v Ln` clause to the formula. + /// Requirements: + /// + /// `Li` must not be `NullLit`. + /// + /// All literals in the input that are not `NullLit` must be distinct. + void addClause(ArrayRef lits); + + /// Returns whether the formula is known to be contradictory. + /// This is the case if any of the clauses is empty. + bool knownContradictory() const { return KnownContradictory; } + + /// Returns the largest variable in the formula. + Variable largestVar() const { return LargestVar; } + + /// Returns the number of clauses in the formula. + /// Valid clause IDs are in the range [1, `numClauses()`]. + ClauseID numClauses() const { return ClauseStarts.size() - 1; } + + /// Returns the number of literals in clause `C`. + size_t clauseSize(ClauseID C) const { + return C == ClauseStarts.size() - 1 ? Clauses.size() - ClauseStarts[C] + : ClauseStarts[C + 1] - ClauseStarts[C]; + } + + /// Returns the literals of clause `C`. + /// If `knownContradictory()` is false, each clause has at least one literal. + llvm::ArrayRef clauseLiterals(ClauseID C) const { + size_t S = clauseSize(C); + if (S == 0) + return llvm::ArrayRef(); + return llvm::ArrayRef(&Clauses[ClauseStarts[C]], S); + } + + /// An iterator over all literals of all clauses in the formula. + /// The iterator allows mutation of the literal through the `*` operator. + /// This is to support solvers that mutate the formula during solving. + class Iterator { + friend class CNFFormula; + CNFFormula *CNF; + size_t Idx; + Iterator(CNFFormula *CNF, size_t Idx) : CNF(CNF), Idx(Idx) {} + + public: + Iterator(const Iterator &) = default; + Iterator &operator=(const Iterator &) = default; + + Iterator &operator++() { + ++Idx; + assert(Idx < CNF->Clauses.size() && "Iterator out of bounds"); + return *this; + } + + Iterator next() const { + Iterator I = *this; + ++I; + return I; + } + + Literal &operator*() const { return CNF->Clauses[Idx]; } + }; + friend class Iterator; + + /// Returns an iterator to the first literal of clause `C`. + Iterator startOfClause(ClauseID C) { return Iterator(this, ClauseStarts[C]); } +}; + +/// Converts the conjunction of `Vals` into a formula in conjunctive normal +/// form where each clause has at least one and at most three literals. +/// `Atomics` is populated with a mapping from `Variables` to the corresponding +/// `Atom`s for atomic booleans in the input formulas. +CNFFormula buildCNF(const llvm::ArrayRef &Formulas, + llvm::DenseMap &Atomics); + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H diff --git a/clang/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h b/clang/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h index b5cd7aa10fd7d2502376049dded4f5c693d26008..d74380b78e935dda7b7391c0b5d06d7589a36e35 100644 --- a/clang/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h +++ b/clang/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h @@ -17,16 +17,17 @@ #include "clang/Analysis/FlowSensitive/Formula.h" #include "clang/Analysis/FlowSensitive/Solver.h" #include "llvm/ADT/ArrayRef.h" -#include namespace clang { namespace dataflow { /// A SAT solver that is an implementation of Algorithm D from Knuth's The Art /// of Computer Programming Volume 4: Satisfiability, Fascicle 6. It is based on -/// the Davis-Putnam-Logemann-Loveland (DPLL) algorithm, keeps references to a -/// single "watched" literal per clause, and uses a set of "active" variables +/// the Davis-Putnam-Logemann-Loveland (DPLL) algorithm [1], keeps references to +/// a single "watched" literal per clause, and uses a set of "active" variables /// for unit propagation. +// +// [1] https://en.wikipedia.org/wiki/DPLL_algorithm class WatchedLiteralsSolver : public Solver { // Count of the iterations of the main loop of the solver. This spans *all* // calls to the underlying solver across the life of this object. It is diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 9d97a75f696f668ac858ce08919b2f7339150d1f..50d3b42c0f8661fde4d593e684f16d3a3fb081ca 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -599,9 +599,6 @@ def warn_drv_unsupported_gpopt : Warning< "ignoring '-mgpopt' option as it cannot be used with %select{|the implicit" " usage of }0-mabicalls">, InGroup; -def warn_drv_unsupported_tocdata: Warning< - "ignoring '-mtocdata' as it is only supported for -mcmodel=small">, - InGroup; def warn_drv_unsupported_sdata : Warning< "ignoring '-msmall-data-limit=' with -mcmodel=large for -fpic or RV64">, InGroup; diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 674742431dcb2d7dfff7284ca8d071d361275388..944b2a38b6e9652c969c4e019d270dcd44ae6192 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -24,7 +24,7 @@ def err_no_matching_target : Error<"no matching target found for target variant def err_unsupported_vendor : Error<"vendor '%0' is not supported: '%1'">; def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'">; def err_unsupported_os : Error<"os '%0' is not supported: '%1'">; -def err_cannot_read_input_list : Error<"could not read %select{alias list|filelist}0 '%1': %2">; +def err_cannot_read_input_list : Error<"could not read %0 input list '%1': %2">; def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X