8 changes: 4 additions & 4 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1796,14 +1796,14 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
FuncAttrs.addAttribute("aarch64_inout_zt0");
}

static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs,
const Decl *Callee) {
static void AddAttributesFromOMPAssumes(llvm::AttrBuilder &FuncAttrs,
const Decl *Callee) {
if (!Callee)
return;

SmallVector<StringRef, 4> Attrs;

for (const AssumptionAttr *AA : Callee->specific_attrs<AssumptionAttr>())
for (const OMPAssumeAttr *AA : Callee->specific_attrs<OMPAssumeAttr>())
AA->getAssumption().split(Attrs, ",");

if (!Attrs.empty())
Expand Down Expand Up @@ -2344,7 +2344,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,

// Attach assumption attributes to the declaration. If this is a call
// site, attach assumptions from the caller to the call as well.
AddAttributesFromAssumes(FuncAttrs, TargetDecl);
AddAttributesFromOMPAssumes(FuncAttrs, TargetDecl);

bool HasOptnone = false;
// The NoBuiltinAttr attached to the target FunctionDecl.
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/CodeGen/CGStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,11 +728,19 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
case attr::AlwaysInline:
alwaysinline = true;
break;
case attr::MustTail:
case attr::MustTail: {
const Stmt *Sub = S.getSubStmt();
const ReturnStmt *R = cast<ReturnStmt>(Sub);
musttail = cast<CallExpr>(R->getRetValue()->IgnoreParens());
break;
} break;
case attr::CXXAssume: {
const Expr *Assumption = cast<CXXAssumeAttr>(A)->getAssumption();
if (getLangOpts().CXXAssumptions &&
!Assumption->HasSideEffects(getContext())) {
llvm::Value *AssumptionVal = EvaluateExprAsBool(Assumption);
Builder.CreateAssumption(AssumptionVal);
}
} break;
}
}
SaveAndRestore save_nomerge(InNoMergeAttributedStmt, nomerge);
Expand Down
111 changes: 85 additions & 26 deletions clang/lib/Driver/OffloadBundler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,17 @@ CreateFileHandler(MemoryBuffer &FirstInput,
}

OffloadBundlerConfig::OffloadBundlerConfig() {
if (llvm::compression::zstd::isAvailable()) {
CompressionFormat = llvm::compression::Format::Zstd;
// Compression level 3 is usually sufficient for zstd since long distance
// matching is enabled.
CompressionLevel = 3;
} else if (llvm::compression::zlib::isAvailable()) {
CompressionFormat = llvm::compression::Format::Zlib;
// Use default level for zlib since higher level does not have significant
// improvement.
CompressionLevel = llvm::compression::zlib::DefaultCompression;
}
auto IgnoreEnvVarOpt =
llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() == "1")
Expand All @@ -937,11 +948,41 @@ OffloadBundlerConfig::OffloadBundlerConfig() {
llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_COMPRESS");
if (CompressEnvVarOpt.has_value())
Compress = CompressEnvVarOpt.value() == "1";

auto CompressionLevelEnvVarOpt =
llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
if (CompressionLevelEnvVarOpt.has_value()) {
llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
int Level;
if (!CompressionLevelStr.getAsInteger(10, Level))
CompressionLevel = Level;
else
llvm::errs()
<< "Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
<< CompressionLevelStr.str() << ". Ignoring it.\n";
}
}

// Utility function to format numbers with commas
static std::string formatWithCommas(unsigned long long Value) {
std::string Num = std::to_string(Value);
int InsertPosition = Num.length() - 3;
while (InsertPosition > 0) {
Num.insert(InsertPosition, ",");
InsertPosition -= 3;
}
return Num;
}

llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
CompressedOffloadBundle::compress(const llvm::MemoryBuffer &Input,
CompressedOffloadBundle::compress(llvm::compression::Params P,
const llvm::MemoryBuffer &Input,
bool Verbose) {
if (!llvm::compression::zstd::isAvailable() &&
!llvm::compression::zlib::isAvailable())
return createStringError(llvm::inconvertibleErrorCode(),
"Compression not supported");

llvm::Timer HashTimer("Hash Calculation Timer", "Hash calculation time",
ClangOffloadBundlerTimerGroup);
if (Verbose)
Expand All @@ -959,25 +1000,15 @@ CompressedOffloadBundle::compress(const llvm::MemoryBuffer &Input,
reinterpret_cast<const uint8_t *>(Input.getBuffer().data()),
Input.getBuffer().size());

llvm::compression::Format CompressionFormat;

if (llvm::compression::zstd::isAvailable())
CompressionFormat = llvm::compression::Format::Zstd;
else if (llvm::compression::zlib::isAvailable())
CompressionFormat = llvm::compression::Format::Zlib;
else
return createStringError(llvm::inconvertibleErrorCode(),
"Compression not supported");

llvm::Timer CompressTimer("Compression Timer", "Compression time",
ClangOffloadBundlerTimerGroup);
if (Verbose)
CompressTimer.startTimer();
llvm::compression::compress(CompressionFormat, BufferUint8, CompressedBuffer);
llvm::compression::compress(P, BufferUint8, CompressedBuffer);
if (Verbose)
CompressTimer.stopTimer();

uint16_t CompressionMethod = static_cast<uint16_t>(CompressionFormat);
uint16_t CompressionMethod = static_cast<uint16_t>(P.format);
uint32_t UncompressedSize = Input.getBuffer().size();

SmallVector<char, 0> FinalBuffer;
Expand All @@ -995,17 +1026,29 @@ CompressedOffloadBundle::compress(const llvm::MemoryBuffer &Input,

if (Verbose) {
auto MethodUsed =
CompressionFormat == llvm::compression::Format::Zstd ? "zstd" : "zlib";
P.format == llvm::compression::Format::Zstd ? "zstd" : "zlib";
double CompressionRate =
static_cast<double>(UncompressedSize) / CompressedBuffer.size();
double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
double CompressionSpeedMBs =
(UncompressedSize / (1024.0 * 1024.0)) / CompressionTimeSeconds;

llvm::errs() << "Compressed bundle format version: " << Version << "\n"
<< "Compression method used: " << MethodUsed << "\n"
<< "Binary size before compression: " << UncompressedSize
<< " bytes\n"
<< "Binary size after compression: " << CompressedBuffer.size()
<< " bytes\n"
<< "Compression level: " << P.level << "\n"
<< "Binary size before compression: "
<< formatWithCommas(UncompressedSize) << " bytes\n"
<< "Binary size after compression: "
<< formatWithCommas(CompressedBuffer.size()) << " bytes\n"
<< "Compression rate: "
<< llvm::format("%.2lf", CompressionRate) << "\n"
<< "Compression ratio: "
<< llvm::format("%.2lf%%", 100.0 / CompressionRate) << "\n"
<< "Compression speed: "
<< llvm::format("%.2lf MB/s", CompressionSpeedMBs) << "\n"
<< "Truncated MD5 hash: "
<< llvm::format_hex(TruncatedHash, 16) << "\n";
}

return llvm::MemoryBuffer::getMemBufferCopy(
llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
}
Expand Down Expand Up @@ -1070,7 +1113,10 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
if (Verbose) {
DecompressTimer.stopTimer();

// Recalculate MD5 hash
double DecompressionTimeSeconds =
DecompressTimer.getTotalTime().getWallTime();

// Recalculate MD5 hash for integrity check
llvm::Timer HashRecalcTimer("Hash Recalculation Timer",
"Hash recalculation time",
ClangOffloadBundlerTimerGroup);
Expand All @@ -1084,16 +1130,27 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
HashRecalcTimer.stopTimer();
bool HashMatch = (StoredHash == RecalculatedHash);

double CompressionRate =
static_cast<double>(UncompressedSize) / CompressedData.size();
double DecompressionSpeedMBs =
(UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;

llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n"
<< "Decompression method: "
<< (CompressionFormat == llvm::compression::Format::Zlib
? "zlib"
: "zstd")
<< "\n"
<< "Size before decompression: " << CompressedData.size()
<< " bytes\n"
<< "Size after decompression: " << UncompressedSize
<< " bytes\n"
<< "Size before decompression: "
<< formatWithCommas(CompressedData.size()) << " bytes\n"
<< "Size after decompression: "
<< formatWithCommas(UncompressedSize) << " bytes\n"
<< "Compression rate: "
<< llvm::format("%.2lf", CompressionRate) << "\n"
<< "Compression ratio: "
<< llvm::format("%.2lf%%", 100.0 / CompressionRate) << "\n"
<< "Decompression speed: "
<< llvm::format("%.2lf MB/s", DecompressionSpeedMBs) << "\n"
<< "Stored hash: " << llvm::format_hex(StoredHash, 16) << "\n"
<< "Recalculated hash: "
<< llvm::format_hex(RecalculatedHash, 16) << "\n"
Expand Down Expand Up @@ -1287,8 +1344,10 @@ Error OffloadBundler::BundleFiles() {
std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
llvm::MemoryBuffer::getMemBufferCopy(
llvm::StringRef(Buffer.data(), Buffer.size()));
auto CompressionResult =
CompressedOffloadBundle::compress(*BufferMemory, BundlerConfig.Verbose);
auto CompressionResult = CompressedOffloadBundle::compress(
{BundlerConfig.CompressionFormat, BundlerConfig.CompressionLevel,
/*zstdEnableLdm=*/true},
*BufferMemory, BundlerConfig.Verbose);
if (auto Error = CompressionResult.takeError())
return Error;

Expand Down
16 changes: 7 additions & 9 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6982,6 +6982,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
(!IsWindowsMSVC || IsMSVC2015Compatible)))
CmdArgs.push_back("-fno-threadsafe-statics");

// Add -fno-assumptions, if it was specified.
if (!Args.hasFlag(options::OPT_fassumptions, options::OPT_fno_assumptions,
true))
CmdArgs.push_back("-fno-assumptions");

// -fgnu-keywords default varies depending on language; only pass if
// specified.
Args.AddLastArg(CmdArgs, options::OPT_fgnu_keywords,
Expand Down Expand Up @@ -8524,7 +8529,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
}

// Begin OffloadBundler

void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
Expand Down Expand Up @@ -8622,11 +8626,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
}
CmdArgs.push_back(TCArgs.MakeArgString(UB));
}
if (TCArgs.hasFlag(options::OPT_offload_compress,
options::OPT_no_offload_compress, false))
CmdArgs.push_back("-compress");
if (TCArgs.hasArg(options::OPT_v))
CmdArgs.push_back("-verbose");
addOffloadCompressArgs(TCArgs, CmdArgs);
// All the inputs are encoded as commands.
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::None(),
Expand Down Expand Up @@ -8895,9 +8895,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
for (const char *LinkArg : LinkCommand->getArguments())
CmdArgs.push_back(LinkArg);

if (Args.hasFlag(options::OPT_offload_compress,
options::OPT_no_offload_compress, false))
CmdArgs.push_back("--compress");
addOffloadCompressArgs(Args, CmdArgs);

const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("clang-linker-wrapper"));
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2863,3 +2863,15 @@ void tools::addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC,
CmdArgs.push_back("+outline-atomics");
}
}

void tools::addOffloadCompressArgs(const llvm::opt::ArgList &TCArgs,
llvm::opt::ArgStringList &CmdArgs) {
if (TCArgs.hasFlag(options::OPT_offload_compress,
options::OPT_no_offload_compress, false))
CmdArgs.push_back("-compress");
if (TCArgs.hasArg(options::OPT_v))
CmdArgs.push_back("-verbose");
if (auto *Arg = TCArgs.getLastArg(options::OPT_offload_compression_level_EQ))
CmdArgs.push_back(
TCArgs.MakeArgString(Twine("-compression-level=") + Arg->getValue()));
}
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ void addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const llvm::Triple &Triple);
void addOffloadCompressArgs(const llvm::opt::ArgList &TCArgs,
llvm::opt::ArgStringList &CmdArgs);

} // end namespace tools
} // end namespace driver
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/Driver/ToolChains/HIPUtility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "HIPUtility.h"
#include "Clang.h"
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Options.h"
Expand Down Expand Up @@ -258,11 +259,7 @@ void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
Args.MakeArgString(std::string("-output=").append(Output));
BundlerArgs.push_back(BundlerOutputArg);

if (Args.hasFlag(options::OPT_offload_compress,
options::OPT_no_offload_compress, false))
BundlerArgs.push_back("-compress");
if (Args.hasArg(options::OPT_v))
BundlerArgs.push_back("-verbose");
addOffloadCompressArgs(Args, BundlerArgs);

