18 changes: 3 additions & 15 deletions clang/include/clang/Lex/HeaderSearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,6 @@ struct HeaderFileInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned Resolved : 1;

/// Whether this is a header inside a framework that is currently
/// being built.
///
/// When a framework is being built, the headers have not yet been placed
/// into the appropriate framework subdirectories, and therefore are
/// provided via a header map. This bit indicates when this is one of
/// those framework headers.
LLVM_PREFERRED_TYPE(bool)
unsigned IndexHeaderMapHeader : 1;

/// Whether this file has been looked up as a header.
LLVM_PREFERRED_TYPE(bool)
unsigned IsValid : 1;
Expand All @@ -132,15 +122,11 @@ struct HeaderFileInfo {
/// external storage.
LazyIdentifierInfoPtr LazyControllingMacro;

/// If this header came from a framework include, this is the name
/// of the framework.
StringRef Framework;

HeaderFileInfo()
: IsLocallyIncluded(false), isImport(false), isPragmaOnce(false),
DirInfo(SrcMgr::C_User), External(false), isModuleHeader(false),
isTextualModuleHeader(false), isCompilingModuleHeader(false),
Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {}
Resolved(false), IsValid(false) {}

/// Retrieve the controlling macro for this header file, if
/// any.
Expand All @@ -154,6 +140,8 @@ struct HeaderFileInfo {
void mergeModuleMembership(ModuleMap::ModuleHeaderRole Role);
};

static_assert(sizeof(HeaderFileInfo) <= 16);

/// An external source of header file information, which may supply
/// information about header files already included.
class ExternalHeaderFileInfoSource {
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Lex/HeaderSearchOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ enum IncludeDirGroup {
/// Paths for '\#include <>' added by '-I'.
Angled,

/// Like Angled, but marks header maps used when building frameworks.
IndexHeaderMap,

/// Like Angled, but marks system directories.
System,

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace serialization {
/// Version 4 of AST files also requires that the version control branch and
/// revision match exactly, since there is no backward compatibility of
/// AST files at this time.
const unsigned VERSION_MAJOR = 32;
const unsigned VERSION_MAJOR = 33;

/// AST file minor version number supported by this version of
/// Clang.
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -1764,4 +1764,8 @@ def UncountedLocalVarsChecker : Checker<"UncountedLocalVarsChecker">,
HelpText<"Check uncounted local variables.">,
Documentation<HasDocumentation>;

def UncheckedLocalVarsChecker : Checker<"UncheckedLocalVarsChecker">,
HelpText<"Check unchecked local variables.">,
Documentation<HasDocumentation>;

} // end alpha.webkit
8 changes: 6 additions & 2 deletions clang/lib/AST/ByteCode/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,14 @@ template <bool Signed> class IntegralAP final {
return IntegralAP<false>(Copy);
}

void bitcastToMemory(std::byte *Dest) const { assert(false); }
void bitcastToMemory(std::byte *Dest) const {
llvm::StoreIntToMemory(V, (uint8_t *)Dest, bitWidth() / 8);
}

static IntegralAP bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
return IntegralAP();
APInt V(BitWidth, static_cast<uint64_t>(0), Signed);
llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8);
return IntegralAP(V);
}

ComparisonCategoryResult compare(const IntegralAP &RHS) const {
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -3062,7 +3062,8 @@ inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
return false;

if constexpr (std::is_same_v<T, Floating>) {
assert(false && "Implement bitcasting to a floating type");
assert(Sem);
S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
} else {
assert(!Sem);
S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
Expand Down
16 changes: 10 additions & 6 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,7 @@ static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
if (!Call->getArg(0)->getType()->isIntegerType() ||
if (Call->getNumArgs() != 2 || !Call->getArg(0)->getType()->isIntegerType() ||
!Call->getArg(1)->getType()->isIntegerType())
return false;

Expand Down Expand Up @@ -1286,7 +1286,9 @@ static bool interp__builtin_ia32_bzhi(InterpState &S, CodePtr OpPC,
const Function *Func,
const CallExpr *Call) {
QualType CallType = Call->getType();
if (!CallType->isIntegerType())
if (Call->getNumArgs() != 2 || !Call->getArg(0)->getType()->isIntegerType() ||
!Call->getArg(1)->getType()->isIntegerType() ||
!CallType->isIntegerType())
return false;

PrimType ValT = *S.Ctx.classify(Call->getArg(0));
Expand All @@ -1311,7 +1313,8 @@ static bool interp__builtin_ia32_lzcnt(InterpState &S, CodePtr OpPC,
const Function *Func,
const CallExpr *Call) {
QualType CallType = Call->getType();
if (!CallType->isIntegerType())
if (!CallType->isIntegerType() ||
!Call->getArg(0)->getType()->isIntegerType())
return false;

APSInt Val = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(0)));
Expand All @@ -1324,7 +1327,8 @@ static bool interp__builtin_ia32_tzcnt(InterpState &S, CodePtr OpPC,
const Function *Func,
const CallExpr *Call) {
QualType CallType = Call->getType();
if (!CallType->isIntegerType())
if (!CallType->isIntegerType() ||
!Call->getArg(0)->getType()->isIntegerType())
return false;

APSInt Val = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(0)));
Expand All @@ -1336,7 +1340,7 @@ static bool interp__builtin_ia32_pdep(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
if (!Call->getArg(0)->getType()->isIntegerType() ||
if (Call->getNumArgs() != 2 || !Call->getArg(0)->getType()->isIntegerType() ||
!Call->getArg(1)->getType()->isIntegerType())
return false;

Expand All @@ -1361,7 +1365,7 @@ static bool interp__builtin_ia32_pext(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
if (!Call->getArg(0)->getType()->isIntegerType() ||
if (Call->getNumArgs() != 2 || !Call->getArg(0)->getType()->isIntegerType() ||
!Call->getArg(1)->getType()->isIntegerType())
return false;

Expand Down
11 changes: 8 additions & 3 deletions clang/lib/Basic/DiagnosticIDs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,12 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
DiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)
Result = diag::Severity::Error;

// Rest of the mappings are only applicable for diagnostics associated with a
// SourceLocation, bail out early for others.
if (!Diag.hasSourceManager())
return Result;

const auto &SM = Diag.getSourceManager();
// Custom diagnostics always are emitted in system headers.
bool ShowInSystemHeader =
!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
Expand All @@ -583,15 +589,14 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// because we also want to ignore extensions and warnings in -Werror and
// -pedantic-errors modes, which *map* warnings/extensions to errors.
if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
Diag.getSourceManager().isInSystemHeader(
Diag.getSourceManager().getExpansionLoc(Loc)))
SM.isInSystemHeader(SM.getExpansionLoc(Loc)))
return diag::Severity::Ignored;

// We also ignore warnings due to system macros
bool ShowInSystemMacro =
!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro;
if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&
Diag.getSourceManager().isInSystemMacro(Loc))
SM.isInSystemMacro(Loc))
return diag::Severity::Ignored;

return Result;
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasAMXCOMPLEX = true;
} else if (Feature == "+amx-fp8") {
HasAMXFP8 = true;
} else if (Feature == "+amx-transpose") {
HasAMXTRANSPOSE = true;
} else if (Feature == "+cmpccxadd") {
HasCMPCCXADD = true;
} else if (Feature == "+raoint") {
Expand Down Expand Up @@ -951,6 +953,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__AMX_COMPLEX__");
if (HasAMXFP8)
Builder.defineMacro("__AMX_FP8__");
if (HasAMXTRANSPOSE)
Builder.defineMacro("__AMX_TRANSPOSE__");
if (HasCMPCCXADD)
Builder.defineMacro("__CMPCCXADD__");
if (HasRAOINT)
Expand Down Expand Up @@ -1079,9 +1083,10 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("amx-bf16", true)
.Case("amx-complex", true)
.Case("amx-fp16", true)
.Case("amx-fp8", true)
.Case("amx-int8", true)
.Case("amx-tile", true)
.Case("amx-fp8", true)
.Case("amx-transpose", true)
.Case("avx", true)
.Case("avx10.1-256", true)
.Case("avx10.1-512", true)
Expand Down Expand Up @@ -1198,9 +1203,10 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("amx-bf16", HasAMXBF16)
.Case("amx-complex", HasAMXCOMPLEX)
.Case("amx-fp16", HasAMXFP16)
.Case("amx-fp8", HasAMXFP8)
.Case("amx-int8", HasAMXINT8)
.Case("amx-tile", HasAMXTILE)
.Case("amx-fp8", HasAMXFP8)
.Case("amx-transpose", HasAMXTRANSPOSE)
.Case("avx", SSELevel >= AVX)
.Case("avx10.1-256", HasAVX10_1)
.Case("avx10.1-512", HasAVX10_1_512)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasAMXBF16 = false;
bool HasAMXCOMPLEX = false;
bool HasAMXFP8 = false;
bool HasAMXTRANSPOSE = false;
bool HasSERIALIZE = false;
bool HasTSXLDTRK = false;
bool HasUSERMSR = false;
Expand Down
52 changes: 52 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16994,6 +16994,58 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// instruction, but it will create a memset that won't be optimized away.
return Builder.CreateMemSet(Ops[0], Ops[1], Ops[2], Align(1), true);
}
// Corresponding to intrisics which will return 2 tiles (tile0_tile1).
case X86::BI__builtin_ia32_t2rpntlvwz0_internal:
case X86::BI__builtin_ia32_t2rpntlvwz0t1_internal:
case X86::BI__builtin_ia32_t2rpntlvwz1_internal:
case X86::BI__builtin_ia32_t2rpntlvwz1t1_internal: {
Intrinsic::ID IID;
switch (BuiltinID) {
default:
llvm_unreachable("Unsupported intrinsic!");
case X86::BI__builtin_ia32_t2rpntlvwz0_internal:
IID = Intrinsic::x86_t2rpntlvwz0_internal;
break;
case X86::BI__builtin_ia32_t2rpntlvwz0t1_internal:
IID = Intrinsic::x86_t2rpntlvwz0t1_internal;
break;
case X86::BI__builtin_ia32_t2rpntlvwz1_internal:
IID = Intrinsic::x86_t2rpntlvwz1_internal;
break;
case X86::BI__builtin_ia32_t2rpntlvwz1t1_internal:
IID = Intrinsic::x86_t2rpntlvwz1t1_internal;
break;
}

// Ops = (Row0, Col0, Col1, DstPtr0, DstPtr1, SrcPtr, Stride)
Value *Call = Builder.CreateCall(CGM.getIntrinsic(IID),
{Ops[0], Ops[1], Ops[2], Ops[5], Ops[6]});

auto *PtrTy = E->getArg(3)->getType()->getAs<PointerType>();
assert(PtrTy && "arg3 must be of pointer type");
QualType PtreeTy = PtrTy->getPointeeType();
llvm::Type *TyPtee = ConvertType(PtreeTy);

// Bitcast amx type (x86_amx) to vector type (256 x i32)
// Then store tile0 into DstPtr0
Value *T0 = Builder.CreateExtractValue(Call, 0);
Value *VecT0 = Builder.CreateIntrinsic(Intrinsic::x86_cast_tile_to_vector,
{TyPtee}, {T0});
Builder.CreateDefaultAlignedStore(VecT0, Ops[3]);

// Then store tile1 into DstPtr1
Value *T1 = Builder.CreateExtractValue(Call, 1);
Value *VecT1 = Builder.CreateIntrinsic(Intrinsic::x86_cast_tile_to_vector,
{TyPtee}, {T1});
Value *Store = Builder.CreateDefaultAlignedStore(VecT1, Ops[4]);

// Note: Here we escape directly use x86_tilestored64_internal to store
// the results due to it can't make sure the Mem written scope. This may
// cause shapes reloads after first amx intrinsic, which current amx reg-
// ister allocation has no ability to handle it.

return Store;
}
case X86::BI__ud2:
// llvm.trap makes a ud2a instruction on x86.
return EmitTrapCall(Intrinsic::trap);
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,9 @@ bool ToolChain::needsProfileRT(const ArgList &Args) {
Args.hasArg(options::OPT_fprofile_instr_generate) ||
Args.hasArg(options::OPT_fprofile_instr_generate_EQ) ||
Args.hasArg(options::OPT_fcreate_profile) ||
Args.hasArg(options::OPT_forder_file_instrumentation);
Args.hasArg(options::OPT_forder_file_instrumentation) ||
Args.hasArg(options::OPT_fprofile_generate_cold_function_coverage) ||
Args.hasArg(options::OPT_fprofile_generate_cold_function_coverage_EQ);
}

bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) {
Expand Down
25 changes: 23 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,28 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
}
}

