46 changes: 46 additions & 0 deletions bolt/lib/Profile/DataAggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2310,6 +2310,52 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
BP.Functions.emplace_back(
YAMLProfileWriter::convert(Function, /*UseDFS=*/false));
}

for (const auto &KV : NamesToBranches) {
const StringRef FuncName = KV.first;
const FuncBranchData &Branches = KV.second;
yaml::bolt::BinaryFunctionProfile YamlBF;
BinaryData *BD = BC.getBinaryDataByName(FuncName);
assert(BD);
uint64_t FuncAddress = BD->getAddress();
if (!BAT->isBATFunction(FuncAddress))
continue;
// Filter out cold fragments
if (!BD->getSectionName().equals(BC.getMainCodeSectionName()))
continue;
BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncAddress);
assert(BF);
YamlBF.Name = FuncName.str();
YamlBF.Id = BF->getFunctionNumber();
YamlBF.Hash = BAT->getBFHash(FuncAddress);
YamlBF.ExecCount = BF->getKnownExecutionCount();
YamlBF.NumBasicBlocks = BAT->getNumBasicBlocks(FuncAddress);
const BoltAddressTranslation::BBHashMapTy &BlockMap =
BAT->getBBHashMap(FuncAddress);

auto addSuccProfile = [&](yaml::bolt::BinaryBasicBlockProfile &YamlBB,
uint64_t SuccOffset, unsigned SuccDataIdx) {
const llvm::bolt::BranchInfo &BI = Branches.Data.at(SuccDataIdx);
yaml::bolt::SuccessorInfo SI;
SI.Index = BlockMap.getBBIndex(SuccOffset);
SI.Count = BI.Branches;
SI.Mispreds = BI.Mispreds;
YamlBB.Successors.emplace_back(SI);
};

for (const auto &[FromOffset, SuccKV] : Branches.IntraIndex) {
yaml::bolt::BinaryBasicBlockProfile YamlBB;
if (!BlockMap.isInputBlock(FromOffset))
continue;
YamlBB.Index = BlockMap.getBBIndex(FromOffset);
YamlBB.Hash = BlockMap.getBBHash(FromOffset);
for (const auto &[SuccOffset, SuccDataIdx] : SuccKV)
addSuccProfile(YamlBB, SuccOffset, SuccDataIdx);
if (YamlBB.ExecCount || !YamlBB.Successors.empty())
YamlBF.Blocks.emplace_back(YamlBB);
}
BP.Functions.emplace_back(YamlBF);
}
}

// Write the profile.
Expand Down
2 changes: 1 addition & 1 deletion bolt/lib/Rewrite/BinaryPassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ static cl::opt<bool> JTFootprintReductionFlag(
"instructions at jump sites"),
cl::cat(BoltOptCategory));