const char *Bundler = Args.MakeArgString(
T.getToolChain().GetProgramPath("clang-offload-bundler"));
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2707,6 +2707,7 @@ class AnnotatingParser {
auto IsQualifiedPointerOrReference = [this](FormatToken *T) {
// This is used to handle cases such as x = (foo *const)&y;
assert(!T->isTypeName(IsCpp) && "Should have already been checked");
(void)IsCpp; // Avoid -Wunused-lambda-capture when assertion is disabled.
// Strip trailing qualifiers such as const or volatile when checking
// whether the parens could be a cast to a pointer/reference type.
while (T) {
Expand Down
62 changes: 61 additions & 1 deletion clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4528,6 +4528,61 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
}
}

/// Parse the argument to C++23's [[assume()]] attribute.
bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
SourceLocation *EndLoc) {
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();

// [dcl.attr.assume]: The expression is potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);

TentativeParsingAction TPA(*this);
ExprResult Res(
Actions.CorrectDelayedTyposInExpr(ParseConditionalExpression()));
if (Res.isInvalid()) {
TPA.Commit();
SkipUntil(tok::r_paren, tok::r_square, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::r_paren))
T.consumeClose();
return true;
}

if (!Tok.isOneOf(tok::r_paren, tok::r_square)) {
// Emit a better diagnostic if this is an otherwise valid expression that
// is not allowed here.
TPA.Revert();
Res = ParseExpression();
if (!Res.isInvalid()) {
auto *E = Res.get();
Diag(E->getExprLoc(), diag::err_assume_attr_expects_cond_expr)
<< AttrName << FixItHint::CreateInsertion(E->getBeginLoc(), "(")
<< FixItHint::CreateInsertion(PP.getLocForEndOfToken(E->getEndLoc()),
")")
<< E->getSourceRange();
}

T.consumeClose();
return true;
}

TPA.Commit();
ArgsUnion Assumption = Res.get();
auto RParen = Tok.getLocation();
T.consumeClose();
Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), nullptr,
SourceLocation(), &Assumption, 1, ParsedAttr::Form::CXX11());

if (EndLoc)
*EndLoc = RParen;

return false;
}

/// ParseCXX11AttributeArgs -- Parse a C++11 attribute-argument-clause.
///
/// [C++11] attribute-argument-clause:
Expand Down Expand Up @@ -4596,7 +4651,12 @@ bool Parser::ParseCXX11AttributeArgs(
if (ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")))
NumArgs = ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Form);
else
// So does C++23's assume() attribute.
else if (!ScopeName && AttrName->isStr("assume")) {
if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc))
return true;
NumArgs = 1;
} else
NumArgs = ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Form);

Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,19 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
}

ExprResult Parser::ParseConditionalExpression() {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteExpression(getCurScope(),
PreferredType.get(Tok.getLocation()));
return ExprError();
}

ExprResult LHS = ParseCastExpression(
AnyCastExpr, /*isAddressOfOperand=*/false, NotTypeCast);
return ParseRHSOfBinaryExpression(LHS, prec::Conditional);
}

/// Parse an assignment expression where part of an Objective-C message
/// send has already been parsed.
///
Expand Down
19 changes: 10 additions & 9 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1771,8 +1771,8 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
}

/// Check if \p AssumptionStr is a known assumption and warn if not.
static void checkAssumptionAttr(Sema &S, SourceLocation Loc,
StringRef AssumptionStr) {
static void checkOMPAssumeAttr(Sema &S, SourceLocation Loc,
StringRef AssumptionStr) {
if (llvm::KnownAssumptionStrings.count(AssumptionStr))
return;

Expand All @@ -1788,22 +1788,23 @@ static void checkAssumptionAttr(Sema &S, SourceLocation Loc,
}

if (!Suggestion.empty())
S.Diag(Loc, diag::warn_assume_attribute_string_unknown_suggested)
S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown_suggested)
<< AssumptionStr << Suggestion;
else
S.Diag(Loc, diag::warn_assume_attribute_string_unknown) << AssumptionStr;
S.Diag(Loc, diag::warn_omp_assume_attribute_string_unknown)
<< AssumptionStr;
}

static void handleAssumumptionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleOMPAssumeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Handle the case where the attribute has a text message.
StringRef Str;
SourceLocation AttrStrLoc;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc))
return;

checkAssumptionAttr(S, AttrStrLoc, Str);
checkOMPAssumeAttr(S, AttrStrLoc, Str);

D->addAttr(::new (S.Context) AssumptionAttr(S.Context, AL, Str));
D->addAttr(::new (S.Context) OMPAssumeAttr(S.Context, AL, Str));
}

/// Normalize the attribute, __foo__ becomes foo.
Expand Down Expand Up @@ -9491,8 +9492,8 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_Unavailable:
handleAttrWithMessage<UnavailableAttr>(S, D, AL);
break;
case ParsedAttr::AT_Assumption:
handleAssumumptionAttr(S, D, AL);
case ParsedAttr::AT_OMPAssume:
handleOMPAssumeAttr(S, D, AL);
break;
case ParsedAttr::AT_ObjCDirect:
handleObjCDirectAttr(S, D, AL);
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3496,7 +3496,7 @@ void Sema::ActOnOpenMPAssumesDirective(SourceLocation Loc,
<< llvm::omp::getAllAssumeClauseOptions()
<< llvm::omp::getOpenMPDirectiveName(DKind);

auto *AA = AssumptionAttr::Create(Context, llvm::join(Assumptions, ","), Loc);
auto *AA = OMPAssumeAttr::Create(Context, llvm::join(Assumptions, ","), Loc);
if (DKind == llvm::omp::Directive::OMPD_begin_assumes) {
OMPAssumeScoped.push_back(AA);
return;
Expand Down Expand Up @@ -7275,10 +7275,10 @@ void Sema::ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Decl *D) {
// only global ones. We apply scoped assumption to the template definition
// though.
if (!inTemplateInstantiation()) {
for (AssumptionAttr *AA : OMPAssumeScoped)
for (OMPAssumeAttr *AA : OMPAssumeScoped)
FD->addAttr(AA);
}
for (AssumptionAttr *AA : OMPAssumeGlobal)
for (OMPAssumeAttr *AA : OMPAssumeGlobal)
FD->addAttr(AA);
}

Expand Down
55 changes: 55 additions & 0 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,15 @@ static Attr *handleAlwaysInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
return ::new (S.Context) AlwaysInlineAttr(S.Context, A);
}

static Attr *handleCXXAssumeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SourceRange Range) {
ExprResult Res = S.ActOnCXXAssumeAttr(St, A, Range);
if (!Res.isUsable())
return nullptr;

return ::new (S.Context) CXXAssumeAttr(S.Context, A, Res.get());
}

static Attr *handleMustTailAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SourceRange Range) {
// Validation is in Sema::ActOnAttributedStmt().
Expand Down Expand Up @@ -594,6 +603,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
switch (A.getKind()) {
case ParsedAttr::AT_AlwaysInline:
return handleAlwaysInlineAttr(S, St, A, Range);
case ParsedAttr::AT_CXXAssume:
return handleCXXAssumeAttr(S, St, A, Range);
case ParsedAttr::AT_FallThrough:
return handleFallThroughAttr(S, St, A, Range);
case ParsedAttr::AT_LoopHint:
Expand Down Expand Up @@ -641,3 +652,47 @@ bool Sema::CheckRebuiltStmtAttributes(ArrayRef<const Attr *> Attrs) {
CheckForDuplicateLoopAttrs<CodeAlignAttr>(*this, Attrs);
return false;
}

ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A,
SourceRange Range) {
if (A.getNumArgs() != 1 || !A.getArgAsExpr(0)) {
Diag(A.getLoc(), diag::err_assume_attr_args) << A.getAttrName() << Range;
return ExprError();
}

auto *Assumption = A.getArgAsExpr(0);
if (Assumption->getDependence() == ExprDependence::None) {
ExprResult Res = BuildCXXAssumeExpr(Assumption, A.getAttrName(), Range);
if (Res.isInvalid())
return ExprError();
Assumption = Res.get();
}

if (!getLangOpts().CPlusPlus23)
Diag(A.getLoc(), diag::ext_cxx23_attr) << A << Range;

return Assumption;
}

ExprResult Sema::BuildCXXAssumeExpr(Expr *Assumption,
const IdentifierInfo *AttrName,
SourceRange Range) {
ExprResult Res = CorrectDelayedTyposInExpr(Assumption);
if (Res.isInvalid())
return ExprError();

Res = CheckPlaceholderExpr(Res.get());
if (Res.isInvalid())
return ExprError();

Res = PerformContextuallyConvertToBool(Res.get());
if (Res.isInvalid())
return ExprError();

Assumption = Res.get();
if (Assumption->HasSideEffects(Context))
Diag(Assumption->getBeginLoc(), diag::warn_assume_side_effects)
<< AttrName << Range;

return Assumption;
}
16 changes: 16 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,7 @@ namespace {
NamedDecl *FirstQualifierInScope = nullptr,
bool AllowInjectedClassName = false);

const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS,
const Stmt *InstS,
Expand Down Expand Up @@ -1980,6 +1981,21 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
Arg, PackIndex);
}

const CXXAssumeAttr *
TemplateInstantiator::TransformCXXAssumeAttr(const CXXAssumeAttr *AA) {
ExprResult Res = getDerived().TransformExpr(AA->getAssumption());
if (!Res.isUsable())
return AA;

Res = getSema().BuildCXXAssumeExpr(Res.get(), AA->getAttrName(),
AA->getRange());
if (!Res.isUsable())
return AA;

return CXXAssumeAttr::CreateImplicit(getSema().Context, Res.get(),
AA->getRange());
}

const LoopHintAttr *
TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get();
Expand Down
50 changes: 50 additions & 0 deletions clang/test/CodeGenCXX/cxx23-assume.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++23 %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++23 -fno-assumptions %s -emit-llvm -o - | FileCheck %s --check-prefix=DISABLED

// DISABLED-NOT: @llvm.assume

bool f();

template <typename T>
void f2() {
[[assume(sizeof(T) == sizeof(int))]];
}

// CHECK: @_Z1gii(i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]])
// CHECK-NEXT: entry:
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32
// CHECK-NEXT: [[Y_ADDR:%.*]] = alloca i32
// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]]
// CHECK-NEXT: store i32 [[Y]], ptr [[Y_ADDR]]
void g(int x, int y) {
// Not emitted because it has side-effects.
[[assume(f())]];

// CHECK-NEXT: call void @llvm.assume(i1 true)
[[assume((1, 2))]];

// CHECK-NEXT: [[X1:%.*]] = load i32, ptr [[X_ADDR]]
// CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X1]], 27
// CHECK-NEXT: call void @llvm.assume(i1 [[CMP1]])
[[assume(x != 27)]];

// CHECK-NEXT: [[X2:%.*]] = load i32, ptr [[X_ADDR]]
// CHECK-NEXT: [[Y2:%.*]] = load i32, ptr [[Y_ADDR]]
// CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[X2]], [[Y2]]
// CHECK-NEXT: call void @llvm.assume(i1 [[CMP2]])
[[assume(x == y)]];

// CHECK-NEXT: call void @_Z2f2IiEvv()
f2<int>();

// CHECK-NEXT: call void @_Z2f2IdEvv()
f2<double>();
}

// CHECK: void @_Z2f2IiEvv()
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @llvm.assume(i1 true)

// CHECK: void @_Z2f2IdEvv()
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @llvm.assume(i1 false)
21 changes: 18 additions & 3 deletions clang/test/Driver/clang-offload-bundler-zlib.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// REQUIRES: zlib
// REQUIRES: zlib && !zstd
// REQUIRES: x86-registered-target
// UNSUPPORTED: target={{.*}}-darwin{{.*}}, target={{.*}}-aix{{.*}}

Expand Down Expand Up @@ -34,13 +34,28 @@
// RUN: diff %t.tgt2 %t.res.tgt2

//
// COMPRESS: Compression method used:
// DECOMPRESS: Decompression method:
// COMPRESS: Compression method used: zlib
// COMPRESS: Compression level: 6
// DECOMPRESS: Decompression method: zlib
// DECOMPRESS: Hashes match: Yes
// NOHOST-NOT: host-
// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx900
// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx906
//

// Check -compression-level= option

// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \
// RUN: -input=%t.tgt1 -input=%t.tgt2 -output=%t.hip.bundle.bc -compress -verbose -compression-level=9 2>&1 | \
// RUN: FileCheck -check-prefix=LEVEL %s
// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \
// RUN: -output=%t.res.tgt1 -output=%t.res.tgt2 -input=%t.hip.bundle.bc -unbundle
// RUN: diff %t.tgt1 %t.res.tgt1
// RUN: diff %t.tgt2 %t.res.tgt2
//
// LEVEL: Compression method used: zlib
// LEVEL: Compression level: 9