if (auto *ColdFuncCoverageArg = Args.getLastArg(
options::OPT_fprofile_generate_cold_function_coverage,
options::OPT_fprofile_generate_cold_function_coverage_EQ)) {
SmallString<128> Path(
ColdFuncCoverageArg->getOption().matches(
options::OPT_fprofile_generate_cold_function_coverage_EQ)
? ColdFuncCoverageArg->getValue()
: "");
llvm::sys::path::append(Path, "default_%m.profraw");
// FIXME: Idealy the file path should be passed through
// `-fprofile-instrument-path=`(InstrProfileOutput), however, this field is
// shared with other profile use path(see PGOOptions), we need to refactor
// PGOOptions to make it work.
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString(
Twine("--instrument-cold-function-only-path=") + Path));
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("--pgo-instrument-cold-function-only");
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("--pgo-function-entry-coverage");
}

Arg *PGOGenArg = nullptr;
if (PGOGenerateArg) {
assert(!CSPGOGenerateArg);
Expand Down Expand Up @@ -1185,8 +1207,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,

Args.addAllArgs(CmdArgs,
{options::OPT_D, options::OPT_U, options::OPT_I_Group,
options::OPT_F, options::OPT_index_header_map,
options::OPT_embed_dir_EQ});
options::OPT_F, options::OPT_embed_dir_EQ});

// Add -Wp, and -Xpreprocessor if using the preprocessor.

Expand Down
16 changes: 14 additions & 2 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,9 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString("--sysroot=" + TC.getSDKLibraryRootDir()));

// Default to PIE for non-static executables.
const bool PIE = !Relocatable && !Shared && !Static;
if (Args.hasFlag(options::OPT_pie, options::OPT_no_pie, PIE))
const bool PIE = Args.hasFlag(options::OPT_pie, options::OPT_no_pie,
!Relocatable && !Shared && !Static);
if (PIE)
CmdArgs.push_back("-pie");

if (!Relocatable) {
Expand All @@ -276,6 +277,12 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-z");
CmdArgs.push_back("start-stop-visibility=hidden");

CmdArgs.push_back("-z");
CmdArgs.push_back("common-page-size=0x4000");

CmdArgs.push_back("-z");
CmdArgs.push_back("max-page-size=0x4000");

// Patch relocated regions of DWARF whose targets are eliminated at link
// time with specific tombstones, such that they're recognisable by the
// PlayStation debugger.
Expand All @@ -295,6 +302,11 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Shared)
CmdArgs.push_back("--shared");

// Provide a base address for non-PIE executables. This includes cases where
// -static is supplied without -pie.
if (!Relocatable && !Shared && !PIE)
CmdArgs.push_back("--image-base=0x400000");

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
Expand Down
30 changes: 6 additions & 24 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3190,24 +3190,17 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
auto It = Opts.UserEntries.begin();
auto End = Opts.UserEntries.end();

// Add -I..., -F..., and -index-header-map options in order.
for (; It < End && Matches(*It, {frontend::IndexHeaderMap, frontend::Angled},
std::nullopt, true);
// Add -I... and -F... options in order.
for (; It < End && Matches(*It, {frontend::Angled}, std::nullopt, true);
++It) {
OptSpecifier Opt = [It, Matches]() {
if (Matches(*It, frontend::IndexHeaderMap, true, true))
return OPT_F;
if (Matches(*It, frontend::IndexHeaderMap, false, true))
return OPT_I;
if (Matches(*It, frontend::Angled, true, true))
return OPT_F;
if (Matches(*It, frontend::Angled, false, true))
return OPT_I;
llvm_unreachable("Unexpected HeaderSearchOptions::Entry.");
}();

if (It->Group == frontend::IndexHeaderMap)
GenerateArg(Consumer, OPT_index_header_map);
GenerateArg(Consumer, Opt, It->Path);
};

Expand Down Expand Up @@ -3319,8 +3312,7 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
llvm::CachedHashString(MacroDef.split('=').first));
}

// Add -I..., -F..., and -index-header-map options in order.
bool IsIndexHeaderMap = false;
// Add -I... and -F... options in order.
bool IsSysrootSpecified =
Args.hasArg(OPT__sysroot_EQ) || Args.hasArg(OPT_isysroot);

Expand All @@ -3339,20 +3331,10 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
return A->getValue();
};

for (const auto *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map)) {
if (A->getOption().matches(OPT_index_header_map)) {
// -index-header-map applies to the next -I or -F.
IsIndexHeaderMap = true;
continue;
}

frontend::IncludeDirGroup Group =
IsIndexHeaderMap ? frontend::IndexHeaderMap : frontend::Angled;

for (const auto *A : Args.filtered(OPT_I, OPT_F)) {
bool IsFramework = A->getOption().matches(OPT_F);
Opts.AddPath(PrefixHeaderPath(A, IsFramework), Group, IsFramework,
/*IgnoreSysroot*/ true);
IsIndexHeaderMap = false;
Opts.AddPath(PrefixHeaderPath(A, IsFramework), frontend::Angled,
IsFramework, /*IgnoreSysroot=*/true);
}

// Add -iprefix/-iwithprefix/-iwithprefixbefore options.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Headers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,9 @@ set(x86_files
ammintrin.h
amxcomplexintrin.h
amxfp16intrin.h
amxintrin.h
amxfp8intrin.h
amxintrin.h
amxtransposeintrin.h
avx10_2_512bf16intrin.h
avx10_2_512convertintrin.h
avx10_2_512minmaxintrin.h
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Headers/amxintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ static __inline__ void __DEFAULT_FN_ATTRS_TILE _tile_release(void) {
/// bytes. Since there is no 2D type in llvm IR, we use vector type to
/// represent 2D tile and the fixed size is maximum amx tile register size.
typedef int _tile1024i __attribute__((__vector_size__(1024), __aligned__(64)));
typedef int _tile1024i_1024a
__attribute__((__vector_size__(1024), __aligned__(1024)));

/// This is internal intrinsic. C/C++ user should avoid calling it directly.
static __inline__ _tile1024i __DEFAULT_FN_ATTRS_INT8
Expand Down
248 changes: 248 additions & 0 deletions clang/lib/Headers/amxtransposeintrin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
/* ===--- amxtransposeintrin.h - AMX_TRANSPOSE intrinsics -*- 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
*
* ===-----------------------------------------------------------------------===
*/

#ifndef __IMMINTRIN_H
#error "Never use <amxtransposeintrin.h> directly; use <immintrin.h> instead."
#endif /* __IMMINTRIN_H */

#ifndef __AMX_TRANSPOSEINTRIN_H
#define __AMX_TRANSPOSEINTRIN_H
#ifdef __x86_64__

#define __DEFAULT_FN_ATTRS_TRANSPOSE \
__attribute__((__always_inline__, __nodebug__, __target__("amx-transpose")))

#define _tile_2rpntlvwz0(tdst, base, stride) \
__builtin_ia32_t2rpntlvwz0(tdst, base, stride)
#define _tile_2rpntlvwz0t1(tdst, base, stride) \
__builtin_ia32_t2rpntlvwz0t1(tdst, base, stride)
#define _tile_2rpntlvwz1(tdst, base, stride) \
__builtin_ia32_t2rpntlvwz1(tdst, base, stride)
#define _tile_2rpntlvwz1t1(tdst, base, stride) \
__builtin_ia32_t2rpntlvwz1t1(tdst, base, stride)

/// Transpose 32-bit elements from \a src and write the result to \a dst.
///
/// \headerfile <immintrin.h>
///
/// \code
/// void _tile_transposed(__tile dst, __tile src);
/// \endcode
///
/// This intrinsic corresponds to the <c> TTRANSPOSED </c> instruction.
///
/// \param dst
/// The destination tile. Max size is 1024 Bytes.
/// \param src
/// The source tile. Max size is 1024 Bytes.
///
/// \code{.operation}
///
/// FOR i := 0 TO (dst.rows-1)
/// tmp[511:0] := 0
/// FOR j := 0 TO (dst.colsb/4-1)
/// tmp.dword[j] := src.row[j].dword[i]
/// ENDFOR
/// dst.row[i] := tmp
/// ENDFOR
///
/// zero_upper_rows(dst, dst.rows)
/// zero_tileconfig_start()
/// \endcode
#define _tile_transposed(dst, src) __builtin_ia32_ttransposed(dst, src)

static __inline__ void __DEFAULT_FN_ATTRS_TRANSPOSE _tile_2rpntlvwz0_internal(
unsigned short row, unsigned short col0, unsigned short col1,
_tile1024i *dst0, _tile1024i *dst1, const void *base,
__SIZE_TYPE__ stride) {
// Use __tile1024i_1024a* to escape the alignment check in
// clang/test/Headers/x86-intrinsics-headers-clean.cpp
__builtin_ia32_t2rpntlvwz0_internal(row, col0, col1, (_tile1024i_1024a *)dst0,
(_tile1024i_1024a *)dst1, base,
(__SIZE_TYPE__)(stride));
}

static __inline__ void __DEFAULT_FN_ATTRS_TRANSPOSE _tile_2rpntlvwz0t1_internal(
unsigned short row, unsigned short col0, unsigned short col1,
_tile1024i *dst0, _tile1024i *dst1, const void *base,
__SIZE_TYPE__ stride) {
__builtin_ia32_t2rpntlvwz0t1_internal(
row, col0, col1, (_tile1024i_1024a *)dst0, (_tile1024i_1024a *)dst1, base,
(__SIZE_TYPE__)(stride));
}

static __inline__ void __DEFAULT_FN_ATTRS_TRANSPOSE _tile_2rpntlvwz1_internal(
unsigned short row, unsigned short col0, unsigned short col1,
_tile1024i *dst0, _tile1024i *dst1, const void *base,
__SIZE_TYPE__ stride) {
__builtin_ia32_t2rpntlvwz1_internal(row, col0, col1, (_tile1024i_1024a *)dst0,
(_tile1024i_1024a *)dst1, base,
(__SIZE_TYPE__)(stride));
}

static __inline__ void __DEFAULT_FN_ATTRS_TRANSPOSE _tile_2rpntlvwz1t1_internal(
unsigned short row, unsigned short col0, unsigned short col1,
_tile1024i *dst0, _tile1024i *dst1, const void *base,
__SIZE_TYPE__ stride) {
__builtin_ia32_t2rpntlvwz1t1_internal(
row, col0, col1, (_tile1024i_1024a *)dst0, (_tile1024i_1024a *)dst1, base,
(__SIZE_TYPE__)(stride));
}

// This is internal intrinsic. C/C++ user should avoid calling it directly.
static __inline__ _tile1024i __DEFAULT_FN_ATTRS_TRANSPOSE
_tile_transposed_internal(unsigned short m, unsigned short n, _tile1024i src) {
return __builtin_ia32_ttransposed_internal(m, n, src);
}

/// Converts a pair of tiles from memory into VNNI format, and places the
/// results in a pair of destinations specified by dst. The pair of tiles
/// in memory is specified via a tsib; the second tile is after the first
/// one, separated by the same stride that separates each row.
/// The tile configuration for the destination tiles indicates the amount
/// of data to read from memory. The instruction will load a number of rows
/// that is equal to twice the number of rows in tmm1. The size of each row
/// is equal to the average width of the destination tiles. If the second
/// tile is configured with zero rows and columns, only the first tile will
/// be written.
/// Provides a hint to the implementation that the data will likely not be
/// reused in the near future and the data caching can be optimized.
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the <c> T2RPNTLVWZ0 </c> instruction.
///
/// \param dst0
/// First tile of destination tile pair. Max size is 1024i*2 Bytes.
/// \param dst1
/// Second tile of destination tile pair. Max size is 1024i*2 Bytes.
/// \param base
/// A pointer to base address.
/// \param stride
/// The stride between the rows' data to be loaded in memory.
__DEFAULT_FN_ATTRS_TRANSPOSE
static void __tile_2rpntlvwz0(__tile1024i *dst0, __tile1024i *dst1,
const void *base, __SIZE_TYPE__ stride) {
_tile_2rpntlvwz0_internal(dst0->row, dst0->col, dst1->col, &dst0->tile,
&dst1->tile, base, stride);
}

/// Converts a pair of tiles from memory into VNNI format, and places the
/// results in a pair of destinations specified by dst. The pair of tiles
/// in memory is specified via a tsib; the second tile is after the first
/// one, separated by the same stride that separates each row.
/// The tile configuration for the destination tiles indicates the amount
/// of data to read from memory. The instruction will load a number of rows
/// that is equal to twice the number of rows in tmm1. The size of each row
/// is equal to the average width of the destination tiles. If the second
/// tile is configured with zero rows and columns, only the first tile will
/// be written.
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the <c> T2RPNTLVWZ0T1 </c> instruction.
///
/// \param dst0
/// First tile of destination tile pair. Max size is 1024i*2 Bytes.
/// \param dst1
/// Second tile of destination tile pair. Max size is 1024i*2 Bytes.
/// \param base
/// A pointer to base address.
/// \param stride
/// The stride between the rows' data to be loaded in memory.
__DEFAULT_FN_ATTRS_TRANSPOSE
static void __tile_2rpntlvwz0t1(__tile1024i *dst0, __tile1024i *dst1,
const void *base, __SIZE_TYPE__ stride) {
_tile_2rpntlvwz0t1_internal(dst0->row, dst0->col, dst1->col, &dst0->tile,
&dst1->tile, base, stride);
}

/// Converts a pair of tiles from memory into VNNI format, and places the
/// results in a pair of destinations specified by dst. The pair of tiles
/// in memory is specified via a tsib; the second tile is after the first
/// one, separated by the same stride that separates each row.
/// The tile configuration for the destination tiles indicates the amount
/// of data to read from memory. The instruction will load a number of rows
/// that is equal to twice the number of rows in tmm1. The size of each row
/// is equal to the average width of the destination tiles. If the second
/// tile is configured with zero rows and columns, only the first tile will
/// be written. The last row will be not be read from memory but instead
/// filled with zeros.
/// Provides a hint to the implementation that the data will likely not be
/// reused in the near future and the data caching can be optimized.
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the <c> T2RPNTLVWZ1 </c> instruction.
///
/// \param dst0
/// First tile of destination tile pair. Max size is 1024i*2 Bytes.
/// \param dst1
/// Second tile of destination tile pair. Max size is 1024i*2 Bytes.
/// \param base
/// A pointer to base address.
/// \param stride
/// The stride between the rows' data to be loaded in memory.
__DEFAULT_FN_ATTRS_TRANSPOSE
static void __tile_2rpntlvwz1(__tile1024i *dst0, __tile1024i *dst1,
const void *base, __SIZE_TYPE__ stride) {
_tile_2rpntlvwz1_internal(dst0->row, dst0->col, dst1->col, &dst0->tile,
&dst1->tile, base, stride);
}

/// Converts a pair of tiles from memory into VNNI format, and places the
/// results in a pair of destinations specified by dst. The pair of tiles
/// in memory is specified via a tsib; the second tile is after the first
/// one, separated by the same stride that separates each row.
/// The tile configuration for the destination tiles indicates the amount
/// of data to read from memory. The instruction will load a number of rows
/// that is equal to twice the number of rows in tmm1. The size of each row
/// is equal to the average width of the destination tiles. If the second
/// tile is configured with zero rows and columns, only the first tile will
/// be written. The last row will be not be read from memory but instead
/// filled with zeros.
/// Provides a hint to the implementation that the data will likely not be
/// reused in the near future and the data caching can be optimized.
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the <c> T2RPNTLVWZ1T1 </c> instruction.
///
/// \param dst0
/// First tile of destination tile pair. Max size is 1024i*2 Bytes.
/// \param dst1
/// Second tile of destination tile pair. Max size is 1024i*2 Bytes.
/// \param base
/// A pointer to base address.
/// \param stride
/// The stride between the rows' data to be loaded in memory.
__DEFAULT_FN_ATTRS_TRANSPOSE
static void __tile_2rpntlvwz1t1(__tile1024i *dst0, __tile1024i *dst1,
const void *base, __SIZE_TYPE__ stride) {
_tile_2rpntlvwz1t1_internal(dst0->row, dst0->col, dst1->col, &dst0->tile,
&dst1->tile, base, stride);
}

/// Transpose 32-bit elements from src and write the result to dst.
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the <c> TTRANSPOSED </c> instruction.
///
/// \param dst
/// The destination tile. Max size is 1024 Bytes.
/// \param src
/// The source tile. Max size is 1024 Bytes.
__DEFAULT_FN_ATTRS_TRANSPOSE
static void __tile_transposed(__tile1024i *dst, __tile1024i src) {
dst->tile = _tile_transposed_internal(dst->row, dst->col, src.tile);
}

#endif /* __x86_64__ */
#endif /* __AMX_TRANSPOSEINTRIN_H */
2 changes: 1 addition & 1 deletion clang/lib/Headers/cmpccxaddintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ typedef enum {
(int)(__D))))