static cl::opt<bool>
cl::opt<bool>
KeepNops("keep-nops",
cl::desc("keep no-op instructions. By default they are removed."),
cl::Hidden, cl::cat(BoltOptCategory));
Expand Down
47 changes: 46 additions & 1 deletion bolt/lib/Rewrite/LinuxKernelRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,17 @@ class LinuxKernelRewriter final : public MetadataRewriter {

/// Paravirtual instruction patch sites.
Error readParaInstructions();
Error rewriteParaInstructions();

Error readBugTable();

/// Read alternative instruction info from .altinstructions.
/// Do no process functions containing instruction annotated with
/// \p Annotation.
void skipFunctionsWithAnnotation(StringRef Annotation) const;

/// Handle alternative instruction info from .altinstructions.
Error readAltInstructions();
Error rewriteAltInstructions();

/// Read .pci_fixup
Error readPCIFixupTable();
Expand Down Expand Up @@ -318,6 +324,12 @@ class LinuxKernelRewriter final : public MetadataRewriter {
if (Error E = rewriteExceptionTable())
return E;

if (Error E = rewriteAltInstructions())
return E;

if (Error E = rewriteParaInstructions())
return E;

if (Error E = rewriteORCTables())
return E;

Expand Down Expand Up @@ -1126,6 +1138,31 @@ Error LinuxKernelRewriter::readParaInstructions() {
return Error::success();
}

void LinuxKernelRewriter::skipFunctionsWithAnnotation(
StringRef Annotation) const {
for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) {
if (!BC.shouldEmit(BF))
continue;
for (const BinaryBasicBlock &BB : BF) {
const bool HasAnnotation = llvm::any_of(BB, [&](const MCInst &Inst) {
return BC.MIB->hasAnnotation(Inst, Annotation);
});
if (HasAnnotation) {
BF.setSimple(false);
break;
}
}
}
}

Error LinuxKernelRewriter::rewriteParaInstructions() {
// Disable output of functions with paravirtual instructions before the
// rewrite support is complete.
skipFunctionsWithAnnotation("ParaSite");

return Error::success();
}

/// Process __bug_table section.
/// This section contains information useful for kernel debugging.
/// Each entry in the section is a struct bug_entry that contains a pointer to
Expand Down Expand Up @@ -1305,6 +1342,14 @@ Error LinuxKernelRewriter::readAltInstructions() {
return Error::success();
}

Error LinuxKernelRewriter::rewriteAltInstructions() {
// Disable output of functions with alt instructions before the rewrite
// support is complete.
skipFunctionsWithAnnotation("AltInst");

return Error::success();
}

/// When the Linux kernel needs to handle an error associated with a given PCI
/// device, it uses a table stored in .pci_fixup section to locate a fixup code
/// specific to the vendor and the problematic device. The section contains a
Expand Down
4 changes: 4 additions & 0 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ extern cl::list<std::string> HotTextMoveSections;
extern cl::opt<bool> Hugify;
extern cl::opt<bool> Instrument;
extern cl::opt<JumpTableSupportLevel> JumpTables;
extern cl::opt<bool> KeepNops;
extern cl::list<std::string> ReorderData;
extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
extern cl::opt<bool> TimeBuild;
Expand Down Expand Up @@ -2031,6 +2032,9 @@ void RewriteInstance::adjustCommandLineOptions() {

if (opts::Lite)
BC->outs() << "BOLT-INFO: enabling lite mode\n";

if (BC->IsLinuxKernel && !opts::KeepNops.getNumOccurrences())
opts::KeepNops = true;
}

namespace {
Expand Down
14 changes: 13 additions & 1 deletion bolt/test/X86/bolt-address-translation-yaml.test
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ READ-BAT-CHECK: BOLT-INFO: Parsed 5 BAT entries
READ-BAT-CHECK: PERF2BOLT: read 79 aggregated LBR entries

YAML-BAT-CHECK: functions:
# Function not covered by BAT - has insns in basic block
YAML-BAT-CHECK: - name: main
YAML-BAT-CHECK-NEXT: fid: 2
YAML-BAT-CHECK-NEXT: hash: 0x9895746D48B2C876
Expand All @@ -35,6 +36,17 @@ YAML-BAT-CHECK-NEXT: - bid: 0
YAML-BAT-CHECK-NEXT: insns: 26
YAML-BAT-CHECK-NEXT: hash: 0xA900AE79CFD40000
YAML-BAT-CHECK-NEXT: succ: [ { bid: 3, cnt: 0 }, { bid: 1, cnt: 0 } ]
# Function covered by BAT - doesn't have insns in basic block
YAML-BAT-CHECK: - name: usqrt
YAML-BAT-CHECK-NEXT: fid: [[#]]
YAML-BAT-CHECK-NEXT: hash: 0x99E67ED32A203023
YAML-BAT-CHECK-NEXT: exec: 21
YAML-BAT-CHECK-NEXT: nblocks: 5
YAML-BAT-CHECK-NEXT: blocks:
YAML-BAT-CHECK: - bid: 1
YAML-BAT-CHECK-NEXT: insns: [[#]]
YAML-BAT-CHECK-NEXT: hash: 0xD70DC695320E0010
YAML-BAT-CHECK-NEXT: succ: {{.*}} { bid: 2, cnt: [[#]] }

CHECK-BOLT-YAML: pre-processing profile using YAML profile reader
CHECK-BOLT-YAML-NEXT: 1 out of 16 functions in the binary (6.2%) have non-empty execution profile
CHECK-BOLT-YAML-NEXT: 5 out of 16 functions in the binary (31.2%) have non-empty execution profile
15 changes: 7 additions & 8 deletions bolt/test/X86/linux-alt-instruction.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,30 @@
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.exe --print-normalized --keep-nops -o %t.out \
# RUN: --alt-inst-feature-size=2 | FileCheck %s
# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=2 -o %t.out \
# RUN: | FileCheck %s

## Older kernels used to have padlen field in alt_instr. Check compatibility.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown --defsym PADLEN=1 \
# RUN: %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.exe --print-normalized --keep-nops --alt-inst-has-padlen \
# RUN: -o %t.out | FileCheck %s
# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-has-padlen -o %t.out \
# RUN: | FileCheck %s

## Check with a larger size of "feature" field in alt_instr.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
# RUN: --defsym FEATURE_SIZE_4=1 %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.exe --print-normalized --keep-nops \
# RUN: --alt-inst-feature-size=4 -o %t.out | FileCheck %s
# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=4 -o %t.out \
# RUN: | FileCheck %s

## Check that out-of-bounds read is handled properly.

# RUN: not llvm-bolt %t.exe --print-normalized --keep-nops \
# RUN: --alt-inst-feature-size=2 -o %t.out
# RUN: not llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=2 -o %t.out

# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 alternative instruction entries
Expand Down
4 changes: 2 additions & 2 deletions bolt/test/X86/linux-orc.s
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
## Verify ORC bindings to instructions.

# RUN: llvm-bolt %t.exe --print-normalized --dump-orc --print-orc -o %t.out \
# RUN: --bolt-info=0 |& FileCheck %s
# RUN: --keep-nops=0 --bolt-info=0 |& FileCheck %s


## Verify ORC bindings after rewrite.
Expand All @@ -37,7 +37,7 @@

## Verify ORC binding after rewrite when some of the functions are skipped.

# RUN: llvm-bolt %t.exe -o %t.out --skip-funcs=bar --bolt-info=0
# RUN: llvm-bolt %t.exe -o %t.out --skip-funcs=bar --bolt-info=0 --keep-nops=0
# RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized --print-orc \
# RUN: |& FileCheck %s

Expand Down
2 changes: 1 addition & 1 deletion bolt/test/X86/linux-parainstructions.s
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

## Verify paravirtual bindings to instructions.

# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s
# RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 | FileCheck %s

# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 paravirtual patch sites
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/ClangTidy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ class ErrorReporter {
if (!tooling::applyAllReplacements(Replacements.get(), Rewrite)) {
llvm::errs() << "Can't apply replacements for file " << File << "\n";
}
AnyNotWritten &= Rewrite.overwriteChangedFiles();
AnyNotWritten |= Rewrite.overwriteChangedFiles();
}

if (AnyNotWritten) {
Expand Down
30 changes: 9 additions & 21 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,16 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(CLANG_BUILT_STANDALONE TRUE)
endif()

# Make sure that our source directory is on the current cmake module path so that
# we can include cmake files from this directory.
list(INSERT CMAKE_MODULE_PATH 0
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules"
"${LLVM_COMMON_CMAKE_UTILS}/Modules"
)

# Must go below project(..)
include(GNUInstallDirs)
include(GetDarwinLinkerVersion)

if(CLANG_BUILT_STANDALONE)
set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
Expand Down Expand Up @@ -140,13 +148,6 @@ if(CLANG_BUILT_STANDALONE)
endif() # LLVM_INCLUDE_TESTS
endif() # standalone

# Make sure that our source directory is on the current cmake module path so that
# we can include cmake files from this directory.
list(INSERT CMAKE_MODULE_PATH 0
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules"
"${LLVM_COMMON_CMAKE_UTILS}/Modules"
)

# This allows disabling clang's XML dependency even if LLVM finds libxml2.
# By default, clang depends on libxml2 if LLVM does.
option(CLANG_ENABLE_LIBXML2 "Whether libclang may depend on libxml2"
Expand Down Expand Up @@ -346,20 +347,7 @@ endif ()
# Determine HOST_LINK_VERSION on Darwin.
set(HOST_LINK_VERSION)
if (APPLE AND NOT CMAKE_LINKER MATCHES ".*lld.*")
set(LD_V_OUTPUT)
execute_process(
COMMAND sh -c "${CMAKE_LINKER} -v 2>&1 | head -1"
RESULT_VARIABLE HAD_ERROR
OUTPUT_VARIABLE LD_V_OUTPUT
)
if (HAD_ERROR)
message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}")
endif()
if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*")
string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT})
elseif ("${LD_V_OUTPUT}" MATCHES "[^0-9]*([0-9.]+).*")
string(REGEX REPLACE "[^0-9]*([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT})
endif()
get_darwin_linker_version(HOST_LINK_VERSION)
message(STATUS "Host linker version: ${HOST_LINK_VERSION}")
endif()

Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ Bug Fixes to C++ Support
- Clang's __builtin_bit_cast will now produce a constant value for records with empty bases. See:
(#GH82383)
- Fix a crash when instantiating a lambda that captures ``this`` outside of its context. Fixes (#GH85343).
- Fix an issue where a namespace alias could be defined using a qualified name (all name components
following the first `::` were ignored).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ def err_expected_semi_after_namespace_name : Error<
"expected ';' after namespace name">;
def err_unexpected_namespace_attributes_alias : Error<
"attributes cannot be specified on namespace alias">;
def err_unexpected_qualified_namespace_alias : Error<
"namespace alias must be a single identifier">;
def err_unexpected_nested_namespace_attribute : Error<
"attributes cannot be specified on a nested namespace definition">;
def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ class EntryRef {
/// The underlying cached entry.
const CachedFileSystemEntry &Entry;

friend class DependencyScanningWorkerFilesystem;

public:
EntryRef(StringRef Name, const CachedFileSystemEntry &Entry)
: Filename(Name), Entry(Entry) {}
Expand Down Expand Up @@ -300,14 +302,15 @@ class DependencyScanningWorkerFilesystem
///
/// Attempts to use the local and shared caches first, then falls back to
/// using the underlying filesystem.
llvm::ErrorOr<EntryRef>
getOrCreateFileSystemEntry(StringRef Filename,
bool DisableDirectivesScanning = false);
llvm::ErrorOr<EntryRef> getOrCreateFileSystemEntry(StringRef Filename);

private:
/// Check whether the file should be scanned for preprocessor directives.
bool shouldScanForDirectives(StringRef Filename);
/// Ensure the directive tokens are populated for this file entry.
///
/// Returns true if the directive tokens are populated for this file entry,
/// false if not (i.e. this entry is not a file or its scan fails).
bool ensureDirectiveTokensArePopulated(EntryRef Entry);

private:
/// For a filename that's not yet associated with any entry in the caches,
/// uses the underlying filesystem to either look up the entry based in the
/// shared cache indexed by unique ID, or creates new entry from scratch.
Expand All @@ -317,11 +320,6 @@ class DependencyScanningWorkerFilesystem
computeAndStoreResult(StringRef OriginalFilename,
StringRef FilenameForLookup);

/// Scan for preprocessor directives for the given entry if necessary and
/// returns a wrapper object with reference semantics.
EntryRef scanForDirectivesIfNecessary(const CachedFileSystemEntry &Entry,
StringRef Filename, bool Disable);

/// Represents a filesystem entry that has been stat-ed (and potentially read)
/// and that's about to be inserted into the cache as `CachedFileSystemEntry`.
struct TentativeEntry {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3463,6 +3463,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
case Type::BTFTagAttributed:
T = cast<BTFTagAttributedType>(T)->getWrappedType();
break;
case Type::CountAttributed:
T = cast<CountAttributedType>(T)->desugar();
break;
case Type::Elaborated:
T = cast<ElaboratedType>(T)->getNamedType();
break;
Expand Down
42 changes: 25 additions & 17 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2753,10 +2753,9 @@ class AnnotatingParser {
}

// Heuristically try to determine whether the parentheses contain a type.
auto IsQualifiedPointerOrReference = [this](FormatToken *T) {
auto IsQualifiedPointerOrReference = [](FormatToken *T, bool IsCpp) {
// This is used to handle cases such as x = (foo *const)&y;
assert(!T->isTypeName(IsCpp) && "Should have already been checked");
(void)IsCpp; // Avoid -Wunused-lambda-capture when assertion is disabled.
// Strip trailing qualifiers such as const or volatile when checking
// whether the parens could be a cast to a pointer/reference type.
while (T) {
Expand Down Expand Up @@ -2789,7 +2788,7 @@ class AnnotatingParser {
!Tok.Previous ||
Tok.Previous->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) ||
Tok.Previous->isTypeName(IsCpp) ||
IsQualifiedPointerOrReference(Tok.Previous);
IsQualifiedPointerOrReference(Tok.Previous, IsCpp);
bool ParensCouldEndDecl =
Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
if (ParensAreType && !ParensCouldEndDecl)
Expand Down Expand Up @@ -4357,9 +4356,11 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace))
return false;

const auto *BeforeLeft = Left.Previous;

// operator co_await(x)
if (Right.is(tok::l_paren) && Left.is(tok::kw_co_await) && Left.Previous &&
Left.Previous->is(tok::kw_operator)) {
if (Right.is(tok::l_paren) && Left.is(tok::kw_co_await) && BeforeLeft &&
BeforeLeft->is(tok::kw_operator)) {
return false;
}
// co_await (x), co_yield (x), co_return (x)
Expand Down Expand Up @@ -4394,8 +4395,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
}
if (Left.is(tok::colon))
return Left.isNot(TT_ObjCMethodExpr);
if (Left.is(tok::coloncolon))
return false;
if (Left.is(tok::coloncolon)) {
return Right.is(tok::star) && Right.is(TT_PointerOrReference) &&
Style.PointerAlignment != FormatStyle::PAS_Left;
}
if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) {
if (Style.Language == FormatStyle::LK_TextProto ||
(Style.Language == FormatStyle::LK_Proto &&
Expand All @@ -4410,8 +4413,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return false;
}
if (Right.is(tok::ellipsis)) {
return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous &&
Left.Previous->is(tok::kw_case));
return Left.Tok.isLiteral() || (Left.is(tok::identifier) && BeforeLeft &&
BeforeLeft->is(tok::kw_case));
}
if (Left.is(tok::l_square) && Right.is(tok::amp))
return Style.SpacesInSquareBrackets;
Expand Down Expand Up @@ -4479,8 +4482,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.is(tok::l_brace) && Right.is(BK_Block))
return true;
// for (auto a = 0, b = 0; const auto& c : {1, 2, 3})
if (Left.Previous && Left.Previous->isTypeOrIdentifier(IsCpp) &&
Right.Next && Right.Next->is(TT_RangeBasedForLoopColon)) {
if (BeforeLeft && BeforeLeft->isTypeOrIdentifier(IsCpp) && Right.Next &&
Right.Next->is(TT_RangeBasedForLoopColon)) {
return getTokenPointerOrReferenceAlignment(Left) !=
FormatStyle::PAS_Right;
}
Expand All @@ -4502,12 +4505,17 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
startsWithInitStatement(Line)))) {
return false;
}
return Left.Previous && !Left.Previous->isOneOf(
tok::l_paren, tok::coloncolon, tok::l_square);
if (!BeforeLeft)
return false;
if (BeforeLeft->is(tok::coloncolon)) {
return Left.is(tok::star) &&
Style.PointerAlignment != FormatStyle::PAS_Right;
}
return !BeforeLeft->isOneOf(tok::l_paren, tok::l_square);
}
// Ensure right pointer alignment with ellipsis e.g. int *...P
if (Left.is(tok::ellipsis) && Left.Previous &&
Left.Previous->isPointerOrReference()) {
if (Left.is(tok::ellipsis) && BeforeLeft &&
BeforeLeft->isPointerOrReference()) {
return Style.PointerAlignment != FormatStyle::PAS_Right;
}

Expand Down Expand Up @@ -4669,13 +4677,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName ||
spaceRequiredBeforeParens(Right);
}
if (!Left.Previous || !Left.Previous->isOneOf(tok::period, tok::arrow)) {
if (!BeforeLeft || !BeforeLeft->isOneOf(tok::period, tok::arrow)) {
if (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch)) {
return Style.SpaceBeforeParensOptions.AfterControlStatements ||
spaceRequiredBeforeParens(Right);
}
if (Left.isOneOf(tok::kw_new, tok::kw_delete)) {
return ((!Line.MightBeFunctionDecl || !Left.Previous) &&
return ((!Line.MightBeFunctionDecl || !BeforeLeft) &&
Style.SpaceBeforeParens != FormatStyle::SBPO_Never) ||
spaceRequiredBeforeParens(Right);
}
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,14 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
SkipUntil(tok::semi);
return nullptr;
}
if (!ExtraNSs.empty()) {
Diag(ExtraNSs.front().NamespaceLoc,
diag::err_unexpected_qualified_namespace_alias)
<< SourceRange(ExtraNSs.front().NamespaceLoc,
ExtraNSs.back().IdentLoc);
SkipUntil(tok::semi);
return nullptr;
}
if (attrLoc.isValid())
Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias);
if (InlineLoc.isValid())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,25 @@ DependencyScanningWorkerFilesystem::readFile(StringRef Filename) {
return TentativeEntry(Stat, std::move(Buffer));
}

EntryRef DependencyScanningWorkerFilesystem::scanForDirectivesIfNecessary(
const CachedFileSystemEntry &Entry, StringRef Filename, bool Disable) {
if (Entry.isError() || Entry.isDirectory() || Disable ||
!shouldScanForDirectives(Filename))
return EntryRef(Filename, Entry);
bool DependencyScanningWorkerFilesystem::ensureDirectiveTokensArePopulated(
EntryRef Ref) {
auto &Entry = Ref.Entry;

if (Entry.isError() || Entry.isDirectory())
return false;

CachedFileContents *Contents = Entry.getCachedContents();
assert(Contents && "contents not initialized");

// Double-checked locking.
if (Contents->DepDirectives.load())
return EntryRef(Filename, Entry);
return true;

std::lock_guard<std::mutex> GuardLock(Contents->ValueLock);

// Double-checked locking.
if (Contents->DepDirectives.load())
return EntryRef(Filename, Entry);
return true;

SmallVector<dependency_directives_scan::Directive, 64> Directives;
// Scan the file for preprocessor directives that might affect the
Expand All @@ -69,16 +70,16 @@ EntryRef DependencyScanningWorkerFilesystem::scanForDirectivesIfNecessary(
Contents->DepDirectiveTokens.clear();
// FIXME: Propagate the diagnostic if desired by the client.
Contents->DepDirectives.store(new std::optional<DependencyDirectivesTy>());
return EntryRef(Filename, Entry);
return false;
}

// This function performed double-checked locking using `DepDirectives`.
// Assigning it must be the last thing this function does, otherwise other
// threads may skip the
// critical section (`DepDirectives != nullptr`), leading to a data race.
// threads may skip the critical section (`DepDirectives != nullptr`), leading
// to a data race.
Contents->DepDirectives.store(
new std::optional<DependencyDirectivesTy>(std::move(Directives)));
return EntryRef(Filename, Entry);
return true;
}

DependencyScanningFilesystemSharedCache::
Expand Down Expand Up @@ -161,34 +162,11 @@ DependencyScanningFilesystemSharedCache::CacheShard::
return *EntriesByFilename.insert({Filename, &Entry}).first->getValue();
}

/// Whitelist file extensions that should be minimized, treating no extension as
/// a source file that should be minimized.
///
/// This is kinda hacky, it would be better if we knew what kind of file Clang
/// was expecting instead.
static bool shouldScanForDirectivesBasedOnExtension(StringRef Filename) {
StringRef Ext = llvm::sys::path::extension(Filename);
if (Ext.empty())
return true; // C++ standard library
return llvm::StringSwitch<bool>(Ext)
.CasesLower(".c", ".cc", ".cpp", ".c++", ".cxx", true)
.CasesLower(".h", ".hh", ".hpp", ".h++", ".hxx", true)
.CasesLower(".m", ".mm", true)
.CasesLower(".i", ".ii", ".mi", ".mmi", true)
.CasesLower(".def", ".inc", true)
.Default(false);
}

static bool shouldCacheStatFailures(StringRef Filename) {
StringRef Ext = llvm::sys::path::extension(Filename);
if (Ext.empty())
return false; // This may be the module cache directory.
// Only cache stat failures on files that are not expected to change during
// the build.
StringRef FName = llvm::sys::path::filename(Filename);
if (FName == "module.modulemap" || FName == "module.map")
return true;
return shouldScanForDirectivesBasedOnExtension(Filename);
return true;
}

DependencyScanningWorkerFilesystem::DependencyScanningWorkerFilesystem(
Expand All @@ -201,11 +179,6 @@ DependencyScanningWorkerFilesystem::DependencyScanningWorkerFilesystem(
updateWorkingDirForCacheLookup();
}

bool DependencyScanningWorkerFilesystem::shouldScanForDirectives(
StringRef Filename) {
return shouldScanForDirectivesBasedOnExtension(Filename);
}

const CachedFileSystemEntry &
DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID(
TentativeEntry TEntry) {
Expand Down Expand Up @@ -259,7 +232,7 @@ DependencyScanningWorkerFilesystem::computeAndStoreResult(

llvm::ErrorOr<EntryRef>
DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
StringRef OriginalFilename, bool DisableDirectivesScanning) {
StringRef OriginalFilename) {
StringRef FilenameForLookup;
SmallString<256> PathBuf;
if (llvm::sys::path::is_absolute_gnu(OriginalFilename)) {
Expand All @@ -276,15 +249,11 @@ DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
assert(llvm::sys::path::is_absolute_gnu(FilenameForLookup));
if (const auto *Entry =
findEntryByFilenameWithWriteThrough(FilenameForLookup))
return scanForDirectivesIfNecessary(*Entry, OriginalFilename,
DisableDirectivesScanning)
.unwrapError();
return EntryRef(OriginalFilename, *Entry).unwrapError();
auto MaybeEntry = computeAndStoreResult(OriginalFilename, FilenameForLookup);
if (!MaybeEntry)
return MaybeEntry.getError();
return scanForDirectivesIfNecessary(*MaybeEntry, OriginalFilename,
DisableDirectivesScanning)
.unwrapError();
return EntryRef(OriginalFilename, *MaybeEntry).unwrapError();
}

llvm::ErrorOr<llvm::vfs::Status>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,8 @@ class DependencyScanningAction : public tooling::ToolAction {
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
if (llvm::ErrorOr<EntryRef> Entry =
LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
return Entry->getDirectiveTokens();
if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry))
return Entry->getDirectiveTokens();
return std::nullopt;
};
}
Expand Down
33 changes: 33 additions & 0 deletions clang/test/ClangScanDeps/modules-extension.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: rm -rf %t
// RUN: split-file %s %t

// This test checks that source files with uncommon extensions still undergo
// dependency directives scan. If header.pch would not and b.h would, the scan
// would fail when parsing `void function(B)` and not knowing the symbol B.

//--- module.modulemap
module __PCH { header "header.pch" }
module B { header "b.h" }

//--- header.pch
#include "b.h"
void function(B);

//--- b.h
typedef int B;

//--- tu.c
int main() {
function(0);
return 0;
}

//--- cdb.json.in
[{
"directory": "DIR",
"file": "DIR/tu.c",
"command": "clang -c DIR/tu.c -fmodules -fmodules-cache-path=DIR/cache -fimplicit-module-maps -include DIR/header.pch"
}]

// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.in > %t/cdb.json
// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full > %t/deps.json
18 changes: 18 additions & 0 deletions clang/test/CodeGen/attr-counted-by-debug-info.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: %clang -emit-llvm -DCOUNTED_BY -S -g %s -o - | FileCheck %s
// RUN: %clang -emit-llvm -S -g %s -o - | FileCheck %s

#ifdef COUNTED_BY
#define __counted_by(member) __attribute__((__counted_by__(member)))
#else
#define __counted_by(member)
#endif

struct {
int num_counters;
long value[] __counted_by(num_counters);
} agent_send_response_port_num;

// CHECK: !DICompositeType(tag: DW_TAG_array_type, baseType: ![[BT:.*]], elements: ![[ELEMENTS:.*]])
// CHECK: ![[BT]] = !DIBasicType(name: "long", size: {{.*}}, encoding: DW_ATE_signed)
// CHECK: ![[ELEMENTS]] = !{![[COUNT:.*]]}
// CHECK: ![[COUNT]] = !DISubrange(count: -1)
2 changes: 2 additions & 0 deletions clang/test/SemaCXX/namespace-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ namespace I {
namespace A1 { int i; }

namespace A2 = A1;

namespace A3::extra::specifiers = A2; // expected-error {{alias must be a single identifier}}
}

int f() {
Expand Down
38 changes: 24 additions & 14 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3621,8 +3621,8 @@ TEST_F(FormatTest, FormatsClasses) {
" : public aaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaa> {};");
verifyFormat("template <class R, class C>\n"
"struct Aaaaaaaaaaaaaaaaa<R (C::*)(int) const>\n"
" : Aaaaaaaaaaaaaaaaa<R (C::*)(int)> {};");
"struct Aaaaaaaaaaaaaaaaa<R (C:: *)(int) const>\n"
" : Aaaaaaaaaaaaaaaaa<R (C:: *)(int)> {};");
verifyFormat("class ::A::B {};");
}

Expand Down Expand Up @@ -11034,10 +11034,10 @@ TEST_F(FormatTest, UnderstandsBinaryOperators) {
}

TEST_F(FormatTest, UnderstandsPointersToMembers) {
verifyFormat("int A::*x;");
verifyFormat("int (S::*func)(void *);");
verifyFormat("void f() { int (S::*func)(void *); }");
verifyFormat("typedef bool *(Class::*Member)() const;");
verifyFormat("int A:: *x;");
verifyFormat("int (S:: *func)(void *);");
verifyFormat("void f() { int (S:: *func)(void *); }");
verifyFormat("typedef bool *(Class:: *Member)() const;");
verifyFormat("void f() {\n"
" (a->*f)();\n"
" a->*x;\n"
Expand All @@ -11052,9 +11052,19 @@ TEST_F(FormatTest, UnderstandsPointersToMembers) {
verifyFormat(
"(aaaaaaaaaa->*bbbbbbb)(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa));");

FormatStyle Style = getLLVMStyle();
EXPECT_EQ(Style.PointerAlignment, FormatStyle::PAS_Right);
verifyFormat("typedef bool *(Class:: *Member)() const;", Style);
verifyFormat("void f(int A:: *p) { int A:: *v = &A::B; }", Style);

Style.PointerAlignment = FormatStyle::PAS_Left;
verifyFormat("typedef bool* (Class::*Member)() const;", Style);
verifyFormat("typedef bool* (Class::* Member)() const;", Style);
verifyFormat("void f(int A::* p) { int A::* v = &A::B; }", Style);

Style.PointerAlignment = FormatStyle::PAS_Middle;
verifyFormat("typedef bool * (Class:: * Member)() const;", Style);
verifyFormat("void f(int A:: * p) { int A:: * v = &A::B; }", Style);
}

TEST_F(FormatTest, UnderstandsUnaryOperators) {
Expand Down Expand Up @@ -12386,7 +12396,7 @@ TEST_F(FormatTest, FormatsFunctionTypes) {
verifyFormat("int (*func)(void *);");
verifyFormat("void f() { int (*func)(void *); }");
verifyFormat("template <class CallbackClass>\n"
"using MyCallback = void (CallbackClass::*)(SomeObject *Data);");
"using Callback = void (CallbackClass:: *)(SomeObject *Data);");

verifyGoogleFormat("A<void*(int*, SomeType*)>;");
verifyGoogleFormat("void* (*a)(int);");
Expand Down Expand Up @@ -19149,13 +19159,13 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) {
"int bbbbbbb = 0;",
Alignment);
// http://llvm.org/PR68079
verifyFormat("using Fn = int (A::*)();\n"
"using RFn = int (A::*)() &;\n"
"using RRFn = int (A::*)() &&;",
verifyFormat("using Fn = int (A:: *)();\n"
"using RFn = int (A:: *)() &;\n"
"using RRFn = int (A:: *)() &&;",
Alignment);
verifyFormat("using Fn = int (A::*)();\n"
"using RFn = int *(A::*)() &;\n"
"using RRFn = double (A::*)() &&;",
verifyFormat("using Fn = int (A:: *)();\n"
"using RFn = int *(A:: *)() &;\n"
"using RRFn = double (A:: *)() &&;",
Alignment);

// PAS_Right
Expand Down
36 changes: 19 additions & 17 deletions clang/unittests/Format/QualifierFixerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ TEST_F(QualifierFixerTest, RightQualifier) {
verifyFormat("Foo inline static const;", "Foo inline const static;", Style);
verifyFormat("Foo inline static const;", Style);

verifyFormat("Foo<T volatile>::Bar<Type const, 5> const volatile A::*;",
verifyFormat("Foo<T volatile>::Bar<Type const, 5> const volatile A:: *;",
"volatile const Foo<volatile T>::Bar<const Type, 5> A::*;",
Style);

Expand Down Expand Up @@ -523,14 +523,15 @@ TEST_F(QualifierFixerTest, RightQualifier) {
verifyFormat("const INTPTR a;", Style);

// Pointers to members
verifyFormat("int S::*a;", Style);
verifyFormat("int const S::*a;", "const int S:: *a;", Style);
verifyFormat("int const S::*const a;", "const int S::* const a;", Style);
verifyFormat("int A::*const A::*p1;", Style);
verifyFormat("float (C::*p)(int);", Style);
verifyFormat("float (C::*const p)(int);", Style);
verifyFormat("float (C::*p)(int) const;", Style);
verifyFormat("float const (C::*p)(int);", "const float (C::*p)(int);", Style);
verifyFormat("int S:: *a;", Style);
verifyFormat("int const S:: *a;", "const int S:: *a;", Style);
verifyFormat("int const S:: *const a;", "const int S::* const a;", Style);
verifyFormat("int A:: *const A:: *p1;", Style);
verifyFormat("float (C:: *p)(int);", Style);
verifyFormat("float (C:: *const p)(int);", Style);
verifyFormat("float (C:: *p)(int) const;", Style);
verifyFormat("float const (C:: *p)(int);", "const float (C::*p)(int);",
Style);
}

TEST_F(QualifierFixerTest, LeftQualifier) {
Expand Down Expand Up @@ -830,14 +831,15 @@ TEST_F(QualifierFixerTest, LeftQualifier) {
verifyFormat("INTPTR const a;", Style);

// Pointers to members
verifyFormat("int S::*a;", Style);
verifyFormat("const int S::*a;", "int const S:: *a;", Style);
verifyFormat("const int S::*const a;", "int const S::* const a;", Style);
verifyFormat("int A::*const A::*p1;", Style);
verifyFormat("float (C::*p)(int);", Style);
verifyFormat("float (C::*const p)(int);", Style);
verifyFormat("float (C::*p)(int) const;", Style);
verifyFormat("const float (C::*p)(int);", "float const (C::*p)(int);", Style);
verifyFormat("int S:: *a;", Style);
verifyFormat("const int S:: *a;", "int const S:: *a;", Style);
verifyFormat("const int S:: *const a;", "int const S::* const a;", Style);
verifyFormat("int A:: *const A:: *p1;", Style);
verifyFormat("float (C:: *p)(int);", Style);
verifyFormat("float (C:: *const p)(int);", Style);
verifyFormat("float (C:: *p)(int) const;", Style);
verifyFormat("const float (C:: *p)(int);", "float const (C::*p)(int);",
Style);
}

TEST_F(QualifierFixerTest, ConstVolatileQualifiersOrder) {
Expand Down
42 changes: 41 additions & 1 deletion clang/www/cxx_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,47 @@ <h2 id="cxx26">C++2c implementation status</h2>
<td><a href="https://wg21.link/P2864R2">P2864R2</a></td>
<td class="full" align="center">Clang 18</td>
</tr>

<!-- Winter 2024 papers (Tokyo) -->
<tr>
<td>Disallow Binding a Returned Glvalue to a Temporary</td>
<td><a href="https://wg21.link/P2748R5">P2748R5</a></td>
<td class="none" align="center">No</td>
</tr>
<tr>
<td>Clarifying rules for brace elision in aggregate initialization</td>
<td><a href="https://wg21.link/P3106R1">P3106R1</a> (<a href="#dr">DR</a>)</td>
<td class="none" align="center">No</td>
</tr>
<tr>
<td>Attributes for Structured Bindings</td>
<td><a href="https://wg21.link/P0609R3">P0609R3</a></td>
<td class="none" align="center">No</td>
</tr>
<tr>
<td>Module Declarations Shouldn’t be Macros</td>
<td><a href="https://wg21.link/P3034R1">P3034R1</a> (<a href="#dr">DR</a>)</td>
<td class="none" align="center">No</td>
</tr>
<tr>
<td>Trivial infinite loops are not Undefined Behavior</td>
<td><a href="https://wg21.link/P2809R3">P2809R3</a> (<a href="#dr">DR</a>)</td>
<td class="none" align="center">No</td>
</tr>
<tr>
<td>Erroneous behaviour for uninitialized reads</td>
<td><a href="https://wg21.link/P2795R5">P2795R5</a></td>
<td class="none" align="center">No</td>
</tr>
<tr>
<td><tt>= delete("should have a reason");</tt></td>
<td><a href="https://wg21.link/P2573R2">P2573R2</a></td>
<td class="none" align="center">No</td>
</tr>
<tr>
<td>Variadic friends</td>
<td><a href="https://wg21.link/P2893R3">P2893R3</a></td>
<td class="none" align="center">No</td>
</tr>
</table>
</details>

Expand Down
19 changes: 19 additions & 0 deletions cmake/Modules/GetDarwinLinkerVersion.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Get the linker version on Darwin
function(get_darwin_linker_version variable)
set(LINK_VERSION)
set(LD_V_OUTPUT)
execute_process(
COMMAND sh -c "${CMAKE_LINKER} -v 2>&1 | head -1"
RESULT_VARIABLE HAD_ERROR
OUTPUT_VARIABLE LD_V_OUTPUT
)
if (HAD_ERROR)
message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}")
endif()
if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*")
string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" LINK_VERSION ${LD_V_OUTPUT})
elseif ("${LD_V_OUTPUT}" MATCHES "[^0-9]*([0-9.]+).*")
string(REGEX REPLACE "[^0-9]*([0-9.]+).*" "\\1" LINK_VERSION ${LD_V_OUTPUT})
endif()
set(${variable} ${LINK_VERSION} PARENT_SCOPE)
endfunction()
10 changes: 10 additions & 0 deletions compiler-rt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ include(SetPlatformToolchainTools)
include(base-config-ix)
include(CompilerRTUtils)
include(CMakeDependentOption)
include(GetDarwinLinkerVersion)

option(COMPILER_RT_BUILD_BUILTINS "Build builtins" ON)
mark_as_advanced(COMPILER_RT_BUILD_BUILTINS)
Expand Down Expand Up @@ -444,6 +445,15 @@ else()
set(SANITIZER_USE_SYMBOLS FALSE)
endif()

# Get the linker version while configuring compiler-rt and explicitly pass it
# in cflags during testing. This fixes the compiler/linker version mismatch
# issue when running a clang built with a newer Xcode in an older Xcode
set(COMPILER_RT_DARWIN_LINKER_VERSION)
if (APPLE AND NOT CMAKE_LINKER MATCHES ".*lld.*")
get_darwin_linker_version(COMPILER_RT_DARWIN_LINKER_VERSION)
message(STATUS "Host linker version: ${COMPILER_RT_DARWIN_LINKER_VERSION}")
endif()

# Build sanitizer runtimes with debug info.
if(MSVC)
# Use /Z7 instead of /Zi for the asan runtime. This avoids the LNK4099
Expand Down
3 changes: 3 additions & 0 deletions compiler-rt/lib/asan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ SET(ASAN_HEADERS
include_directories(..)

set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})

append_list_if(MSVC /Zl ASAN_CFLAGS)

set(ASAN_COMMON_DEFINITIONS ${COMPILER_RT_ASAN_SHADOW_SCALE_DEFINITION})

append_rtti_flag(OFF ASAN_CFLAGS)
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ include_directories(..)
set(SANITIZER_COMMON_DEFINITIONS
HAVE_RPC_XDR_H=${HAVE_RPC_XDR_H})

# note: L not I, this is nodefaultlibs for msvc
append_list_if(MSVC /Zl SANITIZER_COMMON_CFLAGS)
set(SANITIZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})

# Too many existing bugs, needs cleanup.
Expand Down
4 changes: 1 addition & 3 deletions compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ const int SIGFPE = 8;
const int SIGSEGV = 11;
const int SIGPIPE = 13;
const int SIGTERM = 15;
const int SIGPROF = 27;
#if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_APPLE || SANITIZER_NETBSD
const int SIGBUS = 10;
const int SIGSYS = 12;
Expand Down Expand Up @@ -2169,8 +2168,7 @@ static bool is_sync_signal(ThreadSignalContext *sctx, int sig,
return false;
#endif
return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP ||
sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
sig == SIGPROF;
sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS;
}

void sighandler(int sig, __sanitizer_siginfo *info, void *ctx) {
Expand Down
10 changes: 5 additions & 5 deletions compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
}
Free(thr->tctx->sync);

#if !SANITIZER_GO
thr->is_inited = true;
#endif

uptr stk_addr = 0;
uptr stk_size = 0;
uptr tls_addr = 0;
Expand Down Expand Up @@ -200,15 +204,11 @@ void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
}

void ThreadContext::OnStarted(void *arg) {
thr = static_cast<ThreadState *>(arg);
DPrintf("#%d: ThreadStart\n", tid);
new (thr) ThreadState(tid);
thr = new (arg) ThreadState(tid);
if (common_flags()->detect_deadlocks)
thr->dd_lt = ctx->dd->CreateLogicalThread(tid);
thr->tctx = this;
#if !SANITIZER_GO
thr->is_inited = true;
#endif
}

void ThreadFinish(ThreadState *thr) {
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/ubsan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ set(UBSAN_HEADERS
include_directories(..)

set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_list_if(MSVC /Zl UBSAN_CFLAGS)
append_rtti_flag(OFF UBSAN_CFLAGS)
append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CFLAGS)

Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/test/lit.common.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,10 @@ def is_windows_lto_supported():
elif config.use_lld and (not config.has_lld):
config.unsupported = True

if config.host_os == "Darwin":
if getattr(config, "darwin_linker_version", None):
extra_cflags += ["-mlinker-version=" + config.darwin_linker_version]

# Append any extra flags passed in lit_config
append_target_cflags = lit_config.params.get("append_target_cflags", None)
if append_target_cflags:
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/lit.common.configured.in
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ set_default("expensive_checks", @LLVM_ENABLE_EXPENSIVE_CHECKS_PYBOOL@)
set_default("test_standalone_build_libs", @COMPILER_RT_TEST_STANDALONE_BUILD_LIBS_PYBOOL@)
set_default("has_compiler_rt_libatomic", @COMPILER_RT_BUILD_STANDALONE_LIBATOMIC_PYBOOL@)
set_default("aarch64_sme", @COMPILER_RT_HAS_AARCH64_SME_PYBOOL@)
set_default("darwin_linker_version", "@COMPILER_RT_DARWIN_LINKER_VERSION@")
# True iff the test suite supports ignoring the test compiler's runtime library path
# and using `config.compiler_rt_libdir` instead. This only matters when the runtime
# library paths differ.
Expand Down
6 changes: 3 additions & 3 deletions compiler-rt/test/tsan/signal_errno.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ static void MyHandler(int, siginfo_t *s, void *c) {

static void* sendsignal(void *p) {
barrier_wait(&barrier);
pthread_kill(mainth, SIGALRM);
pthread_kill(mainth, SIGPROF);
return 0;
}

Expand All @@ -37,7 +37,7 @@ int main() {
mainth = pthread_self();
struct sigaction act = {};
act.sa_sigaction = &MyHandler;
sigaction(SIGALRM, &act, 0);
sigaction(SIGPROF, &act, 0);
pthread_t th;
pthread_create(&th, 0, sendsignal, 0);
loop();
Expand All @@ -46,7 +46,7 @@ int main() {
}

// CHECK: WARNING: ThreadSanitizer: signal handler spoils errno
// CHECK: Signal 14 handler invoked at:
// CHECK: Signal 27 handler invoked at:
// CHECK: #0 MyHandler(int, {{(__)?}}siginfo{{(_t)?}}*, void*) {{.*}}signal_errno.cpp
// CHECK: main
// CHECK: SUMMARY: ThreadSanitizer: signal handler spoils errno{{.*}}MyHandler
8 changes: 4 additions & 4 deletions compiler-rt/test/tsan/signal_reset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ static void* reset(void *p) {
struct sigaction act = {};
for (int i = 0; i < 1000000; i++) {
act.sa_handler = &handler;
if (sigaction(SIGALRM, &act, 0)) {
if (sigaction(SIGPROF, &act, 0)) {
perror("sigaction");
exit(1);
}
act.sa_handler = SIG_IGN;
if (sigaction(SIGALRM, &act, 0)) {
if (sigaction(SIGPROF, &act, 0)) {
perror("sigaction");
exit(1);
}
Expand All @@ -44,7 +44,7 @@ static void* reset(void *p) {
int main() {
struct sigaction act = {};
act.sa_handler = SIG_IGN;
if (sigaction(SIGALRM, &act, 0)) {
if (sigaction(SIGPROF, &act, 0)) {
perror("sigaction");
exit(1);
}
Expand All @@ -53,7 +53,7 @@ int main() {
t.it_value.tv_sec = 0;
t.it_value.tv_usec = 10;
t.it_interval = t.it_value;
if (setitimer(ITIMER_REAL, &t, 0)) {
if (setitimer(ITIMER_PROF, &t, 0)) {
perror("setitimer");
exit(1);
}
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/test/tsan/signal_sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ int main() {

struct sigaction act = {};
act.sa_handler = &handler;
if (sigaction(SIGVTALRM, &act, 0)) {
if (sigaction(SIGPROF, &act, 0)) {
perror("sigaction");
exit(1);
}
Expand All @@ -39,7 +39,7 @@ int main() {
t.it_value.tv_sec = 0;
t.it_value.tv_usec = 10;
t.it_interval = t.it_value;
if (setitimer(ITIMER_VIRTUAL, &t, 0)) {
if (setitimer(ITIMER_PROF, &t, 0)) {
perror("setitimer");
exit(1);
}
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/test/tsan/signal_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ static void* thr(void *p) {
int main() {
struct sigaction act = {};
act.sa_handler = &handler;
if (sigaction(SIGVTALRM, &act, 0)) {
if (sigaction(SIGPROF, &act, 0)) {
perror("sigaction");
exit(1);
}
Expand All @@ -33,7 +33,7 @@ int main() {
t.it_value.tv_sec = 0;
t.it_value.tv_usec = 10;
t.it_interval = t.it_value;
if (setitimer(ITIMER_VIRTUAL, &t, 0)) {
if (setitimer(ITIMER_PROF, &t, 0)) {
perror("setitimer");
exit(1);
}
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/test/tsan/signal_thread2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static void *thr(void *p) {
int main() {
struct sigaction act = {};
act.sa_handler = &handler;
if (sigaction(SIGALRM, &act, 0)) {
if (sigaction(SIGPROF, &act, 0)) {
perror("sigaction");
exit(1);
}
Expand All @@ -49,7 +49,7 @@ int main() {
t.it_value.tv_sec = 0;
t.it_value.tv_usec = 10;
t.it_interval = t.it_value;
if (setitimer(ITIMER_REAL, &t, 0)) {
if (setitimer(ITIMER_PROF, &t, 0)) {
perror("setitimer");
exit(1);
}
Expand Down
8 changes: 4 additions & 4 deletions flang/lib/Optimizer/Builder/IntrinsicCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3883,7 +3883,7 @@ mlir::Value IntrinsicLibrary::genIeeeClass(mlir::Type resultType,
int pos = 3 + highSignificandSize;
mlir::Value index = builder.create<mlir::arith::AndIOp>(
loc, builder.create<mlir::arith::ShRUIOp>(loc, intVal, signShift),
createIntegerConstant(1 << pos));
createIntegerConstant(1ULL << pos));

// [e] exponent != 0
mlir::Value exponent =
Expand All @@ -3895,7 +3895,7 @@ mlir::Value IntrinsicLibrary::genIeeeClass(mlir::Type resultType,
loc,
builder.create<mlir::arith::CmpIOp>(
loc, mlir::arith::CmpIPredicate::ne, exponent, zero),
createIntegerConstant(1 << --pos), zero));
createIntegerConstant(1ULL << --pos), zero));

// [m] exponent == 1..1 (max exponent)
index = builder.create<mlir::arith::OrIOp>(
Expand All @@ -3904,7 +3904,7 @@ mlir::Value IntrinsicLibrary::genIeeeClass(mlir::Type resultType,
loc,
builder.create<mlir::arith::CmpIOp>(
loc, mlir::arith::CmpIPredicate::eq, exponent, exponentMask),
createIntegerConstant(1 << --pos), zero));
createIntegerConstant(1ULL << --pos), zero));

// [l] low-order significand != 0
index = builder.create<mlir::arith::OrIOp>(
Expand All @@ -3916,7 +3916,7 @@ mlir::Value IntrinsicLibrary::genIeeeClass(mlir::Type resultType,
builder.create<mlir::arith::AndIOp>(loc, intVal,
lowSignificandMask),
zero),
createIntegerConstant(1 << --pos), zero));
createIntegerConstant(1ULL << --pos), zero));

// [h] high-order significand (1 or 2 bits)
index = builder.create<mlir::arith::OrIOp>(
Expand Down
1 change: 1 addition & 0 deletions libcxx/benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ set(BENCHMARK_TESTS
algorithms/make_heap_then_sort_heap.bench.cpp
algorithms/min.bench.cpp
algorithms/min_max_element.bench.cpp
algorithms/mismatch.bench.cpp
algorithms/pop_heap.bench.cpp
algorithms/pstl.stable_sort.bench.cpp
algorithms/push_heap.bench.cpp
Expand Down
31 changes: 31 additions & 0 deletions libcxx/benchmarks/algorithms/mismatch.bench.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include <algorithm>
#include <benchmark/benchmark.h>
#include <random>

// TODO: Look into benchmarking aligned and unaligned memory explicitly
// (currently things happen to be aligned because they are malloced that way)
template <class T>
static void bm_mismatch(benchmark::State& state) {
std::vector<T> vec1(state.range(), '1');
std::vector<T> vec2(state.range(), '1');
std::mt19937_64 rng(std::random_device{}());

vec1.back() = '2';
for (auto _ : state) {
benchmark::DoNotOptimize(vec1);
benchmark::DoNotOptimize(std::mismatch(vec1.begin(), vec1.end(), vec2.begin()));
}
}
BENCHMARK(bm_mismatch<char>)->DenseRange(1, 8)->Range(16, 1 << 20);
BENCHMARK(bm_mismatch<short>)->DenseRange(1, 8)->Range(16, 1 << 20);
BENCHMARK(bm_mismatch<int>)->DenseRange(1, 8)->Range(16, 1 << 20);

BENCHMARK_MAIN();
2 changes: 2 additions & 0 deletions libcxx/docs/ReleaseNotes/19.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Improvements and New Features
- The performance of growing ``std::vector`` has been improved for trivially relocatable types.
- The performance of ``ranges::fill`` and ``ranges::fill_n`` has been improved for ``vector<bool>::iterator``\s,
resulting in a performance increase of up to 1400x.
- The ``std::mismatch`` algorithm has been optimized for integral types, which can lead up to 40x performance
improvements.

Deprecations and Removals
-------------------------
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ set(files
__algorithm/shift_right.h
__algorithm/shuffle.h
__algorithm/sift_down.h
__algorithm/simd_utils.h
__algorithm/sort.h
__algorithm/sort_heap.h
__algorithm/stable_partition.h
Expand Down
82 changes: 77 additions & 5 deletions libcxx/include/__algorithm/mismatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,93 @@
#define _LIBCPP___ALGORITHM_MISMATCH_H

#include <__algorithm/comp.h>
#include <__algorithm/simd_utils.h>
#include <__algorithm/unwrap_iter.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__functional/identity.h>
#include <__type_traits/invoke.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_equality_comparable.h>
#include <__type_traits/operation_traits.h>
#include <__utility/move.h>
#include <__utility/pair.h>
#include <__utility/unreachable.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Iter1, class _Sent1, class _Iter2, class _Pred, class _Proj1, class _Proj2>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter2>
__mismatch_loop(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) {
while (__first1 != __last1) {
if (!std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
break;
++__first1;
++__first2;
}
return std::make_pair(std::move(__first1), std::move(__first2));
}

template <class _Iter1, class _Sent1, class _Iter2, class _Pred, class _Proj1, class _Proj2>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter2>
__mismatch(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) {
return std::__mismatch_loop(__first1, __last1, __first2, __pred, __proj1, __proj2);
}

#if _LIBCPP_VECTORIZE_ALGORITHMS

template <class _Tp,
class _Pred,
class _Proj1,
class _Proj2,
__enable_if_t<is_integral<_Tp>::value && __desugars_to<__equal_tag, _Pred, _Tp, _Tp>::value &&
__is_identity<_Proj1>::value && __is_identity<_Proj2>::value,
int> = 0>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Tp*, _Tp*>
__mismatch(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) {
constexpr size_t __unroll_count = 4;
constexpr size_t __vec_size = __native_vector_size<_Tp>;
using __vec = __simd_vector<_Tp, __vec_size>;
if (!__libcpp_is_constant_evaluated()) {
while (static_cast<size_t>(__last1 - __first1) >= __unroll_count * __vec_size) [[__unlikely__]] {
__vec __lhs[__unroll_count];
__vec __rhs[__unroll_count];

for (size_t __i = 0; __i != __unroll_count; ++__i) {
__lhs[__i] = std::__load_vector<__vec>(__first1 + __i * __vec_size);
__rhs[__i] = std::__load_vector<__vec>(__first2 + __i * __vec_size);
}

for (size_t __i = 0; __i != __unroll_count; ++__i) {
if (auto __cmp_res = __lhs[__i] == __rhs[__i]; !std::__all_of(__cmp_res)) {
auto __offset = __i * __vec_size + std::__find_first_not_set(__cmp_res);
return {__first1 + __offset, __first2 + __offset};
}
}

__first1 += __unroll_count * __vec_size;
__first2 += __unroll_count * __vec_size;
}
}
// TODO: Consider vectorizing the tail
return std::__mismatch_loop(__first1, __last1, __first2, __pred, __proj1, __proj2);
}

#endif // _LIBCPP_VECTORIZE_ALGORITHMS

template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator1, _InputIterator2>
mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) {
for (; __first1 != __last1; ++__first1, (void)++__first2)
if (!__pred(*__first1, *__first2))
break;
return pair<_InputIterator1, _InputIterator2>(__first1, __first2);
__identity __proj;
auto __res = std::__mismatch(
std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2), __pred, __proj, __proj);
return std::make_pair(std::__rewrap_iter(__first1, __res.first), std::__rewrap_iter(__first2, __res.second));
}

template <class _InputIterator1, class _InputIterator2>
Expand Down Expand Up @@ -59,4 +129,6 @@ mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __fi

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP___ALGORITHM_MISMATCH_H
6 changes: 3 additions & 3 deletions libcxx/include/__algorithm/ranges_ends_with.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace ranges {
namespace __ends_with {
struct __fn {
template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Pred, class _Proj1, class _Proj2>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __ends_with_fn_impl_bidirectional(
_LIBCPP_HIDE_FROM_ABI static constexpr bool __ends_with_fn_impl_bidirectional(
_Iter1 __first1,
_Sent1 __last1,
_Iter2 __first2,
Expand All @@ -56,7 +56,7 @@ struct __fn {
}

template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Pred, class _Proj1, class _Proj2>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __ends_with_fn_impl(
_LIBCPP_HIDE_FROM_ABI static constexpr bool __ends_with_fn_impl(
_Iter1 __first1,
_Sent1 __last1,
_Iter2 __first2,
Expand All @@ -65,7 +65,7 @@ struct __fn {
_Proj1& __proj1,
_Proj2& __proj2) {
if constexpr (std::bidirectional_iterator<_Sent1> && std::bidirectional_iterator<_Sent2> &&
(!std::random_access_iterator<_Sent1>)&&(!std::random_access_iterator<_Sent2>)) {
(!std::random_access_iterator<_Sent1>) && (!std::random_access_iterator<_Sent2>)) {
return __ends_with_fn_impl_bidirectional(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2);

} else {
Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/__algorithm/ranges_starts_with.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ struct __fn {
class _Proj1 = identity,
class _Proj2 = identity>
requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr bool operator()(
_Iter1 __first1,
_Sent1 __last1,
_Iter2 __first2,
_Sent2 __last2,
_Pred __pred = {},
_Proj1 __proj1 = {},
_Proj2 __proj2 = {}) const {
_Proj2 __proj2 = {}) {
return __mismatch::__fn::__go(
std::move(__first1),
std::move(__last1),
Expand All @@ -67,8 +67,8 @@ struct __fn {
class _Proj1 = identity,
class _Proj2 = identity>
requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(
_Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr bool
operator()(_Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) {
return __mismatch::__fn::__go(
ranges::begin(__range1),
ranges::end(__range1),
Expand Down
123 changes: 123 additions & 0 deletions libcxx/include/__algorithm/simd_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___ALGORITHM_SIMD_UTILS_H
#define _LIBCPP___ALGORITHM_SIMD_UTILS_H

#include <__bit/bit_cast.h>
#include <__bit/countr.h>
#include <__config>
#include <__type_traits/is_arithmetic.h>
#include <__type_traits/is_same.h>
#include <__utility/integer_sequence.h>
#include <cstddef>
#include <cstdint>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

// TODO: Find out how altivec changes things and allow vectorizations there too.
#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 1700 && !defined(__ALTIVEC__)
# define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 1
#else
# define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 0
#endif

#if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS && !defined(__OPTIMIZE_SIZE__)
# define _LIBCPP_VECTORIZE_ALGORITHMS 1
#else
# define _LIBCPP_VECTORIZE_ALGORITHMS 0
#endif

#if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS

_LIBCPP_BEGIN_NAMESPACE_STD

// This isn't specialized for 64 byte vectors on purpose. They have the potential to significantly reduce performance
// in mixed simd/non-simd workloads and don't provide any performance improvement for currently vectorized algorithms
// as far as benchmarks are concerned.
# if defined(__AVX__)
template <class _Tp>
inline constexpr size_t __native_vector_size = 32 / sizeof(_Tp);
# elif defined(__SSE__) || defined(__ARM_NEON__)
template <class _Tp>
inline constexpr size_t __native_vector_size = 16 / sizeof(_Tp);
# elif defined(__MMX__)
template <class _Tp>
inline constexpr size_t __native_vector_size = 8 / sizeof(_Tp);
# else
template <class _Tp>
inline constexpr size_t __native_vector_size = 1;
# endif

template <class _ArithmeticT, size_t _Np>
using __simd_vector __attribute__((__ext_vector_type__(_Np))) = _ArithmeticT;

template <class _VecT>
inline constexpr size_t __simd_vector_size_v = []<bool _False = false>() -> size_t {
static_assert(_False, "Not a vector!");
}();

template <class _Tp, size_t _Np>
inline constexpr size_t __simd_vector_size_v<__simd_vector<_Tp, _Np>> = _Np;

template <class _Tp, size_t _Np>
_LIBCPP_HIDE_FROM_ABI _Tp __simd_vector_underlying_type_impl(__simd_vector<_Tp, _Np>) {
return _Tp{};
}

template <class _VecT>
using __simd_vector_underlying_type_t = decltype(std::__simd_vector_underlying_type_impl(_VecT{}));

// This isn't inlined without always_inline when loading chars.
template <class _VecT, class _Tp>
_LIBCPP_NODISCARD _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _VecT __load_vector(const _Tp* __ptr) noexcept {
return [=]<size_t... _Indices>(index_sequence<_Indices...>) _LIBCPP_ALWAYS_INLINE noexcept {
return _VecT{__ptr[_Indices]...};
}(make_index_sequence<__simd_vector_size_v<_VecT>>{});
}

template <class _Tp, size_t _Np>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI bool __all_of(__simd_vector<_Tp, _Np> __vec) noexcept {
return __builtin_reduce_and(__builtin_convertvector(__vec, __simd_vector<bool, _Np>));
}

template <class _Tp, size_t _Np>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI size_t __find_first_set(__simd_vector<_Tp, _Np> __vec) noexcept {
using __mask_vec = __simd_vector<bool, _Np>;

// This has MSan disabled du to https://github.com/llvm/llvm-project/issues/85876
auto __impl = [&]<class _MaskT>(_MaskT) _LIBCPP_NO_SANITIZE("memory") noexcept {
return std::__countr_zero(__builtin_bit_cast(_MaskT, __builtin_convertvector(__vec, __mask_vec)));
};

if constexpr (sizeof(__mask_vec) == sizeof(uint8_t)) {
return __impl(uint8_t{});
} else if constexpr (sizeof(__mask_vec) == sizeof(uint16_t)) {
return __impl(uint16_t{});
} else if constexpr (sizeof(__mask_vec) == sizeof(uint32_t)) {
return __impl(uint32_t{});
} else if constexpr (sizeof(__mask_vec) == sizeof(uint64_t)) {
return __impl(uint64_t{});
} else {
static_assert(sizeof(__mask_vec) == 0, "unexpected required size for mask integer type");
return 0;
}
}

template <class _Tp, size_t _Np>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI size_t __find_first_not_set(__simd_vector<_Tp, _Np> __vec) noexcept {
return std::__find_first_set(~__vec);
}

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS

#endif // _LIBCPP___ALGORITHM_SIMD_UTILS_H
9 changes: 9 additions & 0 deletions libcxx/include/__bit/bit_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@

_LIBCPP_BEGIN_NAMESPACE_STD

#ifndef _LIBCPP_CXX03_LANG

template <class _ToType, class _FromType>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI constexpr _ToType __bit_cast(const _FromType& __from) noexcept {
return __builtin_bit_cast(_ToType, __from);
}

#endif // _LIBCPP_CXX03_LANG

#if _LIBCPP_STD_VER >= 20

template <class _ToType, class _FromType>
Expand Down
13 changes: 9 additions & 4 deletions libcxx/include/__bit/countr.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ct
return __builtin_ctzll(__x);
}

#if _LIBCPP_STD_VER >= 20

template <__libcpp_unsigned_integer _Tp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) noexcept {
template <class _Tp>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero(_Tp __t) _NOEXCEPT {
if (__t == 0)
return numeric_limits<_Tp>::digits;

Expand All @@ -59,6 +57,13 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) n
}
}

#if _LIBCPP_STD_VER >= 20

template <__libcpp_unsigned_integer _Tp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) noexcept {
return std::__countr_zero(__t);
}

template <__libcpp_unsigned_integer _Tp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr int countr_one(_Tp __t) noexcept {
return __t != numeric_limits<_Tp>::max() ? std::countr_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits;
Expand Down
34 changes: 23 additions & 11 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -838,21 +838,33 @@ typedef __char32_t char32_t;
# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++2b-extensions")
#endif

// Clang modules take a significant compile time hit when pushing and popping diagnostics.
// Since all the headers are marked as system headers in the modulemap, we can simply disable this
// pushing and popping when building with clang modules.
# if !__has_feature(modules)
# define _LIBCPP_PUSH_EXTENSION_DIAGNOSTICS \
_LIBCPP_DIAGNOSTIC_PUSH \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++11-extensions") \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION \
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++23-extensions")
# define _LIBCPP_POP_EXTENSION_DIAGNOSTICS _LIBCPP_DIAGNOSTIC_POP
# else
# define _LIBCPP_PUSH_EXTENSION_DIAGNOSTICS
# define _LIBCPP_POP_EXTENSION_DIAGNOSTICS
# endif

// Inline namespaces are available in Clang/GCC/MSVC regardless of C++ dialect.
// clang-format off
# define _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_DIAGNOSTIC_PUSH \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++11-extensions") \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION \
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++23-extensions") \
# define _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_PUSH_EXTENSION_DIAGNOSTICS \
namespace _LIBCPP_TYPE_VISIBILITY_DEFAULT std { \
inline namespace _LIBCPP_ABI_NAMESPACE {
# define _LIBCPP_END_NAMESPACE_STD }} _LIBCPP_DIAGNOSTIC_POP
# define _LIBCPP_END_NAMESPACE_STD }} _LIBCPP_POP_EXTENSION_DIAGNOSTICS

# define _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM _LIBCPP_BEGIN_NAMESPACE_STD \
inline namespace __fs { namespace filesystem {
Expand Down
16 changes: 8 additions & 8 deletions libcxx/include/__ranges/as_rvalue_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,18 @@ namespace views {
namespace __as_rvalue {
struct __fn : __range_adaptor_closure<__fn> {
template <class _Range>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
noexcept(noexcept(/**/ as_rvalue_view(std::forward<_Range>(__range))))
-> decltype(/*--*/ as_rvalue_view(std::forward<_Range>(__range))) {
return /*-------------*/ as_rvalue_view(std::forward<_Range>(__range));
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto
operator()(_Range&& __range) noexcept(noexcept(as_rvalue_view(std::forward<_Range>(__range))))
-> decltype(/*--------------------------*/ as_rvalue_view(std::forward<_Range>(__range))) {
return /*---------------------------------*/ as_rvalue_view(std::forward<_Range>(__range));
}

template <class _Range>
requires same_as<range_rvalue_reference_t<_Range>, range_reference_t<_Range>>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
noexcept(noexcept(/**/ views::all(std::forward<_Range>(__range))))
-> decltype(/*--*/ views::all(std::forward<_Range>(__range))) {
return /*-------------*/ views::all(std::forward<_Range>(__range));
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto
operator()(_Range&& __range) noexcept(noexcept(views::all(std::forward<_Range>(__range))))
-> decltype(/*--------------------------*/ views::all(std::forward<_Range>(__range))) {
return /*---------------------------------*/ views::all(std::forward<_Range>(__range));
}
};
} // namespace __as_rvalue
Expand Down
5 changes: 2 additions & 3 deletions libcxx/include/__ranges/repeat_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,13 @@ namespace views {
namespace __repeat {
struct __fn {
template <class _Tp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __value) const
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Tp&& __value)
noexcept(noexcept(ranges::repeat_view(std::forward<_Tp>(__value))))
-> decltype( ranges::repeat_view(std::forward<_Tp>(__value)))
{ return ranges::repeat_view(std::forward<_Tp>(__value)); }


template <class _Tp, class _Bound>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __value, _Bound&& __bound_sentinel) const
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Tp&& __value, _Bound&& __bound_sentinel)
noexcept(noexcept(ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel))))
-> decltype( ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel)))
{ return ranges::repeat_view(std::forward<_Tp>(__value), std::forward<_Bound>(__bound_sentinel)); }
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__ranges/to.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto to(_Args&&... __args)
static_assert(
!is_volatile_v<_Container>, "The target container cannot be volatile-qualified, please remove the volatile");

auto __to_func = []<input_range _Range, class... _Tail>(_Range&& __range, _Tail&&... __tail)
auto __to_func = []<input_range _Range, class... _Tail>(_Range&& __range, _Tail&&... __tail) static
requires requires { //
/**/ ranges::to<_Container>(std::forward<_Range>(__range), std::forward<_Tail>(__tail)...);
}
Expand All @@ -223,7 +223,7 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto to(_Args&&... __args)
// clang-format off
auto __to_func = []<input_range _Range, class... _Tail,
class _DeducedExpr = typename _Deducer<_Container, _Range, _Tail...>::type>
(_Range&& __range, _Tail&& ... __tail)
(_Range&& __range, _Tail&& ... __tail) static
requires requires { //
/**/ ranges::to<_DeducedExpr>(std::forward<_Range>(__range), std::forward<_Tail>(__tail)...);
}
Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/__ranges/zip_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -489,12 +489,12 @@ namespace views {
namespace __zip {

struct __fn {
_LIBCPP_HIDE_FROM_ABI constexpr auto operator()() const noexcept { return empty_view<tuple<>>{}; }
_LIBCPP_HIDE_FROM_ABI static constexpr auto operator()() noexcept { return empty_view<tuple<>>{}; }

template <class... _Ranges>
_LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ranges&&... __rs) const
noexcept(noexcept(zip_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)))
-> decltype(zip_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)) {
_LIBCPP_HIDE_FROM_ABI static constexpr auto
operator()(_Ranges&&... __rs) noexcept(noexcept(zip_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)))
-> decltype(zip_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)) {
return zip_view<all_t<_Ranges>...>(std::forward<_Ranges>(__rs)...);
}
};
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/libcxx.imp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
{ include: [ "<__algorithm/shift_right.h>", "private", "<algorithm>", "public" ] },
{ include: [ "<__algorithm/shuffle.h>", "private", "<algorithm>", "public" ] },
{ include: [ "<__algorithm/sift_down.h>", "private", "<algorithm>", "public" ] },
{ include: [ "<__algorithm/simd_utils.h>", "private", "<algorithm>", "public" ] },
{ include: [ "<__algorithm/sort.h>", "private", "<algorithm>", "public" ] },
{ include: [ "<__algorithm/sort_heap.h>", "private", "<algorithm>", "public" ] },
{ include: [ "<__algorithm/stable_partition.h>", "private", "<algorithm>", "public" ] },
Expand Down
6 changes: 5 additions & 1 deletion libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,10 @@ module std_private_algorithm_minmax [system
export *
}
module std_private_algorithm_minmax_element [system] { header "__algorithm/minmax_element.h" }
module std_private_algorithm_mismatch [system] { header "__algorithm/mismatch.h" }
module std_private_algorithm_mismatch [system] {
header "__algorithm/mismatch.h"
export std_private_algorithm_simd_utils
}
module std_private_algorithm_move [system] { header "__algorithm/move.h" }
module std_private_algorithm_move_backward [system] { header "__algorithm/move_backward.h" }
module std_private_algorithm_next_permutation [system] { header "__algorithm/next_permutation.h" }
Expand Down Expand Up @@ -1048,6 +1051,7 @@ module std_private_algorithm_sort [system
header "__algorithm/sort.h"
export std_private_debug_utils_strict_weak_ordering_check
}
module std_private_algorithm_simd_utils [system] { header "__algorithm/simd_utils.h" }
module std_private_algorithm_sort_heap [system] { header "__algorithm/sort_heap.h" }
module std_private_algorithm_stable_partition [system] { header "__algorithm/stable_partition.h" }
module std_private_algorithm_stable_sort [system] { header "__algorithm/stable_sort.h" }
Expand Down
214 changes: 154 additions & 60 deletions libcxx/test/std/algorithms/alg.nonmodifying/mismatch/mismatch.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,79 +16,173 @@
// template<InputIterator Iter1, InputIterator Iter2Pred>
// constexpr pair<Iter1, Iter2> // constexpr after c++17
// mismatch(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2); // C++14
//
// template<InputIterator Iter1, InputIterator Iter2,
// Predicate<auto, Iter1::value_type, Iter2::value_type> Pred>
// requires CopyConstructible<Pred>
// constexpr pair<Iter1, Iter2> // constexpr after c++17
// mismatch(Iter1 first1, Iter1 last1, Iter2 first2, Pred pred);
//
// template<InputIterator Iter1, InputIterator Iter2, Predicate Pred>
// constexpr pair<Iter1, Iter2> // constexpr after c++17
// mismatch(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, Pred pred); // C++14

// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=50000000
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=100000000

#include <algorithm>
#include <array>
#include <cassert>
#include <vector>

#include "test_macros.h"
#include "test_iterators.h"

#if TEST_STD_VER > 17
TEST_CONSTEXPR bool test_constexpr() {
int ia[] = {1, 3, 6, 7};
int ib[] = {1, 3};
int ic[] = {1, 3, 5, 7};
typedef cpp17_input_iterator<int*> II;
typedef bidirectional_iterator<int*> BI;

auto p1 = std::mismatch(std::begin(ia), std::end(ia), std::begin(ic));
if (p1.first != ia+2 || p1.second != ic+2)
return false;

auto p2 = std::mismatch(std::begin(ia), std::end(ia), std::begin(ic), std::end(ic));
if (p2.first != ia+2 || p2.second != ic+2)
return false;

auto p3 = std::mismatch(std::begin(ib), std::end(ib), std::begin(ic));
if (p3.first != ib+2 || p3.second != ic+2)
return false;

auto p4 = std::mismatch(std::begin(ib), std::end(ib), std::begin(ic), std::end(ic));
if (p4.first != ib+2 || p4.second != ic+2)
return false;

auto p5 = std::mismatch(II(std::begin(ib)), II(std::end(ib)), II(std::begin(ic)));
if (p5.first != II(ib+2) || p5.second != II(ic+2))
return false;
auto p6 = std::mismatch(BI(std::begin(ib)), BI(std::end(ib)), BI(std::begin(ic)), BI(std::end(ic)));
if (p6.first != BI(ib+2) || p6.second != BI(ic+2))
return false;

return true;
}
#include "type_algorithms.h"

template <class Iter, class Container1, class Container2>
TEST_CONSTEXPR_CXX20 void check(Container1 lhs, Container2 rhs, size_t offset) {
if (lhs.size() == rhs.size()) {
assert(std::mismatch(Iter(lhs.data()), Iter(lhs.data() + lhs.size()), Iter(rhs.data())) ==
std::make_pair(Iter(lhs.data() + offset), Iter(rhs.data() + offset)));

assert(std::mismatch(Iter(lhs.data()),
Iter(lhs.data() + lhs.size()),
Iter(rhs.data()),
std::equal_to<typename Container1::value_type>()) ==
std::make_pair(Iter(lhs.data() + offset), Iter(rhs.data() + offset)));
}

#if TEST_STD_VER >= 14
assert(
std::mismatch(Iter(lhs.data()), Iter(lhs.data() + lhs.size()), Iter(rhs.data()), Iter(rhs.data() + rhs.size())) ==
std::make_pair(Iter(lhs.data() + offset), Iter(rhs.data() + offset)));

assert(std::mismatch(Iter(lhs.data()),
Iter(lhs.data() + lhs.size()),
Iter(rhs.data()),
Iter(rhs.data() + rhs.size()),
std::equal_to<typename Container1::value_type>()) ==
std::make_pair(Iter(lhs.data() + offset), Iter(rhs.data() + offset)));
#endif
}

int main(int, char**)
{
int ia[] = {0, 1, 2, 2, 0, 1, 2, 3};
const unsigned sa = sizeof(ia)/sizeof(ia[0]);
int ib[] = {0, 1, 2, 3, 0, 1, 2, 3};
const unsigned sb = sizeof(ib)/sizeof(ib[0]); ((void)sb); // unused in C++11

typedef cpp17_input_iterator<const int*> II;
typedef random_access_iterator<const int*> RAI;

assert(std::mismatch(II(ia), II(ia + sa), II(ib))
== (std::pair<II, II>(II(ia+3), II(ib+3))));

assert(std::mismatch(RAI(ia), RAI(ia + sa), RAI(ib))
== (std::pair<RAI, RAI>(RAI(ia+3), RAI(ib+3))));

#if TEST_STD_VER > 11 // We have the four iteration version
assert(std::mismatch(II(ia), II(ia + sa), II(ib), II(ib+sb))
== (std::pair<II, II>(II(ia+3), II(ib+3))));
struct NonTrivial {
int i_;

TEST_CONSTEXPR_CXX20 NonTrivial(int i) : i_(i) {}
TEST_CONSTEXPR_CXX20 NonTrivial(NonTrivial&& other) : i_(other.i_) { other.i_ = 0; }

TEST_CONSTEXPR_CXX20 friend bool operator==(const NonTrivial& lhs, const NonTrivial& rhs) { return lhs.i_ == rhs.i_; }
};

struct ModTwoComp {
TEST_CONSTEXPR_CXX20 bool operator()(int lhs, int rhs) { return lhs % 2 == rhs % 2; }
};

template <class Iter>
TEST_CONSTEXPR_CXX20 bool test() {
{ // empty ranges
std::array<int, 0> lhs = {};
std::array<int, 0> rhs = {};
check<Iter>(lhs, rhs, 0);
}

{ // same range without mismatch
std::array<int, 8> lhs = {0, 1, 2, 3, 0, 1, 2, 3};
std::array<int, 8> rhs = {0, 1, 2, 3, 0, 1, 2, 3};
check<Iter>(lhs, rhs, 8);
}

{ // same range with mismatch
std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
std::array<int, 8> rhs = {0, 1, 2, 3, 0, 1, 2, 3};
check<Iter>(lhs, rhs, 3);
}

{ // second range is smaller
std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
std::array<int, 2> rhs = {0, 1};
check<Iter>(lhs, rhs, 2);
}

{ // first range is smaller
std::array<int, 2> lhs = {0, 1};
std::array<int, 8> rhs = {0, 1, 2, 2, 0, 1, 2, 3};
check<Iter>(lhs, rhs, 2);
}

{ // use a custom comparator
std::array<int, 4> lhs = {0, 2, 3, 4};
std::array<int, 4> rhs = {0, 0, 4, 4};
assert(std::mismatch(lhs.data(), lhs.data() + lhs.size(), rhs.data(), ModTwoComp()) ==
std::make_pair(lhs.data() + 2, rhs.data() + 2));
#if TEST_STD_VER >= 14
assert(std::mismatch(lhs.data(), lhs.data() + lhs.size(), rhs.data(), rhs.data() + rhs.size(), ModTwoComp()) ==
std::make_pair(lhs.data() + 2, rhs.data() + 2));
#endif
}

assert(std::mismatch(RAI(ia), RAI(ia + sa), RAI(ib), RAI(ib+sb))
== (std::pair<RAI, RAI>(RAI(ia+3), RAI(ib+3))));
return true;
}

struct Test {
template <class Iter>
TEST_CONSTEXPR_CXX20 void operator()() {
test<Iter>();
}
};

TEST_CONSTEXPR_CXX20 bool test() {
types::for_each(types::cpp17_input_iterator_list<int*>(), Test());

{ // use a non-integer type to also test the general case - all elements match
std::array<NonTrivial, 8> lhs = {1, 2, 3, 4, 5, 6, 7, 8};
std::array<NonTrivial, 8> rhs = {1, 2, 3, 4, 5, 6, 7, 8};
check<NonTrivial*>(std::move(lhs), std::move(rhs), 8);
}

{ // use a non-integer type to also test the general case - not all elements match
std::array<NonTrivial, 8> lhs = {1, 2, 3, 4, 7, 6, 7, 8};
std::array<NonTrivial, 8> rhs = {1, 2, 3, 4, 5, 6, 7, 8};
check<NonTrivial*>(std::move(lhs), std::move(rhs), 4);
}

return true;
}

assert(std::mismatch(II(ia), II(ia + sa), II(ib), II(ib+2))
== (std::pair<II, II>(II(ia+2), II(ib+2))));
int main(int, char**) {
test();
#if TEST_STD_VER >= 20
static_assert(test());
#endif

#if TEST_STD_VER > 17
static_assert(test_constexpr());
#endif
{ // check with a lot of elements to test the vectorization optimization
{
std::vector<char> lhs(256);
std::vector<char> rhs(256);
for (size_t i = 0; i != lhs.size(); ++i) {
lhs[i] = 1;
check<char*>(lhs, rhs, i);
lhs[i] = 0;
rhs[i] = 1;
check<char*>(lhs, rhs, i);
rhs[i] = 0;
}
}

{
std::vector<int> lhs(256);
std::vector<int> rhs(256);
for (size_t i = 0; i != lhs.size(); ++i) {
lhs[i] = 1;
check<int*>(lhs, rhs, i);
lhs[i] = 0;
rhs[i] = 1;
check<int*>(lhs, rhs, i);
rhs[i] = 0;
}
}
}

return 0;
}

This file was deleted.

16 changes: 2 additions & 14 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1285,13 +1285,7 @@ static uint64_t addRelaSz(const RelocationBaseSection &relaDyn) {
// output section. When this occurs we cannot just use the OutputSection
// Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to
// overlap with the [DT_RELA, DT_RELA + DT_RELASZ).
static uint64_t addPltRelSz() {
size_t size = in.relaPlt->getSize();
if (in.relaIplt->getParent() == in.relaPlt->getParent() &&
in.relaIplt->name == in.relaPlt->name)
size += in.relaIplt->getSize();
return size;
}
static uint64_t addPltRelSz() { return in.relaPlt->getSize(); }

// Add remaining entries to complete .dynamic contents.
template <class ELFT>
Expand Down Expand Up @@ -1407,13 +1401,7 @@ DynamicSection<ELFT>::computeContents() {
addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
sizeof(Elf_Relr));
}
// .rel[a].plt section usually consists of two parts, containing plt and
// iplt relocations. It is possible to have only iplt relocations in the
// output. In that case relaPlt is empty and have zero offset, the same offset
// as relaIplt has. And we still want to emit proper dynamic tags for that
// case, so here we always use relaPlt as marker for the beginning of
// .rel[a].plt section.
if (isMain && (in.relaPlt->isNeeded() || in.relaIplt->isNeeded())) {
if (isMain && in.relaPlt->isNeeded()) {
addInSec(DT_JMPREL, *in.relaPlt);
entries.emplace_back(DT_PLTRELSZ, addPltRelSz());
switch (config->emachine) {
Expand Down
12 changes: 6 additions & 6 deletions lld/test/ELF/aarch64-gnu-ifunc-nonpreemptable.s
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ main:
# PIE-EMPTY:
# PIE-NEXT: <myfunc>:
# PIE-NEXT: 10270: adrp x16, 0x30000
# PIE-NEXT: 10274: ldr x17, [x16, #896]
# PIE-NEXT: 10278: add x16, x16, #896
# PIE-NEXT: 1027c: br x17
# PIE-NEXT: ldr x17, [x16, #832]
# PIE-NEXT: add x16, x16, #832
# PIE-NEXT: br x17

# PIE-RELOC: .rela.dyn {
# PIE-RELOC-NEXT: 0x30380 R_AARCH64_IRELATIVE - 0x10260
# PIE-RELOC-NEXT: 0x30340 R_AARCH64_IRELATIVE - 0x10260
# PIE-RELOC-NEXT: }
# PIE-RELOC: Hex dump of section '.got.plt':
# NO-APPLY: 0x00030380 00000000 00000000
# APPLY: 0x00030380 60020100 00000000
# NO-APPLY: 0x00030340 00000000 00000000
# APPLY: 0x00030340 60020100 00000000
# PIE-RELOC-EMPTY:
8 changes: 3 additions & 5 deletions lld/test/ELF/gnu-ifunc-dyntags.s
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@

# CHECK: Name Size VMA
# CHECK: .rela.dyn 00000030 0000000000000248
# CHECK: .got.plt 00000010 00000000000033b0
# CHECK: .got.plt 00000010 0000000000003370

# TAGS: Tag Type Name/Value
# TAGS: 0x0000000000000007 RELA 0x248
# TAGS: 0x0000000000000008 RELASZ 48 (bytes)
# TAGS: 0x0000000000000017 JMPREL 0x0
# TAGS: 0x0000000000000002 PLTRELSZ 0 (bytes)
# TAGS: 0x0000000000000003 PLTGOT 0x33B0
# TAGS: 0x0000000000000014 PLTREL RELA
# TAGS-NOT: JMPREL
# TAGS-NOT: PLTREL

# TAGS: Relocations [
# TAGS-NEXT: Section {{.*}} .rela.dyn {
Expand Down
8 changes: 4 additions & 4 deletions lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
# RUN: llvm-readelf -x .got2 %t | FileCheck --check-prefix=HEX2 %s

# RELOC: .rela.dyn {
# RELOC-NEXT: 0x3024C R_PPC_RELATIVE - 0x101A0
# RELOC-NEXT: 0x30250 R_PPC_IRELATIVE - 0x10188
# RELOC-NEXT: 0x3022C R_PPC_RELATIVE - 0x101A0
# RELOC-NEXT: 0x30230 R_PPC_IRELATIVE - 0x10188
# RELOC-NEXT: }

# SYM: 000101a0 0 FUNC GLOBAL DEFAULT {{.*}} func
# HEX: Hex dump of section '.got2':
# HEX-NEXT: 0x0003024c 00000000 ....
# HEX-NEXT: 0x0003022c 00000000 ....

# HEX2: Hex dump of section '.got2':
# HEX2-NEXT: 0x0003024c 000101a0 ....
# HEX2-NEXT: 0x0003022c 000101a0 ....

.section .got2,"aw"
.long func
Expand Down
20 changes: 10 additions & 10 deletions lld/test/ELF/riscv-ifunc-nonpreemptible.s
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefix=DIS64 %s

# RELOC32: .rela.dyn {
# RELOC32-NEXT: 0x3220 R_RISCV_IRELATIVE - 0x117C
# RELOC32-NEXT: 0x3200 R_RISCV_IRELATIVE - 0x117C
# RELOC32-NEXT: }
# RELOC32-LABEL: Hex dump of section '.got.plt':
# NO-APPLY-RELOC32: 0x00003220 00000000
# APPLY-RELOC32: 0x00003220 7c110000
# NO-APPLY-RELOC32: 0x00003200 00000000
# APPLY-RELOC32: 0x00003200 7c110000
# RELOC32-EMPTY:

# SYM32: 0001190 0 FUNC GLOBAL DEFAULT {{.*}} func
Expand All @@ -30,18 +30,18 @@
# DIS32-NEXT: addi a0, a0, 0x10
# DIS32: Disassembly of section .iplt:
# DIS32: <func>:
## 32-bit: &.got.plt[func]-. = 0x3220-0x1190 = 4096*2+144
## 32-bit: &.got.plt[func]-. = 0x3200-0x1190 = 4096*2+0x70
# DIS32-NEXT: 1190: auipc t3, 0x2
# DIS32-NEXT: lw t3, 0x90(t3)
# DIS32-NEXT: lw t3, 0x70(t3)
# DIS32-NEXT: jalr t1, t3
# DIS32-NEXT: nop

# RELOC64: .rela.dyn {
# RELOC64-NEXT: 0x3380 R_RISCV_IRELATIVE - 0x1260
# RELOC64-NEXT: 0x3340 R_RISCV_IRELATIVE - 0x1260
# RELOC64-NEXT: }
# RELOC64-LABEL: Hex dump of section '.got.plt':
# NO-APPLY-RELOC64: 0x00003380 00000000 00000000
# APPLY-RELOC64: 0x00003380 60120000 00000000
# NO-APPLY-RELOC64: 0x00003340 00000000 00000000
# APPLY-RELOC64: 0x00003340 60120000 00000000
# RELOC64-EMPTY:

# SYM64: 000000000001270 0 FUNC GLOBAL DEFAULT {{.*}} func
Expand All @@ -51,9 +51,9 @@
# DIS64-NEXT: addi a0, a0, 0xc
# DIS64: Disassembly of section .iplt:
# DIS64: <func>:
## 64-bit: &.got.plt[func]-. = 0x3380-0x1270 = 4096*2+272
## 64-bit: &.got.plt[func]-. = 0x3340-0x1270 = 4096*2+0xd0
# DIS64-NEXT: 1270: auipc t3, 0x2
# DIS64-NEXT: ld t3, 0x110(t3)
# DIS64-NEXT: ld t3, 0xd0(t3)
# DIS64-NEXT: jalr t1, t3
# DIS64-NEXT: nop

Expand Down
33 changes: 1 addition & 32 deletions lldb/packages/Python/lldbsuite/test/make/Makefile.rules
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ LLDB_BASE_DIR := $(THIS_FILE_DIR)/../../../../../
#
# GNUWin32 uname gives "windows32" or "server version windows32" while
# some versions of MSYS uname return "MSYS_NT*", but most environments
# standardize on "Windows_NT", so we'll make it consistent here.
# standardize on "Windows_NT", so we'll make it consistent here.
# When running tests from Visual Studio, the environment variable isn't
# inherited all the way down to the process spawned for make.
#----------------------------------------------------------------------
Expand Down Expand Up @@ -210,12 +210,6 @@ else
ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES"
DSYM = $(EXE).debug
endif

ifeq "$(MAKE_DWP)" "YES"
MAKE_DWO := YES
DWP_NAME = $(EXE).dwp
DYLIB_DWP_NAME = $(DYLIB_NAME).dwp
endif
endif

LIMIT_DEBUG_INFO_FLAGS =
Expand Down Expand Up @@ -363,7 +357,6 @@ ifneq "$(OS)" "Darwin"

OBJCOPY ?= $(call replace_cc_with,objcopy)
ARCHIVER ?= $(call replace_cc_with,ar)
DWP ?= $(call replace_cc_with,dwp)
override AR = $(ARCHIVER)
endif

Expand Down Expand Up @@ -534,10 +527,6 @@ ifneq "$(CXX)" ""
endif
endif

ifeq "$(GEN_GNU_BUILD_ID)" "YES"
LDFLAGS += -Wl,--build-id
endif

#----------------------------------------------------------------------
# DYLIB_ONLY variable can be used to skip the building of a.out.
# See the sections below regarding dSYM file as well as the building of
Expand Down Expand Up @@ -576,25 +565,11 @@ else
endif
else
ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES"
ifeq "$(SAVE_FULL_DEBUG_BINARY)" "YES"
cp "$(EXE)" "$(EXE).full"
endif
$(OBJCOPY) --only-keep-debug "$(EXE)" "$(DSYM)"
$(OBJCOPY) --strip-debug --add-gnu-debuglink="$(DSYM)" "$(EXE)" "$(EXE)"
endif
ifeq "$(MAKE_DWP)" "YES"
$(DWP) -o "$(DWP_NAME)" $(DWOS)
endif
endif


#----------------------------------------------------------------------
# Support emitting the content of the GNU build-id into a file
# This needs to be used in conjunction with GEN_GNU_BUILD_ID := YES
#----------------------------------------------------------------------
$(EXE).uuid : $(EXE)
$(OBJCOPY) --dump-section=.note.gnu.build-id=$@ $<

#----------------------------------------------------------------------
# Make the dylib
#----------------------------------------------------------------------
Expand Down Expand Up @@ -635,15 +610,9 @@ endif
else
$(LD) $(DYLIB_OBJECTS) $(LDFLAGS) -shared -o "$(DYLIB_FILENAME)"
ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES"
ifeq "$(SAVE_FULL_DEBUG_BINARY)" "YES"
cp "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME).full"
endif
$(OBJCOPY) --only-keep-debug "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME).debug"
$(OBJCOPY) --strip-debug --add-gnu-debuglink="$(DYLIB_FILENAME).debug" "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME)"
endif
ifeq "$(MAKE_DWP)" "YES"
$(DWP) -o $(DYLIB_DWP_FILE) $(DYLIB_DWOS)
endif
endif

#----------------------------------------------------------------------
Expand Down
38 changes: 13 additions & 25 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4377,38 +4377,26 @@ const std::shared_ptr<SymbolFileDWARFDwo> &SymbolFileDWARF::GetDwpSymbolFile() {
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
ModuleSpec module_spec;
module_spec.GetFileSpec() = m_objfile_sp->GetFileSpec();
FileSpec dwp_filespec;
for (const auto &symfile : symfiles.files()) {
module_spec.GetSymbolFileSpec() =
FileSpec(symfile.GetPath() + ".dwp", symfile.GetPathStyle());
LLDB_LOG(log, "Searching for DWP using: \"{0}\"",
module_spec.GetSymbolFileSpec());
dwp_filespec =
FileSpec dwp_filespec =
PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (FileSystem::Instance().Exists(dwp_filespec)) {
break;
}
}
if (!FileSystem::Instance().Exists(dwp_filespec)) {
LLDB_LOG(log, "No DWP file found locally");
// Fill in the UUID for the module we're trying to match for, so we can
// find the correct DWP file, as the Debuginfod plugin uses *only* this
// data to correctly match the DWP file with the binary.
module_spec.GetUUID() = m_objfile_sp->GetUUID();
dwp_filespec =
PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
}
if (FileSystem::Instance().Exists(dwp_filespec)) {
LLDB_LOG(log, "Found DWP file: \"{0}\"", dwp_filespec);
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
GetObjectFile()->GetModule(), &dwp_filespec, 0,
FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp,
dwp_file_data_offset);
if (dwp_obj_file) {
m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>(
*this, dwp_obj_file, DIERef::k_file_index_mask);
LLDB_LOG(log, "Found DWP file: \"{0}\"", dwp_filespec);
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
GetObjectFile()->GetModule(), &dwp_filespec, 0,
FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp,
dwp_file_data_offset);
if (dwp_obj_file) {
m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>(
*this, dwp_obj_file, DIERef::k_file_index_mask);
break;
}
}
}
if (!m_dwp_symfile) {
Expand Down
7 changes: 1 addition & 6 deletions lldb/source/Plugins/SymbolLocator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
# Order matters here: the first symbol locator prevents further searching.
# For DWARF binaries that are both stripped and split, the Default plugin
# will return the stripped binary when asked for the ObjectFile, which then
# prevents an unstripped binary from being requested from the Debuginfod
# provider.
add_subdirectory(Debuginfod)
add_subdirectory(Default)
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
add_subdirectory(DebugSymbols)
endif()
add_subdirectory(Debuginfod)
30 changes: 2 additions & 28 deletions lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,6 @@ llvm::StringRef SymbolVendorELF::GetPluginDescriptionStatic() {
"executables.";
}

// If this is needed elsewhere, it can be exported/moved.
static bool IsDwpSymbolFile(const lldb::ModuleSP &module_sp,
const FileSpec &file_spec) {
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
// Try to create an ObjectFile from the file_spec.
ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
module_sp, &file_spec, 0, FileSystem::Instance().GetByteSize(file_spec),
dwp_file_data_sp, dwp_file_data_offset);
if (!dwp_obj_file || !ObjectFileELF::classof(dwp_obj_file.get()))
return false;
// The presence of a debug_cu_index section is the key identifying feature of
// a DWP file. Make sure we don't fill in the section list on dwp_obj_file
// (by calling GetSectionList(false)) as this is invoked before we may have
// all the symbol files collected and available.
return dwp_obj_file && dwp_obj_file->GetSectionList(false)->FindSectionByType(
eSectionTypeDWARFDebugCuIndex, false);
}

// CreateInstance
//
// Platforms can register a callback to use when creating symbol vendors to
Expand Down Expand Up @@ -106,15 +87,8 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp,
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec dsym_fspec =
PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (!dsym_fspec || IsDwpSymbolFile(module_sp, dsym_fspec)) {
// If we have a stripped binary or if we got a DWP file, we should prefer
// symbols in the executable acquired through a plugin.
ModuleSpec unstripped_spec =
PluginManager::LocateExecutableObjectFile(module_spec);
if (!unstripped_spec)
return nullptr;
dsym_fspec = unstripped_spec.GetFileSpec();
}
if (!dsym_fspec)
return nullptr;

DataBufferSP dsym_file_data_sp;
lldb::offset_t dsym_file_data_offset = 0;
Expand Down
25 changes: 0 additions & 25 deletions lldb/test/API/debuginfod/Normal/Makefile

This file was deleted.

Loading