//
// Check -bundle-align option.
//
Expand Down
19 changes: 17 additions & 2 deletions clang/test/Driver/clang-offload-bundler-zstd.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,28 @@
// RUN: diff %t.tgt1 %t.res.tgt1
// RUN: diff %t.tgt2 %t.res.tgt2
//
// COMPRESS: Compression method used
// DECOMPRESS: Decompression method
// COMPRESS: Compression method used: zstd
// COMPRESS: Compression level: 3
// DECOMPRESS: Decompression method: zstd
// DECOMPRESS: Hashes match: Yes
// NOHOST-NOT: host-
// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx900
// NOHOST-DAG: hip-amdgcn-amd-amdhsa--gfx906
//

// Check -compression-level= option

// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \
// RUN: -input=%t.tgt1 -input=%t.tgt2 -output=%t.hip.bundle.bc -compress -verbose -compression-level=9 2>&1 | \
// RUN: FileCheck -check-prefix=LEVEL %s
// RUN: clang-offload-bundler -type=bc -targets=hip-amdgcn-amd-amdhsa--gfx900,hip-amdgcn-amd-amdhsa--gfx906 \
// RUN: -output=%t.res.tgt1 -output=%t.res.tgt2 -input=%t.hip.bundle.bc -unbundle
// RUN: diff %t.tgt1 %t.res.tgt1
// RUN: diff %t.tgt2 %t.res.tgt2
//
// LEVEL: Compression method used: zstd
// LEVEL: Compression level: 9

//
// Check -bundle-align option.
//
Expand Down
7 changes: 4 additions & 3 deletions clang/test/Driver/hip-offload-compress-zlib.hip
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// REQUIRES: zlib
// REQUIRES: zlib && !zstd
// REQUIRES: x86-registered-target
// REQUIRES: amdgpu-registered-target

Expand All @@ -9,13 +9,14 @@
// RUN: -x hip --offload-arch=gfx1100 --offload-arch=gfx1101 \
// RUN: --no-offload-new-driver -fgpu-rdc -nogpuinc -nogpulib \
// RUN: %S/Inputs/hip_multiple_inputs/a.cu \
// RUN: --offload-compress --offload-device-only --gpu-bundle-output \
// RUN: --offload-compress --offload-compression-level=9 \
// RUN: --offload-device-only --gpu-bundle-output \
// RUN: -o %t.bc \
// RUN: 2>&1 | FileCheck %s

// CHECK: clang-offload-bundler{{.*}} -type=bc
// CHECK-SAME: -targets={{.*}}hip-amdgcn-amd-amdhsa-gfx1100,hip-amdgcn-amd-amdhsa-gfx1101
// CHECK-SAME: -compress -verbose
// CHECK-SAME: -compress -verbose -compression-level=9
// CHECK: Compressed bundle format

// Test uncompress of bundled bitcode.
Expand Down
5 changes: 3 additions & 2 deletions clang/test/Driver/hip-offload-compress-zstd.hip
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
// RUN: -x hip --offload-arch=gfx1100 --offload-arch=gfx1101 \
// RUN: --no-offload-new-driver -fgpu-rdc -nogpuinc -nogpulib \
// RUN: %S/Inputs/hip_multiple_inputs/a.cu \
// RUN: --offload-compress --offload-device-only --gpu-bundle-output \
// RUN: --offload-compress --offload-compression-level=9 \
// RUN: --offload-device-only --gpu-bundle-output \
// RUN: -o %t.bc \
// RUN: 2>&1 | FileCheck %s

// CHECK: clang-offload-bundler{{.*}} -type=bc
// CHECK-SAME: -targets={{.*}}hip-amdgcn-amd-amdhsa-gfx1100,hip-amdgcn-amd-amdhsa-gfx1101
// CHECK-SAME: -compress -verbose
// CHECK-SAME: -compress -verbose -compression-level=9
// CHECK: Compressed bundle format

// Test uncompress of bundled bitcode.
Expand Down
5 changes: 3 additions & 2 deletions clang/test/Driver/linker-wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,13 @@ __attribute__((visibility("protected"), used)) int x;
// RUN: --image=file=%t.elf.o,kind=hip,triple=amdgcn-amd-amdhsa,arch=gfx908
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o \
// RUN: -fembed-offload-object=%t.out
// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-unknown-linux-gnu --compress \
// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-unknown-linux-gnu \
// RUN: --compress --compression-level=6 \
// RUN: --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=HIP

// HIP: clang{{.*}} -o [[IMG_GFX908:.+]] --target=amdgcn-amd-amdhsa -mcpu=gfx908
// HIP: clang{{.*}} -o [[IMG_GFX90A:.+]] --target=amdgcn-amd-amdhsa -mcpu=gfx90a
// HIP: clang-offload-bundler{{.*}}-type=o -bundle-align=4096 -compress -targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx90a,hipv4-amdgcn-amd-amdhsa--gfx908 -input=/dev/null -input=[[IMG_GFX90A]] -input=[[IMG_GFX908]] -output={{.*}}.hipfb
// HIP: clang-offload-bundler{{.*}}-type=o -bundle-align=4096 -compress -compression-level=6 -targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx90a,hipv4-amdgcn-amd-amdhsa--gfx908 -input=/dev/null -input=[[IMG_GFX90A]] -input=[[IMG_GFX908]] -output={{.*}}.hipfb

// RUN: clang-offload-packager -o %t.out \
// RUN: --image=file=%t.elf.o,kind=openmp,triple=amdgcn-amd-amdhsa,arch=gfx908 \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
// CHECK-NEXT: ArcWeakrefUnavailable (SubjectMatchRule_objc_interface)
// CHECK-NEXT: ArmBuiltinAlias (SubjectMatchRule_function)
// CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function)
// CHECK-NEXT: Assumption (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
// CHECK-NEXT: AvailableOnlyInDefaultEvalMethod (SubjectMatchRule_type_alias)
// CHECK-NEXT: BPFPreserveAccessIndex (SubjectMatchRule_record)
Expand Down Expand Up @@ -127,6 +126,7 @@
// CHECK-NEXT: NoThrow (SubjectMatchRule_hasType_functionType)
// CHECK-NEXT: NoUwtable (SubjectMatchRule_hasType_functionType)
// CHECK-NEXT: NotTailCalled (SubjectMatchRule_function)
// CHECK-NEXT: OMPAssume (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: OSConsumed (SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: OSReturnsNotRetained (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: OSReturnsRetained (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_variable_is_parameter)
Expand Down
18 changes: 18 additions & 0 deletions clang/test/Parser/cxx23-assume.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: %clang_cc1 -std=c++23 -x c++ %s -verify

void f(int x, int y) {
[[assume(true)]];
[[assume(1)]];
[[assume(1.0)]];
[[assume(1 + 2 == 3)]];
[[assume(x ? 1 : 2)]];
[[assume(x && y)]];
[[assume(true)]] [[assume(true)]];

[[assume]]; // expected-error {{takes one argument}}
[[assume(]]; // expected-error {{expected expression}}
[[assume()]]; // expected-error {{expected expression}}
[[assume(2]]; // expected-error {{expected ')'}} expected-note {{to match this '('}}
[[assume(x = 2)]]; // expected-error {{requires parentheses}}
[[assume(2, 3)]]; // expected-error {{requires parentheses}} expected-warning {{has no effect}}
}
14 changes: 14 additions & 0 deletions clang/test/SemaCXX/cxx23-assume-disabled.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %clang_cc1 -std=c++23 -x c++ %s -fno-assumptions -verify
// RUN: %clang_cc1 -std=c++23 -x c++ %s -fms-compatibility -verify
// expected-no-diagnostics

// We don't check assumptions at compile time if '-fno-assumptions' is passed,
// or if we're in MSVCCompat mode

constexpr bool f(bool x) {
[[assume(x)]];
return true;
}

static_assert(f(false));

13 changes: 13 additions & 0 deletions clang/test/SemaCXX/cxx23-assume-print.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 -std=c++23 -ast-print %s | FileCheck %s

// CHECK: void f(int x, int y) {
void f(int x, int y) {
// CHECK-NEXT: {{\[}}[assume(true)]]
[[assume(true)]];

// CHECK-NEXT: {{\[}}[assume(2 + 4)]]
[[assume(2 + 4)]];

// CHECK-NEXT: {{\[}}[assume(x == y)]]
[[assume(x == y)]];
}
128 changes: 128 additions & 0 deletions clang/test/SemaCXX/cxx23-assume.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// RUN: %clang_cc1 -std=c++23 -x c++ %s -verify
// RUN: %clang_cc1 -std=c++20 -pedantic -x c++ %s -verify=ext,expected

struct A{};
struct B{ explicit operator bool() { return true; } };

template <bool cond>
void f() {
[[assume(cond)]]; // ext-warning {{C++23 extension}}
}

template <bool cond>
struct S {
void f() {
[[assume(cond)]]; // ext-warning {{C++23 extension}}
}

template <typename T>
constexpr bool g() {
[[assume(cond == sizeof(T))]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
return true;
}
};

bool f2();

template <typename T>
constexpr void f3() {
[[assume(T{})]]; // expected-error {{not contextually convertible to 'bool'}} expected-warning {{has side effects that will be discarded}} ext-warning {{C++23 extension}}
}

void g(int x) {
f<true>();
f<false>();
S<true>{}.f();
S<false>{}.f();
S<true>{}.g<char>();
S<true>{}.g<int>();
[[assume(f2())]]; // expected-warning {{side effects that will be discarded}} ext-warning {{C++23 extension}}

[[assume((x = 3))]]; // expected-warning {{has side effects that will be discarded}} // ext-warning {{C++23 extension}}
[[assume(x++)]]; // expected-warning {{has side effects that will be discarded}} // ext-warning {{C++23 extension}}
[[assume(++x)]]; // expected-warning {{has side effects that will be discarded}} // ext-warning {{C++23 extension}}
[[assume([]{ return true; }())]]; // expected-warning {{has side effects that will be discarded}} // ext-warning {{C++23 extension}}
[[assume(B{})]]; // expected-warning {{has side effects that will be discarded}} // ext-warning {{C++23 extension}}
[[assume((1, 2))]]; // expected-warning {{has no effect}} // ext-warning {{C++23 extension}}

f3<A>(); // expected-note {{in instantiation of}}
f3<B>(); // expected-note {{in instantiation of}}
[[assume]]; // expected-error {{takes one argument}}
[[assume(z)]]; // expected-error {{undeclared identifier}}
[[assume(A{})]]; // expected-error {{not contextually convertible to 'bool'}}
[[assume(true)]] if (true) {} // expected-error {{only applies to empty statements}}
[[assume(true)]] {} // expected-error {{only applies to empty statements}}
[[assume(true)]] for (;false;) {} // expected-error {{only applies to empty statements}}
[[assume(true)]] while (false) {} // expected-error {{only applies to empty statements}}
[[assume(true)]] label:; // expected-error {{cannot be applied to a declaration}}
[[assume(true)]] goto label; // expected-error {{only applies to empty statements}}
}

// Check that 'x' is ODR-used here.
constexpr int h(int x) { return sizeof([=] { [[assume(x)]]; }); } // ext-warning {{C++23 extension}}
static_assert(h(4) == sizeof(int));

static_assert(__has_cpp_attribute(assume) == 202207L);
static_assert(__has_attribute(assume));

constexpr bool i() { // ext-error {{never produces a constant expression}}
[[assume(false)]]; // ext-note {{assumption evaluated to false}} expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
return true;
}

constexpr bool j(bool b) {
[[assume(b)]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
return true;
}

static_assert(i()); // expected-error {{not an integral constant expression}} expected-note {{in call to}}
static_assert(j(true));
static_assert(j(false)); // expected-error {{not an integral constant expression}} expected-note {{in call to}}
static_assert(S<true>{}.g<char>());
static_assert(S<false>{}.g<A>()); // expected-error {{not an integral constant expression}} expected-note {{in call to}}


template <typename T>
constexpr bool f4() {
[[assume(!T{})]]; // expected-error {{invalid argument type 'D'}} // expected-warning 2 {{side effects}} ext-warning {{C++23 extension}}
return sizeof(T) == sizeof(int);
}

template <typename T>
concept C = f4<T>(); // expected-note 3 {{in instantiation of}}
// expected-note@-1 3 {{while substituting}}
// expected-error@-2 2 {{resulted in a non-constant expression}}

struct D {
int x;
};

struct E {
int x;
constexpr explicit operator bool() { return false; }
};

struct F {
int x;
int y;
constexpr explicit operator bool() { return false; }
};

template <typename T>
constexpr int f5() requires C<T> { return 1; } // expected-note {{while checking the satisfaction}}
// expected-note@-1 {{while substituting template arguments}}
// expected-note@-2 {{candidate template ignored}}

template <typename T>
constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while checking the satisfaction}}
// expected-note@-1 4 {{while substituting template arguments}}
// expected-note@-2 {{candidate template ignored}}

static_assert(f5<int>() == 1);
static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint satisfaction}}
// expected-note@-1 3 {{in instantiation of}}
// expected-error@-2 {{no matching function for call}}