#define _cmpccxadd_epi64(__A, __B, __C, __D) \
((long long)(__builtin_ia32_cmpccxadd64((void *)(__A), (long long)(__B), \
((long long)(__builtin_ia32_cmpccxadd64((__A), (long long)(__B), \
(long long)(__C), (int)(__D))))

#endif // __x86_64__
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Headers/immintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,10 @@ _storebe_i64(void * __P, long long __D) {
#include <amxfp8intrin.h>
#endif

#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_TRANSPOSE__)
#include <amxtransposeintrin.h>
#endif

#if !defined(__SCE__) || __has_feature(modules) || \
defined(__AVX512VP2INTERSECT__)
#include <avx512vp2intersectintrin.h>
Expand Down
60 changes: 0 additions & 60 deletions clang/lib/Lex/HeaderSearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -974,13 +974,9 @@ OptionalFileEntryRef HeaderSearch::LookupFile(
const HeaderFileInfo *FromHFI = getExistingFileInfo(*Includer);
assert(FromHFI && "includer without file info");
unsigned DirInfo = FromHFI->DirInfo;
bool IndexHeaderMapHeader = FromHFI->IndexHeaderMapHeader;
StringRef Framework = FromHFI->Framework;

HeaderFileInfo &ToHFI = getFileInfo(*FE);
ToHFI.DirInfo = DirInfo;
ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
ToHFI.Framework = Framework;

if (SearchPath) {
StringRef SearchPathRef(IncluderAndDir.second.getName());
Expand Down Expand Up @@ -1122,23 +1118,6 @@ OptionalFileEntryRef HeaderSearch::LookupFile(
}
}

// Set the `Framework` info if this file is in a header map with framework
// style include spelling or found in a framework dir. The header map case
// is possible when building frameworks which use header maps.
if (CurDir->isHeaderMap() && isAngled) {
size_t SlashPos = Filename.find('/');
if (SlashPos != StringRef::npos)
HFI.Framework =
getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos));
if (CurDir->isIndexHeaderMap())
HFI.IndexHeaderMapHeader = 1;
} else if (CurDir->isFramework()) {
size_t SlashPos = Filename.find('/');
if (SlashPos != StringRef::npos)
HFI.Framework =
getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos));
}

if (checkMSVCHeaderSearch(Diags, MSFE, &File->getFileEntry(), IncludeLoc)) {
if (SuggestedModule)
*SuggestedModule = MSSuggestedModule;
Expand All @@ -1156,41 +1135,6 @@ OptionalFileEntryRef HeaderSearch::LookupFile(
return File;
}

// If we are including a file with a quoted include "foo.h" from inside
// a header in a framework that is currently being built, and we couldn't
// resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
// "Foo" is the name of the framework in which the including header was found.
if (!Includers.empty() && Includers.front().first && !isAngled &&
!Filename.contains('/')) {
const HeaderFileInfo *IncludingHFI =
getExistingFileInfo(*Includers.front().first);
assert(IncludingHFI && "includer without file info");
if (IncludingHFI->IndexHeaderMapHeader) {
SmallString<128> ScratchFilename;
ScratchFilename += IncludingHFI->Framework;
ScratchFilename += '/';
ScratchFilename += Filename;

OptionalFileEntryRef File = LookupFile(
ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, &CurDir,
Includers.front(), SearchPath, RelativePath, RequestingModule,
SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);

if (checkMSVCHeaderSearch(Diags, MSFE,
File ? &File->getFileEntry() : nullptr,
IncludeLoc)) {
if (SuggestedModule)
*SuggestedModule = MSSuggestedModule;
return MSFE;
}

cacheLookupSuccess(LookupFileCache[Filename],
LookupFileCache[ScratchFilename].HitIt, IncludeLoc);
// FIXME: SuggestedModule.
return File;
}
}

if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) {
if (SuggestedModule)
*SuggestedModule = MSSuggestedModule;
Expand Down Expand Up @@ -1358,10 +1302,6 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
HFI.DirInfo = OtherHFI.DirInfo;
HFI.External = (!HFI.IsValid || HFI.External);
HFI.IsValid = true;
HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader;

if (HFI.Framework.empty())
HFI.Framework = OtherHFI.Framework;
}

HeaderFileInfo &HeaderSearch::getFileInfo(FileEntryRef FE) {
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Lex/InitHeaderSearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,

// Compute the DirectoryLookup type.
SrcMgr::CharacteristicKind Type;
if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) {
if (Group == Quoted || Group == Angled) {
Type = SrcMgr::C_User;
} else if (Group == ExternCSystem) {
Type = SrcMgr::C_ExternCSystem;
Expand All @@ -170,9 +170,8 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
if (auto FE = FM.getOptionalFileRef(MappedPathStr)) {
if (const HeaderMap *HM = Headers.CreateHeaderMap(*FE)) {
// It is a headermap, add it to the search path.
IncludePath.emplace_back(
Group, DirectoryLookup(HM, Type, Group == IndexHeaderMap),
UserEntryIdx);
IncludePath.emplace_back(Group, DirectoryLookup(HM, Type),
UserEntryIdx);
return true;
}
}
Expand Down Expand Up @@ -488,7 +487,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
unsigned NumQuoted = SearchList.size();

for (auto &Include : IncludePath)
if (Include.Group == Angled || Include.Group == IndexHeaderMap)
if (Include.Group == Angled)
SearchList.push_back(Include);

RemoveDuplicates(SearchList, NumQuoted, Verbose);
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/CheckExprLifetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1261,12 +1261,12 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
if (pathContainsInit(Path))
return false;

auto *DRE = dyn_cast<DeclRefExpr>(L);
// Suppress false positives for code like the one below:
// Ctor(unique_ptr<T> up) : member(*up), member2(move(up)) {}
if (IsLocalGslOwner && pathOnlyHandlesGslPointer(Path))
// Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
if (DRE && isRecordWithAttr<OwnerAttr>(DRE->getType()))
return false;

auto *DRE = dyn_cast<DeclRefExpr>(L);
auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
if (!VD) {
// A member was initialized to a local block.
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17955,6 +17955,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
<< Name;
Invalid = true;
}
if (TUK == TagUseKind::Declaration)
Invalid = true;
} else if (!PrevDecl) {
Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
}
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaX86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,10 @@ bool SemaX86::CheckBuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_tileloaddt164:
case X86::BI__builtin_ia32_tilestored64:
case X86::BI__builtin_ia32_tilezero:
case X86::BI__builtin_ia32_t2rpntlvwz0:
case X86::BI__builtin_ia32_t2rpntlvwz0t1:
case X86::BI__builtin_ia32_t2rpntlvwz1:
case X86::BI__builtin_ia32_t2rpntlvwz1t1:
return CheckBuiltinTileArgumentsRange(TheCall, 0);
case X86::BI__builtin_ia32_tdpbssd:
case X86::BI__builtin_ia32_tdpbsud:
Expand All @@ -645,6 +649,8 @@ bool SemaX86::CheckBuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_tdphbf8ps:
case X86::BI__builtin_ia32_tdphf8ps:
return CheckBuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2});
case X86::BI__builtin_ia32_ttransposed:
return CheckBuiltinTileArgumentsRange(TheCall, {0, 1});
}
}
static bool isX86_32Builtin(unsigned BuiltinID) {
Expand Down
19 changes: 4 additions & 15 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2120,16 +2120,8 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
HFI.isImport |= (Flags >> 5) & 0x01;
HFI.isPragmaOnce |= (Flags >> 4) & 0x01;
HFI.DirInfo = (Flags >> 1) & 0x07;
HFI.IndexHeaderMapHeader = Flags & 0x01;
HFI.LazyControllingMacro = Reader.getGlobalIdentifierID(
M, endian::readNext<IdentifierID, llvm::endianness::little>(d));
if (unsigned FrameworkOffset =
endian::readNext<uint32_t, llvm::endianness::little>(d)) {
// The framework offset is 1 greater than the actual offset,
// since 0 is used as an indicator for "no framework name".
StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
}

assert((End - d) % 4 == 0 &&
"Wrong data length in HeaderFileInfo deserialization");
Expand Down Expand Up @@ -3903,13 +3895,10 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
F.HeaderFileInfoTableData = Blob.data();
F.LocalNumHeaderFileInfos = Record[1];
if (Record[0]) {
F.HeaderFileInfoTable
= HeaderFileInfoLookupTable::Create(
(const unsigned char *)F.HeaderFileInfoTableData + Record[0],
(const unsigned char *)F.HeaderFileInfoTableData,
HeaderFileInfoTrait(*this, F,
&PP.getHeaderSearchInfo(),
Blob.data() + Record[2]));
F.HeaderFileInfoTable = HeaderFileInfoLookupTable::Create(
(const unsigned char *)F.HeaderFileInfoTableData + Record[0],
(const unsigned char *)F.HeaderFileInfoTableData,
HeaderFileInfoTrait(*this, F));

PP.getHeaderSearchInfo().SetExternalSource(this);
if (!PP.getHeaderSearchInfo().getExternalLookup())
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/Serialization/ASTReaderInternals.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,6 @@ using ASTSelectorLookupTable =
class HeaderFileInfoTrait {
ASTReader &Reader;
ModuleFile &M;
HeaderSearch *HS;
const char *FrameworkStrings;

public:
using external_key_type = FileEntryRef;
Expand All @@ -262,9 +260,8 @@ class HeaderFileInfoTrait {
using hash_value_type = unsigned;
using offset_type = unsigned;

HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS,
const char *FrameworkStrings)
: Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) {}
HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M)
: Reader(Reader), M(M) {}

static hash_value_type ComputeHash(internal_key_ref ikey);
internal_key_type GetInternalKey(external_key_type ekey);
Expand Down
29 changes: 2 additions & 27 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1958,10 +1958,6 @@ namespace {
class HeaderFileInfoTrait {
ASTWriter &Writer;

// Keep track of the framework names we've used during serialization.
SmallString<128> FrameworkStringData;
llvm::StringMap<unsigned> FrameworkNameOffset;

public:
HeaderFileInfoTrait(ASTWriter &Writer) : Writer(Writer) {}

Expand Down Expand Up @@ -2005,7 +2001,7 @@ namespace {
std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
unsigned KeyLen = key.Filename.size() + 1 + 8 + 8;
unsigned DataLen = 1 + sizeof(IdentifierID) + 4;
unsigned DataLen = 1 + sizeof(IdentifierID);
for (auto ModInfo : Data.KnownHeaders)
if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule()))
DataLen += 4;
Expand Down Expand Up @@ -2036,8 +2032,7 @@ namespace {
| (Data.HFI.isImport << 5)
| (Writer.isWritingStdCXXNamedModules() ? 0 :
Data.HFI.isPragmaOnce << 4)
| (Data.HFI.DirInfo << 1)
| Data.HFI.IndexHeaderMapHeader;
| (Data.HFI.DirInfo << 1);
LE.write<uint8_t>(Flags);

if (Data.HFI.LazyControllingMacro.isID())
Expand All @@ -2046,22 +2041,6 @@ namespace {
LE.write<IdentifierID>(
Writer.getIdentifierRef(Data.HFI.LazyControllingMacro.getPtr()));

unsigned Offset = 0;
if (!Data.HFI.Framework.empty()) {
// If this header refers into a framework, save the framework name.
llvm::StringMap<unsigned>::iterator Pos
= FrameworkNameOffset.find(Data.HFI.Framework);
if (Pos == FrameworkNameOffset.end()) {
Offset = FrameworkStringData.size() + 1;
FrameworkStringData.append(Data.HFI.Framework);
FrameworkStringData.push_back(0);

FrameworkNameOffset[Data.HFI.Framework] = Offset;
} else
Offset = Pos->second;
}
LE.write<uint32_t>(Offset);

auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) {
if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) {
uint32_t Value = (ModID << 3) | (unsigned)Role;
Expand All @@ -2077,9 +2056,6 @@ namespace {

assert(Out.tell() - Start == DataLen && "Wrong data length");
}

const char *strings_begin() const { return FrameworkStringData.begin(); }
const char *strings_end() const { return FrameworkStringData.end(); }
};

} // namespace
Expand Down Expand Up @@ -2214,7 +2190,6 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
// Write the header search table
RecordData::value_type Record[] = {HEADER_SEARCH_TABLE, BucketOffset,
NumHeaderSearchEntries, TableData.size()};
TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end());
Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData);

