2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/NetBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}

Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_s, options::OPT_t, options::OPT_r});
options::OPT_s, options::OPT_t});
ToolChain.AddFilePathLibArgs(Args, CmdArgs);

bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/OpenBSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,

Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
options::OPT_t, options::OPT_r});
Args.addAllArgs(CmdArgs,
{options::OPT_T_Group, options::OPT_s, options::OPT_t});

if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,8 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--lto=full");
}

Args.addAllArgs(CmdArgs,
{options::OPT_L, options::OPT_T_Group, options::OPT_s,
options::OPT_t, options::OPT_r});
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
options::OPT_s, options::OPT_t});

if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Driver/ToolChains/Solaris.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,

ToolChain.AddFilePathLibArgs(Args, CmdArgs);

Args.addAllArgs(CmdArgs,
{options::OPT_L, options::OPT_T_Group, options::OPT_r});
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group});

bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -821,8 +821,8 @@ struct FormatToken {

/// Returns whether the token is the left square bracket of a C++
/// structured binding declaration.
bool isCppStructuredBinding(const FormatStyle &Style) const {
if (!Style.isCpp() || isNot(tok::l_square))
bool isCppStructuredBinding(bool IsCpp) const {
if (!IsCpp || isNot(tok::l_square))
return false;
const FormatToken *T = this;
do {
Expand Down
39 changes: 18 additions & 21 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class AnnotatingParser {
const AdditionalKeywords &Keywords,
SmallVector<ScopeType> &Scopes)
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
Keywords(Keywords), Scopes(Scopes) {
IsCpp(Style.isCpp()), Keywords(Keywords), Scopes(Scopes) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata();
}
Expand Down Expand Up @@ -676,26 +676,25 @@ class AnnotatingParser {
// In C++, this can happen either in array of templates (foo<int>[10])
// or when array is a nested template type (unique_ptr<type1<type2>[]>).
bool CppArrayTemplates =
Style.isCpp() && Parent && Parent->is(TT_TemplateCloser) &&
IsCpp && Parent && Parent->is(TT_TemplateCloser) &&
(Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
Contexts.back().ContextType == Context::TemplateArgument);

const bool IsInnerSquare = Contexts.back().InCpp11AttributeSpecifier;
const bool IsCpp11AttributeSpecifier =
isCppAttribute(Style.isCpp(), *Left) || IsInnerSquare;
isCppAttribute(IsCpp, *Left) || IsInnerSquare;

// Treat C# Attributes [STAThread] much like C++ attributes [[...]].
bool IsCSharpAttributeSpecifier =
isCSharpAttributeSpecifier(*Left) ||
Contexts.back().InCSharpAttributeSpecifier;

bool InsideInlineASM = Line.startsWith(tok::kw_asm);
bool IsCppStructuredBinding = Left->isCppStructuredBinding(Style);
bool IsCppStructuredBinding = Left->isCppStructuredBinding(IsCpp);
bool StartsObjCMethodExpr =
!IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
Style.isCpp() && !IsCpp11AttributeSpecifier &&
!IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression &&
Left->isNot(TT_LambdaLSquare) &&
IsCpp && !IsCpp11AttributeSpecifier && !IsCSharpAttributeSpecifier &&
Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
!CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
(!Parent ||
Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
Expand Down Expand Up @@ -723,7 +722,7 @@ class AnnotatingParser {
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->setType(TT_JsComputedPropertyName);
} else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
} else if (IsCpp && Contexts.back().ContextKind == tok::l_brace &&
Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->setType(TT_DesignatedInitializerLSquare);
} else if (IsCSharpAttributeSpecifier) {
Expand Down Expand Up @@ -1161,7 +1160,7 @@ class AnnotatingParser {
if (Previous->is(TT_JsTypeOptionalQuestion))
Previous = Previous->getPreviousNonComment();
if ((CurrentToken->is(tok::colon) && !Style.isTableGen() &&
(!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
(!Contexts.back().ColonIsDictLiteral || !IsCpp)) ||
Style.isProto()) {
OpeningBrace.setType(TT_DictLiteral);
if (Previous->Tok.getIdentifierInfo() ||
Expand Down Expand Up @@ -1230,7 +1229,7 @@ class AnnotatingParser {
}

bool consumeToken() {
if (Style.isCpp()) {
if (IsCpp) {
const auto *Prev = CurrentToken->getPreviousNonComment();
if (Prev && Prev->is(tok::r_square) && Prev->is(TT_AttributeSquare) &&
CurrentToken->isOneOf(tok::kw_if, tok::kw_switch, tok::kw_case,
Expand Down Expand Up @@ -1424,7 +1423,7 @@ class AnnotatingParser {
if (CurrentToken && CurrentToken->is(Keywords.kw_await))
next();
}
if (Style.isCpp() && CurrentToken && CurrentToken->is(tok::kw_co_await))
if (IsCpp && CurrentToken && CurrentToken->is(tok::kw_co_await))
next();
Contexts.back().ColonIsForRangeExpr = true;
if (!CurrentToken || CurrentToken->isNot(tok::l_paren))
Expand Down Expand Up @@ -2590,7 +2589,7 @@ class AnnotatingParser {
/// Determine whether '(' is starting a C++ cast.
bool lParenStartsCppCast(const FormatToken &Tok) {
// C-style casts are only used in C++.
if (!Style.isCpp())
if (!IsCpp)
return false;

FormatToken *LeftOfParens = Tok.getPreviousNonComment();
Expand All @@ -2611,10 +2610,8 @@ class AnnotatingParser {
/// Determine whether ')' is ending a cast.
bool rParenEndsCast(const FormatToken &Tok) {
// C-style casts are only used in C++, C# and Java.
if (!Style.isCSharp() && !Style.isCpp() &&
Style.Language != FormatStyle::LK_Java) {
if (!Style.isCSharp() && !IsCpp && Style.Language != FormatStyle::LK_Java)
return false;
}

// Empty parens aren't casts and there are no casts at the end of the line.
if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen)
Expand Down Expand Up @@ -2691,7 +2688,7 @@ class AnnotatingParser {
if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
tok::kw_requires, tok::kw_throw, tok::arrow,
Keywords.kw_override, Keywords.kw_final) ||
isCppAttribute(Style.isCpp(), *Tok.Next)) {
isCppAttribute(IsCpp, *Tok.Next)) {
return false;
}

Expand Down Expand Up @@ -3012,6 +3009,7 @@ class AnnotatingParser {
AnnotatedLine &Line;
FormatToken *CurrentToken;
bool AutoFound;
bool IsCpp;
const AdditionalKeywords &Keywords;

SmallVector<ScopeType> &Scopes;
Expand Down Expand Up @@ -3559,7 +3557,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
ExpressionParser ExprParser(Style, Keywords, Line);
ExprParser.parse();

if (Style.isCpp()) {
if (IsCpp) {
auto *Tok = getFunctionName(Line);
if (Tok && ((!Scopes.empty() && Scopes.back() == ST_Class) ||
Line.endsWith(TT_FunctionLBrace) || isCtorOrDtorName(Tok))) {
Expand Down Expand Up @@ -3766,7 +3764,6 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
if (AlignArrayOfStructures)
calculateArrayInitializerColumnList(Line);

const bool IsCpp = Style.isCpp();
bool SeenName = false;
bool LineIsFunctionDeclaration = false;
FormatToken *ClosingParen = nullptr;
Expand All @@ -3779,7 +3776,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
AfterLastAttribute = Tok;
if (const bool IsCtorOrDtor = Tok->is(TT_CtorDtorDeclName);
IsCtorOrDtor ||
isFunctionDeclarationName(Style.isCpp(), *Tok, Line, ClosingParen)) {
isFunctionDeclarationName(IsCpp, *Tok, Line, ClosingParen)) {
if (!IsCtorOrDtor)
Tok->setFinalizedType(TT_FunctionDeclarationName);
LineIsFunctionDeclaration = true;
Expand Down Expand Up @@ -4717,7 +4714,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.is(tok::star) && Right.is(tok::comment))
return true;

if (Style.isCpp()) {
if (IsCpp) {
if (Left.is(TT_OverloadedOperator) &&
Right.isOneOf(TT_TemplateOpener, TT_TemplateCloser)) {
return true;
Expand Down Expand Up @@ -5425,7 +5422,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (!Keywords.isVerilogBegin(Right) && Keywords.isVerilogEndOfLabel(Left))
return true;
} else if (Style.BreakAdjacentStringLiterals &&
(Style.isCpp() || Style.isProto() ||
(IsCpp || Style.isProto() ||
Style.Language == FormatStyle::LK_TableGen)) {
if (Left.isStringLiteral() && Right.isStringLiteral())
return true;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/TokenAnnotator.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class AnnotatedLine {
class TokenAnnotator {
public:
TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
: Style(Style), Keywords(Keywords) {}
: Style(Style), IsCpp(Style.isCpp()), Keywords(Keywords) {}

/// Adapts the indent levels of comment lines to the indent of the
/// subsequent line.
Expand Down Expand Up @@ -260,6 +260,8 @@ class TokenAnnotator {

const FormatStyle &Style;

bool IsCpp;

const AdditionalKeywords &Keywords;

SmallVector<ScopeType> Scopes;
Expand Down
43 changes: 21 additions & 22 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ UnwrappedLineParser::UnwrappedLineParser(
llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
IdentifierTable &IdentTable)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
CurrentLines(&Lines), Style(Style), IsCpp(Style.isCpp()),
Keywords(Keywords), CommentPragmasRegex(Style.CommentPragmas),
Tokens(nullptr), Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
? IG_Rejected
: IG_Inited),
Expand Down Expand Up @@ -572,8 +572,8 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
(Style.isJavaScript() &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,
Keywords.kw_as));
ProbablyBracedList = ProbablyBracedList ||
(Style.isCpp() && NextTok->is(tok::l_paren));
ProbablyBracedList =
ProbablyBracedList || (IsCpp && NextTok->is(tok::l_paren));

// If there is a comma, semicolon or right paren after the closing
// brace, we assume this is a braced initializer list.
Expand Down Expand Up @@ -1428,7 +1428,7 @@ void UnwrappedLineParser::parseStructuralElement(
return;
}

if (Style.isCpp()) {
if (IsCpp) {
while (FormatTok->is(tok::l_square) && handleCppAttributes()) {
}
} else if (Style.isVerilog()) {
Expand Down Expand Up @@ -1602,7 +1602,7 @@ void UnwrappedLineParser::parseStructuralElement(
parseJavaScriptEs6ImportExport();
return;
}
if (Style.isCpp()) {
if (IsCpp) {
nextToken();
if (FormatTok->is(tok::kw_namespace)) {
parseNamespace();
Expand Down Expand Up @@ -1646,24 +1646,23 @@ void UnwrappedLineParser::parseStructuralElement(
addUnwrappedLine();
return;
}
if (Style.isCpp() && parseModuleImport())
if (IsCpp && parseModuleImport())
return;
}
if (Style.isCpp() &&
FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
Keywords.kw_slots, Keywords.kw_qslots)) {
if (IsCpp && FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
Keywords.kw_slots, Keywords.kw_qslots)) {
nextToken();
if (FormatTok->is(tok::colon)) {
nextToken();
addUnwrappedLine();
return;
}
}
if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
if (IsCpp && FormatTok->is(TT_StatementMacro)) {
parseStatementMacro();
return;
}
if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) {
if (IsCpp && FormatTok->is(TT_NamespaceMacro)) {
parseNamespace();
return;
}
Expand Down Expand Up @@ -1759,7 +1758,7 @@ void UnwrappedLineParser::parseStructuralElement(
}
break;
case tok::kw_requires: {
if (Style.isCpp()) {
if (IsCpp) {
bool ParsedClause = parseRequires();
if (ParsedClause)
return;
Expand All @@ -1780,7 +1779,7 @@ void UnwrappedLineParser::parseStructuralElement(
if (!parseEnum())
break;
// This only applies to C++ and Verilog.
if (!Style.isCpp() && !Style.isVerilog()) {
if (!IsCpp && !Style.isVerilog()) {
addUnwrappedLine();
return;
}
Expand Down Expand Up @@ -1848,7 +1847,7 @@ void UnwrappedLineParser::parseStructuralElement(
parseParens();
// Break the unwrapped line if a K&R C function definition has a parameter
// declaration.
if (OpeningBrace || !Style.isCpp() || !Previous || eof())
if (OpeningBrace || !IsCpp || !Previous || eof())
break;
if (isC78ParameterDecl(FormatTok,
Tokens->peekNextToken(/*SkipComment=*/true),
Expand Down Expand Up @@ -1977,13 +1976,13 @@ void UnwrappedLineParser::parseStructuralElement(
}
}

if (!Style.isCpp() && FormatTok->is(Keywords.kw_interface)) {
if (!IsCpp && FormatTok->is(Keywords.kw_interface)) {
if (parseStructLike())
return;
break;
}

if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
if (IsCpp && FormatTok->is(TT_StatementMacro)) {
parseStatementMacro();
return;
}
Expand Down Expand Up @@ -2211,7 +2210,7 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() {

bool UnwrappedLineParser::tryToParseLambda() {
assert(FormatTok->is(tok::l_square));
if (!Style.isCpp()) {
if (!IsCpp) {
nextToken();
return false;
}
Expand Down Expand Up @@ -2340,7 +2339,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
!Previous->isOneOf(tok::kw_return, tok::kw_co_await,
tok::kw_co_yield, tok::kw_co_return)) ||
Previous->closesScope())) ||
LeftSquare->isCppStructuredBinding(Style)) {
LeftSquare->isCppStructuredBinding(IsCpp)) {
return false;
}
if (FormatTok->is(tok::l_square) || tok::isLiteral(FormatTok->Tok.getKind()))
Expand Down Expand Up @@ -3153,7 +3152,7 @@ void UnwrappedLineParser::parseForOrWhileLoop(bool HasParens) {
// JS' for await ( ...
if (Style.isJavaScript() && FormatTok->is(Keywords.kw_await))
nextToken();
if (Style.isCpp() && FormatTok->is(tok::kw_co_await))
if (IsCpp && FormatTok->is(tok::kw_co_await))
nextToken();
if (HasParens && FormatTok->is(tok::l_paren)) {
// The type is only set for Verilog basically because we were afraid to
Expand Down Expand Up @@ -3737,7 +3736,7 @@ bool UnwrappedLineParser::parseEnum() {
nextToken();
// If there are two identifiers in a row, this is likely an elaborate
// return type. In Java, this can be "implements", etc.
if (Style.isCpp() && FormatTok->is(tok::identifier))
if (IsCpp && FormatTok->is(tok::identifier))
return false;
}
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ class UnwrappedLineParser {
llvm::BitVector DeclarationScopeStack;

const FormatStyle &Style;
bool IsCpp;
const AdditionalKeywords &Keywords;

llvm::Regex CommentPragmasRegex;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Tooling/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,5 @@ add_clang_library(clangTooling
clangRewrite
clangSerialization
clangToolingCore
${LLVM_PTHREAD_LIB}
)
8 changes: 8 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ namespace strcmp {
static_assert(__builtin_strcmp(kFoobar, kFoobazfoobar + 6) == 0, ""); // both-error {{not an integral constant}} \
// both-note {{dereferenced one-past-the-end}} \
// expected-note {{in call to}}

/// Used to assert because we're passing a dummy pointer to
/// __builtin_strcmp() when evaluating the return statement.
constexpr bool char_memchr_mutable() {
char buffer[] = "mutable";
return __builtin_strcmp(buffer, "mutable") == 0;
}
static_assert(char_memchr_mutable(), "");
}

/// Copied from constant-expression-cxx11.cpp
Expand Down
7 changes: 7 additions & 0 deletions clang/test/AST/Interp/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,3 +1168,10 @@ namespace incdecbool {


}

#if __cplusplus >= 201402L
constexpr int externvar1() { // both-error {{never produces a constant expression}}
extern char arr[]; // both-note {{declared here}}
return arr[0]; // both-note {{read of non-constexpr variable 'arr'}}
}
#endif
40 changes: 40 additions & 0 deletions clang/test/Driver/modules-print-library-module-manifest-path.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Test that -print-library-module-manifest-path finds the correct file.

// FIXME: Enable on all platforms.

// REQUIRES: x86-registered-target

// RUN: rm -rf %t && split-file %s %t && cd %t
// RUN: mkdir -p %t/Inputs/usr/lib/x86_64-linux-gnu
// RUN: touch %t/Inputs/usr/lib/x86_64-linux-gnu/libc++.so

// RUN: %clang -print-library-module-manifest-path \
// RUN: -stdlib=libc++ \
// RUN: --sysroot=%t/Inputs \
// RUN: --target=x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck libcxx-no-module-json.cpp

// RUN: touch %t/Inputs/usr/lib/x86_64-linux-gnu/modules.json
// RUN: %clang -print-library-module-manifest-path \
// RUN: -stdlib=libc++ \
// RUN: --sysroot=%t/Inputs \
// RUN: --target=x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck libcxx.cpp

// RUN: %clang -print-library-module-manifest-path \
// RUN: -stdlib=libstdc++ \
// RUN: --sysroot=%t/Inputs \
// RUN: --target=x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck libstdcxx.cpp

//--- libcxx-no-module-json.cpp

// CHECK: <NOT PRESENT>

//--- libcxx.cpp

// CHECK: {{.*}}/Inputs/usr/lib/x86_64-linux-gnu{{/|\\}}modules.json

//--- libstdcxx.cpp

// CHECK: <NOT PRESENT>
4 changes: 2 additions & 2 deletions compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ static rlim_t getlim(int res) {

static void setlim(int res, rlim_t lim) {
struct rlimit rlim;
if (getrlimit(res, const_cast<struct rlimit *>(&rlim))) {
if (getrlimit(res, &rlim)) {
Report("ERROR: %s getrlimit() failed %d\n", SanitizerToolName, errno);
Die();
}
rlim.rlim_cur = lim;
if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) {
if (setrlimit(res, &rlim)) {
Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
Die();
}
Expand Down
16 changes: 16 additions & 0 deletions compiler-rt/lib/scudo/standalone/checksum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#else
#include <sys/auxv.h>
#endif
#elif defined(__loongarch__)
#include <sys/auxv.h>
#endif

namespace scudo {
Expand Down Expand Up @@ -75,6 +77,20 @@ bool hasHardwareCRC32() {
return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
#endif // SCUDO_FUCHSIA
}
#elif defined(__loongarch__)
// The definition is only pulled in by <sys/auxv.h> since glibc 2.38, so
// supply it if missing.
#ifndef HWCAP_LOONGARCH_CRC32
#define HWCAP_LOONGARCH_CRC32 (1 << 6)
#endif
// Query HWCAP for platform capability, according to *Software Development and
// Build Convention for LoongArch Architectures* v0.1, Section 9.1.
//
// Link:
// https://github.com/loongson/la-softdev-convention/blob/v0.1/la-softdev-convention.adoc#kernel-development
bool hasHardwareCRC32() {
return !!(getauxval(AT_HWCAP) & HWCAP_LOONGARCH_CRC32);
}
#else
// No hardware CRC32 implemented in Scudo for other architectures.
bool hasHardwareCRC32() { return false; }
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/scudo/standalone/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include <arm_acle.h>
#define CRC32_INTRINSIC FIRST_32_SECOND_64(__crc32cw, __crc32cd)
#endif
#ifdef __loongarch__
#include <larchintrin.h>
#define CRC32_INTRINSIC FIRST_32_SECOND_64(__crcc_w_w_w, __crcc_w_d_w)
#endif

namespace scudo {

Expand Down
9 changes: 9 additions & 0 deletions compiler-rt/lib/scudo/standalone/crc32_hw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,13 @@ u32 computeHardwareCRC32(u32 Crc, uptr Data) {
#endif // defined(__CRC32__) || defined(__SSE4_2__) ||
// defined(__ARM_FEATURE_CRC32)

#if defined(__loongarch__)
u32 computeHardwareCRC32(u32 Crc, uptr Data) {
// The LoongArch CRC intrinsics have the two input arguments swapped, and
// expect them to be signed.
return static_cast<u32>(
CRC32_INTRINSIC(static_cast<long>(Data), static_cast<int>(Crc)));
}
#endif // defined(__loongarch__)

} // namespace scudo
54 changes: 34 additions & 20 deletions flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ static void genRuntimeMinMaxlocBody(fir::FirOpBuilder &builder,
unsigned rank, int maskRank,
mlir::Type elementType,
mlir::Type maskElemType,
mlir::Type resultElemTy) {
mlir::Type resultElemTy, bool isDim) {
auto init = [isMax](fir::FirOpBuilder builder, mlir::Location loc,
mlir::Type elementType) {
if (auto ty = elementType.dyn_cast<mlir::FloatType>()) {
Expand Down Expand Up @@ -858,16 +858,27 @@ static void genRuntimeMinMaxlocBody(fir::FirOpBuilder &builder,
maskElemType, resultArr, maskRank == 0);

// Store newly created output array to the reference passed in
fir::SequenceType::Shape resultShape(1, rank);
mlir::Type outputArrTy = fir::SequenceType::get(resultShape, resultElemTy);
mlir::Type outputHeapTy = fir::HeapType::get(outputArrTy);
mlir::Type outputBoxTy = fir::BoxType::get(outputHeapTy);
mlir::Type outputRefTy = builder.getRefType(outputBoxTy);
mlir::Value outputArr = builder.create<fir::ConvertOp>(
loc, outputRefTy, funcOp.front().getArgument(0));

// Store nearly created array to output array
builder.create<fir::StoreOp>(loc, resultArr, outputArr);
if (isDim) {
mlir::Type resultBoxTy =
fir::BoxType::get(fir::HeapType::get(resultElemTy));
mlir::Value outputArr = builder.create<fir::ConvertOp>(
loc, builder.getRefType(resultBoxTy), funcOp.front().getArgument(0));
mlir::Value resultArrScalar = builder.create<fir::ConvertOp>(
loc, fir::HeapType::get(resultElemTy), resultArrInit);
mlir::Value resultBox =
builder.create<fir::EmboxOp>(loc, resultBoxTy, resultArrScalar);
builder.create<fir::StoreOp>(loc, resultBox, outputArr);
} else {
fir::SequenceType::Shape resultShape(1, rank);
mlir::Type outputArrTy = fir::SequenceType::get(resultShape, resultElemTy);
mlir::Type outputHeapTy = fir::HeapType::get(outputArrTy);
mlir::Type outputBoxTy = fir::BoxType::get(outputHeapTy);
mlir::Type outputRefTy = builder.getRefType(outputBoxTy);
mlir::Value outputArr = builder.create<fir::ConvertOp>(
loc, outputRefTy, funcOp.front().getArgument(0));
builder.create<fir::StoreOp>(loc, resultArr, outputArr);
}

builder.create<mlir::func::ReturnOp>(loc);
}

Expand Down Expand Up @@ -1146,11 +1157,14 @@ void SimplifyIntrinsicsPass::simplifyMinMaxlocReduction(

mlir::Operation::operand_range args = call.getArgs();

mlir::Value back = args[6];
mlir::SymbolRefAttr callee = call.getCalleeAttr();
mlir::StringRef funcNameBase = callee.getLeafReference().getValue();
bool isDim = funcNameBase.ends_with("Dim");
mlir::Value back = args[isDim ? 7 : 6];
if (isTrueOrNotConstant(back))
return;

mlir::Value mask = args[5];
mlir::Value mask = args[isDim ? 6 : 5];
mlir::Value maskDef = findMaskDef(mask);

// maskDef is set to NULL when the defining op is not one we accept.
Expand All @@ -1159,10 +1173,8 @@ void SimplifyIntrinsicsPass::simplifyMinMaxlocReduction(
if (maskDef == NULL)
return;

mlir::SymbolRefAttr callee = call.getCalleeAttr();
mlir::StringRef funcNameBase = callee.getLeafReference().getValue();
unsigned rank = getDimCount(args[1]);
if (funcNameBase.ends_with("Dim") || !(rank > 0))
if ((isDim && rank != 1) || !(rank > 0))
return;

fir::FirOpBuilder builder{getSimplificationBuilder(call, kindMap)};
Expand Down Expand Up @@ -1203,22 +1215,24 @@ void SimplifyIntrinsicsPass::simplifyMinMaxlocReduction(

llvm::raw_string_ostream nameOS(funcName);
outType.print(nameOS);
if (isDim)
nameOS << '_' << inputType;
nameOS << '_' << fmfString;

auto typeGenerator = [rank](fir::FirOpBuilder &builder) {
return genRuntimeMinlocType(builder, rank);
};
auto bodyGenerator = [rank, maskRank, inputType, logicalElemType, outType,
isMax](fir::FirOpBuilder &builder,
mlir::func::FuncOp &funcOp) {
isMax, isDim](fir::FirOpBuilder &builder,
mlir::func::FuncOp &funcOp) {
genRuntimeMinMaxlocBody(builder, funcOp, isMax, rank, maskRank, inputType,
logicalElemType, outType);
logicalElemType, outType, isDim);
};

mlir::func::FuncOp newFunc =
getOrCreateFunction(builder, funcName, typeGenerator, bodyGenerator);
builder.create<fir::CallOp>(loc, newFunc,
mlir::ValueRange{args[0], args[1], args[5]});
mlir::ValueRange{args[0], args[1], mask});
call->dropAllReferences();
call->erase();
}
Expand Down
65 changes: 58 additions & 7 deletions flang/test/Transforms/simplifyintrinsics.fir
Original file line number Diff line number Diff line change
Expand Up @@ -2098,13 +2098,13 @@ func.func @_QPtestminloc_doesntwork1d_back(%arg0: !fir.ref<!fir.array<10xi32>> {
// CHECK-NOT: fir.call @_FortranAMinlocInteger4x1_i32_contract_simplified({{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.box<none>) -> ()

// -----
// Check Minloc is not simplified when DIM arg is set
// Check Minloc is simplified when DIM arg is set so long as the result is scalar

func.func @_QPtestminloc_doesntwork1d_dim(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "a"}) -> !fir.array<1xi32> {
func.func @_QPtestminloc_1d_dim(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "a"}) -> !fir.array<1xi32> {
%0 = fir.alloca !fir.box<!fir.heap<i32>>
%c10 = arith.constant 10 : index
%c1 = arith.constant 1 : index
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testminloc_doesntwork1d_dim", uniq_name = "_QFtestminloc_doesntwork1d_dimEtestminloc_doesntwork1d_dim"}
%1 = fir.alloca !fir.array<1xi32> {bindc_name = "testminloc_1d_dim", uniq_name = "_QFtestminloc_1d_dimEtestminloc_1d_dim"}
%2 = fir.shape %c1 : (index) -> !fir.shape<1>
%3 = fir.array_load %1(%2) : (!fir.ref<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.array<1xi32>
%4 = fir.shape %c10 : (index) -> !fir.shape<1>
Expand Down Expand Up @@ -2139,11 +2139,62 @@ func.func @_QPtestminloc_doesntwork1d_dim(%arg0: !fir.ref<!fir.array<10xi32>> {f
%21 = fir.load %1 : !fir.ref<!fir.array<1xi32>>
return %21 : !fir.array<1xi32>
}
// CHECK-LABEL: func.func @_QPtestminloc_doesntwork1d_dim(
// CHECK-LABEL: func.func @_QPtestminloc_1d_dim(
// CHECK-SAME: %[[ARR:.*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "a"}) -> !fir.array<1xi32> {
// CHECK-NOT: fir.call @_FortranAMinlocDimx1_i32_contract_simplified({{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.box<none>) -> ()
// CHECK: fir.call @_FortranAMinlocDim({{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, i32, i32, !fir.ref<i8>, i32, !fir.box<none>, i1) -> none
// CHECK-NOT: fir.call @_FortranAMinlocDimx1_i32_contract_simplified({{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.box<none>) -> ()
// CHECK: fir.call @_FortranAMinlocDimx1_i32_i32_contract_simplified({{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.box<none>) -> ()

// CHECK-LABEL: func.func private @_FortranAMinlocDimx1_i32_i32_contract_simplified(%arg0: !fir.ref<!fir.box<none>>, %arg1: !fir.box<none>, %arg2: !fir.box<none>) attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
// CHECK-NEXT: %[[V0:.*]] = fir.alloca i32
// CHECK-NEXT: %c0_i32 = arith.constant 0 : i32
// CHECK-NEXT: %c1 = arith.constant 1 : index
// CHECK-NEXT: %[[V1:.*]] = fir.allocmem !fir.array<1xi32>
// CHECK-NEXT: %[[V2:.*]] = fir.shape %c1 : (index) -> !fir.shape<1>
// CHECK-NEXT: %[[V3:.*]] = fir.embox %[[V1]](%[[V2]]) : (!fir.heap<!fir.array<1xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<1xi32>>>
// CHECK-NEXT: %c0 = arith.constant 0 : index
// CHECK-NEXT: %[[V4:.*]] = fir.coordinate_of %[[V3]], %c0 : (!fir.box<!fir.heap<!fir.array<1xi32>>>, index) -> !fir.ref<i32>
// CHECK-NEXT: fir.store %c0_i32 to %[[V4]] : !fir.ref<i32>
// CHECK-NEXT: %c0_0 = arith.constant 0 : index
// CHECK-NEXT: %[[V5:.*]] = fir.convert %arg1 : (!fir.box<none>) -> !fir.box<!fir.array<?xi32>>
// CHECK-NEXT: %c1_i32 = arith.constant 1 : i32
// CHECK-NEXT: %c0_i32_1 = arith.constant 0 : i32
// CHECK-NEXT: fir.store %c0_i32_1 to %[[V0]] : !fir.ref<i32>
// CHECK-NEXT: %c2147483647_i32 = arith.constant 2147483647 : i32
// CHECK-NEXT: %c1_2 = arith.constant 1 : index
// CHECK-NEXT: %c0_3 = arith.constant 0 : index
// CHECK-NEXT: %[[V6:.*]]:3 = fir.box_dims %[[V5]], %c0_3 : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
// CHECK-NEXT: %[[V7:.*]] = arith.subi %[[V6]]#1, %c1_2 : index
// CHECK-NEXT: %[[V8:.*]] = fir.do_loop %arg3 = %c0_0 to %[[V7]] step %c1_2 iter_args(%arg4 = %c2147483647_i32) -> (i32) {
// CHECK-NEXT: %c1_i32_4 = arith.constant 1 : i32
// CHECK-NEXT: %[[ISFIRST:.*]] = fir.load %[[FLAG_ALLOC]] : !fir.ref<i32>
// CHECK-NEXT: %[[V12:.*]] = fir.coordinate_of %[[V5]], %arg3 : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
// CHECK-NEXT: %[[V13:.*]] = fir.load %[[V12]] : !fir.ref<i32>
// CHECK-NEXT: %[[V14:.*]] = arith.cmpi slt, %[[V13]], %arg4 : i32
// CHECK-NEXT: %[[ISFIRSTL:.*]] = fir.convert %[[ISFIRST]] : (i32) -> i1
// CHECK-NEXT: %true = arith.constant true
// CHECK-NEXT: %[[ISFIRSTNOT:.*]] = arith.xori %[[ISFIRSTL]], %true : i1
// CHECK-NEXT: %[[ORCOND:.*]] = arith.ori %[[V14]], %[[ISFIRSTNOT]] : i1
// CHECK-NEXT: %[[V15:.*]] = fir.if %[[ORCOND]] -> (i32) {
// CHECK-NEXT: fir.store %c1_i32_4 to %[[V0]] : !fir.ref<i32>
// CHECK-NEXT: %c1_i32_5 = arith.constant 1 : i32
// CHECK-NEXT: %c0_6 = arith.constant 0 : index
// CHECK-NEXT: %[[V16:.*]] = fir.coordinate_of %[[V3]], %c0_6 : (!fir.box<!fir.heap<!fir.array<1xi32>>>, index) -> !fir.ref<i32>
// CHECK-NEXT: %[[V17:.*]] = fir.convert %arg3 : (index) -> i32
// CHECK-NEXT: %[[V18:.*]] = arith.addi %[[V17]], %c1_i32_5 : i32
// CHECK-NEXT: fir.store %[[V18]] to %[[V16]] : !fir.ref<i32>
// CHECK-NEXT: fir.result %[[V13]] : i32
// CHECK-NEXT: } else {
// CHECK-NEXT: fir.result %arg4 : i32
// CHECK-NEXT: }
// CHECK-NEXT: fir.result %[[V15]] : i32
// CHECK-NEXT: }
// CHECK-NEXT: %[[V11:.*]] = fir.convert %arg0 : (!fir.ref<!fir.box<none>>) -> !fir.ref<!fir.box<!fir.heap<i32>>>
// CHECK-NEXT: %[[V12:.*]] = fir.convert %[[V1]] : (!fir.heap<!fir.array<1xi32>>) -> !fir.heap<i32>
// CHECK-NEXT: %[[V13:.*]] = fir.embox %[[V12]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
// CHECK-NEXT: fir.store %[[V13]] to %[[V11]] : !fir.ref<!fir.box<!fir.heap<i32>>>
// CHECK-NEXT: return
// CHECK-NEXT: }



// -----
// Check Minloc is not simplified when dimension of inputArr is unknown
Expand Down
1 change: 1 addition & 0 deletions libc/cmake/modules/LLVMLibCHeaderRules.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ function(add_gen_header target_name)

if(LIBC_TARGET_OS_IS_GPU)
file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/llvm-libc-decls)
file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/llvm-libc-decls/gpu)
set(decl_out_file ${LIBC_INCLUDE_DIR}/llvm-libc-decls/${relative_path})
add_custom_command(
OUTPUT ${decl_out_file}
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ set(files
__fwd/bit_reference.h
__fwd/complex.h
__fwd/fstream.h
__fwd/hash.h
__fwd/functional.h
__fwd/ios.h
__fwd/istream.h
__fwd/mdspan.h
Expand Down
42 changes: 32 additions & 10 deletions libcxx/include/__atomic/atomic_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,24 +104,20 @@ struct __atomic_base // false

_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const
volatile _NOEXCEPT {
std::__cxx_atomic_wait(std::addressof(__a_), __v, __m);
std::__atomic_wait(*this, __v, __m);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
wait(_Tp __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT {
std::__cxx_atomic_wait(std::addressof(__a_), __v, __m);
std::__atomic_wait(*this, __v, __m);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT {
std::__cxx_atomic_notify_one(std::addressof(__a_));
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT {
std::__cxx_atomic_notify_one(std::addressof(__a_));
std::__atomic_notify_one(*this);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); }
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT {
std::__cxx_atomic_notify_all(std::addressof(__a_));
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT {
std::__cxx_atomic_notify_all(std::addressof(__a_));
std::__atomic_notify_all(*this);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); }

#if _LIBCPP_STD_VER >= 20
_LIBCPP_HIDE_FROM_ABI constexpr __atomic_base() noexcept(is_nothrow_default_constructible_v<_Tp>) : __a_(_Tp()) {}
Expand Down Expand Up @@ -200,6 +196,32 @@ struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> {
_LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) _NOEXCEPT { return fetch_xor(__op) ^ __op; }
};

// Here we need _IsIntegral because the default template argument is not enough
// e.g __atomic_base<int> is __atomic_base<int, true>, which inherits from
// __atomic_base<int, false> and the caller of the wait function is
// __atomic_base<int, false>. So specializing __atomic_base<_Tp> does not work
template <class _Tp, bool _IsIntegral>
struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > {
static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_base<_Tp, _IsIntegral>& __a, memory_order __order) {
return __a.load(__order);
}

static _LIBCPP_HIDE_FROM_ABI _Tp
__atomic_load(const volatile __atomic_base<_Tp, _IsIntegral>& __this, memory_order __order) {
return __this.load(__order);
}

static _LIBCPP_HIDE_FROM_ABI const __cxx_atomic_impl<_Tp>*
__atomic_contention_address(const __atomic_base<_Tp, _IsIntegral>& __a) {
return std::addressof(__a.__a_);
}

static _LIBCPP_HIDE_FROM_ABI const volatile __cxx_atomic_impl<_Tp>*
__atomic_contention_address(const volatile __atomic_base<_Tp, _IsIntegral>& __this) {
return std::addressof(__this.__a_);
}
};

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___ATOMIC_ATOMIC_BASE_H
35 changes: 29 additions & 6 deletions libcxx/include/__atomic/atomic_flag.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <__availability>
#include <__chrono/duration.h>
#include <__config>
#include <__memory/addressof.h>
#include <__thread/support.h>
#include <cstdint>

Expand Down Expand Up @@ -50,20 +51,20 @@ struct atomic_flag {

_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(bool __v, memory_order __m = memory_order_seq_cst) const
volatile _NOEXCEPT {
__cxx_atomic_wait(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);
std::__atomic_wait(*this, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
wait(bool __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT {
__cxx_atomic_wait(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);
std::__atomic_wait(*this, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT {
__cxx_atomic_notify_one(&__a_);
std::__atomic_notify_one(*this);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { __cxx_atomic_notify_one(&__a_); }
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); }
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT {
__cxx_atomic_notify_all(&__a_);
std::__atomic_notify_all(*this);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { __cxx_atomic_notify_all(&__a_); }
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); }

#if _LIBCPP_STD_VER >= 20
_LIBCPP_HIDE_FROM_ABI constexpr atomic_flag() _NOEXCEPT : __a_(false) {}
Expand All @@ -78,6 +79,28 @@ struct atomic_flag {
atomic_flag& operator=(const atomic_flag&) volatile = delete;
};

template <>
struct __atomic_waitable_traits<atomic_flag> {
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_ATOMIC_FLAG_TYPE __atomic_load(const atomic_flag& __a, memory_order __order) {
return std::__cxx_atomic_load(&__a.__a_, __order);
}

static _LIBCPP_HIDE_FROM_ABI _LIBCPP_ATOMIC_FLAG_TYPE
__atomic_load(const volatile atomic_flag& __a, memory_order __order) {
return std::__cxx_atomic_load(&__a.__a_, __order);
}

static _LIBCPP_HIDE_FROM_ABI const __cxx_atomic_impl<_LIBCPP_ATOMIC_FLAG_TYPE>*
__atomic_contention_address(const atomic_flag& __a) {
return std::addressof(__a.__a_);
}

static _LIBCPP_HIDE_FROM_ABI const volatile __cxx_atomic_impl<_LIBCPP_ATOMIC_FLAG_TYPE>*
__atomic_contention_address(const volatile atomic_flag& __a) {
return std::addressof(__a.__a_);
}
};

inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test(const volatile atomic_flag* __o) _NOEXCEPT { return __o->test(); }

inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test(const atomic_flag* __o) _NOEXCEPT { return __o->test(); }
Expand Down
128 changes: 88 additions & 40 deletions libcxx/include/__atomic/atomic_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
#include <__memory/addressof.h>
#include <__thread/poll_with_backoff.h>
#include <__thread/support.h>
#include <__type_traits/conjunction.h>
#include <__type_traits/decay.h>
#include <__type_traits/invoke.h>
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
#include <cstring>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand All @@ -27,15 +31,40 @@

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Atp, class _Poll>
struct __libcpp_atomic_wait_poll_impl {
_Atp* __a_;
// The customisation points to enable the following functions:
// - __atomic_wait
// - __atomic_wait_unless
// - __atomic_notify_one
// - __atomic_notify_all
// Note that std::atomic<T>::wait was back-ported to C++03
// The below implementations look ugly to support C++03
template <class _Tp, class = void>
struct __atomic_waitable_traits {
template <class _AtomicWaitable>
static void __atomic_load(_AtomicWaitable&&, memory_order) = delete;

template <class _AtomicWaitable>
static void __atomic_contention_address(_AtomicWaitable&&) = delete;
};

template <class _Tp, class = void>
struct __atomic_waitable : false_type {};

template <class _Tp>
struct __atomic_waitable< _Tp,
__void_t<decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load(
std::declval<const _Tp&>(), std::declval<memory_order>())),
decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(
std::declval<const _Tp&>()))> > : true_type {};

template <class _AtomicWaitable, class _Poll>
struct __atomic_wait_poll_impl {
const _AtomicWaitable& __a_;
_Poll __poll_;
memory_order __order_;

_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_HIDE_FROM_ABI bool operator()() const {
auto __current_val = std::__cxx_atomic_load(__a_, __order_);
auto __current_val = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_load(__a_, __order_);
return __poll_(__current_val);
}
};
Expand All @@ -56,42 +85,45 @@ __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
__libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t);

template <class _Atp, class _Poll>
struct __libcpp_atomic_wait_backoff_impl {
_Atp* __a_;
template <class _AtomicWaitable, class _Poll>
struct __atomic_wait_backoff_impl {
const _AtomicWaitable& __a_;
_Poll __poll_;
memory_order __order_;

using __waitable_traits = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;

_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_HIDE_FROM_ABI bool
__poll_or_get_monitor(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor) const {
// In case the atomic can be waited on directly, the monitor value is just
// the value of the atomic.
__update_monitor_val_and_poll(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor_val) const {
// In case the contention type happens to be __cxx_atomic_contention_t, i.e. __cxx_atomic_impl<int64_t>,
// the platform wait is directly monitoring the atomic value itself.
// `__poll_` takes the current value of the atomic as an in-out argument
// to potentially modify it. After it returns, `__monitor` has a value
// which can be safely waited on by `std::__libcpp_atomic_wait` without any
// ABA style issues.
__monitor = std::__cxx_atomic_load(__a_, __order_);
return __poll_(__monitor);
__monitor_val = __waitable_traits::__atomic_load(__a_, __order_);
return __poll_(__monitor_val);
}

_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_HIDE_FROM_ABI bool __poll_or_get_monitor(void const volatile*, __cxx_contention_t& __monitor) const {
// In case we must wait on an atomic from the pool, the monitor comes from
// `std::__libcpp_atomic_monitor`.
// Only then we may read from `__a_`. This is the "event count" pattern.
__monitor = std::__libcpp_atomic_monitor(__a_);
auto __current_val = std::__cxx_atomic_load(__a_, __order_);
_LIBCPP_HIDE_FROM_ABI bool
__update_monitor_val_and_poll(void const volatile* __contention_address, __cxx_contention_t& __monitor_val) const {
// In case the contention type is anything else, platform wait is monitoring a __cxx_atomic_contention_t
// from the global pool, the monitor comes from __libcpp_atomic_monitor
__monitor_val = std::__libcpp_atomic_monitor(__contention_address);
auto __current_val = __waitable_traits::__atomic_load(__a_, __order_);
return __poll_(__current_val);
}

_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
if (__elapsed > chrono::microseconds(64)) {
__cxx_contention_t __monitor;
if (__poll_or_get_monitor(__a_, __monitor))
auto __contention_address = __waitable_traits::__atomic_contention_address(__a_);
__cxx_contention_t __monitor_val;
if (__update_monitor_val_and_poll(__contention_address, __monitor_val))
return true;
std::__libcpp_atomic_wait(__a_, __monitor);
std::__libcpp_atomic_wait(__contention_address, __monitor_val);
} else if (__elapsed > chrono::microseconds(4))
__libcpp_thread_yield();
else {
Expand All @@ -105,29 +137,44 @@ struct __libcpp_atomic_wait_backoff_impl {
// predicate (is the loaded value unequal to `old`?), the predicate function is
// specified as an argument. The loaded value is given as an in-out argument to
// the predicate. If the predicate function returns `true`,
// `_cxx_atomic_wait_unless` will return. If the predicate function returns
// `__atomic_wait_unless` will return. If the predicate function returns
// `false`, it must set the argument to its current understanding of the atomic
// value. The predicate function must not return `false` spuriously.
template <class _Atp, class _Poll>
template <class _AtomicWaitable, class _Poll>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
__cxx_atomic_wait_unless(_Atp* __a, _Poll&& __poll, memory_order __order) {
__libcpp_atomic_wait_poll_impl<_Atp, __decay_t<_Poll> > __poll_fn = {__a, __poll, __order};
__libcpp_atomic_wait_backoff_impl<_Atp, __decay_t<_Poll> > __backoff_fn = {__a, __poll, __order};
(void)std::__libcpp_thread_poll_with_backoff(__poll_fn, __backoff_fn);
__atomic_wait_unless(const _AtomicWaitable& __a, _Poll&& __poll, memory_order __order) {
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
__atomic_wait_poll_impl<_AtomicWaitable, __decay_t<_Poll> > __poll_impl = {__a, __poll, __order};
__atomic_wait_backoff_impl<_AtomicWaitable, __decay_t<_Poll> > __backoff_fn = {__a, __poll, __order};
std::__libcpp_thread_poll_with_backoff(__poll_impl, __backoff_fn);
}

template <class _AtomicWaitable>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) {
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
std::__cxx_atomic_notify_one(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
}

template <class _AtomicWaitable>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) {
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
}

#else // _LIBCPP_HAS_NO_THREADS

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_notify_all(__cxx_atomic_impl<_Tp> const volatile*) {}
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_notify_one(__cxx_atomic_impl<_Tp> const volatile*) {}
template <class _Atp, class _Poll>
_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_wait_unless(_Atp* __a, _Poll&& __poll, memory_order __order) {
__libcpp_atomic_wait_poll_impl<_Atp, __decay_t<_Poll> > __poll_fn = {__a, __poll, __order};
(void)std::__libcpp_thread_poll_with_backoff(__poll_fn, __spinning_backoff_policy());
template <class _AtomicWaitable, class _Poll>
_LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, _Poll&& __poll, memory_order __order) {
__atomic_wait_poll_impl<_AtomicWaitable, __decay_t<_Poll> > __poll_fn = {__a, __poll, __order};
std::__libcpp_thread_poll_with_backoff(__poll_fn, __spinning_backoff_policy());
}

template <class _AtomicWaitable>
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable&) {}

template <class _AtomicWaitable>
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable&) {}

#endif // _LIBCPP_HAS_NO_THREADS

template <typename _Tp>
Expand All @@ -143,11 +190,12 @@ struct __atomic_compare_unequal_to {
}
};

template <class _Atp, class _Tp>
template <class _AtomicWaitable, class _Up>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
__cxx_atomic_wait(_Atp* __a, _Tp const __val, memory_order __order) {
__atomic_compare_unequal_to<_Tp> __poll_fn = {__val};
std::__cxx_atomic_wait_unless(__a, __poll_fn, __order);
__atomic_wait(_AtomicWaitable& __a, _Up __val, memory_order __order) {
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
__atomic_compare_unequal_to<_Up> __nonatomic_equal = {__val};
std::__atomic_wait_unless(__a, __nonatomic_equal, __order);
}

_LIBCPP_END_NAMESPACE_STD
Expand Down
3 changes: 1 addition & 2 deletions libcxx/include/__filesystem/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
#include <__algorithm/replace_copy.h>
#include <__availability>
#include <__config>
#include <__functional/hash.h>
#include <__functional/unary_function.h>
#include <__fwd/hash.h>
#include <__fwd/functional.h>
#include <__iterator/back_insert_iterator.h>
#include <__iterator/iterator_traits.h>
#include <__type_traits/decay.h>
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/__functional/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <__config>
#include <__functional/invoke.h>
#include <__functional/weak_result_type.h>
#include <__fwd/functional.h>
#include <__type_traits/decay.h>
#include <__type_traits/is_reference_wrapper.h>
#include <__type_traits/is_void.h>
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__functional/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include <__config>
#include <__functional/invoke.h>
#include <__functional/unary_function.h>
#include <__fwd/hash.h>
#include <__fwd/functional.h>
#include <__tuple/sfinae_helpers.h>
#include <__type_traits/is_copy_constructible.h>
#include <__type_traits/is_default_constructible.h>
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__functional/identity.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#define _LIBCPP___FUNCTIONAL_IDENTITY_H

#include <__config>
#include <__functional/reference_wrapper.h>
#include <__fwd/functional.h>
#include <__type_traits/integral_constant.h>
#include <__utility/forward.h>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
//
//===---------------------------------------------------------------------===//

#ifndef _LIBCPP___FWD_HASH_H
#define _LIBCPP___FWD_HASH_H
#ifndef _LIBCPP___FWD_FUNCTIONAL_H
#define _LIBCPP___FWD_FUNCTIONAL_H

#include <__config>

Expand All @@ -20,6 +20,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class>
struct _LIBCPP_TEMPLATE_VIS hash;

template <class>
class _LIBCPP_TEMPLATE_VIS reference_wrapper;

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___FWD_HASH_H
#endif // _LIBCPP___FWD_FUNCTIONAL_H
2 changes: 1 addition & 1 deletion libcxx/include/__thread/id.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#include <__compare/ordering.h>
#include <__config>
#include <__fwd/hash.h>
#include <__fwd/functional.h>
#include <__fwd/ostream.h>
#include <__thread/support.h>

Expand Down
1 change: 0 additions & 1 deletion libcxx/include/__thread/support/pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <__chrono/convert_to_timespec.h>
#include <__chrono/duration.h>
#include <__config>
#include <__fwd/hash.h>
#include <ctime>
#include <errno.h>
#include <pthread.h>
Expand Down
4 changes: 1 addition & 3 deletions libcxx/include/__type_traits/is_reference_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define _LIBCPP___TYPE_TRAITS_IS_REFERENCE_WRAPPER_H

#include <__config>
#include <__fwd/functional.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/remove_cv.h>

Expand All @@ -19,9 +20,6 @@

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
class _LIBCPP_TEMPLATE_VIS reference_wrapper;

template <class _Tp>
struct __is_reference_wrapper_impl : public false_type {};
template <class _Tp>
Expand Down
11 changes: 3 additions & 8 deletions libcxx/include/__type_traits/remove_cv.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,17 @@

_LIBCPP_BEGIN_NAMESPACE_STD

#if __has_builtin(__remove_cv) && !defined(_LIBCPP_COMPILER_GCC)
template <class _Tp>
struct remove_cv {
using type _LIBCPP_NODEBUG = __remove_cv(_Tp);
};

#if defined(_LIBCPP_COMPILER_GCC)
template <class _Tp>
using __remove_cv_t = __remove_cv(_Tp);
using __remove_cv_t = typename remove_cv<_Tp>::type;
#else
template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS remove_cv {
typedef __remove_volatile_t<__remove_const_t<_Tp> > type;
};

template <class _Tp>
using __remove_cv_t = __remove_volatile_t<__remove_const_t<_Tp> >;
using __remove_cv_t = __remove_cv(_Tp);
#endif // __has_builtin(__remove_cv)

#if _LIBCPP_STD_VER >= 14
Expand Down
15 changes: 10 additions & 5 deletions libcxx/include/__type_traits/remove_cvref.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,26 @@

_LIBCPP_BEGIN_NAMESPACE_STD

#if __has_builtin(__remove_cvref) && !defined(_LIBCPP_COMPILER_GCC)
#if defined(_LIBCPP_COMPILER_GCC)
template <class _Tp>
using __remove_cvref_t _LIBCPP_NODEBUG = __remove_cvref(_Tp);
struct __remove_cvref_gcc {
using type = __remove_cvref(_Tp);
};

template <class _Tp>
using __remove_cvref_t _LIBCPP_NODEBUG = typename __remove_cvref_gcc<_Tp>::type;
#else
template <class _Tp>
using __remove_cvref_t _LIBCPP_NODEBUG = __remove_cv_t<__libcpp_remove_reference_t<_Tp> >;
using __remove_cvref_t _LIBCPP_NODEBUG = __remove_cvref(_Tp);
#endif // __has_builtin(__remove_cvref)

template <class _Tp, class _Up>
struct __is_same_uncvref : _IsSame<__remove_cvref_t<_Tp>, __remove_cvref_t<_Up> > {};
using __is_same_uncvref = _IsSame<__remove_cvref_t<_Tp>, __remove_cvref_t<_Up> >;

#if _LIBCPP_STD_VER >= 20
template <class _Tp>
struct remove_cvref {
using type _LIBCPP_NODEBUG = __remove_cvref_t<_Tp>;
using type _LIBCPP_NODEBUG = __remove_cvref(_Tp);
};

template <class _Tp>
Expand Down
7 changes: 1 addition & 6 deletions libcxx/include/__type_traits/unwrap_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define _LIBCPP___TYPE_TRAITS_UNWRAP_REF_H

#include <__config>
#include <__fwd/functional.h>
#include <__type_traits/decay.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand All @@ -23,17 +24,11 @@ struct __unwrap_reference {
typedef _LIBCPP_NODEBUG _Tp type;
};

template <class _Tp>
class reference_wrapper;

template <class _Tp>
struct __unwrap_reference<reference_wrapper<_Tp> > {
typedef _LIBCPP_NODEBUG _Tp& type;
};

template <class _Tp>
struct decay;

#if _LIBCPP_STD_VER >= 20
template <class _Tp>
struct unwrap_reference : __unwrap_reference<_Tp> {};
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/experimental/propagate_const
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
*/

#include <__functional/operations.h>
#include <__fwd/hash.h>
#include <__fwd/functional.h>
#include <__type_traits/conditional.h>
#include <__type_traits/decay.h>
#include <__type_traits/enable_if.h>
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/filesystem
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ inline constexpr bool std::ranges::enable_view<std::filesystem::recursive_direct
#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
# include <concepts>
# include <cstdlib>
# include <cstring>
# include <iosfwd>
# include <new>
# include <system_error>
Expand Down
218 changes: 97 additions & 121 deletions libcxx/include/fstream
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,9 @@ public:
# endif // _LIBCPP_STD_VER >= 26

_LIBCPP_HIDE_FROM_ABI inline static const char* __make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
# ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
_LIBCPP_HIDE_FROM_ABI inline static const wchar_t* __make_mdwstring(ios_base::openmode __mode) _NOEXCEPT;
# endif

protected:
// 27.9.1.5 Overridden virtual functions:
Expand Down Expand Up @@ -314,6 +317,26 @@ private:
void __write_mode();

_LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);

// There are multiple (__)open function, they use different C-API open
// function. After that call these functions behave the same. This function
// does that part and determines the final return value.
_LIBCPP_HIDE_FROM_ABI basic_filebuf* __do_open(FILE* __file, ios_base::openmode __mode) {
__file_ = __file;
if (!__file_)
return nullptr;

__om_ = __mode;
if (__mode & ios_base::ate) {
if (fseek(__file_, 0, SEEK_END)) {
fclose(__file_);
__file_ = nullptr;
return nullptr;
}
}

return this;
}
};

template <class _CharT, class _Traits>
Expand Down Expand Up @@ -548,140 +571,93 @@ const char* basic_filebuf<_CharT, _Traits>::__make_mdstring(ios_base::openmode _
__libcpp_unreachable();
}

# ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
template <class _CharT, class _Traits>
basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const char* __s, ios_base::openmode __mode) {
basic_filebuf<_CharT, _Traits>* __rt = nullptr;
if (__file_ == nullptr) {
if (const char* __mdstr = __make_mdstring(__mode)) {
__rt = this;
__file_ = fopen(__s, __mdstr);
if (__file_) {
__om_ = __mode;
if (__mode & ios_base::ate) {
if (fseek(__file_, 0, SEEK_END)) {
fclose(__file_);
__file_ = nullptr;
__rt = nullptr;
}
}
} else
__rt = nullptr;
}
const wchar_t* basic_filebuf<_CharT, _Traits>::__make_mdwstring(ios_base::openmode __mode) _NOEXCEPT {
switch (__mode & ~ios_base::ate) {
case ios_base::out:
case ios_base::out | ios_base::trunc:
return L"w";
case ios_base::out | ios_base::app:
case ios_base::app:
return L"a";
case ios_base::in:
return L"r";
case ios_base::in | ios_base::out:
return L"r+";
case ios_base::in | ios_base::out | ios_base::trunc:
return L"w+";
case ios_base::in | ios_base::out | ios_base::app:
case ios_base::in | ios_base::app:
return L"a+";
case ios_base::out | ios_base::binary:
case ios_base::out | ios_base::trunc | ios_base::binary:
return L"wb";
case ios_base::out | ios_base::app | ios_base::binary:
case ios_base::app | ios_base::binary:
return L"ab";
case ios_base::in | ios_base::binary:
return L"rb";
case ios_base::in | ios_base::out | ios_base::binary:
return L"r+b";
case ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary:
return L"w+b";
case ios_base::in | ios_base::out | ios_base::app | ios_base::binary:
case ios_base::in | ios_base::app | ios_base::binary:
return L"a+b";
# if _LIBCPP_STD_VER >= 23
case ios_base::out | ios_base::noreplace:
case ios_base::out | ios_base::trunc | ios_base::noreplace:
return L"wx";
case ios_base::in | ios_base::out | ios_base::trunc | ios_base::noreplace:
return L"w+x";
case ios_base::out | ios_base::binary | ios_base::noreplace:
case ios_base::out | ios_base::trunc | ios_base::binary | ios_base::noreplace:
return L"wbx";
case ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary | ios_base::noreplace:
return L"w+bx";
# endif // _LIBCPP_STD_VER >= 23
default:
return nullptr;
}
return __rt;
__libcpp_unreachable();
}
# endif

template <class _CharT, class _Traits>
basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const char* __s, ios_base::openmode __mode) {
if (__file_)
return nullptr;
const char* __mdstr = __make_mdstring(__mode);
if (!__mdstr)
return nullptr;

return __do_open(fopen(__s, __mdstr), __mode);
}

template <class _CharT, class _Traits>
inline basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::__open(int __fd, ios_base::openmode __mode) {
basic_filebuf<_CharT, _Traits>* __rt = nullptr;
if (__file_ == nullptr) {
if (const char* __mdstr = __make_mdstring(__mode)) {
__rt = this;
__file_ = fdopen(__fd, __mdstr);
if (__file_) {
__om_ = __mode;
if (__mode & ios_base::ate) {
if (fseek(__file_, 0, SEEK_END)) {
fclose(__file_);
__file_ = nullptr;
__rt = nullptr;
}
}
} else
__rt = nullptr;
}
}
return __rt;
if (__file_)
return nullptr;
const char* __mdstr = __make_mdstring(__mode);
if (!__mdstr)
return nullptr;

return __do_open(fdopen(__fd, __mdstr), __mode);
}

# ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
// This is basically the same as the char* overload except that it uses _wfopen
// and long mode strings.
template <class _CharT, class _Traits>
basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const wchar_t* __s, ios_base::openmode __mode) {
basic_filebuf<_CharT, _Traits>* __rt = nullptr;
if (__file_ == nullptr) {
__rt = this;
const wchar_t* __mdstr;
switch (__mode & ~ios_base::ate) {
case ios_base::out:
case ios_base::out | ios_base::trunc:
__mdstr = L"w";
break;
case ios_base::out | ios_base::app:
case ios_base::app:
__mdstr = L"a";
break;
case ios_base::in:
__mdstr = L"r";
break;
case ios_base::in | ios_base::out:
__mdstr = L"r+";
break;
case ios_base::in | ios_base::out | ios_base::trunc:
__mdstr = L"w+";
break;
case ios_base::in | ios_base::out | ios_base::app:
case ios_base::in | ios_base::app:
__mdstr = L"a+";
break;
case ios_base::out | ios_base::binary:
case ios_base::out | ios_base::trunc | ios_base::binary:
__mdstr = L"wb";
break;
case ios_base::out | ios_base::app | ios_base::binary:
case ios_base::app | ios_base::binary:
__mdstr = L"ab";
break;
case ios_base::in | ios_base::binary:
__mdstr = L"rb";
break;
case ios_base::in | ios_base::out | ios_base::binary:
__mdstr = L"r+b";
break;
case ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary:
__mdstr = L"w+b";
break;
case ios_base::in | ios_base::out | ios_base::app | ios_base::binary:
case ios_base::in | ios_base::app | ios_base::binary:
__mdstr = L"a+b";
break;
# if _LIBCPP_STD_VER >= 23
case ios_base::out | ios_base::noreplace:
case ios_base::out | ios_base::trunc | ios_base::noreplace:
__mdstr = L"wx";
break;
case ios_base::in | ios_base::out | ios_base::trunc | ios_base::noreplace:
__mdstr = L"w+x";
break;
case ios_base::out | ios_base::binary | ios_base::noreplace:
case ios_base::out | ios_base::trunc | ios_base::binary | ios_base::noreplace:
__mdstr = L"wbx";
break;
case ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary | ios_base::noreplace:
__mdstr = L"w+bx";
break;
# endif // _LIBCPP_STD_VER >= 23
default:
__rt = nullptr;
break;
}
if (__rt) {
__file_ = _wfopen(__s, __mdstr);
if (__file_) {
__om_ = __mode;
if (__mode & ios_base::ate) {
if (fseek(__file_, 0, SEEK_END)) {
fclose(__file_);
__file_ = nullptr;
__rt = nullptr;
}
}
} else
__rt = nullptr;
}
}
return __rt;
if (__file_)
return nullptr;
const wchar_t* __mdstr = __make_mdwstring(__mode);
if (!__mdstr)
return nullptr;

return __do_open(_wfopen(__s, __mdstr), __mode);
}
# endif

Expand Down
6 changes: 3 additions & 3 deletions libcxx/include/latch
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ public:
return try_wait_impl(__value);
}
inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const {
__cxx_atomic_wait_unless(
&__a_.__a_, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }, memory_order_acquire);
std::__atomic_wait_unless(
__a_, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }, memory_order_acquire);
}
inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");
Expand All @@ -114,7 +114,7 @@ public:
}

private:
inline _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
_LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
};

_LIBCPP_END_NAMESPACE_STD
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/libcxx.imp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@
{ include: [ "<__fwd/bit_reference.h>", "private", "<vector>", "public" ] },
{ include: [ "<__fwd/complex.h>", "private", "<complex>", "public" ] },
{ include: [ "<__fwd/fstream.h>", "private", "<iosfwd>", "public" ] },
{ include: [ "<__fwd/hash.h>", "private", "<functional>", "public" ] },
{ include: [ "<__fwd/functional.h>", "private", "<functional>", "public" ] },
{ include: [ "<__fwd/ios.h>", "private", "<iosfwd>", "public" ] },
{ include: [ "<__fwd/istream.h>", "private", "<iosfwd>", "public" ] },
{ include: [ "<__fwd/mdspan.h>", "private", "<mdspan>", "public" ] },
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ module std_private_functional_hash [system] {
export std_private_type_traits_underlying_type
export std_private_utility_pair
}
module std_private_functional_hash_fwd [system] { header "__fwd/hash.h" }
module std_private_functional_fwd [system] { header "__fwd/functional.h" }
module std_private_functional_identity [system] { header "__functional/identity.h" }
module std_private_functional_invoke [system] {
header "__functional/invoke.h"
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/optional
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ namespace std {
#include <__exception/exception.h>
#include <__functional/hash.h>
#include <__functional/invoke.h>
#include <__functional/reference_wrapper.h>
#include <__functional/unary_function.h>
#include <__fwd/functional.h>
#include <__memory/addressof.h>
#include <__memory/construct_at.h>
#include <__tuple/sfinae_helpers.h>
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/semaphore
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ public:
}
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() {
__cxx_atomic_wait_unless(
&__a_.__a_, [this](ptrdiff_t& __old) { return __try_acquire_impl(__old); }, memory_order_relaxed);
std::__atomic_wait_unless(
__a_, [this](ptrdiff_t& __old) { return __try_acquire_impl(__old); }, memory_order_relaxed);
}
template <class _Rep, class _Period>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ namespace std
*/

#include <__config>
#include <__fwd/hash.h> // This is https://llvm.org/PR56938
#include <__fwd/functional.h> // This is https://llvm.org/PR56938
#include <__type_traits/add_const.h>
#include <__type_traits/add_cv.h>
#include <__type_traits/add_lvalue_reference.h>
Expand Down
36 changes: 14 additions & 22 deletions libcxx/src/iostream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,83 +21,75 @@

_LIBCPP_BEGIN_NAMESPACE_STD

_ALIGNAS_TYPE(istream)
_LIBCPP_EXPORTED_FROM_ABI char cin[sizeof(istream)]
alignas(istream) _LIBCPP_EXPORTED_FROM_ABI char cin[sizeof(istream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?cin@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_istream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR
"@std@@@12@A")
#endif
;
_ALIGNAS_TYPE(__stdinbuf<char>) static char __cin[sizeof(__stdinbuf<char>)];
alignas(__stdinbuf<char>) static char __cin[sizeof(__stdinbuf<char>)];
static mbstate_t mb_cin;

#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
_ALIGNAS_TYPE(wistream)
_LIBCPP_EXPORTED_FROM_ABI char wcin[sizeof(wistream)]
alignas(wistream) _LIBCPP_EXPORTED_FROM_ABI char wcin[sizeof(wistream)]
# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?wcin@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_istream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR
"@std@@@12@A")
# endif
;
_ALIGNAS_TYPE(__stdinbuf<wchar_t>) static char __wcin[sizeof(__stdinbuf<wchar_t>)];
alignas(__stdinbuf<wchar_t>) static char __wcin[sizeof(__stdinbuf<wchar_t>)];
static mbstate_t mb_wcin;
#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS

_ALIGNAS_TYPE(ostream)
_LIBCPP_EXPORTED_FROM_ABI char cout[sizeof(ostream)]
alignas(ostream) _LIBCPP_EXPORTED_FROM_ABI char cout[sizeof(ostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?cout@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR
"@std@@@12@A")
#endif
;
_ALIGNAS_TYPE(__stdoutbuf<char>) static char __cout[sizeof(__stdoutbuf<char>)];
alignas(__stdoutbuf<char>) static char __cout[sizeof(__stdoutbuf<char>)];
static mbstate_t mb_cout;

#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
_ALIGNAS_TYPE(wostream)
_LIBCPP_EXPORTED_FROM_ABI char wcout[sizeof(wostream)]
alignas(wostream) _LIBCPP_EXPORTED_FROM_ABI char wcout[sizeof(wostream)]
# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?wcout@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR
"@std@@@12@A")
# endif
;
_ALIGNAS_TYPE(__stdoutbuf<wchar_t>) static char __wcout[sizeof(__stdoutbuf<wchar_t>)];
alignas(__stdoutbuf<wchar_t>) static char __wcout[sizeof(__stdoutbuf<wchar_t>)];
static mbstate_t mb_wcout;
#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS

_ALIGNAS_TYPE(ostream)
_LIBCPP_EXPORTED_FROM_ABI char cerr[sizeof(ostream)]
alignas(ostream) _LIBCPP_EXPORTED_FROM_ABI char cerr[sizeof(ostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?cerr@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR
"@std@@@12@A")
#endif
;
_ALIGNAS_TYPE(__stdoutbuf<char>) static char __cerr[sizeof(__stdoutbuf<char>)];
alignas(__stdoutbuf<char>) static char __cerr[sizeof(__stdoutbuf<char>)];
static mbstate_t mb_cerr;

#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
_ALIGNAS_TYPE(wostream)
_LIBCPP_EXPORTED_FROM_ABI char wcerr[sizeof(wostream)]
alignas(wostream) _LIBCPP_EXPORTED_FROM_ABI char wcerr[sizeof(wostream)]
# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?wcerr@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR
"@std@@@12@A")
# endif
;
_ALIGNAS_TYPE(__stdoutbuf<wchar_t>) static char __wcerr[sizeof(__stdoutbuf<wchar_t>)];
alignas(__stdoutbuf<wchar_t>) static char __wcerr[sizeof(__stdoutbuf<wchar_t>)];
static mbstate_t mb_wcerr;
#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS

_ALIGNAS_TYPE(ostream)
_LIBCPP_EXPORTED_FROM_ABI char clog[sizeof(ostream)]
alignas(ostream) _LIBCPP_EXPORTED_FROM_ABI char clog[sizeof(ostream)]
#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?clog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR
"@std@@@12@A")
#endif
;

#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
_ALIGNAS_TYPE(wostream)
_LIBCPP_EXPORTED_FROM_ABI char wclog[sizeof(wostream)]
alignas(wostream) _LIBCPP_EXPORTED_FROM_ABI char wclog[sizeof(wostream)]
# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
__asm__("?wclog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR
"@std@@@12@A")
Expand Down
1 change: 0 additions & 1 deletion libcxx/test/libcxx/transitive_includes/cxx23.csv
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ experimental/utility utility
filesystem compare
filesystem cstddef
filesystem cstdint
filesystem cstring
filesystem ctime
filesystem iomanip
filesystem limits
Expand Down
1 change: 0 additions & 1 deletion libcxx/test/libcxx/transitive_includes/cxx26.csv
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ experimental/utility utility
filesystem compare
filesystem cstddef
filesystem cstdint
filesystem cstring
filesystem ctime
filesystem iomanip
filesystem limits
Expand Down
2 changes: 0 additions & 2 deletions libcxx/utils/generate_iwyu_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ def IWYU_mapping(header: str) -> typing.Optional[typing.List[str]]:
return ["atomic", "mutex", "semaphore", "thread"]
elif header == "__tree":
return ["map", "set"]
elif header == "__fwd/hash.h":
return ["functional"]
elif header == "__fwd/pair.h":
return ["utility"]
elif header == "__fwd/subrange.h":
Expand Down
4 changes: 3 additions & 1 deletion lld/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ add_subdirectory(tools/lld)

if (LLVM_INCLUDE_TESTS)
add_custom_target(LLDUnitTests)
llvm_add_unittests(LLD_UNITTESTS_ADDED)
if (TARGET llvm_gtest)
add_subdirectory(unittests)
endif()
add_subdirectory(test)
endif()

Expand Down
3 changes: 1 addition & 2 deletions lld/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ configure_lit_site_cfg(
"LLD_SOURCE_DIR"
)

set(LLD_TEST_DEPS lld)
set(LLD_TEST_DEPS lld LLDUnitTests)
if (NOT LLD_BUILT_STANDALONE)
list(APPEND LLD_TEST_DEPS
FileCheck
LLDUnitTests
count
dsymutil
llc
Expand Down
6 changes: 3 additions & 3 deletions lldb/include/lldb/Core/Debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

namespace llvm {
class raw_ostream;
class ThreadPool;
class ThreadPoolInterface;
} // namespace llvm

namespace lldb_private {
Expand Down Expand Up @@ -499,8 +499,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
return m_broadcaster_manager_sp;
}

/// Shared thread poll. Use only with ThreadPoolTaskGroup.
static llvm::ThreadPool &GetThreadPool();
/// Shared thread pool. Use only with ThreadPoolTaskGroup.
static llvm::ThreadPoolInterface &GetThreadPool();

/// Report warning events.
///
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Core/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2195,7 +2195,7 @@ Status Debugger::RunREPL(LanguageType language, const char *repl_options) {
return err;
}

llvm::ThreadPool &Debugger::GetThreadPool() {
llvm::ThreadPoolInterface &Debugger::GetThreadPool() {
assert(g_thread_pool &&
"Debugger::GetThreadPool called before Debugger::Initialize");
return *g_thread_pool;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,8 @@ ClangExpressionParser::ClangExpressionParser(
// Supported subsets of x86
if (target_machine == llvm::Triple::x86 ||
target_machine == llvm::Triple::x86_64) {
m_compiler->getTargetOpts().Features.push_back("+sse");
m_compiler->getTargetOpts().Features.push_back("+sse2");
m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse");
m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse2");
}

// Set the target CPU to generate code for. This will be empty for any CPU
Expand Down
10 changes: 0 additions & 10 deletions llvm/cmake/modules/AddLLVM.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2509,13 +2509,3 @@ function(setup_host_tool tool_name setting_name exe_var_name target_var_name)
add_custom_target(${target_var_name} DEPENDS ${exe_name})
endif()
endfunction()

# Adds the unittests folder if gtest is available.
function(llvm_add_unittests tests_added)
if (EXISTS ${LLVM_THIRD_PARTY_DIR}/unittest/googletest/include/gtest/gtest.h)
add_subdirectory(unittests)
set(${tests_added} ON PARENT_SCOPE)
else()
message(WARNING "gtest not found, unittests will not be available")
endif()
endfunction()
9 changes: 4 additions & 5 deletions llvm/docs/Contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,9 @@ in order to update the last commit with all pending changes.
``clang/tools/clang-format/git-clang-format``.

The LLVM project has migrated to GitHub Pull Requests as its review process.
We still have an active :ref:`Phabricator <phabricator-reviews>`
instance for the duration of the migration. If you want to contribute to LLVM
now, please use GitHub. For more information about the workflow of using GitHub
Pull Requests see our :ref:`GitHub <github-reviews>` documentation.
For more information about the workflow of using GitHub Pull Requests see our
:ref:`GitHub <github-reviews>` documentation. We still have an read-only
`LLVM's Phabricator <https://reviews.llvm.org>`_ instance.

To make sure the right people see your patch, please select suitable reviewers
and add them to your patch when requesting a review. Suitable reviewers are the
Expand Down Expand Up @@ -185,5 +184,5 @@ of LLVM's high-level design, as well as its internals:
.. _clang-format-diff.py: https://reviews.llvm.org/source/llvm-github/browse/main/clang/tools/clang-format/clang-format-diff.py
.. _git-clang-format: https://reviews.llvm.org/source/llvm-github/browse/main/clang/tools/clang-format/git-clang-format
.. _LLVM's GitHub: https://github.com/llvm/llvm-project
.. _LLVM's Phabricator (deprecated): https://reviews.llvm.org/
.. _LLVM's Phabricator (read-only): https://reviews.llvm.org/
.. _LLVM's Open Projects page: https://llvm.org/OpenProjects.html#what
4 changes: 2 additions & 2 deletions llvm/docs/DeveloperPolicy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ awareness of. For such changes, the following should be done:

.. warning::

Phabricator is deprecated and will be switched to read-only mode in October
2023, for new code contributions use :ref:`GitHub Pull Requests <github-reviews>`.
Phabricator is deprecated is available in read-only mode,
for new code contributions use :ref:`GitHub Pull Requests <github-reviews>`.
This section contains old information that needs to be updated.

* When performing the code review for the change, please add any applicable
Expand Down
441 changes: 0 additions & 441 deletions llvm/docs/Phabricator.rst

This file was deleted.

Binary file removed llvm/docs/Phabricator_premerge_results.png
Binary file not shown.
Binary file removed llvm/docs/Phabricator_premerge_unit_tests.png
Binary file not shown.
1 change: 0 additions & 1 deletion llvm/docs/UserGuides.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ intermediate LLVM representation.
JITLink
NewPassManager
NVPTXUsage
Phabricator
Passes
ReportingGuide
ResponseGuide
Expand Down
36 changes: 0 additions & 36 deletions llvm/include/llvm/CodeGen/TargetLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -596,42 +596,6 @@ class TargetLoweringBase {
/// avoided.
bool isJumpExpensive() const { return JumpIsExpensive; }

// Costs parameters used by
// SelectionDAGBuilder::shouldKeepJumpConditionsTogether.
// shouldKeepJumpConditionsTogether will use these parameter value to
// determine if two conditions in the form `br (and/or cond1, cond2)` should
// be split into two branches or left as one.
//
// BaseCost is the cost threshold (in latency). If the estimated latency of
// computing both `cond1` and `cond2` is below the cost of just computing
// `cond1` + BaseCost, the two conditions will be kept together. Otherwise
// they will be split.
//
// LikelyBias increases BaseCost if branch probability info indicates that it
// is likely that both `cond1` and `cond2` will be computed.
//
// UnlikelyBias decreases BaseCost if branch probability info indicates that
// it is likely that both `cond1` and `cond2` will be computed.
//
// Set any field to -1 to make it ignored (setting BaseCost to -1 results in
// `shouldKeepJumpConditionsTogether` always returning false).
struct CondMergingParams {
int BaseCost;
int LikelyBias;
int UnlikelyBias;
};
// Return params for deciding if we should keep two branch conditions merged
// or split them into two separate branches.
// Arg0: The binary op joining the two conditions (and/or).
// Arg1: The first condition (cond1)
// Arg2: The second condition (cond2)
virtual CondMergingParams
getJumpConditionMergingParams(Instruction::BinaryOps, const Value *,
const Value *) const {
// -1 will always result in splitting.
return {-1, -1, -1};
}

/// Return true if selects are only cheaper than branches if the branch is
/// unlikely to be predicted right.
bool isPredictableSelectExpensive() const {
Expand Down
6 changes: 3 additions & 3 deletions llvm/include/llvm/Debuginfod/Debuginfod.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Expected<std::string> getCachedOrDownloadArtifact(
StringRef UniqueKey, StringRef UrlPath, StringRef CacheDirectoryPath,
ArrayRef<StringRef> DebuginfodUrls, std::chrono::milliseconds Timeout);

class ThreadPool;
class ThreadPoolInterface;

struct DebuginfodLogEntry {
std::string Message;
Expand Down Expand Up @@ -135,7 +135,7 @@ class DebuginfodCollection {
// error.
Expected<bool> updateIfStale();
DebuginfodLog &Log;
ThreadPool &Pool;
ThreadPoolInterface &Pool;
Timer UpdateTimer;
sys::Mutex UpdateMutex;

Expand All @@ -145,7 +145,7 @@ class DebuginfodCollection {

public:
DebuginfodCollection(ArrayRef<StringRef> Paths, DebuginfodLog &Log,
ThreadPool &Pool, double MinInterval);
ThreadPoolInterface &Pool, double MinInterval);
Error update();
Error updateForever(std::chrono::milliseconds Interval);
Expected<std::string> findDebugBinaryPath(object::BuildIDRef);
Expand Down
7 changes: 0 additions & 7 deletions llvm/include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,6 @@ namespace llvm {
std::optional<unsigned> DWARFAddressSpace = std::nullopt,
StringRef Name = "", DINodeArray Annotations = nullptr);

/// Create a __ptrauth qualifier.
DIDerivedType *createPtrAuthQualifiedType(DIType *FromTy, unsigned Key,
bool IsAddressDiscriminated,
unsigned ExtraDiscriminator,
bool IsaPointer,
bool authenticatesNullValues);

/// Create debugging information entry for a pointer to member.
/// \param PointeeTy Type pointed to by this pointer.
/// \param SizeInBits Size.
Expand Down
124 changes: 23 additions & 101 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ class DIType : public DIScope {

unsigned getLine() const { return Line; }
uint64_t getSizeInBits() const { return SizeInBits; }
uint32_t getAlignInBits() const;
uint32_t getAlignInBits() const { return SubclassData32; }
uint32_t getAlignInBytes() const { return getAlignInBits() / CHAR_BIT; }
uint64_t getOffsetInBits() const { return OffsetInBits; }
DIFlags getFlags() const { return Flags; }
Expand Down Expand Up @@ -972,40 +972,6 @@ class DIStringType : public DIType {
///
/// TODO: Split out members (inheritance, fields, methods, etc.).
class DIDerivedType : public DIType {
public:
/// Pointer authentication (__ptrauth) metadata.
struct PtrAuthData {
union {
struct {
unsigned Key : 4;
unsigned IsAddressDiscriminated : 1;
unsigned ExtraDiscriminator : 16;
unsigned IsaPointer : 1;
unsigned AuthenticatesNullValues : 1;
} Data;
unsigned RawData;
} Payload;

PtrAuthData(unsigned FromRawData) { Payload.RawData = FromRawData; }
PtrAuthData(unsigned Key, bool IsDiscr, unsigned Discriminator,
bool IsaPointer, bool AuthenticatesNullValues) {
assert(Key < 16);
assert(Discriminator <= 0xffff);
Payload.Data.Key = Key;
Payload.Data.IsAddressDiscriminated = IsDiscr;
Payload.Data.ExtraDiscriminator = Discriminator;
Payload.Data.IsaPointer = IsaPointer;
Payload.Data.AuthenticatesNullValues = AuthenticatesNullValues;
}
bool operator==(struct PtrAuthData Other) const {
return Payload.RawData == Other.Payload.RawData;
}
bool operator!=(struct PtrAuthData Other) const {
return !(*this == Other);
}
};

private:
friend class LLVMContextImpl;
friend class MDNode;

Expand All @@ -1016,70 +982,59 @@ class DIDerivedType : public DIType {
DIDerivedType(LLVMContext &C, StorageType Storage, unsigned Tag,
unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits,
uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
ArrayRef<Metadata *> Ops)
: DIType(C, DIDerivedTypeKind, Storage, Tag, Line, SizeInBits,
AlignInBits, OffsetInBits, Flags, Ops),
DWARFAddressSpace(DWARFAddressSpace) {
if (PtrAuthData)
SubclassData32 = PtrAuthData->Payload.RawData;
}
DWARFAddressSpace(DWARFAddressSpace) {}
~DIDerivedType() = default;
static DIDerivedType *
getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, DIFile *File,
unsigned Line, DIScope *Scope, DIType *BaseType, uint64_t SizeInBits,
uint32_t AlignInBits, uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
Metadata *ExtraData, DINodeArray Annotations, StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, Tag, getCanonicalMDString(Context, Name), File,
Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits,
DWARFAddressSpace, PtrAuthData, Flags, ExtraData,
Annotations.get(), Storage, ShouldCreate);
DWARFAddressSpace, Flags, ExtraData, Annotations.get(),
Storage, ShouldCreate);
}
static DIDerivedType *
getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File,
unsigned Line, Metadata *Scope, Metadata *BaseType,
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
Metadata *ExtraData, Metadata *Annotations, StorageType Storage,
bool ShouldCreate = true);

TempDIDerivedType cloneImpl() const {
return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(),
getScope(), getBaseType(), getSizeInBits(),
getAlignInBits(), getOffsetInBits(),
getDWARFAddressSpace(), getPtrAuthData(), getFlags(),
getExtraData(), getAnnotations());
return getTemporary(
getContext(), getTag(), getName(), getFile(), getLine(), getScope(),
getBaseType(), getSizeInBits(), getAlignInBits(), getOffsetInBits(),
getDWARFAddressSpace(), getFlags(), getExtraData(), getAnnotations());
}

public:
DEFINE_MDNODE_GET(DIDerivedType,
(unsigned Tag, MDString *Name, Metadata *File,
unsigned Line, Metadata *Scope, Metadata *BaseType,
uint64_t SizeInBits, uint32_t AlignInBits,
uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
Metadata *ExtraData = nullptr,
Metadata *Annotations = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, OffsetInBits, DWARFAddressSpace, PtrAuthData,
Flags, ExtraData, Annotations))
DEFINE_MDNODE_GET(
DIDerivedType,
(unsigned Tag, MDString *Name, Metadata *File, unsigned Line,
Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits,
uint32_t AlignInBits, uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
Metadata *ExtraData = nullptr, Metadata *Annotations = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits,
OffsetInBits, DWARFAddressSpace, Flags, ExtraData, Annotations))
DEFINE_MDNODE_GET(DIDerivedType,
(unsigned Tag, StringRef Name, DIFile *File, unsigned Line,
DIScope *Scope, DIType *BaseType, uint64_t SizeInBits,
uint32_t AlignInBits, uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
Metadata *ExtraData = nullptr,
DINodeArray Annotations = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, OffsetInBits, DWARFAddressSpace, PtrAuthData,
Flags, ExtraData, Annotations))
AlignInBits, OffsetInBits, DWARFAddressSpace, Flags,
ExtraData, Annotations))

TempDIDerivedType clone() const { return cloneImpl(); }

Expand All @@ -1093,39 +1048,6 @@ class DIDerivedType : public DIType {
return DWARFAddressSpace;
}

std::optional<PtrAuthData> getPtrAuthData() const;

/// \returns The PointerAuth key.
std::optional<unsigned> getPtrAuthKey() const {
if (auto PtrAuthData = getPtrAuthData())
return (unsigned)PtrAuthData->Payload.Data.Key;
return std::nullopt;
}
/// \returns The PointerAuth address discrimination bit.
std::optional<bool> isPtrAuthAddressDiscriminated() const {
if (auto PtrAuthData = getPtrAuthData())
return (bool)PtrAuthData->Payload.Data.IsAddressDiscriminated;
return std::nullopt;
}
/// \returns The PointerAuth extra discriminator.
std::optional<unsigned> getPtrAuthExtraDiscriminator() const {
if (auto PtrAuthData = getPtrAuthData())
return (unsigned)PtrAuthData->Payload.Data.ExtraDiscriminator;
return std::nullopt;
}
/// \returns The PointerAuth IsaPointer bit.
std::optional<bool> isPtrAuthIsaPointer() const {
if (auto PtrAuthData = getPtrAuthData())
return (bool)PtrAuthData->Payload.Data.IsaPointer;
return std::nullopt;
}
/// \returns The PointerAuth authenticates null values bit.
std::optional<bool> getPtrAuthAuthenticatesNullValues() const {
if (auto PtrAuthData = getPtrAuthData())
return (bool)PtrAuthData->Payload.Data.AuthenticatesNullValues;
return std::nullopt;
}

/// Get extra data associated with this derived type.
///
/// Class type for pointer-to-members, objective-c property node for ivars,
Expand Down
7 changes: 4 additions & 3 deletions llvm/include/llvm/Support/BalancedPartitioning.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

namespace llvm {

class ThreadPool;
class ThreadPoolInterface;
/// A function with a set of utility nodes where it is beneficial to order two
/// functions close together if they have similar utility nodes
class BPFunctionNode {
Expand Down Expand Up @@ -115,7 +115,7 @@ class BalancedPartitioning {
/// threads, so we need to track how many active threads that could spawn more
/// threads.
struct BPThreadPool {
ThreadPool &TheThreadPool;
ThreadPoolInterface &TheThreadPool;
std::mutex mtx;
std::condition_variable cv;
/// The number of threads that could spawn more threads
Expand All @@ -128,7 +128,8 @@ class BalancedPartitioning {
/// acceptable for other threads to add more tasks while blocking on this
/// call.
void wait();
BPThreadPool(ThreadPool &TheThreadPool) : TheThreadPool(TheThreadPool) {}
BPThreadPool(ThreadPoolInterface &TheThreadPool)
: TheThreadPool(TheThreadPool) {}
};

/// Run a recursive bisection of a given list of FunctionNodes
Expand Down
184 changes: 111 additions & 73 deletions llvm/include/llvm/Support/ThreadPool.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ namespace llvm {

class ThreadPoolTaskGroup;

/// A ThreadPool for asynchronous parallel execution on a defined number of
/// threads.
///
/// The pool keeps a vector of threads alive, waiting on a condition variable
/// for some work to become available.
/// This defines the abstract base interface for a ThreadPool allowing
/// asynchronous parallel execution on a defined number of threads.
///
/// It is possible to reuse one thread pool for different groups of tasks
/// by grouping tasks using ThreadPoolTaskGroup. All tasks are processed using
Expand All @@ -49,16 +46,31 @@ class ThreadPoolTaskGroup;
/// available threads are used up by tasks waiting for a task that has no thread
/// left to run on (this includes waiting on the returned future). It should be
/// generally safe to wait() for a group as long as groups do not form a cycle.
class ThreadPool {
class ThreadPoolInterface {
/// The actual method to enqueue a task to be defined by the concrete
/// implementation.
virtual void asyncEnqueue(std::function<void()> Task,
ThreadPoolTaskGroup *Group) = 0;

public:
/// Construct a pool using the hardware strategy \p S for mapping hardware
/// execution resources (threads, cores, CPUs)
/// Defaults to using the maximum execution resources in the system, but
/// accounting for the affinity mask.
ThreadPool(ThreadPoolStrategy S = hardware_concurrency());
/// Destroying the pool will drain the pending tasks and wait. The current
/// thread may participate in the execution of the pending tasks.
virtual ~ThreadPoolInterface();

/// Blocking destructor: the pool will wait for all the threads to complete.
~ThreadPool();
/// Blocking wait for all the threads to complete and the queue to be empty.
/// It is an error to try to add new tasks while blocking on this call.
/// Calling wait() from a task would deadlock waiting for itself.
virtual void wait() = 0;

/// Blocking wait for only all the threads in the given group to complete.
/// It is possible to wait even inside a task, but waiting (directly or
/// indirectly) on itself will deadlock. If called from a task running on a
/// worker thread, the call may process pending tasks while waiting in order
/// not to waste the thread.
virtual void wait(ThreadPoolTaskGroup &Group) = 0;

/// Returns the maximum number of worker this pool can eventually grow to.
virtual unsigned getMaxConcurrency() const = 0;

/// Asynchronous submission of a task to the pool. The returned future can be
/// used to wait for the task to finish and is *non-blocking* on destruction.
Expand Down Expand Up @@ -92,102 +104,85 @@ class ThreadPool {
&Group);
}

private:
/// Asynchronous submission of a task to the pool. The returned future can be
/// used to wait for the task to finish and is *non-blocking* on destruction.
template <typename ResTy>
std::shared_future<ResTy> asyncImpl(std::function<ResTy()> Task,
ThreadPoolTaskGroup *Group) {
auto Future = std::async(std::launch::deferred, std::move(Task)).share();
asyncEnqueue([Future]() { Future.wait(); }, Group);
return Future;
}
};

#if LLVM_ENABLE_THREADS
/// A ThreadPool implementation using std::threads.
///
/// The pool keeps a vector of threads alive, waiting on a condition variable
/// for some work to become available.
class StdThreadPool : public ThreadPoolInterface {
public:
/// Construct a pool using the hardware strategy \p S for mapping hardware
/// execution resources (threads, cores, CPUs)
/// Defaults to using the maximum execution resources in the system, but
/// accounting for the affinity mask.
StdThreadPool(ThreadPoolStrategy S = hardware_concurrency());

/// Blocking destructor: the pool will wait for all the threads to complete.
~StdThreadPool() override;

/// Blocking wait for all the threads to complete and the queue to be empty.
/// It is an error to try to add new tasks while blocking on this call.
/// Calling wait() from a task would deadlock waiting for itself.
void wait();
void wait() override;

/// Blocking wait for only all the threads in the given group to complete.
/// It is possible to wait even inside a task, but waiting (directly or
/// indirectly) on itself will deadlock. If called from a task running on a
/// worker thread, the call may process pending tasks while waiting in order
/// not to waste the thread.
void wait(ThreadPoolTaskGroup &Group);
void wait(ThreadPoolTaskGroup &Group) override;

// Returns the maximum number of worker threads in the pool, not the current
// number of threads!
unsigned getMaxConcurrency() const { return MaxThreadCount; }
/// Returns the maximum number of worker threads in the pool, not the current
/// number of threads!
unsigned getMaxConcurrency() const override { return MaxThreadCount; }

// TODO: misleading legacy name warning!
// TODO: Remove, misleading legacy name warning!
LLVM_DEPRECATED("Use getMaxConcurrency instead", "getMaxConcurrency")
unsigned getThreadCount() const { return MaxThreadCount; }

/// Returns true if the current thread is a worker thread of this thread pool.
bool isWorkerThread() const;

private:
/// Helpers to create a promise and a callable wrapper of \p Task that sets
/// the result of the promise. Returns the callable and a future to access the
/// result.
template <typename ResTy>
static std::pair<std::function<void()>, std::future<ResTy>>
createTaskAndFuture(std::function<ResTy()> Task) {
std::shared_ptr<std::promise<ResTy>> Promise =
std::make_shared<std::promise<ResTy>>();
auto F = Promise->get_future();
return {
[Promise = std::move(Promise), Task]() { Promise->set_value(Task()); },
std::move(F)};
}
static std::pair<std::function<void()>, std::future<void>>
createTaskAndFuture(std::function<void()> Task) {
std::shared_ptr<std::promise<void>> Promise =
std::make_shared<std::promise<void>>();
auto F = Promise->get_future();
return {[Promise = std::move(Promise), Task]() {
Task();
Promise->set_value();
},
std::move(F)};
}

/// Returns true if all tasks in the given group have finished (nullptr means
/// all tasks regardless of their group). QueueLock must be locked.
bool workCompletedUnlocked(ThreadPoolTaskGroup *Group) const;

/// Asynchronous submission of a task to the pool. The returned future can be
/// used to wait for the task to finish and is *non-blocking* on destruction.
template <typename ResTy>
std::shared_future<ResTy> asyncImpl(std::function<ResTy()> Task,
ThreadPoolTaskGroup *Group) {

#if LLVM_ENABLE_THREADS
/// Wrap the Task in a std::function<void()> that sets the result of the
/// corresponding future.
auto R = createTaskAndFuture(Task);

void asyncEnqueue(std::function<void()> Task,
ThreadPoolTaskGroup *Group) override {
int requestedThreads;
{
// Lock the queue and push the new task
std::unique_lock<std::mutex> LockGuard(QueueLock);

// Don't allow enqueueing after disabling the pool
assert(EnableFlag && "Queuing a thread during ThreadPool destruction");
Tasks.emplace_back(std::make_pair(std::move(R.first), Group));
Tasks.emplace_back(std::make_pair(std::move(Task), Group));
requestedThreads = ActiveThreads + Tasks.size();
}
QueueCondition.notify_one();
grow(requestedThreads);
return R.second.share();

#else // LLVM_ENABLE_THREADS Disabled

// Get a Future with launch::deferred execution using std::async
auto Future = std::async(std::launch::deferred, std::move(Task)).share();
// Wrap the future so that both ThreadPool::wait() can operate and the
// returned future can be sync'ed on.
Tasks.emplace_back(std::make_pair([Future]() { Future.get(); }, Group));
return Future;
#endif
}

#if LLVM_ENABLE_THREADS
// Grow to ensure that we have at least `requested` Threads, but do not go
// over MaxThreadCount.
/// Grow to ensure that we have at least `requested` Threads, but do not go
/// over MaxThreadCount.
void grow(int requested);

void processTasks(ThreadPoolTaskGroup *WaitingForGroup);
#endif

/// Threads in flight
std::vector<llvm::thread> Threads;
Expand All @@ -209,25 +204,68 @@ class ThreadPool {
/// Number of threads active for tasks in the given group (only non-zero).
DenseMap<ThreadPoolTaskGroup *, unsigned> ActiveGroups;

#if LLVM_ENABLE_THREADS // avoids warning for unused variable
/// Signal for the destruction of the pool, asking thread to exit.
bool EnableFlag = true;
#endif

const ThreadPoolStrategy Strategy;

/// Maximum number of threads to potentially grow this pool to.
const unsigned MaxThreadCount;
};

#endif // LLVM_ENABLE_THREADS Disabled

/// A non-threaded implementation.
class SingleThreadExecutor : public ThreadPoolInterface {
public:
/// Construct a non-threaded pool, ignoring using the hardware strategy.
SingleThreadExecutor(ThreadPoolStrategy ignored = {});

/// Blocking destructor: the pool will first execute the pending tasks.
~SingleThreadExecutor() override;

/// Blocking wait for all the tasks to execute first
void wait() override;

/// Blocking wait for only all the tasks in the given group to complete.
void wait(ThreadPoolTaskGroup &Group) override;

/// Returns always 1: there is no concurrency.
unsigned getMaxConcurrency() const override { return 1; }

// TODO: Remove, misleading legacy name warning!
LLVM_DEPRECATED("Use getMaxConcurrency instead", "getMaxConcurrency")
unsigned getThreadCount() const { return 1; }

/// Returns true if the current thread is a worker thread of this thread pool.
bool isWorkerThread() const;

private:
/// Asynchronous submission of a task to the pool. The returned future can be
/// used to wait for the task to finish and is *non-blocking* on destruction.
void asyncEnqueue(std::function<void()> Task,
ThreadPoolTaskGroup *Group) override {
Tasks.emplace_back(std::make_pair(std::move(Task), Group));
}

/// Tasks waiting for execution in the pool.
std::deque<std::pair<std::function<void()>, ThreadPoolTaskGroup *>> Tasks;
};

#if LLVM_ENABLE_THREADS
using ThreadPool = StdThreadPool;
#else
using ThreadPool = SingleThreadExecutor;
#endif

/// A group of tasks to be run on a thread pool. Thread pool tasks in different
/// groups can run on the same threadpool but can be waited for separately.
/// It is even possible for tasks of one group to submit and wait for tasks
/// of another group, as long as this does not form a loop.
class ThreadPoolTaskGroup {
public:
/// The ThreadPool argument is the thread pool to forward calls to.
ThreadPoolTaskGroup(ThreadPool &Pool) : Pool(Pool) {}
ThreadPoolTaskGroup(ThreadPoolInterface &Pool) : Pool(Pool) {}

/// Blocking destructor: will wait for all the tasks in the group to complete
/// by calling ThreadPool::wait().
Expand All @@ -244,7 +282,7 @@ class ThreadPoolTaskGroup {
void wait() { Pool.wait(*this); }

private:
ThreadPool &Pool;
ThreadPoolInterface &Pool;
};

} // namespace llvm
Expand Down
Loading