static_assert(f5<double>() == 2);
static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
3 changes: 3 additions & 0 deletions clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,9 @@ fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles,

if (Args.hasArg(OPT_compress))
CmdArgs.push_back("-compress");
if (auto *Arg = Args.getLastArg(OPT_compression_level_eq))
CmdArgs.push_back(
Args.MakeArgString(Twine("-compression-level=") + Arg->getValue()));

SmallVector<StringRef> Targets = {"-targets=host-x86_64-unknown-linux"};
for (const auto &[File, Arch] : InputFiles)
Expand Down
2 changes: 2 additions & 0 deletions clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def save_temps : Flag<["--"], "save-temps">,
Flags<[WrapperOnlyOption]>, HelpText<"Save intermediate results">;
def compress : Flag<["--"], "compress">,
Flags<[WrapperOnlyOption]>, HelpText<"Compress bundled files">;
def compression_level_eq : Joined<["--"], "compression-level=">,
Flags<[WrapperOnlyOption]>, HelpText<"Specify the compression level (integer)">;

def wrapper_time_trace_eq : Joined<["--"], "wrapper-time-trace=">,
Flags<[WrapperOnlyOption]>, MetaVarName<"<file>">,
Expand Down
5 changes: 5 additions & 0 deletions clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ int main(int argc, const char **argv) {
cl::init(false), cl::cat(ClangOffloadBundlerCategory));
cl::opt<bool> Verbose("verbose", cl::desc("Print debug information.\n"),
cl::init(false), cl::cat(ClangOffloadBundlerCategory));
cl::opt<int> CompressionLevel(
"compression-level", cl::desc("Specify the compression level (integer)"),
cl::value_desc("n"), cl::Optional, cl::cat(ClangOffloadBundlerCategory));

// Process commandline options and report errors
sys::PrintStackTraceOnErrorSignal(argv[0]);
Expand Down Expand Up @@ -178,6 +181,8 @@ int main(int argc, const char **argv) {
BundlerConfig.Compress = Compress;
if (Verbose.getNumOccurrences() > 0)
BundlerConfig.Verbose = Verbose;
if (CompressionLevel.getNumOccurrences() > 0)
BundlerConfig.CompressionLevel = CompressionLevel;

BundlerConfig.TargetNames = TargetNames;
BundlerConfig.InputFileNames = InputFileNames;
Expand Down
2 changes: 1 addition & 1 deletion clang/www/cxx_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ <h2 id="cxx23">C++23 implementation status</h2>
<tr>
<td>Portable assumptions</td>
<td><a href="https://wg21.link/P1774R8">P1774R8</a></td>
<td class="none" align="center">No</td>
<td class="unreleased" align="center">Clang 19</td>
</tr>
<tr>
<td>Support for UTF-8 as a portable source file encoding</td>
Expand Down
12 changes: 6 additions & 6 deletions libc/src/__support/UInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128
#include "src/__support/math_extras.h" // SumCarry, DiffBorrow
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128, LIBC_TYPES_HAS_INT64
#include "src/__support/math_extras.h" // SumCarry, DiffBorrow
#include "src/__support/number_pair.h"

#include <stddef.h> // For size_t
Expand Down Expand Up @@ -940,11 +940,11 @@ namespace internal {
// availability.
template <size_t Bits>
struct WordTypeSelector : cpp::type_identity<
#if defined(UINT64_MAX)
#ifdef LIBC_TYPES_HAS_INT64
uint64_t
#else
uint32_t
#endif
#endif // LIBC_TYPES_HAS_INT64
> {
};
// Except if we request 32 bits explicitly.
Expand Down
7 changes: 6 additions & 1 deletion libc/src/__support/macros/properties/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "src/__support/macros/properties/cpu_features.h"
#include "src/__support/macros/properties/os.h"

#include <stdint.h> // __SIZEOF_INT128__
#include <stdint.h> // UINT64_MAX, __SIZEOF_INT128__

// 'long double' properties.
#if (LDBL_MANT_DIG == 53)
Expand All @@ -28,6 +28,11 @@
#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128
#endif

// int64 / uint64 support
#if defined(UINT64_MAX)
#define LIBC_TYPES_HAS_INT64
#endif // UINT64_MAX

// int128 / uint128 support
#if defined(__SIZEOF_INT128__)
#define LIBC_TYPES_HAS_INT128
Expand Down
9 changes: 3 additions & 6 deletions libc/src/string/memory_utils/op_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "src/__support/common.h"
#include "src/__support/endian.h"
#include "src/__support/macros/optimization.h"
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT64
#include "src/string/memory_utils/op_builtin.h"
#include "src/string/memory_utils/utils.h"

Expand All @@ -37,10 +38,6 @@ static_assert((UINTPTR_MAX == 4294967295U) ||
(UINTPTR_MAX == 18446744073709551615UL),
"We currently only support 32- or 64-bit platforms");

#if defined(UINT64_MAX)
#define LLVM_LIBC_HAS_UINT64
#endif

namespace LIBC_NAMESPACE {
// Compiler types using the vector attributes.
using generic_v128 = uint8_t __attribute__((__vector_size__(16)));
Expand All @@ -60,9 +57,9 @@ template <typename T> struct is_scalar : cpp::false_type {};
template <> struct is_scalar<uint8_t> : cpp::true_type {};
template <> struct is_scalar<uint16_t> : cpp::true_type {};
template <> struct is_scalar<uint32_t> : cpp::true_type {};
#ifdef LLVM_LIBC_HAS_UINT64
#ifdef LIBC_TYPES_HAS_INT64
template <> struct is_scalar<uint64_t> : cpp::true_type {};
#endif // LLVM_LIBC_HAS_UINT64
#endif // LIBC_TYPES_HAS_INT64
// Meant to match std::numeric_limits interface.
// NOLINTNEXTLINE(readability-identifier-naming)
template <typename T> constexpr bool is_scalar_v = is_scalar<T>::value;
Expand Down
14 changes: 7 additions & 7 deletions libc/test/src/string/memory_utils/op_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
//===----------------------------------------------------------------------===//

#include "memory_check_utils.h"
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT64
#include "src/string/memory_utils/op_aarch64.h"
#include "src/string/memory_utils/op_builtin.h"
#include "src/string/memory_utils/op_generic.h" // LLVM_LIBC_HAS_UINT64
#include "src/string/memory_utils/op_riscv.h"
#include "src/string/memory_utils/op_x86.h"
#include "test/UnitTest/Test.h"
Expand Down Expand Up @@ -124,9 +124,9 @@ using MemsetImplementations = testing::TypeList<
builtin::Memset<32>, //
builtin::Memset<64>,
#endif
#ifdef LLVM_LIBC_HAS_UINT64
#ifdef LIBC_TYPES_HAS_INT64
generic::Memset<uint64_t>, generic::Memset<cpp::array<uint64_t, 2>>,
#endif
#endif // LIBC_TYPES_HAS_INT64
#ifdef __AVX512F__
generic::Memset<generic_v512>, generic::Memset<cpp::array<generic_v512, 2>>,
#endif
Expand Down Expand Up @@ -210,9 +210,9 @@ using BcmpImplementations = testing::TypeList<
#ifndef LIBC_TARGET_ARCH_IS_ARM // Removing non uint8_t types for ARM
generic::Bcmp<uint16_t>,
generic::Bcmp<uint32_t>, //
#ifdef LLVM_LIBC_HAS_UINT64
#ifdef LIBC_TYPES_HAS_INT64
generic::Bcmp<uint64_t>,
#endif // LLVM_LIBC_HAS_UINT64
#endif // LIBC_TYPES_HAS_INT64
generic::BcmpSequence<uint16_t, uint8_t>,
generic::BcmpSequence<uint32_t, uint8_t>, //
generic::BcmpSequence<uint32_t, uint16_t>, //
Expand Down Expand Up @@ -292,9 +292,9 @@ using MemcmpImplementations = testing::TypeList<
#ifndef LIBC_TARGET_ARCH_IS_ARM // Removing non uint8_t types for ARM
generic::Memcmp<uint16_t>,
generic::Memcmp<uint32_t>, //
#ifdef LLVM_LIBC_HAS_UINT64
#ifdef LIBC_TYPES_HAS_INT64
generic::Memcmp<uint64_t>,
#endif // LLVM_LIBC_HAS_UINT64
#endif // LIBC_TYPES_HAS_INT64
generic::MemcmpSequence<uint16_t, uint8_t>,
generic::MemcmpSequence<uint32_t, uint16_t, uint8_t>, //
#endif // LIBC_TARGET_ARCH_IS_ARM
Expand Down
4 changes: 2 additions & 2 deletions libcxx/docs/Status/Cxx23Issues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
`2997 <https://wg21.link/LWG2997>`__,"LWG 491 and the specification of ``{forward_,}list::unique``","June 2021","",""
`3410 <https://wg21.link/LWG3410>`__,"``lexicographical_compare_three_way`` is overspecified","June 2021","|Complete|","17.0","|spaceship|"
`3430 <https://wg21.link/LWG3430>`__,"``std::fstream`` & co. should be constructible from string_view","June 2021","",""
`3462 <https://wg21.link/LWG3462>`__,"§[formatter.requirements]: Formatter requirements forbid use of ``fc.arg()``","June 2021","","","|format|"
`3462 <https://wg21.link/LWG3462>`__,"§[formatter.requirements]: Formatter requirements forbid use of ``fc.arg()``","June 2021","|Nothing To Do|","","|format|"
`3481 <https://wg21.link/LWG3481>`__,"``viewable_range`` mishandles lvalue move-only views","June 2021","Superseded by `P2415R2 <https://wg21.link/P2415R2>`__","","|ranges|"
`3506 <https://wg21.link/LWG3506>`__,"Missing allocator-extended constructors for ``priority_queue``","June 2021","|Complete|","14.0"
`3517 <https://wg21.link/LWG3517>`__,"``join_view::iterator``'s ``iter_swap`` is underconstrained","June 2021","|Complete|","14.0","|ranges|"
Expand Down Expand Up @@ -169,7 +169,7 @@
"`3683 <https://wg21.link/LWG3683>`__","``operator==`` for ``polymorphic_allocator`` cannot deduce template argument in common cases","July 2022","",""
"`3687 <https://wg21.link/LWG3687>`__","``expected<cv void, E>`` move constructor should move","July 2022","|Complete|","16.0"
"`3692 <https://wg21.link/LWG3692>`__","``zip_view::iterator``'s ``operator<=>`` is overconstrained","July 2022","","","|ranges| |spaceship|"
"`3701 <https://wg21.link/LWG3701>`__","Make ``formatter<remove_cvref_t<const charT[N]>, charT>`` requirement explicit","July 2022","","","|format|"
"`3701 <https://wg21.link/LWG3701>`__","Make ``formatter<remove_cvref_t<const charT[N]>, charT>`` requirement explicit","July 2022","|Complete|","15.0","|format|"
"`3702 <https://wg21.link/LWG3702>`__","Should ``zip_transform_view::iterator`` remove ``operator<``","July 2022","","","|ranges| |spaceship|"
"`3703 <https://wg21.link/LWG3703>`__","Missing requirements for ``expected<T, E>`` requires ``is_void<T>``","July 2022","|Complete|","16.0"
"`3704 <https://wg21.link/LWG3704>`__","LWG 2059 added overloads that might be ill-formed for sets","July 2022","",""
Expand Down
6 changes: 6 additions & 0 deletions libcxx/include/__fwd/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ template <size_t _Ip, class _Tp, size_t _Size>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp&& get(const array<_Tp, _Size>&&) _NOEXCEPT;
#endif

template <class>
struct __is_std_array : false_type {};

template <class _Tp, size_t _Size>
struct __is_std_array<array<_Tp, _Size> > : true_type {};

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___FWD_ARRAY_H
96 changes: 27 additions & 69 deletions libcxx/include/__utility/pair.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,13 @@ struct _LIBCPP_TEMPLATE_VIS pair
#else
struct _CheckArgs {
template <int&...>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_explicit_default() {
return is_default_constructible<_T1>::value && is_default_constructible<_T2>::value &&
!__enable_implicit_default<>();
static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit_default() {
return __is_implicitly_default_constructible<_T1>::value && __is_implicitly_default_constructible<_T2>::value;
}

template <int&...>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit_default() {
return __is_implicitly_default_constructible<_T1>::value && __is_implicitly_default_constructible<_T2>::value;
static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_default() {
return is_default_constructible<_T1>::value && is_default_constructible<_T2>::value;
}

template <class _U1, class _U2>
Expand All @@ -139,58 +138,25 @@ struct _LIBCPP_TEMPLATE_VIS pair
static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_implicit() {
return is_convertible<_U1, first_type>::value && is_convertible<_U2, second_type>::value;
}

template <class _U1, class _U2>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_explicit() {
return __is_pair_constructible<_U1, _U2>() && !__is_implicit<_U1, _U2>();
}

template <class _U1, class _U2>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit() {
return __is_pair_constructible<_U1, _U2>() && __is_implicit<_U1, _U2>();
}
};

template <bool _MaybeEnable>
using _CheckArgsDep _LIBCPP_NODEBUG =
typename conditional< _MaybeEnable, _CheckArgs, __check_tuple_constructor_fail>::type;

template <bool _Dummy = true, __enable_if_t<_CheckArgsDep<_Dummy>::__enable_explicit_default(), int> = 0>
explicit _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair() _NOEXCEPT_(
is_nothrow_default_constructible<first_type>::value&& is_nothrow_default_constructible<second_type>::value)
: first(), second() {}

template <bool _Dummy = true, __enable_if_t<_CheckArgsDep<_Dummy>::__enable_implicit_default(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair() _NOEXCEPT_(
is_nothrow_default_constructible<first_type>::value&& is_nothrow_default_constructible<second_type>::value)
template <bool _Dummy = true, __enable_if_t<_CheckArgsDep<_Dummy>::__enable_default(), int> = 0>
explicit(!_CheckArgsDep<_Dummy>::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair()
_NOEXCEPT_(
is_nothrow_default_constructible<first_type>::value&& is_nothrow_default_constructible<second_type>::value)
: first(), second() {}

template <bool _Dummy = true,
__enable_if_t<_CheckArgsDep<_Dummy>::template __enable_explicit<_T1 const&, _T2 const&>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(_T1 const& __t1, _T2 const& __t2)
template <bool _Dummy = true,
__enable_if_t<_CheckArgsDep<_Dummy>::template __is_pair_constructible<_T1 const&, _T2 const&>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(
!_CheckArgsDep<_Dummy>::template __is_implicit<_T1 const&, _T2 const&>()) pair(_T1 const& __t1, _T2 const& __t2)
_NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value&& is_nothrow_copy_constructible<second_type>::value)
: first(__t1), second(__t2) {}

template <bool _Dummy = true,
__enable_if_t<_CheckArgsDep<_Dummy>::template __enable_implicit<_T1 const&, _T2 const&>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(_T1 const& __t1, _T2 const& __t2)
_NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value&& is_nothrow_copy_constructible<second_type>::value)
: first(__t1), second(__t2) {}

template <
# if _LIBCPP_STD_VER >= 23 // http://wg21.link/P1951
class _U1 = _T1,
class _U2 = _T2,
# else
class _U1,
class _U2,
# endif
__enable_if_t<_CheckArgs::template __enable_explicit<_U1, _U2>(), int> = 0 >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(_U1&& __u1, _U2&& __u2)
_NOEXCEPT_(is_nothrow_constructible<first_type, _U1>::value&& is_nothrow_constructible<second_type, _U2>::value)
: first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {
}

template <
# if _LIBCPP_STD_VER >= 23 // http://wg21.link/P1951
class _U1 = _T1,
Expand All @@ -199,9 +165,11 @@ struct _LIBCPP_TEMPLATE_VIS pair
class _U1,
class _U2,
# endif
__enable_if_t<_CheckArgs::template __enable_implicit<_U1, _U2>(), int> = 0 >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(_U1&& __u1, _U2&& __u2)
_NOEXCEPT_(is_nothrow_constructible<first_type, _U1>::value&& is_nothrow_constructible<second_type, _U2>::value)
__enable_if_t<_CheckArgs::template __is_pair_constructible<_U1, _U2>(), int> = 0 >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>())
pair(_U1&& __u1, _U2&& __u2)
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1>::value &&
is_nothrow_constructible<second_type, _U2>::value))
: first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {
}

Expand All @@ -215,28 +183,18 @@ struct _LIBCPP_TEMPLATE_VIS pair

template <class _U1,
class _U2,
__enable_if_t<_CheckArgs::template __enable_explicit<_U1 const&, _U2 const&>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(pair<_U1, _U2> const& __p)
_NOEXCEPT_(is_nothrow_constructible<first_type, _U1 const&>::value&&
is_nothrow_constructible<second_type, _U2 const&>::value)
: first(__p.first), second(__p.second) {}

template <class _U1,
class _U2,
__enable_if_t<_CheckArgs::template __enable_implicit<_U1 const&, _U2 const&>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(pair<_U1, _U2> const& __p)
_NOEXCEPT_(is_nothrow_constructible<first_type, _U1 const&>::value&&
is_nothrow_constructible<second_type, _U2 const&>::value)
__enable_if_t<_CheckArgs::template __is_pair_constructible<_U1 const&, _U2 const&>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(
!_CheckArgs::template __is_implicit<_U1 const&, _U2 const&>()) pair(pair<_U1, _U2> const& __p)
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1 const&>::value &&
is_nothrow_constructible<second_type, _U2 const&>::value))
: first(__p.first), second(__p.second) {}