// Free all of the strings we had to duplicate.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ add_clang_library(clangStaticAnalyzerCheckers
WebKit/RefCntblBaseVirtualDtorChecker.cpp
WebKit/UncountedCallArgsChecker.cpp
WebKit/UncountedLambdaCapturesChecker.cpp
WebKit/UncountedLocalVarsChecker.cpp
WebKit/RawPtrRefLocalVarsChecker.cpp

LINK_LIBS
clangAST
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,14 @@ std::optional<bool> isUncountedPtr(const QualType T) {
return false;
}

std::optional<bool> isUncheckedPtr(const QualType T) {
if (T->isPointerType() || T->isReferenceType()) {
if (auto *CXXRD = T->getPointeeCXXRecordDecl())
return isUnchecked(CXXRD);
}
return false;
}

std::optional<bool> isUnsafePtr(const QualType T) {
if (T->isPointerType() || T->isReferenceType()) {
if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
/// class, false if not, std::nullopt if inconclusive.
std::optional<bool> isUncountedPtr(const clang::QualType T);

/// \returns true if \p T is either a raw pointer or reference to an unchecked
/// class, false if not, std::nullopt if inconclusive.
std::optional<bool> isUncheckedPtr(const clang::QualType T);

/// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or its
/// variant, false if not.
bool isSafePtrType(const clang::QualType T);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,18 @@ bool isGuardedScopeEmbeddedInGuardianScope(const VarDecl *Guarded,
return false;
}

class UncountedLocalVarsChecker
class RawPtrRefLocalVarsChecker
: public Checker<check::ASTDecl<TranslationUnitDecl>> {
BugType Bug{this,
"Uncounted raw pointer or reference not provably backed by "
"ref-counted variable",
"WebKit coding guidelines"};
BugType Bug;
mutable BugReporter *BR;

public:
RawPtrRefLocalVarsChecker(const char *description)
: Bug(this, description, "WebKit coding guidelines") {}

virtual std::optional<bool> isUnsafePtr(const QualType T) const = 0;
virtual const char *ptrKind() const = 0;

void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
BugReporter &BRArg) const {
BR = &BRArg;
Expand All @@ -182,14 +185,14 @@ class UncountedLocalVarsChecker
// visit template instantiations or lambda classes. We
// want to visit those, so we make our own RecursiveASTVisitor.
struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
const UncountedLocalVarsChecker *Checker;
const RawPtrRefLocalVarsChecker *Checker;
Decl *DeclWithIssue{nullptr};

TrivialFunctionAnalysis TFA;

using Base = RecursiveASTVisitor<LocalVisitor>;

explicit LocalVisitor(const UncountedLocalVarsChecker *Checker)
explicit LocalVisitor(const RawPtrRefLocalVarsChecker *Checker)
: Checker(Checker) {
assert(Checker);
}
Expand Down Expand Up @@ -261,7 +264,7 @@ class UncountedLocalVarsChecker
if (shouldSkipVarDecl(V))
return;

std::optional<bool> IsUncountedPtr = isUncountedPtr(V->getType());
std::optional<bool> IsUncountedPtr = isUnsafePtr(V->getType());
if (IsUncountedPtr && *IsUncountedPtr) {
if (tryToFindPtrOrigin(
Value, /*StopAtFirstRefCountedObj=*/false,
Expand Down Expand Up @@ -324,7 +327,7 @@ class UncountedLocalVarsChecker
llvm::raw_svector_ostream Os(Buf);

if (dyn_cast<ParmVarDecl>(V)) {
Os << "Assignment to an uncounted parameter ";
Os << "Assignment to an " << ptrKind() << " parameter ";
printQuotedQualifiedName(Os, V);
Os << " is unsafe.";

Expand All @@ -342,7 +345,7 @@ class UncountedLocalVarsChecker
else
Os << "Variable ";
printQuotedQualifiedName(Os, V);
Os << " is uncounted and unsafe.";
Os << " is " << ptrKind() << " and unsafe.";

PathDiagnosticLocation BSLoc(V->getLocation(), BR->getSourceManager());
auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
Expand All @@ -352,6 +355,29 @@ class UncountedLocalVarsChecker
}
}
};

class UncountedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
public:
UncountedLocalVarsChecker()
: RawPtrRefLocalVarsChecker("Uncounted raw pointer or reference not "
"provably backed by ref-counted variable") {}
std::optional<bool> isUnsafePtr(const QualType T) const final {
return isUncountedPtr(T);
}
const char *ptrKind() const final { return "uncounted"; }
};

class UncheckedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
public:
UncheckedLocalVarsChecker()
: RawPtrRefLocalVarsChecker("Unchecked raw pointer or reference not "
"provably backed by checked variable") {}
std::optional<bool> isUnsafePtr(const QualType T) const final {
return isUncheckedPtr(T);
}
const char *ptrKind() const final { return "unchecked"; }
};

} // namespace

void ento::registerUncountedLocalVarsChecker(CheckerManager &Mgr) {
Expand All @@ -361,3 +387,11 @@ void ento::registerUncountedLocalVarsChecker(CheckerManager &Mgr) {
bool ento::shouldRegisterUncountedLocalVarsChecker(const CheckerManager &) {
return true;
}

void ento::registerUncheckedLocalVarsChecker(CheckerManager &Mgr) {
Mgr.registerChecker<UncheckedLocalVarsChecker>();
}

bool ento::shouldRegisterUncheckedLocalVarsChecker(const CheckerManager &) {
return true;
}
87 changes: 87 additions & 0 deletions clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// RUN: %clang_cc1 -verify=ref,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s
// RUN: %clang_cc1 -verify=ref,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fno-signed-char
// RUN: %clang_cc1 -verify=ref,both -std=c++2a -fsyntax-only -triple aarch64_be-linux-gnu %s

// RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fno-signed-char -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple aarch64_be-linux-gnu %s -fexperimental-new-constant-interpreter

// both-no-diagnostics

typedef decltype(nullptr) nullptr_t;
typedef __INTPTR_TYPE__ intptr_t;

static_assert(sizeof(int) == 4);
static_assert(sizeof(long long) == 8);

template <class To, class From>
constexpr To bit_cast(const From &from) {
static_assert(sizeof(To) == sizeof(From));
return __builtin_bit_cast(To, from);
}

template <class Intermediate, class Init>
constexpr bool check_round_trip(const Init &init) {
return bit_cast<Init>(bit_cast<Intermediate>(init)) == init;
}

template <class Intermediate, class Init>
constexpr Init round_trip(const Init &init) {
return bit_cast<Init>(bit_cast<Intermediate>(init));
}




namespace test_long_double {
#if __x86_64
#if 0
constexpr __int128_t test_cast_to_int128 = bit_cast<__int128_t>((long double)0); // expected-error{{must be initialized by a constant expression}}\
// expected-note{{in call}}
#endif
constexpr long double ld = 3.1425926539;

struct bytes {
unsigned char d[16];
};

// static_assert(round_trip<bytes>(ld), "");

static_assert(round_trip<long double>(10.0L));

#if 0
constexpr bool f(bool read_uninit) {
bytes b = bit_cast<bytes>(ld);
unsigned char ld_bytes[10] = {
0x0, 0x48, 0x9f, 0x49, 0xf0,
0x3c, 0x20, 0xc9, 0x0, 0x40,
};

for (int i = 0; i != 10; ++i)
if (ld_bytes[i] != b.d[i])
return false;

if (read_uninit && b.d[10]) // expected-note{{read of uninitialized object is not allowed in a constant expression}}
return false;

return true;
}

static_assert(f(/*read_uninit=*/false), "");
static_assert(f(/*read_uninit=*/true), ""); // expected-error{{static assertion expression is not an integral constant expression}} \
// expected-note{{in call to 'f(true)'}}
#endif
constexpr bytes ld539 = {
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0xc0, 0x86,
0x8, 0x40, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
};

constexpr long double fivehundredandthirtynine = 539.0;

static_assert(bit_cast<long double>(ld539) == fivehundredandthirtynine, "");
#else
static_assert(round_trip<__int128_t>(34.0L));
#endif
}
9 changes: 8 additions & 1 deletion clang/test/AST/ByteCode/builtin-bit-cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ constexpr bool operator==(const struct bits<N, T, P>& lhs, const struct bits<N,
return lhs.bits == rhs.bits;
}

#ifdef __SIZEOF_INT128__
static_assert(check_round_trip<__int128_t>((__int128_t)34));
static_assert(check_round_trip<__int128_t>((__int128_t)-34));
#endif

static_assert(check_round_trip<double>(17.0));


namespace simple {
constexpr int A = __builtin_bit_cast(int, 10);
Expand Down Expand Up @@ -103,7 +110,7 @@ namespace simple {
static_assert(check_round_trip<unsigned>((int)0x12345678));
static_assert(check_round_trip<unsigned>((int)0x87654321));
static_assert(check_round_trip<unsigned>((int)0x0C05FEFE));
// static_assert(round_trip<float>((int)0x0C05FEFE));
static_assert(round_trip<float>((int)0x0C05FEFE));


/// This works in GCC and in the bytecode interpreter, but the current interpreter
Expand Down
2 changes: 2 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/mock-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ class CheckedObj {
public:
void incrementPtrCount();
void decrementPtrCount();
void method();
int trivial() { return 123; }
};

class RefCountableAndCheckable {
Expand Down
342 changes: 342 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedLocalVarsChecker -verify %s

#include "mock-types.h"
#include "mock-system-header.h"

void someFunction();

namespace raw_ptr {
void foo() {
CheckedObj *bar;
// FIXME: later on we might warn on uninitialized vars too
}

void bar(CheckedObj *) {}
} // namespace raw_ptr

namespace reference {
void foo_ref() {
CheckedObj automatic;
CheckedObj &bar = automatic;
// expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
someFunction();
bar.method();
}

void foo_ref_trivial() {
CheckedObj automatic;
CheckedObj &bar = automatic;
}

void bar_ref(CheckedObj &) {}
} // namespace reference

namespace guardian_scopes {
void foo1() {
CheckedPtr<CheckedObj> foo;
{ CheckedObj *bar = foo.get(); }
}

void foo2() {
CheckedPtr<CheckedObj> foo;
// missing embedded scope here
CheckedObj *bar = foo.get();
// expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
someFunction();
bar->method();
}

void foo3() {
CheckedPtr<CheckedObj> foo;
{
{ CheckedObj *bar = foo.get(); }
}
}

void foo4() {
{
CheckedPtr<CheckedObj> foo;
{ CheckedObj *bar = foo.get(); }
}
}

void foo5() {
CheckedPtr<CheckedObj> foo;
auto* bar = foo.get();
bar->trivial();
}

void foo6() {
CheckedPtr<CheckedObj> foo;
auto* bar = foo.get();
// expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
bar->method();
}

struct SelfReferencingStruct {
SelfReferencingStruct* ptr;
CheckedObj* obj { nullptr };
};

void foo7(CheckedObj* obj) {
SelfReferencingStruct bar = { &bar, obj };
bar.obj->method();
}

} // namespace guardian_scopes

namespace auto_keyword {
class Foo {
CheckedObj *provide_ref_ctnbl();

void evil_func() {
CheckedObj *bar = provide_ref_ctnbl();
// expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
auto *baz = provide_ref_ctnbl();
// expected-warning@-1{{Local variable 'baz' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
auto *baz2 = this->provide_ref_ctnbl();
// expected-warning@-1{{Local variable 'baz2' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
[[clang::suppress]] auto *baz_suppressed = provide_ref_ctnbl(); // no-warning
}

void func() {
CheckedObj *bar = provide_ref_ctnbl();
// expected-warning@-1{{Local variable 'bar' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
if (bar)
bar->method();
}
};
} // namespace auto_keyword

namespace guardian_casts {
void foo1() {
CheckedPtr<CheckedObj> foo;
{
CheckedObj *bar = downcast<CheckedObj>(foo.get());
bar->method();
}
foo->method();
}

void foo2() {
CheckedPtr<CheckedObj> foo;
{
CheckedObj *bar =
static_cast<CheckedObj *>(downcast<CheckedObj>(foo.get()));
someFunction();
}
}
} // namespace guardian_casts

namespace guardian_ref_conversion_operator {
void foo() {
CheckedRef<CheckedObj> rc;
{
CheckedObj &rr = rc;
rr.method();
someFunction();
}
}
} // namespace guardian_ref_conversion_operator

namespace ignore_for_if {
CheckedObj *provide_ref_ctnbl() { return nullptr; }

void foo() {
// no warnings
if (CheckedObj *a = provide_ref_ctnbl())
a->trivial();
for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;)
b->trivial();
CheckedObj *array[1];
for (CheckedObj *c : array)
c->trivial();
while (CheckedObj *d = provide_ref_ctnbl())
d->trivial();
do {
CheckedObj *e = provide_ref_ctnbl();
e->trivial();
} while (1);
someFunction();
}

void bar() {
if (CheckedObj *a = provide_ref_ctnbl()) {
// expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
a->method();
}
for (CheckedObj *b = provide_ref_ctnbl(); b != nullptr;) {
// expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
b->method();
}
CheckedObj *array[1];
for (CheckedObj *c : array) {
// expected-warning@-1{{Local variable 'c' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
c->method();
}

while (CheckedObj *d = provide_ref_ctnbl()) {
// expected-warning@-1{{Local variable 'd' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
d->method();
}
do {
CheckedObj *e = provide_ref_ctnbl();
// expected-warning@-1{{Local variable 'e' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
e->method();
} while (1);
someFunction();
}

} // namespace ignore_for_if

namespace ignore_system_headers {

CheckedObj *provide_checkable();

void system_header() {
localVar<CheckedObj>(provide_checkable);
}

} // ignore_system_headers

namespace conditional_op {
CheckedObj *provide_checkable();
bool bar();

void foo() {
CheckedObj *a = bar() ? nullptr : provide_checkable();
// expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
CheckedPtr<CheckedObj> b = provide_checkable();
{
CheckedObj* c = bar() ? nullptr : b.get();
c->method();
CheckedObj* d = bar() ? b.get() : nullptr;
d->method();
}
}

} // namespace conditional_op

namespace local_assignment_basic {

CheckedObj *provide_checkable();

void foo(CheckedObj* a) {
CheckedObj* b = a;
// expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
if (b->trivial())
b = provide_checkable();
}

void bar(CheckedObj* a) {
CheckedObj* b;
// expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
b = provide_checkable();
}

void baz() {
CheckedPtr a = provide_checkable();
{
CheckedObj* b = a.get();
// expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
b = provide_checkable();
}
}

} // namespace local_assignment_basic

namespace local_assignment_to_parameter {

CheckedObj *provide_checkable();
void someFunction();

void foo(CheckedObj* a) {
a = provide_checkable();
// expected-warning@-1{{Assignment to an unchecked parameter 'a' is unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
someFunction();
a->method();
}

} // namespace local_assignment_to_parameter

namespace local_assignment_to_static_local {

CheckedObj *provide_checkable();
void someFunction();

void foo() {
static CheckedObj* a = nullptr;
// expected-warning@-1{{Static local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
a = provide_checkable();
someFunction();
a->method();
}

} // namespace local_assignment_to_static_local

namespace local_assignment_to_global {

CheckedObj *provide_ref_cntbl();
void someFunction();

CheckedObj* g_a = nullptr;
// expected-warning@-1{{Global variable 'local_assignment_to_global::g_a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}

void foo() {
g_a = provide_ref_cntbl();
someFunction();
g_a->method();
}

} // namespace local_assignment_to_global

namespace local_refcountable_checkable_object {

RefCountableAndCheckable* provide_obj();

void local_raw_ptr() {
RefCountableAndCheckable* a = nullptr;
// expected-warning@-1{{Local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
a = provide_obj();
a->method();
}

void local_checked_ptr() {
RefPtr<RefCountableAndCheckable> a = nullptr;
a = provide_obj();
a->method();
}

void local_var_with_guardian_checked_ptr() {
RefPtr<RefCountableAndCheckable> a = provide_obj();
{
auto* b = a.get();
b->method();
}
}

void local_var_with_guardian_checked_ptr_with_assignment() {
RefPtr<RefCountableAndCheckable> a = provide_obj();
{
RefCountableAndCheckable* b = a.get();
// expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
b = provide_obj();
b->method();
}
}

void local_var_with_guardian_checked_ref() {
Ref<RefCountableAndCheckable> a = *provide_obj();
{
RefCountableAndCheckable& b = a;
b.method();
}
}

void static_var() {
static RefCountableAndCheckable* a = nullptr;
// expected-warning@-1{{Static local variable 'a' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}}
a = provide_obj();
}

} // namespace local_refcountable_checkable_object
36 changes: 36 additions & 0 deletions clang/test/CodeGen/X86/amx_transpose.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown -target-feature +amx-transpose \
// RUN: -target-feature +avx512f -emit-llvm -o - -Wall -Werror -pedantic -Wno-gnu-statement-expression| FileCheck %s

#include <immintrin.h>
#include <stddef.h>

void test_tile_2rpntlvwz0(const void *A, size_t B) {
// CHECK-LABEL: @test_tile_2rpntlvwz0
// CHECK: call void @llvm.x86.t2rpntlvwz0(i8 1, ptr %{{.*}}, i64 %{{.*}})
_tile_2rpntlvwz0(1, A, B);
}

void test_tile_2rpntlvwz0t1(const void *A, size_t B) {
// CHECK-LABEL: @test_tile_2rpntlvwz0t1
// CHECK: call void @llvm.x86.t2rpntlvwz0t1(i8 1, ptr %{{.*}}, i64 %{{.*}})
_tile_2rpntlvwz0t1(1, A, B);
}

void test_tile_2rpntlvwz1(const void *A, size_t B) {
// CHECK-LABEL: @test_tile_2rpntlvwz1
// CHECK: call void @llvm.x86.t2rpntlvwz1(i8 1, ptr %{{.*}}, i64 %{{.*}})
_tile_2rpntlvwz1(1, A, B);
}

void test_tile_2rpntlvwz1t1(const void *A, size_t B) {
// CHECK-LABEL: @test_tile_2rpntlvwz1t1
// CHECK: call void @llvm.x86.t2rpntlvwz1t1(i8 1, ptr %{{.*}}, i64 %{{.*}})
_tile_2rpntlvwz1t1(1, A, B);
}

void test_tile_transposed(void)
{
// CHECK-LABEL: @test_tile_transposed
// CHECK: call void @llvm.x86.ttransposed(i8 1, i8 2)
_tile_transposed(1, 2);
}
66 changes: 66 additions & 0 deletions clang/test/CodeGen/X86/amx_transpose_api.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// RUN: %clang_cc1 %s -flax-vector-conversions=none -ffreestanding -triple=x86_64-unknown-unknown -target-feature +avx512f \
// RUN: -target-feature +amx-transpose \
// RUN: -emit-llvm -o - -Werror -pedantic | FileCheck %s --check-prefixes=CHECK

#include <immintrin.h>

char buf[2048];
#define STRIDE 32

char buf2[2048];

void test_tile_2rpntlvwz0(__tile1024i dst0, __tile1024i dst1) {
//CHECK-LABEL: @test_tile_2rpntlvwz0
//CHECK: call { x86_amx, x86_amx } @llvm.x86.t2rpntlvwz0.internal
//CHECK-NEXT: {{%.*}} = extractvalue { x86_amx, x86_amx } {{%.*}}, 0
//CHECK-NEXT: {{%.*}} = call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
//CHECK-NEXT: store <256 x i32> {{%.*}}, ptr {{%.*}}
//CHECK-NEXT: {{%.*}} = extractvalue { x86_amx, x86_amx } {{%.*}}, 1
//CHECK-NEXT: {{%.*}} = call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
//CHECK-NEXT: store <256 x i32> {{%.*}}, ptr {{%.*}}
__tile_2rpntlvwz0(&dst0, &dst1, buf, STRIDE);
}

void test_tile_2rpntlvwz0t1(__tile1024i dst0, __tile1024i dst1) {
//CHECK-LABEL: @test_tile_2rpntlvwz0t1
//CHECK: call { x86_amx, x86_amx } @llvm.x86.t2rpntlvwz0t1.internal
//CHECK-NEXT: {{%.*}} = extractvalue { x86_amx, x86_amx } {{%.*}}, 0
//CHECK-NEXT: {{%.*}} = call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
//CHECK-NEXT: store <256 x i32> {{%.*}}, ptr {{%.*}}
//CHECK-NEXT: {{%.*}} = extractvalue { x86_amx, x86_amx } {{%.*}}, 1
//CHECK-NEXT: {{%.*}} = call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
//CHECK-NEXT: store <256 x i32> {{%.*}}, ptr {{%.*}}
__tile_2rpntlvwz0t1(&dst0, &dst1, buf, STRIDE);
}

void test_tile_2rpntlvwz1(__tile1024i dst0, __tile1024i dst1) {
//CHECK-LABEL: @test_tile_2rpntlvwz1
//CHECK: call { x86_amx, x86_amx } @llvm.x86.t2rpntlvwz1.internal
//CHECK-NEXT: {{%.*}} = extractvalue { x86_amx, x86_amx } {{%.*}}, 0
//CHECK-NEXT: {{%.*}} = call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
//CHECK-NEXT: store <256 x i32> {{%.*}}, ptr {{%.*}}
//CHECK-NEXT: {{%.*}} = extractvalue { x86_amx, x86_amx } {{%.*}}, 1
//CHECK-NEXT: {{%.*}} = call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
//CHECK-NEXT: store <256 x i32> {{%.*}}, ptr {{%.*}}
__tile_2rpntlvwz1(&dst0, &dst1, buf, STRIDE);
}

void test_tile_2rpntlvwz1t1(__tile1024i dst0, __tile1024i dst1) {
//CHECK-LABEL: @test_tile_2rpntlvwz1t1
//CHECK: call { x86_amx, x86_amx } @llvm.x86.t2rpntlvwz1t1.internal
//CHECK-NEXT: {{%.*}} = extractvalue { x86_amx, x86_amx } {{%.*}}, 0
//CHECK-NEXT: {{%.*}} = call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
//CHECK-NEXT: store <256 x i32> {{%.*}}, ptr {{%.*}}
//CHECK-NEXT: {{%.*}} = extractvalue { x86_amx, x86_amx } {{%.*}}, 1
//CHECK-NEXT: {{%.*}} = call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
//CHECK-NEXT: store <256 x i32> {{%.*}}, ptr {{%.*}}
__tile_2rpntlvwz1t1(&dst0, &dst1, buf, STRIDE);
}

void test_tile_transposed(__tile1024i dst, __tile1024i src) {
//CHECK-LABEL: @test_tile_transposed
//CHECK-DAG: call x86_amx @llvm.x86.cast.vector.to.tile.v256i32(<256 x i32> {{%.*}})
//CHECK-DAG: call x86_amx @llvm.x86.ttransposed.internal
//CHECK-DAG: call <256 x i32> @llvm.x86.cast.tile.to.vector.v256i32(x86_amx {{%.*}})
__tile_transposed(&dst, src);
}
31 changes: 31 additions & 0 deletions clang/test/CodeGen/X86/amx_transpose_errors.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown \
// RUN: -target-feature +amx-int8 -target-feature +amx-bf16 -target-feature +amx-transpose \
// RUN: -target-feature +avx512f -target-feature +amx-element-evex -verify

#include <immintrin.h>
#include <stddef.h>
#include <immintrin.h>
#include <stddef.h>

// Transpose
void test_tile_2rpntlvwz0(const void *A, size_t B) {
_tile_2rpntlvwz0(8, A, B); // expected-error {{argument value 8 is outside the valid range [0, 7]}}
}

void test_tile_2rpntlvwz0t1(const void *A, size_t B) {
_tile_2rpntlvwz0t1(8, A, B); // expected-error {{argument value 8 is outside the valid range [0, 7]}}
}

void test_tile_2rpntlvwz1(const void *A, size_t B) {
_tile_2rpntlvwz1(8, A, B); // expected-error {{argument value 8 is outside the valid range [0, 7]}}
}

void test_tile_2rpntlvwz1t1(const void *A, size_t B) {
_tile_2rpntlvwz1t1(8, A, B); // expected-error {{argument value 8 is outside the valid range [0, 7]}}
}

void test_tile_transposed()
{
_tile_transposed(8, 2); // expected-error {{argument value 8 is outside the valid range [0, 7]}}
_tile_transposed(1, 8); // expected-error {{argument value 8 is outside the valid range [0, 7]}}
}
4 changes: 4 additions & 0 deletions clang/test/CodeGen/X86/cmpccxadd-builtins-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ int test_cmpccxadd32(void *__A, int __B, int __C) {
long long test_cmpccxadd64(void *__A, long long __B, long long __C) {
return _cmpccxadd_epi64(__A, __B, __C, 16); // expected-error {{argument value 16 is outside the valid range [0, 15]}}
}

long long test_cmpccxadd64_2(int *__A, long long __B, long long __C) {
return _cmpccxadd_epi64(__A, __B, __C, 3); // expected-warning {{incompatible pointer types passing 'int *' to parameter of type 'long long *'}}
}
46 changes: 46 additions & 0 deletions clang/test/CodeGen/fat-lto-objects-cfi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// REQUIRES: x86-registered-target

// RUN: %clang_cc1 -triple x86_64-unknown-fuchsia -O2 -flto -ffat-lto-objects \
// RUN: -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fvisibility=hidden -emit-llvm -o - %s \
// RUN: | FileCheck %s

// CHECK: llvm.embedded.object
// CHECK-SAME: section ".llvm.lto"

// CHECK-LABEL: define hidden void @foo
// CHECK: entry:
// CHECK-NEXT: %cmp14.not = icmp eq i64 %len, 0
// CHECK-NEXT: br i1 %cmp14.not, label %for.end7, label %for.cond1.preheader.preheader
// CHECK: for.cond1.preheader.preheader: ; preds = %entry
// CHECK-NEXT: %arrayidx.1 = getelementptr inbounds nuw i8, ptr %ptr, i64 4
// CHECK-NEXT: br label %for.cond1.preheader

// CHECK-NOT: @llvm.type.test

// The code below is a reduced case from https://github.com/llvm/llvm-project/issues/112053
#define __PRINTFLIKE(__fmt, __varargs) __attribute__((__format__(__printf__, __fmt, __varargs)))
typedef void func(void* arg, const char* fmt, ...) __PRINTFLIKE(2, 3);
typedef __SIZE_TYPE__ size_t;
typedef unsigned long uintptr_t;

extern "C"
void foo(const void* ptr, size_t len, long disp_addr,
func* printf_func, void* printf_arg) {
uintptr_t address = (uintptr_t)ptr;
size_t count;

for (count = 0; count < len; count += 16) {
union {
unsigned int buf[4];
unsigned char cbuf[16];
} u;
size_t s = 10;
size_t i;

for (i = 0; i < s / 4; i++) {
u.buf[i] = ((const unsigned int*)address)[i];
printf_func(printf_arg, "%08x ", static_cast<unsigned int>(u.buf[i]));
}
}
}

19 changes: 19 additions & 0 deletions clang/test/CodeGen/pgo-cold-function-coverage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Test -fprofile-generate-cold-function-coverage

// RUN: rm -rf %t && split-file %s %t
// RUN: %clang --target=x86_64 -O2 -fprofile-generate-cold-function-coverage=/xxx/yyy/ -fprofile-sample-accurate -fprofile-sample-use=%t/pgo-cold-func.prof -S -emit-llvm -o - %t/pgo-cold-func.c | FileCheck %s

// CHECK: @__llvm_profile_filename = {{.*}} c"/xxx/yyy/default_%m.profraw\00"

// CHECK: store i8 0, ptr @__profc_bar, align 1
// CHECK-NOT: @__profc_foo

//--- pgo-cold-func.prof
foo:1:1
1: 1

//--- pgo-cold-func.c
int bar(int x) { return x;}
int foo(int x) {
return x;
}
2 changes: 1 addition & 1 deletion clang/test/Driver/avr-toolchain.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
// RUN: %clang -### --target=avr --sysroot=%S/Inputs/basic_avr_tree -S %s 2>&1 | FileCheck --check-prefixes=NOMCU,LINKA %s
// RUN: %clang -### --target=avr --sysroot=%S/Inputs/ -S %s 2>&1 | FileCheck --check-prefixes=NOMCU,LINKA %s
// RUN: %clang -### --target=avr --sysroot=%S/Inputs/basic_avr_tree %s 2>&1 | FileCheck --check-prefixes=NOMCU,LINKB %s
// NOMCU: warning: no target microcontroller specified on command line, cannot link standard libraries, please pass -mmcu=<mcu name>
// NOMCU: warning: no target microcontroller specified, please pass -mmcu=<mcu name>
// LINKB: warning: standard library not linked and so no interrupt vector table or compiler runtime routines will be linked
// LINKB: warning: support for passing the data section address to the linker for microcontroller '' is not implemented
// NOMCU-NOT: warning: {{.*}} avr-gcc
Expand Down
9 changes: 9 additions & 0 deletions clang/test/Driver/fprofile-generate-cold-function-coverage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang -### -c -fprofile-generate-cold-function-coverage %s 2>&1 | FileCheck %s
// CHECK: "--instrument-cold-function-only-path=default_%m.profraw"
// CHECK: "--pgo-instrument-cold-function-only"
// CHECK: "--pgo-function-entry-coverage"
// CHECK-NOT: "-fprofile-instrument"
// CHECK-NOT: "-fprofile-instrument-path=

// RUN: %clang -### -c -fprofile-generate-cold-function-coverage=dir %s 2>&1 | FileCheck %s --check-prefix=CHECK-EQ
// CHECK-EQ: "--instrument-cold-function-only-path=dir{{/|\\\\}}default_%m.profraw"
4 changes: 0 additions & 4 deletions clang/test/Driver/index-header-map.c

This file was deleted.

18 changes: 18 additions & 0 deletions clang/test/Driver/ps5-linker.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@
// CHECK-NO-PIE-NOT: "-pie"
// CHECK-SHARED: "--shared"

// Test the driver supplies an --image-base to the linker only for non-pie
// executables.

// RUN: %clang --target=x86_64-sie-ps5 -static %s -### 2>&1 | FileCheck --check-prefixes=CHECK-BASE %s
// RUN: %clang --target=x86_64-sie-ps5 -no-pie %s -### 2>&1 | FileCheck --check-prefixes=CHECK-BASE %s

// CHECK-BASE: {{ld(\.exe)?}}"
// CHECK-BASE-SAME: "--image-base=0x400000"

// RUN: %clang --target=x86_64-sie-ps5 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-NO-BASE %s
// RUN: %clang --target=x86_64-sie-ps5 -r %s -### 2>&1 | FileCheck --check-prefixes=CHECK-NO-BASE %s
// RUN: %clang --target=x86_64-sie-ps5 -shared %s -### 2>&1 | FileCheck --check-prefixes=CHECK-NO-BASE %s

// CHECK-NO-BASE: {{ld(\.exe)?}}"
// CHECK-NO-BASE-NOT: --image-base

// Test the driver passes PlayStation-specific options to the linker that are
// appropriate for the type of output. Many options don't apply for relocatable
// output (-r).
Expand All @@ -37,6 +53,8 @@
// CHECK-EXE-SAME: "--unresolved-symbols=report-all"
// CHECK-EXE-SAME: "-z" "now"
// CHECK-EXE-SAME: "-z" "start-stop-visibility=hidden"
// CHECK-EXE-SAME: "-z" "common-page-size=0x4000"
// CHECK-EXE-SAME: "-z" "max-page-size=0x4000"
// CHECK-EXE-SAME: "-z" "dead-reloc-in-nonalloc=.debug_*=0xffffffffffffffff"
// CHECK-EXE-SAME: "-z" "dead-reloc-in-nonalloc=.debug_ranges=0xfffffffffffffffe"
// CHECK-EXE-SAME: "-z" "dead-reloc-in-nonalloc=.debug_loc=0xfffffffffffffffe"
Expand Down
7 changes: 7 additions & 0 deletions clang/test/Driver/x86-target-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,13 @@
// AMX-COMPLEX: "-target-feature" "+amx-complex"
// NO-AMX-COMPLEX: "-target-feature" "-amx-complex"

// RUN: %clang -target x86_64-unknown-linux-gnu -mamx-transpose %s \
// RUN: -### -o %t.o 2>&1 | FileCheck -check-prefix=AMX-TRANSPOSE %s
// RUN: %clang -target x86_64-unknown-linux-gnu -mno-amx-transpose %s \
// RUN: -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-AMX-TRANSPOSE %s
// AMX-TRANSPOSE: "-target-feature" "+amx-transpose"
// NO-AMX-TRANSPOSE: "-target-feature" "-amx-transpose"

// RUN: %clang --target=i386 -march=i386 -mhreset %s -### 2>&1 | FileCheck -check-prefix=HRESET %s
// RUN: %clang --target=i386 -march=i386 -mno-hreset %s -### 2>&1 | FileCheck -check-prefix=NO-HRESET %s
// HRESET: "-target-feature" "+hreset"
Expand Down
12 changes: 12 additions & 0 deletions clang/test/Preprocessor/x86_target_features.c
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,18 @@

// NO-AMX-COMPLEX-NOT: #define __AMX_COMPLEX__ 1

// RUN: %clang -target x86_64-unknown-linux-gnu -march=x86-64 -mamx-transpose -x c \
// RUN: -E -dM -o - %s | FileCheck -check-prefix=AMX-TRANSPOSE %s

// AMX-TRANSPOSE: #define __AMX_TRANSPOSE__ 1

// RUN: %clang -target x86_64-unknown-linux-gnu -march=x86-64 -mno-amx-transpose -x c \
// RUN: -E -dM -o - %s | FileCheck -check-prefix=NO-AMX-TRANSPOSE %s
// RUN: %clang -target x86_64-unknown-linux-gnu -march=x86-64 -mamx-transpose -mno-amx-tile \
// RUN: -x c -E -dM -o - %s | FileCheck -check-prefix=NO-AMX-TRANSPOSE %s

// NO-AMX-TRANSPOSE-NOT: #define __AMX_TRANSPOSE__ 1

// RUN: %clang -target i386-unknown-unknown -march=atom -mavxvnni -x c -E -dM -o - %s | FileCheck -match-full-lines --check-prefix=AVXVNNI %s

// AVXVNNI: #define __AVX2__ 1
Expand Down
13 changes: 13 additions & 0 deletions clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,19 @@ struct X {
std::unique_ptr<int> pointer;
};

struct [[gsl::Owner]] XOwner {
int* get() const [[clang::lifetimebound]];
};
struct X2 {
// A common usage that moves the passing owner to the class.
// verify no warning on this case.
X2(XOwner owner) :
pointee(owner.get()),
owner(std::move(owner)) {}
int* pointee;
XOwner owner;
};

std::vector<int>::iterator getIt();
std::vector<int> getVec();

Expand Down
8 changes: 8 additions & 0 deletions clang/test/SemaCXX/enum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,11 @@ struct PR28903 {
})
};
};

namespace GH112208 {
class C {
enum E { e = 0 };
void f(int, enum E;); // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
// expected-error {{unexpected ';' before ')'}}
};
}
2 changes: 1 addition & 1 deletion clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ Expected<StringRef> linkDeviceInputFiles(ArrayRef<std::string> InputFiles,
CmdArgs.push_back("--suppress-warnings");
if (Error Err = executeCommands(*LLVMLinkPath, CmdArgs))
return std::move(Err);
return *OutFileOrErr;
return Args.MakeArgString(*OutFileOrErr);
}

// This utility function is used to gather all SYCL device library files that
Expand Down
5 changes: 1 addition & 4 deletions clang/unittests/Lex/HeaderSearchTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ class HeaderSearchTest : public ::testing::Test {
// Test class supports only one HMap at a time.
assert(!HMap);
HMap = HeaderMap::Create(*FE, FileMgr);
auto DL =
DirectoryLookup(HMap.get(), SrcMgr::C_User, /*isFramework=*/false);
auto DL = DirectoryLookup(HMap.get(), SrcMgr::C_User);
Search.AddSearchPath(DL, isAngled);
}

Expand Down Expand Up @@ -251,7 +250,6 @@ TEST_F(HeaderSearchTest, HeaderFrameworkLookup) {
auto FI = Search.getExistingFileInfo(FE);
EXPECT_TRUE(FI);
EXPECT_TRUE(FI->IsValid);
EXPECT_EQ(FI->Framework.str(), "Foo");
EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
}

Expand Down Expand Up @@ -321,7 +319,6 @@ TEST_F(HeaderSearchTest, HeaderMapFrameworkLookup) {
auto FI = Search.getExistingFileInfo(FE);
EXPECT_TRUE(FI);
EXPECT_TRUE(FI->IsValid);
EXPECT_EQ(FI->Framework.str(), "Foo");
EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
}

Expand Down
41 changes: 17 additions & 24 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,45 +164,33 @@ void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
}

// Deletes the specified signal from newset, if it is not present in oldset
// Equivalently: newset[signum] = newset[signum] & oldset[signum]
static void KeepUnblocked(__sanitizer_sigset_t &newset,
__sanitizer_sigset_t &oldset, int signum) {
if (!internal_sigismember(&oldset, signum))
internal_sigdelset(&newset, signum);
}

// Block asynchronous signals
void BlockSignals(__sanitizer_sigset_t *oldset) {
__sanitizer_sigset_t currentset;
SetSigProcMask(NULL, &currentset);

__sanitizer_sigset_t newset;
internal_sigfillset(&newset);
__sanitizer_sigset_t set;
internal_sigfillset(&set);
# if SANITIZER_LINUX && !SANITIZER_ANDROID
// Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
// on any thread, setuid call hangs.
// See test/sanitizer_common/TestCases/Linux/setuid.c.
KeepUnblocked(newset, currentset, 33);
internal_sigdelset(&set, 33);
# endif
# if SANITIZER_LINUX
// Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls.
// If this signal is blocked, such calls cannot be handled and the process may
// hang.
KeepUnblocked(newset, currentset, 31);
internal_sigdelset(&set, 31);

// Don't block synchronous signals
// but also don't unblock signals that the user had deliberately blocked.
KeepUnblocked(newset, currentset, SIGSEGV);
KeepUnblocked(newset, currentset, SIGBUS);
KeepUnblocked(newset, currentset, SIGILL);
KeepUnblocked(newset, currentset, SIGTRAP);
KeepUnblocked(newset, currentset, SIGABRT);
KeepUnblocked(newset, currentset, SIGFPE);
KeepUnblocked(newset, currentset, SIGPIPE);
internal_sigdelset(&set, SIGSEGV);
internal_sigdelset(&set, SIGBUS);
internal_sigdelset(&set, SIGILL);
internal_sigdelset(&set, SIGTRAP);
internal_sigdelset(&set, SIGABRT);
internal_sigdelset(&set, SIGFPE);
internal_sigdelset(&set, SIGPIPE);
# endif

SetSigProcMask(&newset, oldset);
SetSigProcMask(&set, oldset);
}

ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {
Expand Down Expand Up @@ -268,6 +256,11 @@ int internal_madvise(uptr addr, uptr length, int advice) {
return internal_syscall(SYSCALL(madvise), addr, length, advice);
}

# if SANITIZER_FREEBSD
uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
return internal_syscall(SYSCALL(close_range), lowfd, highfd, flags);
}
# endif
uptr internal_close(fd_t fd) { return internal_syscall(SYSCALL(close), fd); }

uptr internal_open(const char *filename, int flags) {
Expand Down
3 changes: 3 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ namespace __sanitizer {
// Don't use directly, use __sanitizer::OpenFile() instead.
uptr internal_open(const char *filename, int flags);
uptr internal_open(const char *filename, int flags, u32 mode);
# if SANITIZER_FREEBSD
uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags);
# endif
uptr internal_close(fd_t fd);

uptr internal_read(fd_t fd, void *buf, uptr count);
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,11 @@ pid_t StartSubprocess(const char *program, const char *const argv[],
internal_close(stderr_fd);
}

# if SANITIZER_FREEBSD
internal_close_range(3, ~static_cast<fd_t>(0), 0);
# else
for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
# endif

internal_execve(program, const_cast<char **>(&argv[0]),
const_cast<char *const *>(envp));
Expand Down
1 change: 0 additions & 1 deletion compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ set(SANITIZER_UNITTESTS
sanitizer_array_ref_test.cpp
sanitizer_atomic_test.cpp
sanitizer_bitvector_test.cpp
sanitizer_block_signals.cpp
sanitizer_bvgraph_test.cpp
sanitizer_chained_origin_depot_test.cpp
sanitizer_common_test.cpp
Expand Down
76 changes: 0 additions & 76 deletions compiler-rt/lib/sanitizer_common/tests/sanitizer_block_signals.cpp

This file was deleted.

2 changes: 1 addition & 1 deletion flang/include/flang/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ def CUFDeviceGlobal :
Pass<"cuf-device-global", "mlir::ModuleOp"> {
let summary = "Flag globals used in device function with data attribute";
let dependentDialects = [
"cuf::CUFDialect"
"cuf::CUFDialect", "mlir::gpu::GPUDialect", "mlir::NVVM::NVVMDialect"
];
}

Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Optimizer/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2931,6 +2931,9 @@ struct GlobalOpConversion : public fir::FIROpConversion<fir::GlobalOp> {
comdatOp =
rewriter.create<mlir::LLVM::ComdatOp>(module.getLoc(), comdatName);
}
if (auto select = comdatOp.lookupSymbol<mlir::LLVM::ComdatSelectorOp>(
global.getSymName()))
return;
mlir::OpBuilder::InsertionGuard guard(rewriter);
rewriter.setInsertionPointToEnd(&comdatOp.getBody().back());
auto selectorOp = rewriter.create<mlir::LLVM::ComdatSelectorOp>(
Expand Down
38 changes: 19 additions & 19 deletions flang/lib/Optimizer/Transforms/CUFDeviceGlobal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "flang/Optimizer/Transforms/CUFCommon.h"
#include "flang/Runtime/CUDA/common.h"
#include "flang/Runtime/allocatable.h"
#include "mlir/Dialect/LLVMIR/NVVMDialect.h"
#include "mlir/IR/SymbolTable.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/DialectConversion.h"
Expand Down Expand Up @@ -62,27 +63,26 @@ class CUFDeviceGlobal : public fir::impl::CUFDeviceGlobalBase<CUFDeviceGlobal> {

// Copying the device global variable into the gpu module
mlir::SymbolTable parentSymTable(mod);
auto gpuMod =
parentSymTable.lookup<mlir::gpu::GPUModuleOp>(cudaDeviceModuleName);
if (gpuMod) {
mlir::SymbolTable gpuSymTable(gpuMod);
for (auto globalOp : mod.getOps<fir::GlobalOp>()) {
auto attr = globalOp.getDataAttrAttr();
if (!attr)
continue;
switch (attr.getValue()) {
case cuf::DataAttribute::Device:
case cuf::DataAttribute::Constant:
case cuf::DataAttribute::Managed: {
auto globalName{globalOp.getSymbol().getValue()};
if (gpuSymTable.lookup<fir::GlobalOp>(globalName)) {
break;
}
gpuSymTable.insert(globalOp->clone());
} break;
default:
auto gpuMod = cuf::getOrCreateGPUModule(mod, parentSymTable);
if (!gpuMod)
return signalPassFailure();
mlir::SymbolTable gpuSymTable(gpuMod);
for (auto globalOp : mod.getOps<fir::GlobalOp>()) {
auto attr = globalOp.getDataAttrAttr();
if (!attr)
continue;
switch (attr.getValue()) {
case cuf::DataAttribute::Device:
case cuf::DataAttribute::Constant:
case cuf::DataAttribute::Managed: {
auto globalName{globalOp.getSymbol().getValue()};
if (gpuSymTable.lookup<fir::GlobalOp>(globalName)) {
break;
}
gpuSymTable.insert(globalOp->clone());
} break;
default:
break;
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions flang/test/Fir/CUDA/cuda-implicit-device-global.f90
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ // Test that global used in device function are flagged with the correct
// CHECK: fir.call @_FortranAioBeginExternalListOutput(%{{.*}}, %[[CONV]], %{{.*}}) fastmath<contract> : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
// CHECK: fir.global linkonce @_QQcl[[SYMBOL]] {data_attr = #cuf.cuda<constant>} constant : !fir.char<1,32>

// CHECK-LABEL: gpu.module @cuda_device_mod [#nvvm.target]
// CHECK: fir.global linkonce @_QQclX6995815537abaf90e86ce166af128f3a

// -----

func.func @_QMdataPsetvalue() {
Expand All @@ -47,3 +50,6 @@ // Test that global used in device function are flagged with the correct
// CHECK: %[[CONV:.*]] = fir.convert %[[GLOBAL]] : (!fir.ref<!fir.char<1,32>>) -> !fir.ref<i8>
// CHECK: fir.call @_FortranAioBeginExternalListOutput(%{{.*}}, %[[CONV]], %{{.*}}) fastmath<contract> : (i32, !fir.ref<i8>, i32) -> !fir.ref<i8>
// CHECK: fir.global linkonce @_QQcl[[SYMBOL]] constant : !fir.char<1,32>

// CHECK-LABEL: gpu.module @cuda_device_mod [#nvvm.target]
// CHECK-NOT: fir.global linkonce @_QQclX6995815537abaf90e86ce166af128f3a
14 changes: 14 additions & 0 deletions flang/test/Fir/comdat-present.fir
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: fir-opt %s --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %s
// RUN: fir-opt %s --fir-to-llvm-ir="target=x86_64-pc-windows-msvc" | FileCheck %s

fir.global linkonce_odr @global_linkonce_odr constant : i32 {
%0 = arith.constant 0 : i32
fir.has_value %0 : i32
}

llvm.comdat @__llvm_comdat {
llvm.comdat_selector @global_linkonce_odr any
}

// CHECK-LABEL: llvm.comdat @__llvm_comdat
// CHECK: llvm.comdat_selector @global_linkonce_odr any
2 changes: 1 addition & 1 deletion flang/test/Fir/tco-default-datalayout.fir
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ module {
// CHECK: module attributes {
// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec<
// ...
// CHECK-SAME: #dlti.dl_entry<i64, dense<[32, 64]> : vector<2xi64>>,
// CHECK-SAME: i64 = dense<[32, 64]> : vector<2xi64>,
// ...
// CHECK-SAME: llvm.data_layout = ""
2 changes: 1 addition & 1 deletion flang/test/Fir/tco-explicit-datalayout.fir
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ module attributes {llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i6
// CHECK: module attributes {
// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec<
// ...
// CHECK-SAME: #dlti.dl_entry<i64, dense<128> : vector<2xi64>>,
// CHECK-SAME: i64 = dense<128> : vector<2xi64>,
// ...
// CHECK-SAME: llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:128-i128:128-f80:128-n8:16:32:64-S128"
7 changes: 0 additions & 7 deletions libc/hdr/fenv_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

// In some environment, FE_ALL_EXCEPT is set to 0 and the remaining exceptions
// FE_* are missing.
#if (FE_ALL_EXCEPT == 0)
#ifndef FE_DIVBYZERO
#define FE_DIVBYZERO 0
#endif // FE_DIVBYZERO
Expand All @@ -39,12 +38,6 @@
#ifndef FE_UNDERFLOW
#define FE_UNDERFLOW 0
#endif // FE_UNDERFLOW
#else
// If this is not provided by the system, define it for use internally.
#ifndef __FE_DENORM
#define __FE_DENORM (1 << 6)
#endif
#endif

// Rounding mode macros might be missing.
#ifndef FE_DOWNWARD
Expand Down
2 changes: 1 addition & 1 deletion libc/hdr/types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ add_proxy_header_library(
HDRS
mode_t.h
DEPENDS
../fcntl_overlay
libc.hdr.fcntl_overlay
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.mode_t
libc.include.fcntl
Expand Down
3 changes: 3 additions & 0 deletions libc/include/llvm-libc-macros/linux/fcntl-macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@
// Close on succesful
#define F_CLOEXEC 1

// Close on execute for fcntl.
#define FD_CLOEXEC 1

#define F_RDLCK 0
#define F_WRLCK 1
#define F_UNLCK 2
Expand Down
88 changes: 88 additions & 0 deletions libc/src/__support/OSUtil/linux/i386/syscall.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//===---------- inline implementation of i386 syscalls ------------* 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_I386_SYSCALL_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_I386_SYSCALL_H

#include "src/__support/common.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

LIBC_INLINE long syscall_impl(long num) {
long ret;
LIBC_INLINE_ASM("int $128" : "=a"(ret) : "a"(num) : "memory");
return ret;
}

LIBC_INLINE long syscall_impl(long num, long arg1) {
long ret;
LIBC_INLINE_ASM("int $128" : "=a"(ret) : "a"(num), "b"(arg1) : "memory");
return ret;
}

LIBC_INLINE long syscall_impl(long num, long arg1, long arg2) {
long ret;
LIBC_INLINE_ASM("int $128"
: "=a"(ret)
: "a"(num), "b"(arg1), "c"(arg2)
: "memory");
return ret;
}

LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3) {
long ret;
LIBC_INLINE_ASM("int $128"
: "=a"(ret)
: "a"(num), "b"(arg1), "c"(arg2), "d"(arg3)
: "memory");
return ret;
}

LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3,
long arg4) {
long ret;
LIBC_INLINE_ASM("int $128"
: "=a"(ret)
: "a"(num), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4)
: "memory");
return ret;
}

LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3,
long arg4, long arg5) {
long ret;
LIBC_INLINE_ASM("int $128"
: "=a"(ret)
: "a"(num), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4),
"D"(arg5)
: "memory");
return ret;
}

LIBC_INLINE long syscall_impl(long num, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6) {
long ret;
LIBC_INLINE_ASM(R"(
push %[arg6]
push %%ebp
mov 4(%%esp), %%ebp
int $128
pop %%ebp
add $4, %%esp
)"
: "=a"(ret)
: "a"(num), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4),
"D"(arg5), [arg6] "m"(arg6)
: "memory");
return ret;
}

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_I386_SYSCALL_H
4 changes: 3 additions & 1 deletion libc/src/__support/OSUtil/linux/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/architectures.h"

#ifdef LIBC_TARGET_ARCH_IS_X86_64
#ifdef LIBC_TARGET_ARCH_IS_X86_32
#include "i386/syscall.h"
#elif defined(LIBC_TARGET_ARCH_IS_X86_64)
#include "x86_64/syscall.h"
#elif defined(LIBC_TARGET_ARCH_IS_AARCH64)
#include "aarch64/syscall.h"
Expand Down
22 changes: 13 additions & 9 deletions libc/test/UnitTest/FPMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,31 +297,35 @@ struct ModifyMXCSR {
#define EXPECT_FP_EXCEPTION(expected) \
do { \
if (math_errhandling & MATH_ERREXCEPT) { \
EXPECT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
((expected) ? (expected) : FE_ALL_EXCEPT), \
(expected)); \
EXPECT_EQ( \
LIBC_NAMESPACE::fputil::test_except( \
static_cast<int>(FE_ALL_EXCEPT)) & \
((expected) ? (expected) : static_cast<int>(FE_ALL_EXCEPT)), \
(expected)); \
} \
} while (0)

#define ASSERT_FP_EXCEPTION(expected) \
do { \
if (math_errhandling & MATH_ERREXCEPT) { \
ASSERT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
((expected) ? (expected) : FE_ALL_EXCEPT), \
(expected)); \
ASSERT_EQ( \
LIBC_NAMESPACE::fputil::test_except( \
static_cast<int>(FE_ALL_EXCEPT)) & \
((expected) ? (expected) : static_cast<int>(FE_ALL_EXCEPT)), \
(expected)); \
} \
} while (0)

#define EXPECT_FP_EQ_WITH_EXCEPTION(expected_val, actual_val, expected_except) \
do { \
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
LIBC_NAMESPACE::fputil::clear_except(static_cast<int>(FE_ALL_EXCEPT)); \
EXPECT_FP_EQ(expected_val, actual_val); \
EXPECT_FP_EXCEPTION(expected_except); \
} while (0)

#define EXPECT_FP_IS_NAN_WITH_EXCEPTION(actual_val, expected_except) \
do { \
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
LIBC_NAMESPACE::fputil::clear_except(static_cast<int>(FE_ALL_EXCEPT)); \
EXPECT_FP_IS_NAN(actual_val); \
EXPECT_FP_EXCEPTION(expected_except); \
} while (0)
Expand Down Expand Up @@ -374,7 +378,7 @@ struct ModifyMXCSR {
using namespace LIBC_NAMESPACE::fputil::testing; \
ForceRoundingMode __r((rounding_mode)); \
if (__r.success) { \
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
LIBC_NAMESPACE::fputil::clear_except(static_cast<int>(FE_ALL_EXCEPT)); \
EXPECT_FP_EQ((expected), (actual)); \
EXPECT_FP_EXCEPTION(expected_except); \
} \
Expand Down
1 change: 0 additions & 1 deletion libc/test/src/search/hsearch_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include "src/search/hsearch.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
#include <asm-generic/errno-base.h>

TEST(LlvmLibcHsearchTest, CreateTooLarge) {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
Expand Down
1 change: 1 addition & 0 deletions libc/test/src/sys/mman/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,5 +163,6 @@ add_libc_unittest(
libc.src.unistd.ftruncate
libc.src.unistd.close
libc.src.__support.OSUtil.osutil
libc.hdr.fcntl_macros
libc.test.UnitTest.ErrnoSetterMatcher
)
2 changes: 0 additions & 2 deletions libc/test/src/sys/mman/linux/mlock_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
#include "test/UnitTest/LibcTest.h"
#include "test/UnitTest/Test.h"

#include <asm-generic/errno-base.h>
#include <asm-generic/mman.h>
#include <linux/capability.h>
#include <sys/mman.h>
#include <sys/resource.h>
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/sys/mman/linux/shm_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/fcntl_macros.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/fcntl/fcntl.h"
#include "src/sys/mman/mmap.h"
Expand All @@ -16,7 +17,6 @@
#include "src/unistd/ftruncate.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/LibcTest.h"
#include <asm-generic/fcntl.h>
#include <sys/syscall.h>

using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/__format/formatter_floating_point.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <__concepts/arithmetic.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__cstddef/ptrdiff_t.h>
#include <__format/concepts.h>
#include <__format/format_parse_context.h>
#include <__format/formatter.h>
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/__string/char_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <__assert>
#include <__compare/ordering.h>
#include <__config>
#include <__cstddef/ptrdiff_t.h>
#include <__functional/hash.h>
#include <__functional/identity.h>
#include <__iterator/iterator_traits.h>
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ set(BENCHMARK_TESTS
formatter_float.bench.cpp
formatter_int.bench.cpp
function.bench.cpp
hash.bench.cpp
join_view.bench.cpp
lexicographical_compare_three_way.bench.cpp
map.bench.cpp
Expand Down
80 changes: 80 additions & 0 deletions libcxx/test/benchmarks/hash.bench.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03

#include <cstdint>
#include <cstddef>
#include <functional>

#include "benchmark/benchmark.h"

#include "GenerateInput.h"
#include "test_macros.h"

constexpr std::size_t TestNumInputs = 1024;

template <class _Size>
inline TEST_ALWAYS_INLINE _Size loadword(const void* __p) {
_Size __r;
std::memcpy(&__r, __p, sizeof(__r));
return __r;
}

inline TEST_ALWAYS_INLINE std::size_t hash_len_16(std::size_t __u, std::size_t __v) {
const std::size_t __mul = 0x9ddfea08eb382d69ULL;
std::size_t __a = (__u ^ __v) * __mul;
__a ^= (__a >> 47);
std::size_t __b = (__v ^ __a) * __mul;
__b ^= (__b >> 47);
__b *= __mul;
return __b;
}

template <std::size_t _Len>
inline TEST_ALWAYS_INLINE std::size_t hash_len_0_to_8(const char* __s) {
static_assert(_Len == 4 || _Len == 8, "");
const uint64_t __a = loadword<uint32_t>(__s);
const uint64_t __b = loadword<uint32_t>(__s + _Len - 4);
return hash_len_16(_Len + (__a << 3), __b);
}

struct UInt32Hash {
UInt32Hash() = default;
inline TEST_ALWAYS_INLINE std::size_t operator()(uint32_t data) const {
return hash_len_0_to_8<4>(reinterpret_cast<const char*>(&data));
}
};

template <class HashFn, class GenInputs>
void BM_Hash(benchmark::State& st, HashFn fn, GenInputs gen) {
auto in = gen(st.range(0));
const auto end = in.data() + in.size();
std::size_t last_hash = 0;
benchmark::DoNotOptimize(&last_hash);
while (st.KeepRunning()) {
for (auto it = in.data(); it != end; ++it) {
benchmark::DoNotOptimize(last_hash += fn(*it));
}
benchmark::ClobberMemory();
}
}

BENCHMARK_CAPTURE(BM_Hash, uint32_random_std_hash, std::hash<uint32_t>{}, getRandomIntegerInputs<uint32_t>)
->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Hash, uint32_random_custom_hash, UInt32Hash{}, getRandomIntegerInputs<uint32_t>)
->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Hash, uint32_top_std_hash, std::hash<uint32_t>{}, getSortedTopBitsIntegerInputs<uint32_t>)
->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Hash, uint32_top_custom_hash, UInt32Hash{}, getSortedTopBitsIntegerInputs<uint32_t>)
->Arg(TestNumInputs);

BENCHMARK_MAIN();
Loading