36 changes: 17 additions & 19 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -881,20 +881,23 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
return true;
}

/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
/// that the template parameter 'PrevDecl' is being shadowed by a new
/// declaration at location Loc. Returns true to indicate that this is
/// an error, and false otherwise.
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl,
bool SupportedForCompatibility) {
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");

// C++ [temp.local]p4:
// A template-parameter shall not be redeclared within its
// scope (including nested scopes).
// C++23 [temp.local]p6:
// The name of a template-parameter shall not be bound to any following.
// declaration whose locus is contained by the scope to which the
// template-parameter belongs.
//
// Make this a warning when MSVC compatibility is requested.
unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow
: diag::err_template_param_shadow;
// When MSVC compatibility is enabled, the diagnostic is always a warning
// by default. Otherwise, it an error unless SupportedForCompatibility is
// true, in which case it is a default-to-error warning.
unsigned DiagId =
getLangOpts().MSVCCompat
? diag::ext_template_param_shadow
: (SupportedForCompatibility ? diag::ext_compat_template_param_shadow
: diag::err_template_param_shadow);
const auto *ND = cast<NamedDecl>(PrevDecl);
Diag(Loc, DiagId) << ND->getDeclName();
NoteTemplateParameterLocation(*ND);
Expand Down Expand Up @@ -8502,9 +8505,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
return false;

// Find the nearest enclosing declaration scope.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
S = S->getDeclParent();

// C++ [temp.pre]p6: [P2096]
// A template, explicit specialization, or partial specialization shall not
Expand Down Expand Up @@ -10619,11 +10620,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}

// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
// Get the innermost enclosing declaration scope.
S = S->getDeclParent();

// Determine the type of the declaration.
TypeSourceInfo *T = GetTypeForDeclarator(D);
Expand Down
16 changes: 11 additions & 5 deletions clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,21 +301,27 @@ compareValueToThreshold(ProgramStateRef State, NonLoc Value, NonLoc Threshold,
// calling `evalBinOpNN`:
if (isNegative(SVB, State, Value) && isUnsigned(SVB, Threshold)) {
if (CheckEquality) {
// negative_value == unsigned_value is always false
// negative_value == unsigned_threshold is always false
return {nullptr, State};
}
// negative_value < unsigned_value is always false
// negative_value < unsigned_threshold is always true
return {State, nullptr};
}
if (isUnsigned(SVB, Value) && isNegative(SVB, State, Threshold)) {
// unsigned_value == negative_value and unsigned_value < negative_value are
// both always false
// unsigned_value == negative_threshold and
// unsigned_value < negative_threshold are both always false
return {nullptr, State};
}
// FIXME: these special cases are sufficient for handling real-world
// FIXME: These special cases are sufficient for handling real-world
// comparisons, but in theory there could be contrived situations where
// automatic conversion of a symbolic value (which can be negative and can be
// positive) leads to incorrect results.
// NOTE: We NEED to use the `evalBinOpNN` call in the "common" case, because
// we want to ensure that assumptions coming from this precondition and
// assumptions coming from regular C/C++ operator calls are represented by
// constraints on the same symbolic expression. A solution that would
// evaluate these "mathematical" compariosns through a separate pathway would
// be a step backwards in this sense.

const BinaryOperatorKind OpKind = CheckEquality ? BO_EQ : BO_LT;
auto BelowThreshold =
Expand Down
65 changes: 32 additions & 33 deletions clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,48 +124,47 @@ class CStringChecker : public Checker< eval::Call,
const CallEvent &)>;