template <class _U1, class _U2, __enable_if_t<_CheckArgs::template __enable_explicit<_U1, _U2>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(pair<_U1, _U2>&& __p) _NOEXCEPT_(
is_nothrow_constructible<first_type, _U1&&>::value&& is_nothrow_constructible<second_type, _U2&&>::value)
: first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {}

template <class _U1, class _U2, __enable_if_t<_CheckArgs::template __enable_implicit<_U1, _U2>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(pair<_U1, _U2>&& __p) _NOEXCEPT_(
is_nothrow_constructible<first_type, _U1&&>::value&& is_nothrow_constructible<second_type, _U2&&>::value)
template <class _U1, class _U2, __enable_if_t<_CheckArgs::template __is_pair_constructible<_U1, _U2>(), int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>())
pair(pair<_U1, _U2>&& __p)
_NOEXCEPT_((is_nothrow_constructible<first_type, _U1&&>::value &&
is_nothrow_constructible<second_type, _U2&&>::value))
: first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {}

# if _LIBCPP_STD_VER >= 23
Expand Down
16 changes: 8 additions & 8 deletions libcxx/include/span
Original file line number Diff line number Diff line change
Expand Up @@ -130,24 +130,29 @@ template<class R>

#include <__assert>
#include <__config>
#include <__fwd/array.h>
#include <__fwd/span.h>
#include <__iterator/bounded_iter.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
#include <__iterator/wrap_iter.h>
#include <__memory/pointer_traits.h>
#include <__ranges/concepts.h>
#include <__ranges/data.h>
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/enable_view.h>
#include <__ranges/size.h>
#include <__type_traits/is_array.h>
#include <__type_traits/is_const.h>
#include <__type_traits/is_convertible.h>
#include <__type_traits/remove_cv.h>
#include <__type_traits/remove_cvref.h>
#include <__type_traits/remove_reference.h>
#include <__type_traits/type_identity.h>
#include <__utility/forward.h>
#include <array> // for array
#include <cstddef> // for byte
#include <cstddef> // for byte
#include <initializer_list>
#include <stdexcept>
#include <version>

Expand All @@ -171,12 +176,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD

#if _LIBCPP_STD_VER >= 20

template <class _Tp>
struct __is_std_array : false_type {};

template <class _Tp, size_t _Sz>
struct __is_std_array<array<_Tp, _Sz>> : true_type {};

template <class _Tp>
struct __is_std_span : false_type {};

Expand Down Expand Up @@ -586,6 +585,7 @@ _LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS

#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
# include <array>
# include <concepts>
# include <functional>
# include <iterator>
Expand Down
1 change: 0 additions & 1 deletion libcxx/test/libcxx/transitive_includes/cxx23.csv
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,6 @@ shared_mutex string
shared_mutex version
source_location cstdint
source_location version
span array
span cstddef
span initializer_list
span limits
Expand Down
1 change: 0 additions & 1 deletion libcxx/test/libcxx/transitive_includes/cxx26.csv
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,6 @@ shared_mutex string
shared_mutex version
source_location cstdint
source_location version
span array
span cstddef
span initializer_list
span limits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@ struct test_initialization {
// Before C++20, default initialization doesn't work inside constexpr for
// trivially default constructible types. This only apply to non-empty arrays,
// since empty arrays don't hold an element of type T.
if (TEST_STD_AT_LEAST_20_OR_RUNTIME_EVALUATED || !std::is_trivially_default_constructible<T>::value) {
std::array<T, 1> a1; (void)a1;
std::array<T, 2> a2; (void)a2;
std::array<T, 3> a3; (void)a3;
#if TEST_STD_VER < 20
if (!(TEST_IS_CONSTANT_EVALUATED && std::is_trivially_default_constructible<T>::value))
#endif
{
std::array<T, 1> a1;
(void)a1;
std::array<T, 2> a2;
(void)a2;
std::array<T, 3> a3;
(void)a3;
}

std::array<NoDefault, 0> nodefault; (void)nodefault;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// requires pair-like-convertible-from<PairLike, const I&, const S&>
// constexpr operator PairLike() const;

#include <array>
#include <cassert>
#include <concepts>
#include <ranges>
Expand Down
16 changes: 16 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1635,6 +1635,22 @@ Currently, only the following parameter attributes are defined:

This attribute cannot be applied to return values.

``range(<ty> <a>, <b>)``
This attribute expresses the possible range of the parameter or return value.
If the value is not in the specified range, it is converted to poison.
The arguments passed to ``range`` have the following properties:

- The type must match the scalar type of the parameter or return value.
- The pair ``a,b`` represents the range ``[a,b)``.
- Both ``a`` and ``b`` are constants.
- The range is allowed to wrap.
- The range should not represent the full or empty set. That is, ``a!=b``.

This attribute may only be applied to parameters or return values with integer
or vector of integer types.

For vector-typed parameters, the range is applied element-wise.

.. _gc:

Garbage Collector Strategy Names
Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/ADT/FoldingSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#ifndef LLVM_ADT_FOLDINGSET_H
#define LLVM_ADT_FOLDINGSET_H

#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -354,6 +355,12 @@ class FoldingSetNodeID {
AddInteger(unsigned(I));
AddInteger(unsigned(I >> 32));
}
void AddInteger(const APInt &Int) {
const auto *Parts = Int.getRawData();
for (int i = 0, N = Int.getNumWords(); i < N; ++i) {
AddInteger(Parts[i]);
}
}

void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
void AddString(StringRef String);
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ namespace llvm {
bool parseFnAttributeValuePairs(AttrBuilder &B,
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp, LocTy &BuiltinLoc);
bool parseRangeAttr(AttrBuilder &B);
bool parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
Attribute::AttrKind AttrKind);

Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ enum AttributeKindCodes {
ATTR_KIND_WRITABLE = 89,
ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
ATTR_KIND_DEAD_ON_UNWIND = 91,
ATTR_KIND_RANGE = 92,
};

enum ComdatSelectionKindCodes {
Expand Down
23 changes: 23 additions & 0 deletions llvm/include/llvm/IR/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class AttributeMask;
class AttributeImpl;
class AttributeListImpl;
class AttributeSetNode;
class ConstantRange;
class FoldingSetNodeID;
class Function;
class LLVMContext;
Expand Down Expand Up @@ -103,6 +104,9 @@ class Attribute {
static bool isTypeAttrKind(AttrKind Kind) {
return Kind >= FirstTypeAttr && Kind <= LastTypeAttr;
}
static bool isConstantRangeAttrKind(AttrKind Kind) {
return Kind >= FirstConstantRangeAttr && Kind <= LastConstantRangeAttr;
}

static bool canUseAsFnAttr(AttrKind Kind);
static bool canUseAsParamAttr(AttrKind Kind);
Expand All @@ -125,6 +129,8 @@ class Attribute {
static Attribute get(LLVMContext &Context, StringRef Kind,
StringRef Val = StringRef());
static Attribute get(LLVMContext &Context, AttrKind Kind, Type *Ty);
static Attribute get(LLVMContext &Context, AttrKind Kind,
const ConstantRange &CR);

/// Return a uniquified Attribute object that has the specific
/// alignment set.
Expand Down Expand Up @@ -180,6 +186,9 @@ class Attribute {
/// Return true if the attribute is a type attribute.
bool isTypeAttribute() const;

/// Return true if the attribute is a ConstantRange attribute.
bool isConstantRangeAttribute() const;

/// Return true if the attribute is any kind of attribute.
bool isValid() const { return pImpl; }

Expand Down Expand Up @@ -213,6 +222,10 @@ class Attribute {
/// a type attribute.
Type *getValueAsType() const;

/// Return the attribute's value as a ConstantRange. This requires the
/// attribute to be a ConstantRange attribute.
ConstantRange getValueAsConstantRange() const;

/// Returns the alignment field of an attribute as a byte alignment
/// value.
MaybeAlign getAlignment() const;
Expand Down Expand Up @@ -251,6 +264,9 @@ class Attribute {
/// Return the FPClassTest for nofpclass
FPClassTest getNoFPClass() const;

/// Returns the value of the range attribute.
ConstantRange getRange() const;

/// The Attribute is converted to a string of equivalent mnemonic. This
/// is, presumably, for writing out the mnemonics for the assembly writer.
std::string getAsString(bool InAttrGrp = false) const;
Expand Down Expand Up @@ -1189,6 +1205,13 @@ class AttrBuilder {
// Add nofpclass attribute
AttrBuilder &addNoFPClassAttr(FPClassTest NoFPClassMask);

/// Add a ConstantRange attribute with the given range.
AttrBuilder &addConstantRangeAttr(Attribute::AttrKind Kind,
const ConstantRange &CR);

/// Add range attribute.
AttrBuilder &addRangeAttr(const ConstantRange &CR);

ArrayRef<Attribute> attrs() const { return Attrs; }

bool operator==(const AttrBuilder &B) const;
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class StrBoolAttr<string S> : Attr<S, []>;
/// Arbitrary string attribute.
class ComplexStrAttr<string S, list<AttrProperty> P> : Attr<S, P>;

/// ConstantRange attribute.
class ConstantRangeAttr<string S, list<AttrProperty> P> : Attr<S, P>;

/// Target-independent enum attributes.

/// Alignment of parameter (5 bits) stored as log2 of alignment with +1 bias.
Expand Down Expand Up @@ -218,6 +221,9 @@ def OptimizeNone : EnumAttr<"optnone", [FnAttr]>;
/// Similar to byval but without a copy.
def Preallocated : TypeAttr<"preallocated", [FnAttr, ParamAttr]>;

/// Parameter or return value is within the specified range.
def Range : ConstantRangeAttr<"range", [ParamAttr, RetAttr]>;

/// Function does not access memory.
def ReadNone : EnumAttr<"readnone", [ParamAttr]>;

Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/Support/Compression.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ bool isAvailable();

void compress(ArrayRef<uint8_t> Input,
SmallVectorImpl<uint8_t> &CompressedBuffer,
int Level = DefaultCompression);
int Level = DefaultCompression, bool EnableLdm = false);

Error decompress(ArrayRef<uint8_t> Input, uint8_t *Output,
size_t &UncompressedSize);
Expand Down Expand Up @@ -94,10 +94,13 @@ struct Params {
constexpr Params(Format F)
: format(F), level(F == Format::Zlib ? zlib::DefaultCompression
: zstd::DefaultCompression) {}
constexpr Params(Format F, int L, bool Ldm = false)
: format(F), level(L), zstdEnableLdm(Ldm) {}
Params(DebugCompressionType Type) : Params(formatFor(Type)) {}

Format format;
int level;
bool zstdEnableLdm = false; // Enable zstd long distance matching
// This may support multi-threading for zstd in the future. Note that
// different threads may produce different output, so be careful if certain
// output determinism is desired.
Expand Down
43 changes: 43 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,8 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B,

return true;
}
case Attribute::Range:
return parseRangeAttr(B);
default:
B.addAttribute(Attr);
Lex.Lex();
Expand Down Expand Up @@ -3008,6 +3010,47 @@ bool LLParser::parseRequiredTypeAttr(AttrBuilder &B, lltok::Kind AttrToken,
return false;
}

/// parseRangeAttr
/// ::= range(<ty> <n>,<n>)
bool LLParser::parseRangeAttr(AttrBuilder &B) {
Lex.Lex();

APInt Lower;
APInt Upper;
Type *Ty = nullptr;
LocTy TyLoc;

auto ParseAPSInt = [&](unsigned BitWidth, APInt &Val) {
if (Lex.getKind() != lltok::APSInt)
return tokError("expected integer");
if (Lex.getAPSIntVal().getBitWidth() > BitWidth)
return tokError(
"integer is too large for the bit width of specified type");
Val = Lex.getAPSIntVal().extend(BitWidth);
Lex.Lex();
return false;
};

if (parseToken(lltok::lparen, "expected '('") || parseType(Ty, TyLoc))
return true;
if (!Ty->isIntegerTy())
return error(TyLoc, "the range must have integer type!");

unsigned BitWidth = Ty->getPrimitiveSizeInBits();

if (ParseAPSInt(BitWidth, Lower) ||
parseToken(lltok::comma, "expected ','") || ParseAPSInt(BitWidth, Upper))
return true;
if (Lower == Upper)
return tokError("the range should not represent the full or empty set!");

if (parseToken(lltok::rparen, "expected ')'"))
return true;

B.addRangeAttr(ConstantRange(Lower, Upper));
return false;
}

/// parseOptionalOperandBundles
/// ::= /*empty*/
/// ::= '[' OperandBundle [, OperandBundle ]* ']'
Expand Down
41 changes: 41 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,30 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
return getFnValueByID(ValNo, Ty, TyID, ConstExprInsertBB);
}

Expected<ConstantRange> readConstantRange(ArrayRef<uint64_t> Record,
unsigned &OpNum) {
if (Record.size() - OpNum < 3)
return error("Too few records for range");
unsigned BitWidth = Record[OpNum++];
if (BitWidth > 64) {
unsigned LowerActiveWords = Record[OpNum];
unsigned UpperActiveWords = Record[OpNum++] >> 32;
if (Record.size() - OpNum < LowerActiveWords + UpperActiveWords)
return error("Too few records for range");
APInt Lower =
readWideAPInt(ArrayRef(&Record[OpNum], LowerActiveWords), BitWidth);
OpNum += LowerActiveWords;
APInt Upper =
readWideAPInt(ArrayRef(&Record[OpNum], UpperActiveWords), BitWidth);
OpNum += UpperActiveWords;
return ConstantRange(Lower, Upper);
} else {
int64_t Start = BitcodeReader::decodeSignRotatedValue(Record[OpNum++]);
int64_t End = BitcodeReader::decodeSignRotatedValue(Record[OpNum++]);
return ConstantRange(APInt(BitWidth, Start), APInt(BitWidth, End));
}
}

/// Upgrades old-style typeless byval/sret/inalloca attributes by adding the
/// corresponding argument's pointee type. Also upgrades intrinsics that now
/// require an elementtype attribute.
Expand Down Expand Up @@ -2103,6 +2127,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::CoroDestroyOnlyWhenComplete;
case bitc::ATTR_KIND_DEAD_ON_UNWIND:
return Attribute::DeadOnUnwind;
case bitc::ATTR_KIND_RANGE:
return Attribute::Range;
}
}

Expand Down Expand Up @@ -2272,6 +2298,21 @@ Error BitcodeReader::parseAttributeGroupBlock() {
return error("Not a type attribute");

B.addTypeAttr(Kind, HasType ? getTypeByID(Record[++i]) : nullptr);
} else if (Record[i] == 7) {
Attribute::AttrKind Kind;

i++;
if (Error Err = parseAttrKind(Record[i++], &Kind))
return Err;
if (!Attribute::isConstantRangeAttrKind(Kind))
return error("Not a ConstantRange attribute");

Expected<ConstantRange> MaybeCR = readConstantRange(Record, i);
if (!MaybeCR)
return MaybeCR.takeError();
i--;

B.addConstantRangeAttr(Kind, MaybeCR.get());
} else {
return error("Invalid attribute group entry");
}
Expand Down
61 changes: 41 additions & 20 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE;
case Attribute::DeadOnUnwind:
return bitc::ATTR_KIND_DEAD_ON_UNWIND;
case Attribute::Range:
return bitc::ATTR_KIND_RANGE;
case Attribute::EndAttrKinds:
llvm_unreachable("Can not encode end-attribute kinds marker.");
case Attribute::None:
Expand All @@ -856,6 +858,39 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
llvm_unreachable("Trying to encode unknown attribute");
}

static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) {
if ((int64_t)V >= 0)
Vals.push_back(V << 1);
else
Vals.push_back((-V << 1) | 1);
}

static void emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, const APInt &A) {
// We have an arbitrary precision integer value to write whose
// bit width is > 64. However, in canonical unsigned integer
// format it is likely that the high bits are going to be zero.
// So, we only write the number of active words.
unsigned NumWords = A.getActiveWords();
const uint64_t *RawData = A.getRawData();
for (unsigned i = 0; i < NumWords; i++)
emitSignedInt64(Vals, RawData[i]);
}

static void emitConstantRange(SmallVectorImpl<uint64_t> &Record,
const ConstantRange &CR) {
unsigned BitWidth = CR.getBitWidth();
Record.push_back(BitWidth);
if (BitWidth > 64) {
Record.push_back(CR.getLower().getActiveWords() |
(uint64_t(CR.getUpper().getActiveWords()) << 32));
emitWideAPInt(Record, CR.getLower());
emitWideAPInt(Record, CR.getUpper());
} else {
emitSignedInt64(Record, CR.getLower().getSExtValue());
emitSignedInt64(Record, CR.getUpper().getSExtValue());
}
}

void ModuleBitcodeWriter::writeAttributeGroupTable() {
const std::vector<ValueEnumerator::IndexAndAttrSet> &AttrGrps =
VE.getAttributeGroups();
Expand Down Expand Up @@ -889,13 +924,17 @@ void ModuleBitcodeWriter::writeAttributeGroupTable() {
Record.append(Val.begin(), Val.end());
Record.push_back(0);
}
} else {
assert(Attr.isTypeAttribute());
} else if (Attr.isTypeAttribute()) {
Type *Ty = Attr.getValueAsType();
Record.push_back(Ty ? 6 : 5);
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
if (Ty)
Record.push_back(VE.getTypeID(Attr.getValueAsType()));
} else {
assert(Attr.isConstantRangeAttribute());
Record.push_back(7);
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
emitConstantRange(Record, Attr.getValueAsConstantRange());
}
}

Expand Down Expand Up @@ -1716,24 +1755,6 @@ void ModuleBitcodeWriter::writeDIGenericSubrange(
Record.clear();
}

static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) {
if ((int64_t)V >= 0)
Vals.push_back(V << 1);
else
Vals.push_back((-V << 1) | 1);
}

static void emitWideAPInt(SmallVectorImpl<uint64_t> &Vals, const APInt &A) {
// We have an arbitrary precision integer value to write whose
// bit width is > 64. However, in canonical unsigned integer
// format it is likely that the high bits are going to be zero.
// So, we only write the number of active words.
unsigned NumWords = A.getActiveWords();
const uint64_t *RawData = A.getRawData();
for (unsigned i = 0; i < NumWords; i++)
emitSignedInt64(Vals, RawData[i]);
}

void ModuleBitcodeWriter::writeDIEnumerator(const DIEnumerator *N,
SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev) {
Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4004,7 +4004,14 @@ Register LegalizerHelper::getVectorElementPointer(Register VecPtr, LLT VecTy,

Index = clampVectorIndex(MIRBuilder, Index, VecTy);

LLT IdxTy = MRI.getType(Index);
// Convert index to the correct size for the address space.
const DataLayout &DL = MIRBuilder.getDataLayout();
unsigned AS = MRI.getType(VecPtr).getAddressSpace();
unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
if (IdxTy != MRI.getType(Index))
Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);

auto Mul = MIRBuilder.buildMul(IdxTy, Index,
MIRBuilder.buildConstant(IdxTy, EltSize));

Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/CodeGen/MachineVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,16 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
if (OffsetTy.isPointerOrPointerVector())
report("gep offset operand must not be a pointer", MI);

if (PtrTy.isPointerOrPointerVector()) {
const DataLayout &DL = MF->getDataLayout();
unsigned AS = PtrTy.getAddressSpace();
unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
if (OffsetTy.getScalarSizeInBits() != IndexSizeInBits) {
report("gep offset operand must match index size for address space",
MI);
}
}

// TODO: Is the offset allowed to be a scalar with a vector?
break;
}
Expand Down
28 changes: 27 additions & 1 deletion llvm/lib/IR/AttributeImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/Support/TrailingObjects.h"
#include <cassert>
#include <cstddef>
Expand All @@ -46,6 +47,7 @@ class AttributeImpl : public FoldingSetNode {
IntAttrEntry,
StringAttrEntry,
TypeAttrEntry,
ConstantRangeAttrEntry,
};