CallDescriptionMap<FnCheck> Callbacks = {
{{CDF_MaybeBuiltin, {"memcpy"}, 3},
{{CDM::CLibrary, {"memcpy"}, 3},
std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"wmemcpy"}, 3},
{{CDM::CLibrary, {"wmemcpy"}, 3},
std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Wide)},
{{CDF_MaybeBuiltin, {"mempcpy"}, 3},
{{CDM::CLibrary, {"mempcpy"}, 3},
std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Regular)},
{{CDF_None, {"wmempcpy"}, 3},
{{CDM::Unspecified, {"wmempcpy"}, 3},
std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Wide)},
{{CDF_MaybeBuiltin, {"memcmp"}, 3},
{{CDM::CLibrary, {"memcmp"}, 3},
std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"wmemcmp"}, 3},
{{CDM::CLibrary, {"wmemcmp"}, 3},
std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Wide)},
{{CDF_MaybeBuiltin, {"memmove"}, 3},
{{CDM::CLibrary, {"memmove"}, 3},
std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"wmemmove"}, 3},
{{CDM::CLibrary, {"wmemmove"}, 3},
std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Wide)},
{{CDF_MaybeBuiltin, {"memset"}, 3}, &CStringChecker::evalMemset},
{{CDF_MaybeBuiltin, {"explicit_memset"}, 3}, &CStringChecker::evalMemset},
{{CDF_MaybeBuiltin, {"strcpy"}, 2}, &CStringChecker::evalStrcpy},
{{CDF_MaybeBuiltin, {"strncpy"}, 3}, &CStringChecker::evalStrncpy},
{{CDF_MaybeBuiltin, {"stpcpy"}, 2}, &CStringChecker::evalStpcpy},
{{CDF_MaybeBuiltin, {"strlcpy"}, 3}, &CStringChecker::evalStrlcpy},
{{CDF_MaybeBuiltin, {"strcat"}, 2}, &CStringChecker::evalStrcat},
{{CDF_MaybeBuiltin, {"strncat"}, 3}, &CStringChecker::evalStrncat},
{{CDF_MaybeBuiltin, {"strlcat"}, 3}, &CStringChecker::evalStrlcat},
{{CDF_MaybeBuiltin, {"strlen"}, 1}, &CStringChecker::evalstrLength},
{{CDF_MaybeBuiltin, {"wcslen"}, 1}, &CStringChecker::evalstrLength},
{{CDF_MaybeBuiltin, {"strnlen"}, 2}, &CStringChecker::evalstrnLength},
{{CDF_MaybeBuiltin, {"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
{{CDF_MaybeBuiltin, {"strcmp"}, 2}, &CStringChecker::evalStrcmp},
{{CDF_MaybeBuiltin, {"strncmp"}, 3}, &CStringChecker::evalStrncmp},
{{CDF_MaybeBuiltin, {"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
{{CDF_MaybeBuiltin, {"strncasecmp"}, 3},
&CStringChecker::evalStrncasecmp},
{{CDF_MaybeBuiltin, {"strsep"}, 2}, &CStringChecker::evalStrsep},
{{CDF_MaybeBuiltin, {"bcopy"}, 3}, &CStringChecker::evalBcopy},
{{CDF_MaybeBuiltin, {"bcmp"}, 3},
{{CDM::CLibrary, {"memset"}, 3}, &CStringChecker::evalMemset},
{{CDM::CLibrary, {"explicit_memset"}, 3}, &CStringChecker::evalMemset},
{{CDM::CLibrary, {"strcpy"}, 2}, &CStringChecker::evalStrcpy},
{{CDM::CLibrary, {"strncpy"}, 3}, &CStringChecker::evalStrncpy},
{{CDM::CLibrary, {"stpcpy"}, 2}, &CStringChecker::evalStpcpy},
{{CDM::CLibrary, {"strlcpy"}, 3}, &CStringChecker::evalStrlcpy},
{{CDM::CLibrary, {"strcat"}, 2}, &CStringChecker::evalStrcat},
{{CDM::CLibrary, {"strncat"}, 3}, &CStringChecker::evalStrncat},
{{CDM::CLibrary, {"strlcat"}, 3}, &CStringChecker::evalStrlcat},
{{CDM::CLibrary, {"strlen"}, 1}, &CStringChecker::evalstrLength},
{{CDM::CLibrary, {"wcslen"}, 1}, &CStringChecker::evalstrLength},
{{CDM::CLibrary, {"strnlen"}, 2}, &CStringChecker::evalstrnLength},
{{CDM::CLibrary, {"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
{{CDM::CLibrary, {"strcmp"}, 2}, &CStringChecker::evalStrcmp},
{{CDM::CLibrary, {"strncmp"}, 3}, &CStringChecker::evalStrncmp},
{{CDM::CLibrary, {"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
{{CDM::CLibrary, {"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
{{CDM::CLibrary, {"strsep"}, 2}, &CStringChecker::evalStrsep},
{{CDM::CLibrary, {"bcopy"}, 3}, &CStringChecker::evalBcopy},
{{CDM::CLibrary, {"bcmp"}, 3},
std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"bzero"}, 2}, &CStringChecker::evalBzero},
{{CDF_MaybeBuiltin, {"explicit_bzero"}, 2}, &CStringChecker::evalBzero},
{{CDF_MaybeBuiltin, {"sprintf"}, 2}, &CStringChecker::evalSprintf},
{{CDF_MaybeBuiltin, {"snprintf"}, 2}, &CStringChecker::evalSnprintf},
{{CDM::CLibrary, {"bzero"}, 2}, &CStringChecker::evalBzero},
{{CDM::CLibrary, {"explicit_bzero"}, 2}, &CStringChecker::evalBzero},
{{CDM::CLibrary, {"sprintf"}, 2}, &CStringChecker::evalSprintf},
{{CDM::CLibrary, {"snprintf"}, 2}, &CStringChecker::evalSnprintf},
};

// These require a bit of special handling.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>,
/// first one wins.
///
/// eval::Call
bool evalCall(const CallExpr *CE, CheckerContext &C) const { return true; }
bool evalCall(const CallEvent &Call, CheckerContext &C) const { return true; }

/// Handles assumptions on symbolic values.
///
Expand Down
50 changes: 22 additions & 28 deletions clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,28 +718,24 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
{{{"isupper"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{{"isxdigit"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},

{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncat)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrncat)}},
TR::Prop({{1, 2}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcpy)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrlcpy)}},
TR::Prop({{1, 2}}, {{0}})},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcat)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrlcat)}},
TR::Prop({{1, 2}}, {{0}})},
{{CDF_MaybeBuiltin, {{"snprintf"}}},
{{CDM::CLibrary, {{"snprintf"}}},
TR::Prop({{1}, 3}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"sprintf"}}},
{{CDM::CLibrary, {{"sprintf"}}},
TR::Prop({{1}, 2}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strcpy"}}},
{{CDM::CLibrary, {{"strcpy"}}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDM::CLibrary, {{"stpcpy"}}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDM::CLibrary, {{"strcat"}}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDM::CLibrary, {{"wcsncat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"stpcpy"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strcat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"wcsncat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strdupa"}}},
TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"wcsdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDM::CLibrary, {{"strdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDM::CLibrary, {{"strdupa"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDM::CLibrary, {{"wcsdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},

// Sinks
{{{"system"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
Expand All @@ -753,31 +749,29 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
{{{"execvp"}}, TR::Sink({{0, 1}}, MsgSanitizeSystemArgs)},
{{{"execvpe"}}, TR::Sink({{0, 1, 2}}, MsgSanitizeSystemArgs)},
{{{"dlopen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
{{CDF_MaybeBuiltin, {{"malloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"calloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"alloca"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"memccpy"}}},
TR::Sink({{3}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"realloc"}}},
TR::Sink({{1}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"malloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"calloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"alloca"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"memccpy"}}}, TR::Sink({{3}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"realloc"}}}, TR::Sink({{1}}, MsgTaintedBufferSize)},
{{{{"setproctitle"}}}, TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
{{{{"setproctitle_fast"}}},
TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},

// SinkProps
{{CDF_MaybeBuiltin, BI.getName(Builtin::BImemcpy)},
{{CDM::CLibrary, BI.getName(Builtin::BImemcpy)},
TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BImemmove)}},
{{CDM::CLibrary, {BI.getName(Builtin::BImemmove)}},
TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncpy)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrncpy)}},
TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrndup)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrndup)}},
TR::SinkProp({{1}}, {{0, 1}}, {{ReturnValueIndex}},
MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"bcopy"}}},
{{CDM::CLibrary, {{"bcopy"}}},
TR::SinkProp({{2}}, {{0, 2}}, {{1}}, MsgTaintedBufferSize)}};

// `getenv` returns taint only in untrusted environments.
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,13 @@ class MallocChecker
{{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
{{{"calloc"}, 2}, &MallocChecker::checkCalloc},
{{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDF_MaybeBuiltin, {"strndup"}, 2}, &MallocChecker::checkStrdup},
{{CDF_MaybeBuiltin, {"strdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},
{{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
{{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
{{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
{{CDF_MaybeBuiltin, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{CDF_MaybeBuiltin, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
Expand Down
21 changes: 14 additions & 7 deletions clang/lib/StaticAnalyzer/Core/CallDescription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ static MaybeCount readRequiredParams(MaybeCount RequiredArgs,
return std::nullopt;
}

ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
ento::CallDescription::CallDescription(Mode MatchAs,
ArrayRef<StringRef> QualifiedName,
MaybeCount RequiredArgs /*= None*/,
MaybeCount RequiredParams /*= None*/)
: RequiredArgs(RequiredArgs),
RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
Flags(Flags) {
MatchAs(MatchAs) {
assert(!QualifiedName.empty());
this->QualifiedName.reserve(QualifiedName.size());
llvm::transform(QualifiedName, std::back_inserter(this->QualifiedName),
Expand All @@ -52,7 +52,8 @@ ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
ento::CallDescription::CallDescription(ArrayRef<StringRef> QualifiedName,
MaybeCount RequiredArgs /*= None*/,
MaybeCount RequiredParams /*= None*/)
: CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {}
: CallDescription(Mode::Unspecified, QualifiedName, RequiredArgs,
RequiredParams) {}

bool ento::CallDescription::matches(const CallEvent &Call) const {
// FIXME: Add ObjC Message support.
Expand All @@ -74,14 +75,20 @@ bool ento::CallDescription::matchesAsWritten(const CallExpr &CE) const {
return matchesImpl(FD, CE.getNumArgs(), FD->param_size());
}

bool ento::CallDescription::matchesImpl(const FunctionDecl *Callee,
size_t ArgCount,
bool ento::CallDescription::matchesImpl(const FunctionDecl *FD, size_t ArgCount,
size_t ParamCount) const {
const auto *FD = Callee;
if (!FD)
return false;

if (Flags & CDF_MaybeBuiltin) {
const bool isMethod = isa<CXXMethodDecl>(FD);

if (MatchAs == Mode::SimpleFunc && isMethod)
return false;

if (MatchAs == Mode::CXXMethod && !isMethod)
return false;

if (MatchAs == Mode::CLibrary) {
return CheckerContext::isCLibraryFunction(FD, getFunctionName()) &&
(!RequiredArgs || *RequiredArgs <= ArgCount) &&
(!RequiredParams || *RequiredParams <= ParamCount);
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}
)
2 changes: 2 additions & 0 deletions clang/test/AST/Interp/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ constexpr int dependent[4] = {
static_assert(dependent[2] == dependent[0], "");
static_assert(dependent[3] == dependent[1], "");

union { char x[]; } r = {0};

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc99-extensions"
#pragma clang diagnostic ignored "-Winitializer-overrides"
Expand Down
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
20 changes: 15 additions & 5 deletions clang/test/AST/Interp/complex.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify -Wno-unused-value %s
// RUN: %clang_cc1 -verify=ref -Wno-unused-value %s

// expected-no-diagnostics
// ref-no-diagnostics
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -Wno-unused-value %s
// RUN: %clang_cc1 -verify=both,ref -Wno-unused-value %s

constexpr _Complex double z1 = {1.0, 2.0};
static_assert(__real(z1) == 1.0, "");
Expand Down Expand Up @@ -256,3 +253,16 @@ namespace DeclRefCopy {
}
static_assert(localComplexArray() == (24 + 42), "");
}

namespace Builtin {
constexpr _Complex float A = __builtin_complex(10.0f, 20.0f);
static_assert(__real(A) == 10, "");
static_assert(__imag(A) == 20, "");

constexpr _Complex double B = __builtin_complex(10.0, 20.0);
static_assert(__real(B) == 10, "");
static_assert(__imag(B) == 20, "");


constexpr _Complex float C = __builtin_complex(10.0f, 20.0); // both-error {{arguments are of different types}}
}
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
2 changes: 1 addition & 1 deletion clang/test/Analysis/analyzer-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
// CHECK-NEXT: unix.DynamicMemoryModeling:Optimistic = false
// CHECK-NEXT: unix.Errno:AllowErrnoReadOutsideConditionExpressions = true
// CHECK-NEXT: unix.StdCLibraryFunctions:DisplayLoadedSummaries = false
// CHECK-NEXT: unix.StdCLibraryFunctions:ModelPOSIX = false
// CHECK-NEXT: unix.StdCLibraryFunctions:ModelPOSIX = true
// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: verbose-report-filename = false
// CHECK-NEXT: widen-loops = false
5 changes: 5 additions & 0 deletions clang/test/Analysis/std-c-library-functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple i686-unknown-linux \
// RUN: -verify

Expand All @@ -11,6 +12,7 @@
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple x86_64-unknown-linux \
// RUN: -verify

Expand All @@ -19,6 +21,7 @@
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple armv7-a15-linux \
// RUN: -verify

Expand All @@ -27,6 +30,7 @@
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple thumbv7-a15-linux \
// RUN: -verify

Expand All @@ -36,6 +40,7 @@
// RUN: -analyzer-config unix.StdCLibraryFunctions:DisplayLoadedSummaries=true \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple i686-unknown-linux 2>&1 | FileCheck %s

// CHECK: Loaded summary for: int isalnum(int)
Expand Down
22 changes: 18 additions & 4 deletions clang/test/CXX/temp/temp.res/temp.local/p6.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y
// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y -Wno-error=strict-primary-template-shadow

namespace N {}

Expand Down Expand Up @@ -127,16 +127,30 @@ template<int T> struct Z { // expected-note 16{{declared here}}
template<typename T> // expected-note {{declared here}}
void f(int T) {} // expected-error {{declaration of 'T' shadows template parameter}}

// FIXME: These are ill-formed: a template-parameter shall not have the same name as the template name.
namespace A {
template<typename T> struct T {}; // expected-error{{declaration of 'T' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
template<typename T> struct U {
template<typename V> struct V {}; // expected-error{{declaration of 'V' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
};
}
namespace B {
template<typename T> void T() {}
template<typename T> void T() {} // expected-warning{{declaration of 'T' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}

template<typename T> struct U {
template<typename V> void V(); // expected-warning{{declaration of 'V' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
};
}
namespace C {
template<typename T> int T;
template<typename T> int T; // expected-warning{{declaration of 'T' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
template<typename T> struct U {
template<typename V> static int V; // expected-warning{{declaration of 'V' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
};
}

namespace PR28023 {
Expand Down
24 changes: 8 additions & 16 deletions clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-rotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ void test_builtin_ppc_rldimi() {
// CHECK: %res = alloca i64, align 8
// CHECK-NEXT: [[RA:%[0-9]+]] = load i64, ptr @ull, align 8
// CHECK-NEXT: [[RB:%[0-9]+]] = load i64, ptr @ull, align 8
// CHECK-NEXT: [[RC:%[0-9]+]] = call i64 @llvm.fshl.i64(i64 [[RA]], i64 [[RA]], i64 63)
// CHECK-NEXT: [[RD:%[0-9]+]] = and i64 [[RC]], 72057593769492480
// CHECK-NEXT: [[RE:%[0-9]+]] = and i64 [[RB]], -72057593769492481
// CHECK-NEXT: [[RF:%[0-9]+]] = or i64 [[RD]], [[RE]]
// CHECK-NEXT: store i64 [[RF]], ptr %res, align 8
// CHECK-NEXT: [[RC:%[0-9]+]] = call i64 @llvm.ppc.rldimi(i64 [[RA]], i64 [[RB]], i32 63, i64 72057593769492480)
// CHECK-NEXT: store i64 [[RC]], ptr %res, align 8
// CHECK-NEXT: ret void

/*shift = 63, mask = 0x00FFFFFFF0000000 = 72057593769492480, ~mask = 0xFF0000000FFFFFFF = -72057593769492481*/
Expand All @@ -32,11 +29,8 @@ void test_builtin_ppc_rlwimi() {
// CHECK: %res = alloca i32, align 4
// CHECK-NEXT: [[RA:%[0-9]+]] = load i32, ptr @ui, align 4
// CHECK-NEXT: [[RB:%[0-9]+]] = load i32, ptr @ui, align 4
// CHECK-NEXT: [[RC:%[0-9]+]] = call i32 @llvm.fshl.i32(i32 [[RA]], i32 [[RA]], i32 31)
// CHECK-NEXT: [[RD:%[0-9]+]] = and i32 [[RC]], 16776960
// CHECK-NEXT: [[RE:%[0-9]+]] = and i32 [[RB]], -16776961
// CHECK-NEXT: [[RF:%[0-9]+]] = or i32 [[RD]], [[RE]]
// CHECK-NEXT: store i32 [[RF]], ptr %res, align 4
// CHECK-NEXT: [[RC:%[0-9]+]] = call i32 @llvm.ppc.rlwimi(i32 [[RA]], i32 [[RB]], i32 31, i32 16776960)
// CHECK-NEXT: store i32 [[RC]], ptr %res, align 4
// CHECK-NEXT: ret void

/*shift = 31, mask = 0xFFFF00 = 16776960, ~mask = 0xFFFFFFFFFF0000FF = -16776961*/
Expand All @@ -47,9 +41,8 @@ void test_builtin_ppc_rlwnm() {
// CHECK-LABEL: test_builtin_ppc_rlwnm
// CHECK: %res = alloca i32, align 4
// CHECK-NEXT: [[RA:%[0-9]+]] = load i32, ptr @ui, align 4
// CHECK-NEXT: [[RB:%[0-9]+]] = call i32 @llvm.fshl.i32(i32 [[RA]], i32 [[RA]], i32 31)
// CHECK-NEXT: [[RC:%[0-9]+]] = and i32 [[RB]], 511
// CHECK-NEXT: store i32 [[RC]], ptr %res, align 4
// CHECK-NEXT: [[RB:%[0-9]+]] = call i32 @llvm.ppc.rlwnm(i32 [[RA]], i32 31, i32 511)
// CHECK-NEXT: store i32 [[RB]], ptr %res, align 4
// CHECK-NEXT: ret void

/*shift = 31, mask = 0x1FF = 511*/
Expand All @@ -63,9 +56,8 @@ void test_builtin_ppc_rlwnm2(unsigned int shift) {
// CHECK-NEXT: store i32 %shift, ptr %shift.addr, align 4
// CHECK-NEXT: [[RA:%[0-9]+]] = load i32, ptr @ui, align 4
// CHECK-NEXT: [[RB:%[0-9]+]] = load i32, ptr %shift.addr, align 4
// CHECK-NEXT: [[RC:%[0-9]+]] = call i32 @llvm.fshl.i32(i32 [[RA]], i32 [[RA]], i32 [[RB]])
// CHECK-NEXT: [[RD:%[0-9]+]] = and i32 [[RC]], 511
// CHECK-NEXT: store i32 [[RD]], ptr %res, align 4
// CHECK-NEXT: [[RC:%[0-9]+]] = call i32 @llvm.ppc.rlwnm(i32 [[RA]], i32 [[RB]], i32 511)
// CHECK-NEXT: store i32 [[RC]], ptr %res, align 4
// CHECK-NEXT: ret void

/*mask = 0x1FF = 511*/
Expand Down
6 changes: 6 additions & 0 deletions clang/test/Layout/dump-complete-invalid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %clang_cc1 -verify -fsyntax-only -fdump-record-layouts-complete %s

struct Incomplete; // expected-note {{forward declaration}}

// Check we don't crash on trying to print out an invalid declaration.
struct Invalid : Incomplete {}; // expected-error {{base class has incomplete type}}
57 changes: 56 additions & 1 deletion clang/test/Layout/dump-complete.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -emit-llvm-only -fdump-record-layouts-complete %s | FileCheck %s
// RUN: %clang_cc1 -fsyntax-only -fdump-record-layouts-complete %s | FileCheck %s

struct a {
int x;
Expand All @@ -12,7 +12,62 @@ class c {};

class d;

template <typename>
struct s {
int x;
};

template <typename T>
struct ts {
T x;
};

template <>
struct ts<void> {
float f;
};

void f() {
ts<int> a;
ts<double> b;
ts<void> c;
}

namespace gh83671 {
template <class _Tp, _Tp __v>
struct integral_constant {
static constexpr const _Tp value = __v;
typedef integral_constant type;
};

template <bool _Val>
using _BoolConstant = integral_constant<bool, _Val>;

template <class _Tp, class _Up>
struct is_same : _BoolConstant<__is_same(_Tp, _Up)> {};

template < class _Tp >
class numeric_limits {};

template < class _Tp >
class numeric_limits< const _Tp > : public numeric_limits< _Tp > {};
}

namespace gh83684 {
template <class Pointer>
struct AllocationResult {
Pointer ptr = nullptr;
int count = 0;
};
}

// CHECK: 0 | struct a
// CHECK: 0 | struct b
// CHECK: 0 | class c
// CHECK: 0 | struct ts<void>
// CHECK-NEXT: 0 | float
// CHECK: 0 | struct ts<int>
// CHECK: 0 | struct ts<double>
// CHECK-NOT: 0 | class d
// CHECK-NOT: 0 | struct s
// CHECK-NOT: 0 | struct AllocationResult
8 changes: 8 additions & 0 deletions clang/test/Parser/cxx-declarator-attribute-crash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s

// expected-error@+5{{brackets are not allowed here}}
// expected-error@+4{{a type specifier is required for all declarations}}
// expected-warning@+3{{unknown attribute 'h' ignored}}
// expected-error@+2{{definition of variable with array type}}
// expected-error@+1{{expected ';'}}
[][[h]]l
21 changes: 10 additions & 11 deletions clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,11 +488,10 @@ TEST(CallDescription, NegativeMatchQualifiedNames) {
}

TEST(CallDescription, MatchBuiltins) {
// Test CDF_MaybeBuiltin - a flag that allows matching weird builtins.
// Test CDM::CLibrary - a flag that allows matching weird builtins.
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{{"memset"}, 3}, false},
{{CDF_MaybeBuiltin, {"memset"}, 3}, true}})),
{{{{"memset"}, 3}, false}, {{CDM::CLibrary, {"memset"}, 3}, true}})),
"void foo() {"
" int x;"
" __builtin___memset_chk(&x, 0, sizeof(x),"
Expand All @@ -503,8 +502,8 @@ TEST(CallDescription, MatchBuiltins) {
SCOPED_TRACE("multiple similar builtins");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDF_MaybeBuiltin, {"memcpy"}, 3}, false},
{{CDF_MaybeBuiltin, {"wmemcpy"}, 3}, true}})),
{{{CDM::CLibrary, {"memcpy"}, 3}, false},
{{CDM::CLibrary, {"wmemcpy"}, 3}, true}})),
R"(void foo(wchar_t *x, wchar_t *y) {
__builtin_wmemcpy(x, y, sizeof(wchar_t));
})"));
Expand All @@ -513,17 +512,17 @@ TEST(CallDescription, MatchBuiltins) {
SCOPED_TRACE("multiple similar builtins reversed order");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDF_MaybeBuiltin, {"wmemcpy"}, 3}, true},
{{CDF_MaybeBuiltin, {"memcpy"}, 3}, false}})),
{{{CDM::CLibrary, {"wmemcpy"}, 3}, true},
{{CDM::CLibrary, {"memcpy"}, 3}, false}})),
R"(void foo(wchar_t *x, wchar_t *y) {
__builtin_wmemcpy(x, y, sizeof(wchar_t));
})"));
}
{
SCOPED_TRACE("lookbehind and lookahead mismatches");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDF_MaybeBuiltin, {"func"}}, false}})),
std::unique_ptr<FrontendAction>(
new CallDescriptionAction<>({{{CDM::CLibrary, {"func"}}, false}})),
R"(
void funcXXX();
void XXXfunc();
Expand All @@ -537,8 +536,8 @@ TEST(CallDescription, MatchBuiltins) {
{
SCOPED_TRACE("lookbehind and lookahead matches");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDF_MaybeBuiltin, {"func"}}, true}})),
std::unique_ptr<FrontendAction>(
new CallDescriptionAction<>({{{CDM::CLibrary, {"func"}}, true}})),
R"(
void func();
void func_XXX();
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/builtins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ set(GENERIC_SOURCES

# We only build BF16 files when "__bf16" is available.
set(BF16_SOURCES
extendbfsf2.c
truncdfbf2.c
truncsfbf2.c
)
Expand Down
13 changes: 13 additions & 0 deletions compiler-rt/lib/builtins/extendbfsf2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//===-- lib/extendbfsf2.c - bfloat -> single conversion -----------*- C -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#define SRC_BFLOAT16
#define DST_SINGLE
#include "fp_extend_impl.inc"

COMPILER_RT_ABI float __extendbfsf2(src_t a) { return __extendXfYf2__(a); }
15 changes: 15 additions & 0 deletions compiler-rt/lib/builtins/fp_extend.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ static inline int src_rep_t_clz_impl(src_rep_t a) {

#define src_rep_t_clz src_rep_t_clz_impl

#elif defined SRC_BFLOAT16
#ifdef COMPILER_RT_HAS_BFLOAT16
typedef __bf16 src_t;
#else
typedef uint16_t src_t;
#endif
typedef uint16_t src_rep_t;
#define SRC_REP_C UINT16_C
static const int srcBits = sizeof(src_t) * CHAR_BIT;
static const int srcSigFracBits = 7;
// -1 accounts for the sign bit.
// srcBits - srcSigFracBits - 1
static const int srcExpBits = 8;
#define src_rep_t_clz __builtin_clz

#else
#error Source should be half, single, or double precision!
#endif // end source precision
Expand Down
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
13 changes: 12 additions & 1 deletion flang/docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,24 @@
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
"myst_parser",
"sphinx.ext.todo",
"sphinx.ext.mathjax",
"sphinx.ext.intersphinx",
"sphinx.ext.autodoc",
]

# When building man pages, we do not use the markdown pages,
# So, we can continue without the myst_parser dependencies.
# Doing so reduces dependencies of some packaged llvm distributions.
try:
import myst_parser

extensions.append("myst_parser")
except ImportError:
if not tags.has("builder-man"):
raise


# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
myst_heading_anchors = 6
Expand Down
7 changes: 7 additions & 0 deletions flang/include/flang/Optimizer/CodeGen/CodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

namespace fir {

class LLVMTypeConverter;

struct NameUniquer;

#define GEN_PASS_DECL_FIRTOLLVMLOWERING
Expand Down Expand Up @@ -80,6 +82,11 @@ std::unique_ptr<mlir::Pass> createLLVMDialectToLLVMPass(
std::unique_ptr<mlir::Pass> createBoxedProcedurePass();
std::unique_ptr<mlir::Pass> createBoxedProcedurePass(bool useThunks);

/// Populate the given list with patterns that convert from FIR to LLVM.
void populateFIRToLLVMConversionPatterns(fir::LLVMTypeConverter &converter,
mlir::RewritePatternSet &patterns,
fir::FIRToLLVMPassOptions &options);

// declarative passes
#define GEN_PASS_REGISTRATION
#include "flang/Optimizer/CodeGen/CGPasses.h.inc"
Expand Down
54 changes: 30 additions & 24 deletions flang/lib/Optimizer/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3937,30 +3937,7 @@ class FIRToLLVMLowering
options.applyTBAA || applyTBAA,
options.forceUnifiedTBAATree, *dl};
mlir::RewritePatternSet pattern(context);
pattern.insert<
AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
BoxOffsetOpConversion, BoxProcHostOpConversion, BoxRankOpConversion,
BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion,
CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DivcOpConversion,
EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion,
HasValueOpConversion, InsertOnRangeOpConversion,
InsertValueOpConversion, IsPresentOpConversion,
LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion,
SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
SliceOpConversion, StoreOpConversion, StringLitOpConversion,
SubcOpConversion, TypeDescOpConversion, TypeInfoOpConversion,
UnboxCharOpConversion, UnboxProcOpConversion, UndefOpConversion,
UnreachableOpConversion, UnrealizedConversionCastOpConversion,
XArrayCoorOpConversion, XEmboxOpConversion, XReboxOpConversion,
ZeroOpConversion>(typeConverter, options);
fir::populateFIRToLLVMConversionPatterns(typeConverter, pattern, options);
mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern);
mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern);
mlir::arith::populateArithToLLVMConversionPatterns(typeConverter, pattern);
Expand Down Expand Up @@ -4072,3 +4049,32 @@ fir::createLLVMDialectToLLVMPass(llvm::raw_ostream &output,
fir::LLVMIRLoweringPrinter printer) {
return std::make_unique<LLVMIRLoweringPass>(output, printer);
}

void fir::populateFIRToLLVMConversionPatterns(
fir::LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns,
fir::FIRToLLVMPassOptions &options) {
patterns.insert<
AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
BoxOffsetOpConversion, BoxProcHostOpConversion, BoxRankOpConversion,
BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion,
CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DivcOpConversion,
EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion,
HasValueOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion,
MulcOpConversion, NegcOpConversion, NoReassocOpConversion,
SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
ShiftOpConversion, SliceOpConversion, StoreOpConversion,
StringLitOpConversion, SubcOpConversion, TypeDescOpConversion,
TypeInfoOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
UndefOpConversion, UnreachableOpConversion,
UnrealizedConversionCastOpConversion, XArrayCoorOpConversion,
XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(converter,
options);
}
3 changes: 2 additions & 1 deletion flang/lib/Optimizer/Transforms/MemoryAllocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ class MemoryAllocationOpt
return keepStackAllocation(alloca, &func.front(), options);
});

patterns.insert<AllocaOpConversion>(context, analysis.getReturns(func));
llvm::SmallVector<mlir::Operation *> returnOps = analysis.getReturns(func);
patterns.insert<AllocaOpConversion>(context, returnOps);
if (mlir::failed(
mlir::applyPartialConversion(func, target, std::move(patterns)))) {
mlir::emitError(func.getLoc(),
Expand Down
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
2 changes: 2 additions & 0 deletions flang/test/Fir/memory-allocation-opt.fir
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// RUN: fir-opt --memory-allocation-opt="dynamic-array-on-heap=true maximum-array-alloc-size=1024" %s | FileCheck %s
// FIXME: started crashing on windows https://github.com/llvm/llvm-project/issues/83534
// UNSUPPORTED: system-windows

// Test for size of array being too big.

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
1 change: 1 addition & 0 deletions libc/config/baremetal/arm/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.fenv
libc.include.errno
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.math
libc.include.stdio
Expand Down
1 change: 1 addition & 0 deletions libc/config/baremetal/riscv/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.fenv
libc.include.errno
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.math
libc.include.stdio
Expand Down
1 change: 1 addition & 0 deletions libc/config/darwin/arm/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.errno
libc.include.fenv
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.limits
libc.include.math
Expand Down
1 change: 1 addition & 0 deletions libc/config/darwin/x86_64/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set(TARGET_PUBLIC_HEADERS
# Fenv is currently disabled.
#libc.include.fenv
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.limits
libc.include.math
Expand Down
1 change: 1 addition & 0 deletions libc/config/gpu/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.ctype
libc.include.string
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.limits
libc.include.math
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/aarch64/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.features
libc.include.fenv
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.limits
libc.include.math
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/arm/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.fenv
libc.include.errno
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.math
libc.include.stdckdint
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/riscv/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.features
libc.include.fenv
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.limits
libc.include.math
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/headers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.features
libc.include.fenv
libc.include.float
libc.include.stdint
libc.include.inttypes
libc.include.limits
libc.include.math
Expand Down
8 changes: 8 additions & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ add_gen_header(
.llvm-libc-macros.float_macros
)

add_gen_header(
stdint
DEF_FILE stdint.h.def
GEN_HDR stdint.h
DEPENDS
.llvm-libc-macros.stdint_macros
)

add_gen_header(
limits
DEF_FILE limits.h.def
Expand Down
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-macros/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ add_macro_header(
file-seek-macros.h
)

add_macro_header(
stdint_macros
HDR
stdint-macros.h
)

add_macro_header(
float_macros
HDR
Expand Down
878 changes: 878 additions & 0 deletions libc/include/llvm-libc-macros/stdint-macros.h

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions libc/include/llvm-libc-types/float128.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,17 @@
// https://github.com/llvm/llvm-project/issues/80195
#if defined(__STDC_IEC_60559_BFP__) && !defined(__clang__) && \
!defined(__cplusplus)
// Use _Float128 C23 type.
#define LIBC_COMPILER_HAS_C23_FLOAT128
#define LIBC_TYPES_HAS_FLOAT128
typedef _Float128 float128;
#elif defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
// Use __float128 type. gcc and clang sometime use __SIZEOF_FLOAT128__ to
// notify the availability of __float128.
// clang also uses __FLOAT128__ macro to notify the availability of __float128
// type: https://reviews.llvm.org/D15120
#define LIBC_COMPILER_HAS_FLOAT128_EXTENSION
#define LIBC_TYPES_HAS_FLOAT128
typedef __float128 float128;
#elif (LDBL_MANT_DIG == 113)
// Use long double.
#define LIBC_TYPES_HAS_FLOAT128
typedef long double float128;
#endif

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//===--- ByteCodeGenError.h - Byte code generation error --------*- C++ -*-===//
//===-- C standard library header stdint.h --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "ByteCodeGenError.h"
#ifndef LLVM_LIBC_STDINT_H
#define LLVM_LIBC_STDINT_H

using namespace clang;
using namespace clang::interp;
#include <llvm-libc-macros/stdint-macros.h>

char ByteCodeGenError::ID;
#endif // LLVM_LIBC_STDINT_H
3 changes: 3 additions & 0 deletions libc/spec/stdc.td
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,8 @@ def StdC : StandardSpec<"stdc"> {
]
>;

HeaderSpec StdInt = HeaderSpec<"StdInt.h">;

HeaderSpec Limits = HeaderSpec<"limits.h">;

NamedType SigAtomicT = NamedType<"sig_atomic_t">;
Expand Down Expand Up @@ -1268,6 +1270,7 @@ def StdC : StandardSpec<"stdc"> {
Errno,
Fenv,
Float,
StdInt,
Limits,
Math,
String,
Expand Down
4 changes: 2 additions & 2 deletions libc/src/__support/FPUtil/ManipulationFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ LIBC_INLINE T nextafter(T from, U to) {
} // namespace fputil
} // namespace LIBC_NAMESPACE

#ifdef LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#ifdef LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
#include "x86_64/NextAfterLongDouble.h"
#endif // LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80

#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_MANIPULATIONFUNCTIONS_H
4 changes: 2 additions & 2 deletions libc/src/__support/FPUtil/NormalFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ template <typename T> struct NormalFloat {
}
};

#ifdef LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#ifdef LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
template <>
LIBC_INLINE void
NormalFloat<long double>::init_from_bits(FPBits<long double> bits) {
Expand Down Expand Up @@ -261,7 +261,7 @@ template <> LIBC_INLINE NormalFloat<long double>::operator long double() const {
result.set_implicit_bit(1);
return result.get_val();
}
#endif // LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80

} // namespace fputil
} // namespace LIBC_NAMESPACE
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/dyadic_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

namespace LIBC_NAMESPACE::fputil {

// A generic class to perform comuptations of high precision floating points.
// A generic class to perform computations of high precision floating points.
// We store the value in dyadic format, including 3 fields:
// sign : boolean value - false means positive, true means negative
// exponent: the exponent value of the least significant bit of the mantissa.
Expand Down
8 changes: 4 additions & 4 deletions libc/src/__support/FPUtil/generic/sqrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ template <typename T> struct SpecialLongDouble {
static constexpr bool VALUE = false;
};

#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
template <> struct SpecialLongDouble<long double> {
static constexpr bool VALUE = true;
};
#endif // LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80

template <typename T>
LIBC_INLINE void normalize(int &exponent,
Expand All @@ -43,12 +43,12 @@ LIBC_INLINE void normalize(int &exponent,
mantissa <<= shift;
}

#ifdef LIBC_LONG_DOUBLE_IS_FLOAT64
#ifdef LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64
template <>
LIBC_INLINE void normalize<long double>(int &exponent, uint64_t &mantissa) {
normalize<double>(exponent, mantissa);
}
#elif !defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#elif !defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
template <>
LIBC_INLINE void normalize<long double>(int &exponent, UInt128 &mantissa) {
const uint64_t hi_bits = static_cast<uint64_t>(mantissa >> 64);
Expand Down
4 changes: 2 additions & 2 deletions libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ LIBC_INLINE long double sqrt(long double x);

// Correctly rounded SQRT for all rounding modes.
// Shift-and-add algorithm.
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
LIBC_INLINE long double sqrt(long double x) {
using LDBits = FPBits<long double>;
using StorageType = typename LDBits::StorageType;
Expand Down Expand Up @@ -130,7 +130,7 @@ LIBC_INLINE long double sqrt(long double x) {
return out.get_val();
}
}
#endif // LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80

} // namespace x86
} // namespace fputil
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/x86_64/sqrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ template <> LIBC_INLINE double sqrt<double>(double x) {
return result;
}

#ifdef LIBC_LONG_DOUBLE_IS_FLOAT64
#ifdef LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64
template <> LIBC_INLINE long double sqrt<long double>(long double x) {
long double result;
__asm__ __volatile__("sqrtsd %x1, %x0" : "=x"(result) : "x"(x));
Expand Down
8 changes: 3 additions & 5 deletions libc/src/__support/GPU/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
if(NOT LIBC_TARGET_OS_IS_GPU)
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
return()
endif()

foreach(target nvptx amdgpu generic)
add_subdirectory(${target})
list(APPEND target_gpu_utils libc.src.__support.GPU.${target}.${target}_utils)
endforeach()
add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
set(target_gpu_utils libc.src.__support.GPU.${LIBC_TARGET_ARCHITECTURE}.${LIBC_TARGET_ARCHITECTURE}_utils)

add_header_library(
utils
Expand Down
4 changes: 2 additions & 2 deletions libc/src/__support/float_to_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ class FloatToString {
}
};

#if !defined(LIBC_LONG_DOUBLE_IS_FLOAT64) && \
#if !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) && \
!defined(LIBC_COPT_FLOAT_TO_STR_NO_SPECIALIZE_LD)
// --------------------------- LONG DOUBLE FUNCTIONS ---------------------------

Expand Down Expand Up @@ -837,7 +837,7 @@ template <> class FloatToString<long double> {
}
};

#endif // !LIBC_LONG_DOUBLE_IS_FLOAT64 &&
#endif // !LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64 &&
// !LIBC_COPT_FLOAT_TO_STR_NO_SPECIALIZE_LD

} // namespace LIBC_NAMESPACE
Expand Down
17 changes: 7 additions & 10 deletions libc/src/__support/macros/properties/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@

// 'long double' properties.
#if (LDBL_MANT_DIG == 53)
#define LIBC_LONG_DOUBLE_IS_FLOAT64
#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64
#elif (LDBL_MANT_DIG == 64)
#define LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#define LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
#elif (LDBL_MANT_DIG == 113)
#define LIBC_LONG_DOUBLE_IS_FLOAT128
#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128
#endif

// float16 support.
// -- float16 support ---------------------------------------------------------
// TODO: move this logic to "llvm-libc-types/float16.h"
#if defined(LIBC_TARGET_ARCH_IS_X86_64) && defined(LIBC_TARGET_CPU_HAS_SSE2)
#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 1500)) || \
Expand All @@ -50,11 +50,8 @@ using float16 = _Float16;
#endif
#endif

// float128 support.
#if defined(LIBC_COMPILER_HAS_C23_FLOAT128) || \
defined(LIBC_COMPILER_HAS_FLOAT128_EXTENSION) || \
defined(LIBC_LONG_DOUBLE_IS_FLOAT128)
#define LIBC_TYPES_HAS_FLOAT128
#endif
// -- float128 support --------------------------------------------------------
// LIBC_TYPES_HAS_FLOAT128 and 'float128' type are provided by
// "include/llvm-libc-types/float128.h"

#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H
16 changes: 9 additions & 7 deletions libc/src/__support/str_to_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ template <class T> LIBC_INLINE void set_implicit_bit(fputil::FPBits<T> &) {
return;
}

#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
template <>
LIBC_INLINE void
set_implicit_bit<long double>(fputil::FPBits<long double> &result) {
result.set_implicit_bit(result.get_biased_exponent() != 0);
}
#endif
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80

// This Eisel-Lemire implementation is based on the algorithm described in the
// paper Number Parsing at a Gigabyte per Second, Software: Practice and
Expand Down Expand Up @@ -176,7 +176,7 @@ eisel_lemire(ExpandedFloat<T> init_num,
return output;
}

#if !defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#if !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
template <>
LIBC_INLINE cpp::optional<ExpandedFloat<long double>>
eisel_lemire<long double>(ExpandedFloat<long double> init_num,
Expand Down Expand Up @@ -297,7 +297,7 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num,
output.exponent = exp2;
return output;
}
#endif
#endif // !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)

// The nth item in POWERS_OF_TWO represents the greatest power of two less than
// 10^n. This tells us how much we can safely shift without overshooting.
Expand Down Expand Up @@ -460,7 +460,7 @@ template <> class ClingerConsts<double> {
static constexpr double MAX_EXACT_INT = 9007199254740991.0;
};

#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
template <> class ClingerConsts<long double> {
public:
static constexpr long double POWERS_OF_TEN_ARRAY[] = {
Expand All @@ -473,7 +473,7 @@ template <> class ClingerConsts<long double> {
static constexpr long double MAX_EXACT_INT =
ClingerConsts<double>::MAX_EXACT_INT;
};
#elif defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
template <> class ClingerConsts<long double> {
public:
static constexpr long double POWERS_OF_TEN_ARRAY[] = {
Expand All @@ -484,7 +484,7 @@ template <> class ClingerConsts<long double> {
static constexpr int32_t DIGITS_IN_MANTISSA = 21;
static constexpr long double MAX_EXACT_INT = 18446744073709551615.0L;
};
#else
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
template <> class ClingerConsts<long double> {
public:
static constexpr long double POWERS_OF_TEN_ARRAY[] = {
Expand All @@ -498,6 +498,8 @@ template <> class ClingerConsts<long double> {
static constexpr long double MAX_EXACT_INT =
10384593717069655257060992658440191.0L;
};
#else
#error "Unknown long double type"
#endif

// Take an exact mantissa and exponent and attempt to convert it using only
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/__support/FPUtil/fpbits_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
}
#else
TEST(LlvmLibcFPBitsTest, LongDoubleType) {
#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
return; // The tests for the "double" type cover for this case.
#else
using LongDoubleBits = FPBits<long double>;
Expand Down
8 changes: 5 additions & 3 deletions libc/test/src/__support/str_to_long_double_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ namespace LIBC_NAMESPACE {
using LlvmLibcStrToLongDblTest = LlvmLibcStrToFloatTest<long double>;
using LIBC_NAMESPACE::operator""_u128;

#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)

TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat64AsLongDouble) {
eisel_lemire_test(123, 0, 0x1EC00000000000, 1029);
}

#elif defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)

TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80Simple) {
eisel_lemire_test(123, 0, 0xf600000000000000, 16389);
Expand Down Expand Up @@ -54,7 +54,7 @@ TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80Fallback) {
ASSERT_FALSE(internal::eisel_lemire<long double>({1, -1000}).has_value());
}

#else // Quad precision long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)

TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat128Simple) {
eisel_lemire_test(123, 0, 0x1ec00'00000000'00000000'00000000_u128, 16389);
Expand All @@ -77,6 +77,8 @@ TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat128Fallback) {
.has_value());
}

#else
#error "Unknown long double type"
#endif

} // namespace LIBC_NAMESPACE
8 changes: 5 additions & 3 deletions libc/test/src/math/smoke/nanl_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
#include "test/UnitTest/Test.h"
#include <signal.h>

#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
#define SELECT_LONG_DOUBLE(val, _, __) val
#elif defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
#define SELECT_LONG_DOUBLE(_, val, __) val
#else
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
#define SELECT_LONG_DOUBLE(_, __, val) val
#else
#error "Unknown long double type"
#endif

class LlvmLibcNanlTest : public LIBC_NAMESPACE::testing::Test {
Expand Down
112 changes: 56 additions & 56 deletions libc/test/src/stdio/sprintf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -775,29 +775,29 @@ TEST_F(LlvmLibcSPrintfTest, FloatHexExpConv) {
// Length Modifier Tests.

written = LIBC_NAMESPACE::sprintf(buff, "%La", 0.1L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0xc.ccccccccccccccdp-7");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.999999999999999999999999999ap-4");
#endif

written = LIBC_NAMESPACE::sprintf(buff, "%La", 1.0e1000L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0xf.38db1f9dd3dac05p+3318");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "inf");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.e71b63f3ba7b580af1a52d2a7379p+3321");
#endif

written = LIBC_NAMESPACE::sprintf(buff, "%La", 1.0e-1000L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0x8.68a9188a89e1467p-3325");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "0x0p+0");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.0d152311513c28ce202627c06ec2p-3322");
#endif

Expand Down Expand Up @@ -899,20 +899,20 @@ TEST_F(LlvmLibcSPrintfTest, FloatHexExpConv) {
ASSERT_STREQ_LEN(written, buff, "0x0p+0");

written = LIBC_NAMESPACE::sprintf(buff, "%.1La", 0.1L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0xc.dp-7");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
#endif

written = LIBC_NAMESPACE::sprintf(buff, "%.1La", 0xf.fffffffffffffffp16380L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0x1.0p+16384");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "inf");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383");
#endif

Expand Down Expand Up @@ -1158,8 +1158,8 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {

// Some float128 systems (specifically the ones used for aarch64 buildbots)
// don't respect signs for long double NaNs.
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80) || \
defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) || \
defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
written = LIBC_NAMESPACE::sprintf(buff, "%LF", -ld_nan);
ASSERT_STREQ_LEN(written, buff, "-NAN");
#endif
Expand Down Expand Up @@ -1354,20 +1354,20 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalConv) {

/*
written = LIBC_NAMESPACE::sprintf(buff, "%.1La", 0.1L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0xc.dp-7");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
#endif
written = LIBC_NAMESPACE::sprintf(buff, "%.1La",
0xf.fffffffffffffffp16380L); #if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0x1.0p+16384");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
0xf.fffffffffffffffp16380L); #if
defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) ASSERT_STREQ_LEN(written, buff,
"0x1.0p+16384"); #elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "inf");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383");
#endif
*/
Expand Down Expand Up @@ -1603,8 +1603,8 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalLongDoubleConv) {

// Length Modifier Tests.

// TODO(michaelrj): Add tests for LIBC_LONG_DOUBLE_IS_FLOAT64 and 128 bit long
// double systems.
// TODO(michaelrj): Add tests for LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64 and 128
// bit long double systems.
// TODO(michaelrj): Fix the tests to only depend on the digits the long double
// is accurate for.

Expand All @@ -1614,7 +1614,7 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalLongDoubleConv) {
written = LIBC_NAMESPACE::sprintf(buff, "%.Lf", -2.5L);
ASSERT_STREQ_LEN(written, buff, "-2");

#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)

written = LIBC_NAMESPACE::sprintf(buff, "%Lf", 1e100L);
ASSERT_STREQ_LEN(written, buff,
Expand Down Expand Up @@ -1930,7 +1930,7 @@ TEST_F(LlvmLibcSPrintfTest, FloatDecimalLongDoubleConv) {
"570449525088342437216896462077260223998756027453411520977536701491759878"
"422771447006016890777855573925295187921971811871399320142563330377888532"
"179817332113");
#endif // LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
}

TEST_F(LlvmLibcSPrintfTest, FloatExponentConv) {
Expand Down Expand Up @@ -2171,20 +2171,20 @@ TEST_F(LlvmLibcSPrintfTest, FloatExponentConv) {

/*
written = LIBC_NAMESPACE::sprintf(buff, "%.1La", 0.1L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0xc.dp-7");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
#endif
written = LIBC_NAMESPACE::sprintf(buff, "%.1La",
0xf.fffffffffffffffp16380L); #if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0x1.0p+16384");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
0xf.fffffffffffffffp16380L); #if
defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) ASSERT_STREQ_LEN(written, buff,
"0x1.0p+16384"); #elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "inf");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383");
#endif
*/
Expand Down Expand Up @@ -2423,7 +2423,7 @@ TEST_F(LlvmLibcSPrintfTest, FloatExponentLongDoubleConv) {
ForceRoundingMode r(RoundingMode::Nearest);
// Length Modifier Tests.

#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
written = LIBC_NAMESPACE::sprintf(buff, "%.9Le", 1000000000500000000.1L);
ASSERT_STREQ_LEN(written, buff, "1.000000001e+18");

Expand Down Expand Up @@ -2783,34 +2783,34 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) {
written = LIBC_NAMESPACE::sprintf(buff, "%.10g", 0x1.0p-1074);
ASSERT_STREQ_LEN(written, buff, "4.940656458e-324");

#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)

written = LIBC_NAMESPACE::sprintf(buff, "%.60Lg", 0xa.aaaaaaaaaaaaaabp-7L);
ASSERT_STREQ_LEN(
written, buff,
"0.0833333333333333333355920878593448009041821933351457118988037");

#endif // LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80

// Long double precision tests.
// These are currently commented out because they require long double support
// that isn't ready yet.
/*
written = LIBC_NAMESPACE::sprintf(buff, "%.1La", 0.1L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0xc.dp-7");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
#endif
written = LIBC_NAMESPACE::sprintf(buff, "%.1La",
0xf.fffffffffffffffp16380L); #if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0x1.0p+16384");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
0xf.fffffffffffffffp16380L); #if
defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) ASSERT_STREQ_LEN(written, buff,
"0x1.0p+16384"); #elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "inf");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383");
#endif
*/
Expand Down Expand Up @@ -3053,7 +3053,7 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoLongDoubleConv) {

// Length Modifier Tests.

#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)

written = LIBC_NAMESPACE::sprintf(buff, "%Lg", 0xf.fffffffffffffffp+16380L);
ASSERT_STREQ_LEN(written, buff, "1.18973e+4932");
Expand All @@ -3064,7 +3064,7 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoLongDoubleConv) {
written = LIBC_NAMESPACE::sprintf(buff, "%Lg", 9.99999999999e-100L);
ASSERT_STREQ_LEN(written, buff, "1e-99");

#endif // LIBC_LONG_DOUBLE_IS_X86_FLOAT80
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80

// TODO: Uncomment the below tests after long double support is added
/*
Expand Down Expand Up @@ -3171,29 +3171,29 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoLongDoubleConv) {
*/
/*
written = LIBC_NAMESPACE::sprintf(buff, "%La", 0.1L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0xc.ccccccccccccccdp-7");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.999999999999999999999999999ap-4");
#endif
written = LIBC_NAMESPACE::sprintf(buff, "%La", 1.0e1000L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0xf.38db1f9dd3dac05p+3318");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "inf");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.e71b63f3ba7b580af1a52d2a7379p+3321");
#endif
written = LIBC_NAMESPACE::sprintf(buff, "%La", 1.0e-1000L);
#if defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
ASSERT_STREQ_LEN(written, buff, "0x8.68a9188a89e1467p-3325");
#elif defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
ASSERT_STREQ_LEN(written, buff, "0x0p+0");
#else // 128 bit long double
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
ASSERT_STREQ_LEN(written, buff, "0x1.0d152311513c28ce202627c06ec2p-3322");
#endif
*/
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/stdio/sscanf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ TEST(LlvmLibcSScanfTest, FloatConvLengthModifier) {
EXPECT_EQ(ret_val, 1);
// 1e600 may be larger than the maximum long double (if long double is double).
// In that case both of these should be evaluated as inf.
#ifdef LIBC_LONG_DOUBLE_IS_FLOAT64
#ifdef LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64
EXPECT_FP_EQ(ld_result, d_inf);
#else
EXPECT_FP_EQ(ld_result, 1.0e600L);
Expand Down
10 changes: 6 additions & 4 deletions libc/test/src/stdlib/strtold_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@

#include <stddef.h>

#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
#define SELECT_CONST(val, _, __) val
#elif defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
#define SELECT_CONST(_, val, __) val
#else
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
#define SELECT_CONST(_, __, val) val
#else
#error "Unknown long double type"
#endif

class LlvmLibcStrToLDTest : public LIBC_NAMESPACE::testing::Test {
public:
#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
void run_test(const char *inputString, const ptrdiff_t expectedStrLen,
const uint64_t expectedRawData, const int expectedErrno = 0)
#else
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
22 changes: 10 additions & 12 deletions libcxx/include/__format/parser_std_format_spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,10 @@ class _LIBCPP_TEMPLATE_VIS __parser {
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator __parse(_ParseContext& __ctx, __fields __fields) {
auto __begin = __ctx.begin();
auto __end = __ctx.end();
if (__begin == __end || *__begin == _CharT('}'))
if (__begin == __end || *__begin == _CharT('}') || (__fields.__use_range_fill_ && *__begin == _CharT(':')))
return __begin;

if (__parse_fill_align(__begin, __end, __fields.__use_range_fill_) && __begin == __end)
if (__parse_fill_align(__begin, __end) && __begin == __end)
return __begin;

if (__fields.__sign_) {
Expand Down Expand Up @@ -574,12 +574,10 @@ class _LIBCPP_TEMPLATE_VIS __parser {
return false;
}

_LIBCPP_HIDE_FROM_ABI constexpr void __validate_fill_character(_CharT __fill, bool __use_range_fill) {
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_fill_character(_CharT __fill) {
// The forbidden fill characters all code points formed from a single code unit, thus the
// check can be omitted when more code units are used.
if (__use_range_fill && (__fill == _CharT('{') || __fill == _CharT(':')))
std::__throw_format_error("The fill option contains an invalid value");
else if (__fill == _CharT('{'))
if (__fill == _CharT('{'))
std::__throw_format_error("The fill option contains an invalid value");
}

Expand All @@ -590,7 +588,7 @@ class _LIBCPP_TEMPLATE_VIS __parser {
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|| (same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2)
# endif
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end, bool __use_range_fill) {
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
Expand All @@ -606,7 +604,7 @@ class _LIBCPP_TEMPLATE_VIS __parser {
// The forbidden fill characters all are code points encoded
// in one code unit, thus the check can be omitted when more
// code units are used.
__validate_fill_character(*__begin, __use_range_fill);
__validate_fill_character(*__begin);

std::copy_n(__begin, __code_units, std::addressof(__fill_.__data[0]));
__begin += __code_units + 1;
Expand All @@ -623,7 +621,7 @@ class _LIBCPP_TEMPLATE_VIS __parser {
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <contiguous_iterator _Iterator>
requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4)
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end, bool __use_range_fill) {
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
Expand All @@ -632,7 +630,7 @@ class _LIBCPP_TEMPLATE_VIS __parser {
if (!__unicode::__is_scalar_value(*__begin))
std::__throw_format_error("The fill option contains an invalid value");

__validate_fill_character(*__begin, __use_range_fill);
__validate_fill_character(*__begin);

__fill_.__data[0] = *__begin;
__begin += 2;
Expand All @@ -651,14 +649,14 @@ class _LIBCPP_TEMPLATE_VIS __parser {
# else // _LIBCPP_HAS_NO_UNICODE
// range-fill and tuple-fill are identical
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end, bool __use_range_fill) {
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
if (__begin + 1 != __end) {
if (__parse_alignment(*(__begin + 1))) {
__validate_fill_character(*__begin, __use_range_fill);
__validate_fill_character(*__begin);

__fill_.__data[0] = *__begin;
__begin += 2;
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
Loading