AttributeImpl(AttrEntryKind KindID) : KindID(KindID) {}
Expand All @@ -59,6 +61,9 @@ class AttributeImpl : public FoldingSetNode {
bool isIntAttribute() const { return KindID == IntAttrEntry; }
bool isStringAttribute() const { return KindID == StringAttrEntry; }
bool isTypeAttribute() const { return KindID == TypeAttrEntry; }
bool isConstantRangeAttribute() const {
return KindID == ConstantRangeAttrEntry;
}

bool hasAttribute(Attribute::AttrKind A) const;
bool hasAttribute(StringRef Kind) const;
Expand All @@ -72,6 +77,8 @@ class AttributeImpl : public FoldingSetNode {

Type *getValueAsType() const;

ConstantRange getValueAsConstantRange() const;

/// Used when sorting the attributes.
bool operator<(const AttributeImpl &AI) const;

Expand All @@ -82,8 +89,10 @@ class AttributeImpl : public FoldingSetNode {
Profile(ID, getKindAsEnum(), getValueAsInt());
else if (isStringAttribute())
Profile(ID, getKindAsString(), getValueAsString());
else
else if (isTypeAttribute())
Profile(ID, getKindAsEnum(), getValueAsType());
else
Profile(ID, getKindAsEnum(), getValueAsConstantRange());
}

static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind) {
Expand All @@ -108,6 +117,13 @@ class AttributeImpl : public FoldingSetNode {
ID.AddInteger(Kind);
ID.AddPointer(Ty);
}

static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind,
const ConstantRange &CR) {
ID.AddInteger(Kind);
ID.AddInteger(CR.getLower());
ID.AddInteger(CR.getUpper());
}
};

static_assert(std::is_trivially_destructible<AttributeImpl>::value,
Expand Down Expand Up @@ -196,6 +212,16 @@ class TypeAttributeImpl : public EnumAttributeImpl {
Type *getTypeValue() const { return Ty; }
};

class ConstantRangeAttributeImpl : public EnumAttributeImpl {
ConstantRange CR;

public:
ConstantRangeAttributeImpl(Attribute::AttrKind Kind, const ConstantRange &CR)
: EnumAttributeImpl(ConstantRangeAttrEntry, Kind), CR(CR) {}

ConstantRange getConstantRangeValue() const { return CR; }
};

class AttributeBitSet {
/// Bitset with a bit for each available attribute Attribute::AttrKind.
uint8_t AvailableAttrs[12] = {};
Expand Down
81 changes: 79 additions & 2 deletions llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/AttributeMask.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Type.h"
Expand Down Expand Up @@ -165,6 +166,31 @@ Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
return Attribute(PA);
}

Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
const ConstantRange &CR) {
assert(Attribute::isConstantRangeAttrKind(Kind) &&
"Not a ConstantRange attribute");
LLVMContextImpl *pImpl = Context.pImpl;
FoldingSetNodeID ID;
ID.AddInteger(Kind);
ID.AddInteger(CR.getLower());
ID.AddInteger(CR.getUpper());

void *InsertPoint;
AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);

if (!PA) {
// If we didn't find any existing attributes of the same shape then create a
// new one and insert it.
PA = new (pImpl->ConstantRangeAttributeAlloc.Allocate())
ConstantRangeAttributeImpl(Kind, CR);
pImpl->AttrsSet.InsertNode(PA, InsertPoint);
}

// Return the Attribute that we found or created.
return Attribute(PA);
}

Attribute Attribute::getWithAlignment(LLVMContext &Context, Align A) {
assert(A <= llvm::Value::MaximumAlignment && "Alignment too large.");
return get(Context, Alignment, A.value());
Expand Down Expand Up @@ -287,9 +313,14 @@ bool Attribute::isTypeAttribute() const {
return pImpl && pImpl->isTypeAttribute();
}

bool Attribute::isConstantRangeAttribute() const {
return pImpl && pImpl->isConstantRangeAttribute();
}

Attribute::AttrKind Attribute::getKindAsEnum() const {
if (!pImpl) return None;
assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute()) &&
assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
isConstantRangeAttribute()) &&
"Invalid attribute type to get the kind as an enum!");
return pImpl->getKindAsEnum();
}
Expand Down Expand Up @@ -329,6 +360,11 @@ Type *Attribute::getValueAsType() const {
return pImpl->getValueAsType();
}

ConstantRange Attribute::getValueAsConstantRange() const {
assert(isConstantRangeAttribute() &&
"Invalid attribute type to get the value as a ConstantRange!");
return pImpl->getValueAsConstantRange();
}

bool Attribute::hasAttribute(AttrKind Kind) const {
return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None);
Expand Down Expand Up @@ -408,6 +444,12 @@ FPClassTest Attribute::getNoFPClass() const {
return static_cast<FPClassTest>(pImpl->getValueAsInt());
}

ConstantRange Attribute::getRange() const {
assert(hasAttribute(Attribute::Range) &&
"Trying to get range args from non-range attribute");
return pImpl->getValueAsConstantRange();
}

static const char *getModRefStr(ModRefInfo MR) {
switch (MR) {
case ModRefInfo::NoModRef:
Expand Down Expand Up @@ -562,6 +604,18 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return Result;
}

if (hasAttribute(Attribute::Range)) {
std::string Result;
raw_string_ostream OS(Result);
ConstantRange CR = getValueAsConstantRange();
OS << "range(";
OS << "i" << CR.getBitWidth() << " ";
OS << CR.getLower() << ", " << CR.getUpper();
OS << ")";
OS.flush();
return Result;
}

// Convert target-dependent attributes to strings of the form:
//
// "kind"
Expand Down Expand Up @@ -651,7 +705,8 @@ bool AttributeImpl::hasAttribute(StringRef Kind) const {
}

Attribute::AttrKind AttributeImpl::getKindAsEnum() const {
assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute());
assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
isConstantRangeAttribute());
return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();
}

Expand Down Expand Up @@ -680,6 +735,12 @@ Type *AttributeImpl::getValueAsType() const {
return static_cast<const TypeAttributeImpl *>(this)->getTypeValue();
}

ConstantRange AttributeImpl::getValueAsConstantRange() const {
assert(isConstantRangeAttribute());
return static_cast<const ConstantRangeAttributeImpl *>(this)
->getConstantRangeValue();
}

bool AttributeImpl::operator<(const AttributeImpl &AI) const {
if (this == &AI)
return false;
Expand All @@ -693,6 +754,7 @@ bool AttributeImpl::operator<(const AttributeImpl &AI) const {
return getKindAsEnum() < AI.getKindAsEnum();
assert(!AI.isEnumAttribute() && "Non-unique attribute");
assert(!AI.isTypeAttribute() && "Comparison of types would be unstable");
assert(!AI.isConstantRangeAttribute() && "Unclear how to compare ranges");
// TODO: Is this actually needed?
assert(AI.isIntAttribute() && "Only possibility left");
return getValueAsInt() < AI.getValueAsInt();
Expand Down Expand Up @@ -1881,6 +1943,15 @@ AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) {
return addTypeAttr(Attribute::InAlloca, Ty);
}

AttrBuilder &AttrBuilder::addConstantRangeAttr(Attribute::AttrKind Kind,
const ConstantRange &CR) {
return addAttribute(Attribute::get(Ctx, Kind, CR));
}

AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
return addConstantRangeAttr(Attribute::Range, CR);
}

AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
// TODO: Could make this O(n) as we're merging two sorted lists.
for (const auto &I : B.attrs())
Expand Down Expand Up @@ -1952,6 +2023,12 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
Incompatible.addAttribute(Attribute::SExt).addAttribute(Attribute::ZExt);
}

if (!Ty->isIntOrIntVectorTy()) {
// Attributes that only apply to integers or vector of integers.
if (ASK & ASK_SAFE_TO_DROP)
Incompatible.addAttribute(Attribute::Range);
}

if (!Ty->isPointerTy()) {
// Attributes that only apply to pointers.
if (ASK & ASK_SAFE_TO_DROP)
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/IR/LLVMContextImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class AttributeImpl;
class AttributeListImpl;
class AttributeSetNode;
class BasicBlock;
class ConstantRangeAttributeImpl;
struct DiagnosticHandler;
class DPMarker;
class ElementCount;
Expand Down Expand Up @@ -1562,6 +1563,8 @@ class LLVMContextImpl {

BumpPtrAllocator Alloc;
UniqueStringSaver Saver{Alloc};
SpecificBumpPtrAllocator<ConstantRangeAttributeImpl>
ConstantRangeAttributeAlloc;

DenseMap<unsigned, IntegerType *> IntegerTypes;

Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2039,6 +2039,11 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
Check((Val & ~static_cast<unsigned>(fcAllFlags)) == 0,
"Invalid value for 'nofpclass' test mask", V);
}
if (Attrs.hasAttribute(Attribute::Range)) {
auto CR = Attrs.getAttribute(Attribute::Range).getValueAsConstantRange();
Check(Ty->isIntOrIntVectorTy(CR.getBitWidth()),
"Range bit width must match type bit width!", V);
}
}

void Verifier::checkUnsignedBaseTenFuncAttr(AttributeList Attrs, StringRef Attr,
Expand Down
43 changes: 33 additions & 10 deletions llvm/lib/Support/Compression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void compression::compress(Params P, ArrayRef<uint8_t> Input,
zlib::compress(Input, Output, P.level);
break;
case compression::Format::Zstd:
zstd::compress(Input, Output, P.level);
zstd::compress(Input, Output, P.level, P.zstdEnableLdm);
break;
}
}
Expand Down Expand Up @@ -163,17 +163,39 @@ Error zlib::decompress(ArrayRef<uint8_t> Input,

bool zstd::isAvailable() { return true; }

#include <zstd.h> // Ensure ZSTD library is included

void zstd::compress(ArrayRef<uint8_t> Input,
SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
unsigned long CompressedBufferSize = ::ZSTD_compressBound(Input.size());
SmallVectorImpl<uint8_t> &CompressedBuffer, int Level,
bool EnableLdm) {
ZSTD_CCtx *Cctx = ZSTD_createCCtx();
if (!Cctx)
report_bad_alloc_error("Failed to create ZSTD_CCtx");

if (ZSTD_isError(ZSTD_CCtx_setParameter(
Cctx, ZSTD_c_enableLongDistanceMatching, EnableLdm ? 1 : 0))) {
ZSTD_freeCCtx(Cctx);
report_bad_alloc_error("Failed to set ZSTD_c_enableLongDistanceMatching");
}

if (ZSTD_isError(
ZSTD_CCtx_setParameter(Cctx, ZSTD_c_compressionLevel, Level))) {
ZSTD_freeCCtx(Cctx);
report_bad_alloc_error("Failed to set ZSTD_c_compressionLevel");
}

unsigned long CompressedBufferSize = ZSTD_compressBound(Input.size());
CompressedBuffer.resize_for_overwrite(CompressedBufferSize);
unsigned long CompressedSize =
::ZSTD_compress((char *)CompressedBuffer.data(), CompressedBufferSize,
(const char *)Input.data(), Input.size(), Level);

size_t const CompressedSize =
ZSTD_compress2(Cctx, CompressedBuffer.data(), CompressedBufferSize,
Input.data(), Input.size());

ZSTD_freeCCtx(Cctx);

if (ZSTD_isError(CompressedSize))
report_bad_alloc_error("Allocation failed");
// Tell MemorySanitizer that zstd output buffer is fully initialized.
// This avoids a false report when running LLVM with uninstrumented ZLib.
report_bad_alloc_error("Compression failed");

__msan_unpoison(CompressedBuffer.data(), CompressedSize);
if (CompressedSize < CompressedBuffer.size())
CompressedBuffer.truncate(CompressedSize);
Expand Down Expand Up @@ -205,7 +227,8 @@ Error zstd::decompress(ArrayRef<uint8_t> Input,
#else
bool zstd::isAvailable() { return false; }
void zstd::compress(ArrayRef<uint8_t> Input,
SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
SmallVectorImpl<uint8_t> &CompressedBuffer, int Level,
bool EnableLdm) {
llvm_unreachable("zstd::compress is unavailable");
}
Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,
Expand Down
112 changes: 56 additions & 56 deletions llvm/lib/Target/X86/MCTargetDesc/X86ATTInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ bool X86ATTInstPrinter::printVecCompareInstr(const MCInst *MI,
// Custom print the vector compare instructions to get the immediate
// translated into the mnemonic.
switch (MI->getOpcode()) {
case X86::CMPPDrmi: case X86::CMPPDrri:
case X86::CMPPSrmi: case X86::CMPPSrri:
case X86::CMPSDrm: case X86::CMPSDrr:
case X86::CMPSDrm_Int: case X86::CMPSDrr_Int:
case X86::CMPSSrm: case X86::CMPSSrr:
case X86::CMPSSrm_Int: case X86::CMPSSrr_Int:
case X86::CMPPDrmi: case X86::CMPPDrri:
case X86::CMPPSrmi: case X86::CMPPSrri:
case X86::CMPSDrmi: case X86::CMPSDrri:
case X86::CMPSDrmi_Int: case X86::CMPSDrri_Int:
case X86::CMPSSrmi: case X86::CMPSSrri:
case X86::CMPSSrmi_Int: case X86::CMPSSrri_Int:
if (Imm >= 0 && Imm <= 7) {
OS << '\t';
printCMPMnemonic(MI, /*IsVCMP*/false, OS);
Expand All @@ -117,56 +117,56 @@ bool X86ATTInstPrinter::printVecCompareInstr(const MCInst *MI,
}
break;

case X86::VCMPPDrmi: case X86::VCMPPDrri:
case X86::VCMPPDYrmi: case X86::VCMPPDYrri:
case X86::VCMPPDZ128rmi: case X86::VCMPPDZ128rri:
case X86::VCMPPDZ256rmi: case X86::VCMPPDZ256rri:
case X86::VCMPPDZrmi: case X86::VCMPPDZrri:
case X86::VCMPPSrmi: case X86::VCMPPSrri:
case X86::VCMPPSYrmi: case X86::VCMPPSYrri:
case X86::VCMPPSZ128rmi: case X86::VCMPPSZ128rri:
case X86::VCMPPSZ256rmi: case X86::VCMPPSZ256rri:
case X86::VCMPPSZrmi: case X86::VCMPPSZrri:
case X86::VCMPSDrm: case X86::VCMPSDrr:
case X86::VCMPSDZrm: case X86::VCMPSDZrr:
case X86::VCMPSDrm_Int: case X86::VCMPSDrr_Int:
case X86::VCMPSDZrm_Int: case X86::VCMPSDZrr_Int:
case X86::VCMPSSrm: case X86::VCMPSSrr:
case X86::VCMPSSZrm: case X86::VCMPSSZrr:
case X86::VCMPSSrm_Int: case X86::VCMPSSrr_Int:
case X86::VCMPSSZrm_Int: case X86::VCMPSSZrr_Int:
case X86::VCMPPDZ128rmik: case X86::VCMPPDZ128rrik:
case X86::VCMPPDZ256rmik: case X86::VCMPPDZ256rrik:
case X86::VCMPPDZrmik: case X86::VCMPPDZrrik:
case X86::VCMPPSZ128rmik: case X86::VCMPPSZ128rrik:
case X86::VCMPPSZ256rmik: case X86::VCMPPSZ256rrik:
case X86::VCMPPSZrmik: case X86::VCMPPSZrrik:
case X86::VCMPSDZrm_Intk: case X86::VCMPSDZrr_Intk:
case X86::VCMPSSZrm_Intk: case X86::VCMPSSZrr_Intk:
case X86::VCMPPDZ128rmbi: case X86::VCMPPDZ128rmbik:
case X86::VCMPPDZ256rmbi: case X86::VCMPPDZ256rmbik:
case X86::VCMPPDZrmbi: case X86::VCMPPDZrmbik:
case X86::VCMPPSZ128rmbi: case X86::VCMPPSZ128rmbik:
case X86::VCMPPSZ256rmbi: case X86::VCMPPSZ256rmbik:
case X86::VCMPPSZrmbi: case X86::VCMPPSZrmbik:
case X86::VCMPPDZrrib: case X86::VCMPPDZrribk:
case X86::VCMPPSZrrib: case X86::VCMPPSZrribk:
case X86::VCMPSDZrrb_Int: case X86::VCMPSDZrrb_Intk:
case X86::VCMPSSZrrb_Int: case X86::VCMPSSZrrb_Intk:
case X86::VCMPPHZ128rmi: case X86::VCMPPHZ128rri:
case X86::VCMPPHZ256rmi: case X86::VCMPPHZ256rri:
case X86::VCMPPHZrmi: case X86::VCMPPHZrri:
case X86::VCMPSHZrm: case X86::VCMPSHZrr:
case X86::VCMPSHZrm_Int: case X86::VCMPSHZrr_Int:
case X86::VCMPPHZ128rmik: case X86::VCMPPHZ128rrik:
case X86::VCMPPHZ256rmik: case X86::VCMPPHZ256rrik:
case X86::VCMPPHZrmik: case X86::VCMPPHZrrik:
case X86::VCMPSHZrm_Intk: case X86::VCMPSHZrr_Intk:
case X86::VCMPPHZ128rmbi: case X86::VCMPPHZ128rmbik:
case X86::VCMPPHZ256rmbi: case X86::VCMPPHZ256rmbik:
case X86::VCMPPHZrmbi: case X86::VCMPPHZrmbik:
case X86::VCMPPHZrrib: case X86::VCMPPHZrribk:
case X86::VCMPSHZrrb_Int: case X86::VCMPSHZrrb_Intk:
case X86::VCMPPDrmi: case X86::VCMPPDrri:
case X86::VCMPPDYrmi: case X86::VCMPPDYrri:
case X86::VCMPPDZ128rmi: case X86::VCMPPDZ128rri:
case X86::VCMPPDZ256rmi: case X86::VCMPPDZ256rri:
case X86::VCMPPDZrmi: case X86::VCMPPDZrri:
case X86::VCMPPSrmi: case X86::VCMPPSrri:
case X86::VCMPPSYrmi: case X86::VCMPPSYrri:
case X86::VCMPPSZ128rmi: case X86::VCMPPSZ128rri:
case X86::VCMPPSZ256rmi: case X86::VCMPPSZ256rri:
case X86::VCMPPSZrmi: case X86::VCMPPSZrri:
case X86::VCMPSDrmi: case X86::VCMPSDrri:
case X86::VCMPSDZrmi: case X86::VCMPSDZrri:
case X86::VCMPSDrmi_Int: case X86::VCMPSDrri_Int:
case X86::VCMPSDZrmi_Int: case X86::VCMPSDZrri_Int:
case X86::VCMPSSrmi: case X86::VCMPSSrri:
case X86::VCMPSSZrmi: case X86::VCMPSSZrri:
case X86::VCMPSSrmi_Int: case X86::VCMPSSrri_Int:
case X86::VCMPSSZrmi_Int: case X86::VCMPSSZrri_Int:
case X86::VCMPPDZ128rmik: case X86::VCMPPDZ128rrik:
case X86::VCMPPDZ256rmik: case X86::VCMPPDZ256rrik:
case X86::VCMPPDZrmik: case X86::VCMPPDZrrik:
case X86::VCMPPSZ128rmik: case X86::VCMPPSZ128rrik:
case X86::VCMPPSZ256rmik: case X86::VCMPPSZ256rrik:
case X86::VCMPPSZrmik: case X86::VCMPPSZrrik:
case X86::VCMPSDZrmi_Intk: case X86::VCMPSDZrri_Intk:
case X86::VCMPSSZrmi_Intk: case X86::VCMPSSZrri_Intk:
case X86::VCMPPDZ128rmbi: case X86::VCMPPDZ128rmbik:
case X86::VCMPPDZ256rmbi: case X86::VCMPPDZ256rmbik:
case X86::VCMPPDZrmbi: case X86::VCMPPDZrmbik:
case X86::VCMPPSZ128rmbi: case X86::VCMPPSZ128rmbik:
case X86::VCMPPSZ256rmbi: case X86::VCMPPSZ256rmbik:
case X86::VCMPPSZrmbi: case X86::VCMPPSZrmbik:
case X86::VCMPPDZrrib: case X86::VCMPPDZrribk:
case X86::VCMPPSZrrib: case X86::VCMPPSZrribk:
case X86::VCMPSDZrrib_Int: case X86::VCMPSDZrrib_Intk:
case X86::VCMPSSZrrib_Int: case X86::VCMPSSZrrib_Intk:
case X86::VCMPPHZ128rmi: case X86::VCMPPHZ128rri:
case X86::VCMPPHZ256rmi: case X86::VCMPPHZ256rri:
case X86::VCMPPHZrmi: case X86::VCMPPHZrri:
case X86::VCMPSHZrmi: case X86::VCMPSHZrri:
case X86::VCMPSHZrmi_Int: case X86::VCMPSHZrri_Int:
case X86::VCMPPHZ128rmik: case X86::VCMPPHZ128rrik:
case X86::VCMPPHZ256rmik: case X86::VCMPPHZ256rrik:
case X86::VCMPPHZrmik: case X86::VCMPPHZrrik:
case X86::VCMPSHZrmi_Intk: case X86::VCMPSHZrri_Intk:
case X86::VCMPPHZ128rmbi: case X86::VCMPPHZ128rmbik:
case X86::VCMPPHZ256rmbi: case X86::VCMPPHZ256rmbik:
case X86::VCMPPHZrmbi: case X86::VCMPPHZrmbik:
case X86::VCMPPHZrrib: case X86::VCMPPHZrribk:
case X86::VCMPSHZrrib_Int: case X86::VCMPSHZrrib_Intk:
if (Imm >= 0 && Imm <= 31) {
OS << '\t';
printCMPMnemonic(MI, /*IsVCMP*/true, OS);
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/X86/MCTargetDesc/X86EncodingOptimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ bool X86::optimizeInstFromVEX3ToVEX2(MCInst &MI, const MCInstrDesc &Desc) {
case X86::VCMPPDYrri:
case X86::VCMPPSrri:
case X86::VCMPPSYrri:
case X86::VCMPSDrr:
case X86::VCMPSSrr: {
case X86::VCMPSDrri:
case X86::VCMPSSrri: {
switch (MI.getOperand(3).getImm() & 0x7) {
default:
return false;
Expand Down
40 changes: 20 additions & 20 deletions llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,24 +272,24 @@ void X86InstPrinterCommon::printCMPMnemonic(const MCInst *MI, bool IsVCmp,
case X86::VCMPPSZrrib: case X86::VCMPPSZrribk:
OS << "ps\t";
break;
case X86::CMPSDrm: case X86::CMPSDrr:
case X86::CMPSDrm_Int: case X86::CMPSDrr_Int:
case X86::VCMPSDrm: case X86::VCMPSDrr:
case X86::VCMPSDrm_Int: case X86::VCMPSDrr_Int:
case X86::VCMPSDZrm: case X86::VCMPSDZrr:
case X86::VCMPSDZrm_Int: case X86::VCMPSDZrr_Int:
case X86::VCMPSDZrm_Intk: case X86::VCMPSDZrr_Intk:
case X86::VCMPSDZrrb_Int: case X86::VCMPSDZrrb_Intk:
case X86::CMPSDrmi: case X86::CMPSDrri:
case X86::CMPSDrmi_Int: case X86::CMPSDrri_Int:
case X86::VCMPSDrmi: case X86::VCMPSDrri:
case X86::VCMPSDrmi_Int: case X86::VCMPSDrri_Int:
case X86::VCMPSDZrmi: case X86::VCMPSDZrri:
case X86::VCMPSDZrmi_Int: case X86::VCMPSDZrri_Int:
case X86::VCMPSDZrmi_Intk: case X86::VCMPSDZrri_Intk:
case X86::VCMPSDZrrib_Int: case X86::VCMPSDZrrib_Intk:
OS << "sd\t";
break;
case X86::CMPSSrm: case X86::CMPSSrr:
case X86::CMPSSrm_Int: case X86::CMPSSrr_Int:
case X86::VCMPSSrm: case X86::VCMPSSrr:
case X86::VCMPSSrm_Int: case X86::VCMPSSrr_Int:
case X86::VCMPSSZrm: case X86::VCMPSSZrr:
case X86::VCMPSSZrm_Int: case X86::VCMPSSZrr_Int:
case X86::VCMPSSZrm_Intk: case X86::VCMPSSZrr_Intk:
case X86::VCMPSSZrrb_Int: case X86::VCMPSSZrrb_Intk:
case X86::CMPSSrmi: case X86::CMPSSrri:
case X86::CMPSSrmi_Int: case X86::CMPSSrri_Int:
case X86::VCMPSSrmi: case X86::VCMPSSrri:
case X86::VCMPSSrmi_Int: case X86::VCMPSSrri_Int:
case X86::VCMPSSZrmi: case X86::VCMPSSZrri:
case X86::VCMPSSZrmi_Int: case X86::VCMPSSZrri_Int:
case X86::VCMPSSZrmi_Intk: case X86::VCMPSSZrri_Intk:
case X86::VCMPSSZrrib_Int: case X86::VCMPSSZrrib_Intk:
OS << "ss\t";
break;
case X86::VCMPPHZ128rmi: case X86::VCMPPHZ128rri:
Expand All @@ -304,10 +304,10 @@ void X86InstPrinterCommon::printCMPMnemonic(const MCInst *MI, bool IsVCmp,
case X86::VCMPPHZrrib: case X86::VCMPPHZrribk:
OS << "ph\t";
break;
case X86::VCMPSHZrm: case X86::VCMPSHZrr:
case X86::VCMPSHZrm_Int: case X86::VCMPSHZrr_Int:
case X86::VCMPSHZrrb_Int: case X86::VCMPSHZrrb_Intk:
case X86::VCMPSHZrm_Intk: case X86::VCMPSHZrr_Intk:
case X86::VCMPSHZrmi: case X86::VCMPSHZrri:
case X86::VCMPSHZrmi_Int: case X86::VCMPSHZrri_Int:
case X86::VCMPSHZrrib_Int: case X86::VCMPSHZrrib_Intk:
case X86::VCMPSHZrmi_Intk: case X86::VCMPSHZrri_Intk:
OS << "sh\t";
break;
}
Expand Down
Loading