1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
}

Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
Buffer.markInitialized(BitOffset, BitWidth);
return true;
});
}
Expand Down
24 changes: 17 additions & 7 deletions clang/lib/Basic/Diagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,8 @@ class WarningsSpecialCaseList : public llvm::SpecialCaseList {
// the last section take precedence in such cases.
void processSections(DiagnosticsEngine &Diags);

bool isDiagSuppressed(diag::kind DiagId, StringRef FilePath) const;
bool isDiagSuppressed(diag::kind DiagId, SourceLocation DiagLoc,
const SourceManager &SM) const;

private:
// Find the longest glob pattern that matches FilePath amongst
Expand Down Expand Up @@ -573,13 +574,14 @@ void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
WarningSuppressionList->processSections(*this);
DiagSuppressionMapping =
[WarningSuppressionList(std::move(WarningSuppressionList))](
diag::kind DiagId, StringRef Path) {
return WarningSuppressionList->isDiagSuppressed(DiagId, Path);
diag::kind DiagId, SourceLocation DiagLoc, const SourceManager &SM) {
return WarningSuppressionList->isDiagSuppressed(DiagId, DiagLoc, SM);
};
}

bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
StringRef FilePath) const {
SourceLocation DiagLoc,
const SourceManager &SM) const {
const Section *DiagSection = DiagToSection.lookup(DiagId);
if (!DiagSection)
return false;
Expand All @@ -589,7 +591,13 @@ bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
return false;
const llvm::StringMap<llvm::SpecialCaseList::Matcher> &CategoriesToMatchers =
SrcEntriesIt->getValue();
return globsMatches(CategoriesToMatchers, FilePath);
// We also use presumed locations here to improve reproducibility for
// preprocessed inputs.
if (PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc); PLoc.isValid())
return globsMatches(
CategoriesToMatchers,
llvm::sys::path::remove_leading_dotslash(PLoc.getFilename()));
return false;
}

bool WarningsSpecialCaseList::globsMatches(
Expand All @@ -614,8 +622,10 @@ bool WarningsSpecialCaseList::globsMatches(
}

bool DiagnosticsEngine::isSuppressedViaMapping(diag::kind DiagId,
StringRef FilePath) const {
return DiagSuppressionMapping && DiagSuppressionMapping(DiagId, FilePath);
SourceLocation DiagLoc) const {
if (!hasSourceManager() || !DiagSuppressionMapping)
return false;
return DiagSuppressionMapping(DiagId, DiagLoc, getSourceManager());
}

void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
Expand Down
11 changes: 2 additions & 9 deletions clang/lib/Basic/DiagnosticIDs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,15 +601,8 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
return diag::Severity::Ignored;

// Clang-diagnostics pragmas always take precedence over suppression mapping.
if (!Mapping.isPragma() && Diag.DiagSuppressionMapping) {
// We also use presumed locations here to improve reproducibility for
// preprocessed inputs.
if (PresumedLoc PLoc = SM.getPresumedLoc(Loc);
PLoc.isValid() && Diag.isSuppressedViaMapping(
DiagID, llvm::sys::path::remove_leading_dotslash(
PLoc.getFilename())))
return diag::Severity::Ignored;
}
if (!Mapping.isPragma() && Diag.isSuppressedViaMapping(DiagID, Loc))
return diag::Severity::Ignored;

return Result;
}
Expand Down
58 changes: 33 additions & 25 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
DiagnosticsEngine &diags)
: builder(&context), astCtx(astctx), langOpts(astctx.getLangOpts()),
theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))},
diags(diags), target(astCtx.getTargetInfo()) {}
diags(diags), target(astCtx.getTargetInfo()), genTypes(*this) {}

mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {
assert(cLoc.isValid() && "expected valid source location");
Expand Down Expand Up @@ -67,7 +67,8 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {
return;
}
} else {
errorNYI(global->getSourceRange(), "global variable declaration");
assert(cast<VarDecl>(global)->isFileVarDecl() &&
"Cannot emit local var decl as global");
}

// TODO(CIR): Defer emitting some global definitions until later
Expand All @@ -77,9 +78,27 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {
void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
mlir::Operation *op) {
auto const *funcDecl = cast<FunctionDecl>(gd.getDecl());
auto funcOp = builder.create<cir::FuncOp>(
getLoc(funcDecl->getSourceRange()), funcDecl->getIdentifier()->getName());
theModule.push_back(funcOp);
if (clang::IdentifierInfo *identifier = funcDecl->getIdentifier()) {
auto funcOp = builder.create<cir::FuncOp>(
getLoc(funcDecl->getSourceRange()), identifier->getName());
theModule.push_back(funcOp);
} else {
errorNYI(funcDecl->getSourceRange().getBegin(),
"function definition with a non-identifier for a name");
}
}

void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
bool isTentative) {
mlir::Type type = getTypes().convertType(vd->getType());
if (clang::IdentifierInfo *identifier = vd->getIdentifier()) {
auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()),
identifier->getName(), type);
theModule.push_back(varOp);
} else {
errorNYI(vd->getSourceRange().getBegin(),
"variable definition with a non-identifier for a name");
}
}

void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
Expand All @@ -103,6 +122,9 @@ void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
return;
}

if (const auto *vd = dyn_cast<VarDecl>(decl))
return emitGlobalVarDefinition(vd, !vd->hasDefinition());

llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition");
}

Expand All @@ -126,13 +148,13 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
emitGlobal(fd);
break;
}
}
}

DiagnosticBuilder CIRGenModule::errorNYI(llvm::StringRef feature) {
unsigned diagID = diags.getCustomDiagID(
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
return diags.Report(diagID) << feature;
case Decl::Var: {
auto *vd = cast<VarDecl>(decl);
emitGlobal(vd);
break;
}
}
}

DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
Expand All @@ -142,21 +164,7 @@ DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
return diags.Report(loc, diagID) << feature;
}

DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
llvm::StringRef feature,
llvm::StringRef name) {
unsigned diagID = diags.getCustomDiagID(
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0: %1");
return diags.Report(loc, diagID) << feature << name;
}

DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
llvm::StringRef feature) {
return errorNYI(loc.getBegin(), feature) << loc;
}

DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
llvm::StringRef feature,
llvm::StringRef name) {
return errorNYI(loc.getBegin(), feature, name) << loc;
}
33 changes: 26 additions & 7 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,22 @@
#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H

#include "CIRGenTypeCache.h"
#include "CIRGenTypes.h"

#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringRef.h"

namespace clang {
class ASTContext;
class CodeGenOptions;
class Decl;
class DiagnosticBuilder;
class DiagnosticsEngine;
class GlobalDecl;
class LangOptions;
class SourceLocation;
class SourceRange;
class TargetInfo;
class VarDecl;

namespace CIRGen {

Expand Down Expand Up @@ -64,8 +63,13 @@ class CIRGenModule : public CIRGenTypeCache {

const clang::TargetInfo &target;

CIRGenTypes genTypes;

public:
mlir::ModuleOp getModule() const { return theModule; }
mlir::OpBuilder &getBuilder() { return builder; }
clang::ASTContext &getASTContext() const { return astCtx; }
CIRGenTypes &getTypes() { return genTypes; }

/// Helpers to convert the presumed location of Clang's SourceLocation to an
/// MLIR Location.
Expand All @@ -81,13 +85,28 @@ class CIRGenModule : public CIRGenTypeCache {
void emitGlobalDefinition(clang::GlobalDecl gd,
mlir::Operation *op = nullptr);
void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);
void emitGlobalVarDefinition(const clang::VarDecl *vd,
bool isTentative = false);

/// Helpers to emit "not yet implemented" error diagnostics
DiagnosticBuilder errorNYI(llvm::StringRef);
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef, llvm::StringRef);

template <typename T>
DiagnosticBuilder errorNYI(SourceLocation loc, llvm::StringRef feature,
const T &name) {
unsigned diagID =
diags.getCustomDiagID(DiagnosticsEngine::Error,
"ClangIR code gen Not Yet Implemented: %0: %1");
return diags.Report(loc, diagID) << feature << name;
}

DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef);
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef, llvm::StringRef);

template <typename T>
DiagnosticBuilder errorNYI(SourceRange loc, llvm::StringRef feature,
const T &name) {
return errorNYI(loc.getBegin(), feature, name) << loc;
}
};
} // namespace CIRGen

Expand Down
87 changes: 87 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "CIRGenTypes.h"

#include "CIRGenModule.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"

using namespace clang;
using namespace clang::CIRGen;

CIRGenTypes::CIRGenTypes(CIRGenModule &genModule)
: cgm(genModule), context(genModule.getASTContext()) {}

CIRGenTypes::~CIRGenTypes() {}

mlir::Type CIRGenTypes::convertType(QualType type) {
type = context.getCanonicalType(type);
const Type *ty = type.getTypePtr();

// For types that haven't been implemented yet or are otherwise unsupported,
// report an error and return 'int'.

mlir::Type resultType = nullptr;
switch (ty->getTypeClass()) {
case Type::Builtin: {
switch (cast<BuiltinType>(ty)->getKind()) {
// Signed types.
case BuiltinType::Char_S:
case BuiltinType::Int:
case BuiltinType::Int128:
case BuiltinType::Long:
case BuiltinType::LongLong:
case BuiltinType::SChar:
case BuiltinType::Short:
case BuiltinType::WChar_S:
resultType = cir::IntType::get(cgm.getBuilder().getContext(),
context.getTypeSize(ty),
/*isSigned=*/true);
break;
// Unsigned types.
case BuiltinType::Char8:
case BuiltinType::Char16:
case BuiltinType::Char32:
case BuiltinType::Char_U:
case BuiltinType::UChar:
case BuiltinType::UInt:
case BuiltinType::UInt128:
case BuiltinType::ULong:
case BuiltinType::ULongLong:
case BuiltinType::UShort:
case BuiltinType::WChar_U:
resultType = cir::IntType::get(cgm.getBuilder().getContext(),
context.getTypeSize(ty),
/*isSigned=*/false);
break;
default:
cgm.errorNYI(SourceLocation(), "processing of built-in type", type);
resultType = cir::IntType::get(cgm.getBuilder().getContext(), 32,
/*isSigned=*/true);
break;
}
break;
}
case Type::BitInt: {
const auto *bitIntTy = cast<BitIntType>(type);
if (bitIntTy->getNumBits() > cir::IntType::maxBitwidth()) {
cgm.errorNYI(SourceLocation(), "large _BitInt type", type);
resultType = cir::IntType::get(cgm.getBuilder().getContext(), 32,
/*isSigned=*/true);
} else {
resultType =
cir::IntType::get(cgm.getBuilder().getContext(),
bitIntTy->getNumBits(), bitIntTy->isSigned());
}
break;
}
default:
cgm.errorNYI(SourceLocation(), "processing of type", type);
resultType =
cir::IntType::get(cgm.getBuilder().getContext(), 32, /*isSigned=*/true);
break;
}

assert(resultType && "Type conversion not yet implemented");

return resultType;
}
47 changes: 47 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenTypes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===--- CIRGenTypes.h - Type translation for CIR CodeGen -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is the code that handles AST -> CIR type lowering.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H
#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H

#include "clang/CIR/Dialect/IR/CIRTypes.h"

namespace clang {
class ASTContext;
class QualType;
} // namespace clang

namespace mlir {
class Type;
}

namespace clang::CIRGen {

class CIRGenModule;

/// This class organizes the cross-module state that is used while lowering
/// AST types to CIR types.
class CIRGenTypes {
CIRGenModule &cgm;
clang::ASTContext &context;

public:
CIRGenTypes(CIRGenModule &cgm);
~CIRGenTypes();

/// Convert a Clang type into a mlir::Type.
mlir::Type convertType(clang::QualType type);
};

} // namespace clang::CIRGen

#endif
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
add_clang_library(clangCIR
CIRGenerator.cpp
CIRGenModule.cpp
CIRGenTypes.cpp

DEPENDS
MLIRCIR
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ void cir::CIRDialect::initialize() {
>();
}

//===----------------------------------------------------------------------===//
// GlobalOp
//===----------------------------------------------------------------------===//

// TODO(CIR): The properties of global variables that require verification
// haven't been implemented yet.
mlir::LogicalResult cir::GlobalOp::verify() { return success(); }

void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState,
llvm::StringRef sym_name, mlir::Type sym_type) {
odsState.addAttribute(getSymNameAttrName(odsState.name),
odsBuilder.getStringAttr(sym_name));
odsState.addAttribute(getSymTypeAttrName(odsState.name),
mlir::TypeAttr::get(sym_type));
}

//===----------------------------------------------------------------------===//
// FuncOp
//===----------------------------------------------------------------------===//
Expand All @@ -56,6 +72,8 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
p.printSymbolName(getSymName());
}

// TODO(CIR): The properties of functions that require verification haven't
// been implemented yet.
mlir::LogicalResult cir::FuncOp::verify() { return success(); }

//===----------------------------------------------------------------------===//
Expand Down
120 changes: 116 additions & 4 deletions clang/lib/CIR/Dialect/IR/CIRTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,18 @@
//
//===----------------------------------------------------------------------===//

#include "clang/CIR/Dialect/IR/CIRTypes.h"

#include "mlir/IR/DialectImplementation.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "llvm/ADT/TypeSwitch.h"

//===----------------------------------------------------------------------===//
// Get autogenerated stuff
//===----------------------------------------------------------------------===//

#define GET_TYPEDEF_CLASSES
#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"

using namespace mlir;
using namespace cir;
Expand All @@ -20,18 +31,119 @@ using namespace cir;
//===----------------------------------------------------------------------===//

Type CIRDialect::parseType(DialectAsmParser &parser) const {
// No types yet to parse
return Type{};
llvm::SMLoc typeLoc = parser.getCurrentLocation();
llvm::StringRef mnemonic;
Type genType;

// Try to parse as a tablegen'd type.
OptionalParseResult parseResult =
generatedTypeParser(parser, &mnemonic, genType);
if (parseResult.has_value())
return genType;

// TODO(CIR) Attempt to parse as a raw C++ type.
parser.emitError(typeLoc) << "unknown CIR type: " << mnemonic;
return Type();
}

void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
// No types yet to print
// Try to print as a tablegen'd type.
if (generatedTypePrinter(type, os).succeeded())
return;

// TODO(CIR) Attempt to print as a raw C++ type.
llvm::report_fatal_error("printer is missing a handler for this type");
}

//===----------------------------------------------------------------------===//
// IntType Definitions
//===----------------------------------------------------------------------===//

Type IntType::parse(mlir::AsmParser &parser) {
mlir::MLIRContext *context = parser.getBuilder().getContext();
llvm::SMLoc loc = parser.getCurrentLocation();
bool isSigned;
unsigned width;

if (parser.parseLess())
return {};

// Fetch integer sign.
llvm::StringRef sign;
if (parser.parseKeyword(&sign))
return {};
if (sign == "s")
isSigned = true;
else if (sign == "u")
isSigned = false;
else {
parser.emitError(loc, "expected 's' or 'u'");
return {};
}

if (parser.parseComma())
return {};

// Fetch integer size.
if (parser.parseInteger(width))
return {};
if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
parser.emitError(loc, "expected integer width to be from ")
<< IntType::minBitwidth() << " up to " << IntType::maxBitwidth();
return {};
}

if (parser.parseGreater())
return {};

return IntType::get(context, width, isSigned);
}

void IntType::print(mlir::AsmPrinter &printer) const {
char sign = isSigned() ? 's' : 'u';
printer << '<' << sign << ", " << getWidth() << '>';
}

llvm::TypeSize
IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
return llvm::TypeSize::getFixed(getWidth());
}

uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
return (uint64_t)(getWidth() / 8);
}

uint64_t
IntType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout,
::mlir::DataLayoutEntryListRef params) const {
return (uint64_t)(getWidth() / 8);
}

mlir::LogicalResult
IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
unsigned width, bool isSigned) {
if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
emitError() << "IntType only supports widths from "
<< IntType::minBitwidth() << " up to "
<< IntType::maxBitwidth();
return mlir::failure();
}
return mlir::success();
}

//===----------------------------------------------------------------------===//
// CIR Dialect
//===----------------------------------------------------------------------===//

void CIRDialect::registerTypes() {
// No types yet to register
// Register tablegen'd types.
addTypes<
#define GET_TYPEDEF_LIST
#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
>();

// Register raw C++ types.
// TODO(CIR) addTypes<StructType>();
}
4 changes: 4 additions & 0 deletions clang/lib/CIR/Dialect/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ add_clang_library(MLIRCIR

LINK_LIBS PUBLIC
MLIRIR
MLIRDLTIDialect
MLIRDataLayoutInterfaces
MLIRFuncDialect
clangAST
)
6 changes: 6 additions & 0 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4515,7 +4515,13 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
ToolChain::getOpenMPTriple(Arg->getValue(0)) == TC->getTriple()) {
Arg->claim();
unsigned Index = Args.getBaseArgs().MakeIndex(Arg->getValue(1));
unsigned Prev = Index;
ExtractedArg = getOpts().ParseOneArg(Args, Index);
if (!ExtractedArg || Index > Prev + 1) {
TC->getDriver().Diag(diag::err_drv_invalid_Xopenmp_target_with_args)
<< Arg->getAsString(Args);
continue;
}
Arg = ExtractedArg.get();
}

Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1596,8 +1596,10 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs(
Prev = Index;
std::unique_ptr<Arg> XOpenMPTargetArg(Opts.ParseOneArg(Args, Index));
if (!XOpenMPTargetArg || Index > Prev + 1) {
getDriver().Diag(diag::err_drv_invalid_Xopenmp_target_with_args)
<< A->getAsString(Args);
if (!A->isClaimed()) {
getDriver().Diag(diag::err_drv_invalid_Xopenmp_target_with_args)
<< A->getAsString(Args);
}
continue;
}
if (XOpenMPTargetNoTriple && XOpenMPTargetArg &&
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,26 @@ bool arm::isARMAProfile(const llvm::Triple &Triple) {
return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::A;
}

/// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
bool arm::isARMEABIBareMetal(const llvm::Triple &Triple) {
auto arch = Triple.getArch();
if (arch != llvm::Triple::arm && arch != llvm::Triple::thumb &&
arch != llvm::Triple::armeb && arch != llvm::Triple::thumbeb)
return false;

if (Triple.getVendor() != llvm::Triple::UnknownVendor)
return false;

if (Triple.getOS() != llvm::Triple::UnknownOS)
return false;

if (Triple.getEnvironment() != llvm::Triple::EABI &&
Triple.getEnvironment() != llvm::Triple::EABIHF)
return false;

return true;
}

// Get Arch/CPU from args.
void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch,
llvm::StringRef &CPU, bool FromAs) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Arch/ARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ int getARMSubArchVersionNumber(const llvm::Triple &Triple);
bool isARMMProfile(const llvm::Triple &Triple);
bool isARMAProfile(const llvm::Triple &Triple);
bool isARMBigEndian(const llvm::Triple &Triple, const llvm::opt::ArgList &Args);
bool isARMEABIBareMetal(const llvm::Triple &Triple);

} // end namespace arm
} // end namespace tools
Expand Down
25 changes: 2 additions & 23 deletions clang/lib/Driver/ToolChains/BareMetal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,27 +128,6 @@ BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
}
}

/// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
static bool isARMBareMetal(const llvm::Triple &Triple) {
if (Triple.getArch() != llvm::Triple::arm &&
Triple.getArch() != llvm::Triple::thumb &&
Triple.getArch() != llvm::Triple::armeb &&
Triple.getArch() != llvm::Triple::thumbeb)
return false;

if (Triple.getVendor() != llvm::Triple::UnknownVendor)
return false;

if (Triple.getOS() != llvm::Triple::UnknownOS)
return false;

if (Triple.getEnvironment() != llvm::Triple::EABI &&
Triple.getEnvironment() != llvm::Triple::EABIHF)
return false;

return true;
}

/// Is the triple {aarch64.aarch64_be}-none-elf?
static bool isAArch64BareMetal(const llvm::Triple &Triple) {
if (Triple.getArch() != llvm::Triple::aarch64 &&
Expand Down Expand Up @@ -267,7 +246,7 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
}

bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
return arm::isARMEABIBareMetal(Triple) || isAArch64BareMetal(Triple) ||
isRISCVBareMetal(Triple) || isPPCBareMetal(Triple);
}

Expand Down Expand Up @@ -561,7 +540,7 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
// and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and
// arm*-*-*bsd).
if (isARMBareMetal(TC.getTriple()))
if (arm::isARMEABIBareMetal(TC.getTriple()))
CmdArgs.push_back("--target2=rel");

CmdArgs.push_back("-o");
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "Arch/SystemZ.h"
#include "Arch/VE.h"
#include "Arch/X86.h"
#include "BareMetal.h"
#include "HIPAMD.h"
#include "Hexagon.h"
#include "MSP430.h"
Expand Down Expand Up @@ -151,6 +152,9 @@ static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
}
}

if (arm::isARMEABIBareMetal(Triple))
return false;

return true;
}

Expand Down
23 changes: 21 additions & 2 deletions clang/test/AST/ByteCode/builtin-bit-cast-bitfields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,11 @@ namespace BitFields {
enum byte : unsigned char {};

constexpr BF bf = {0x3};
/// Requires bitcasts to composite types.
static_assert(bit_cast<bits<2>>(bf).bits == bf.z);
static_assert(bit_cast<unsigned char>(bf));

static_assert(__builtin_bit_cast(byte, bf));
static_assert(__builtin_bit_cast(byte, bf)); // expected-error {{not an integral constant expression}} \
// expected-note {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'byte' is invalid}}

struct M {
// ref-note@+1 {{subobject declared here}}
Expand Down Expand Up @@ -439,3 +439,22 @@ namespace Enums {
static_assert(
bit_cast<X>((unsigned char)0x40).direction == X::direction::right);
}

namespace IndeterminateBits {
struct S {
unsigned a : 13;
unsigned : 17;
unsigned b : 2;
};
constexpr unsigned A = __builtin_bit_cast(unsigned, S{12, 3}); // expected-error {{must be initialized by a constant expression}} \
// expected-note {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'unsigned int' is invalid}}


/// GCC refuses to compile this as soon as we access the indeterminate bits
/// in the static_assert. MSVC accepts it.
struct S2 {
unsigned char a : 2;
};
constexpr unsigned char B = __builtin_bit_cast(unsigned char, S2{3});
static_assert(B == (LITTLE_END ? 3 : 192));
}
21 changes: 7 additions & 14 deletions clang/test/AST/ByteCode/builtin-bit-cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,8 @@ namespace simple {
static_assert(check_round_trip<unsigned>((int)0x0C05FEFE));
static_assert(round_trip<float>((int)0x0C05FEFE));


/// This works in GCC and in the bytecode interpreter, but the current interpreter
/// diagnoses it.
/// FIXME: Should also be rejected in the bytecode interpreter.
static_assert(__builtin_bit_cast(intptr_t, nullptr) == 0); // ref-error {{not an integral constant expression}} \
// ref-note {{indeterminate value can only initialize an object}}
static_assert(__builtin_bit_cast(intptr_t, nullptr) == 0); // both-error {{not an integral constant expression}} \
// both-note {{indeterminate value can only initialize an object}}

constexpr int test_from_nullptr_pass = (__builtin_bit_cast(unsigned char[sizeof(nullptr)], nullptr), 0);
constexpr unsigned char NPData[sizeof(nullptr)] = {1,2,3,4};
Expand Down Expand Up @@ -394,7 +390,6 @@ void bad_types() {
};
static_assert(__builtin_bit_cast(int, X{0}) == 0); // both-error {{not an integral constant expression}} \
// both-note {{bit_cast from a union type is not allowed in a constant expression}}
#if 1

struct G {
int g;
Expand All @@ -405,19 +400,17 @@ void bad_types() {
// both-error@+2 {{constexpr variable 'x' must be initialized by a constant expression}}
// both-note@+1 {{bit_cast to a union type is not allowed in a constant expression}}
constexpr X x = __builtin_bit_cast(X, G{0});
#endif

struct has_pointer {
int *ptr; // both-note {{invalid type 'int *' is a member of 'has_pointer'}}
int *ptr; // both-note 2{{invalid type 'int *' is a member of 'has_pointer'}}
};

constexpr intptr_t ptr = __builtin_bit_cast(intptr_t, has_pointer{0}); // both-error {{constexpr variable 'ptr' must be initialized by a constant expression}} \
// both-note {{bit_cast from a pointer type is not allowed in a constant expression}}

#if 0
// expected-error@+2 {{constexpr variable 'hptr' must be initialized by a constant expression}}
// expected-note@+1 {{bit_cast to a pointer type is not allowed in a constant expression}}
constexpr has_pointer hptr = __builtin_bit_cast(has_pointer, 0ul);
#endif
// both-error@+2 {{constexpr variable 'hptr' must be initialized by a constant expression}}
// both-note@+1 {{bit_cast to a pointer type is not allowed in a constant expression}}
constexpr has_pointer hptr = __builtin_bit_cast(has_pointer, (intptr_t)0);
}

void test_array_fill() {
Expand Down
59 changes: 59 additions & 0 deletions clang/test/CIR/global-var-simple.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Global variables of intergal types
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s

char c;
// CHECK: cir.global @c : !cir.int<s, 8>

signed char sc;
// CHECK: cir.global @sc : !cir.int<s, 8>

unsigned char uc;
// CHECK: cir.global @uc : !cir.int<u, 8>

short ss;
// CHECK: cir.global @ss : !cir.int<s, 16>

unsigned short us;
// CHECK: cir.global @us : !cir.int<u, 16>

int si;
// CHECK: cir.global @si : !cir.int<s, 32>

unsigned ui;
// CHECK: cir.global @ui : !cir.int<u, 32>

long sl;
// CHECK: cir.global @sl : !cir.int<s, 64>

unsigned long ul;
// CHECK: cir.global @ul : !cir.int<u, 64>

long long sll;
// CHECK: cir.global @sll : !cir.int<s, 64>

unsigned long long ull;
// CHECK: cir.global @ull : !cir.int<u, 64>

__int128 s128;
// CHECK: cir.global @s128 : !cir.int<s, 128>

unsigned __int128 u128;
// CHECK: cir.global @u128 : !cir.int<u, 128>

wchar_t wc;
// CHECK: cir.global @wc : !cir.int<s, 32>

char8_t c8;
// CHECK: cir.global @c8 : !cir.int<u, 8>

char16_t c16;
// CHECK: cir.global @c16 : !cir.int<u, 16>

char32_t c32;
// CHECK: cir.global @c32 : !cir.int<u, 32>

_BitInt(20) sb20;
// CHECK: cir.global @sb20 : !cir.int<s, 20>

unsigned _BitInt(48) ub48;
// CHECK: cir.global @ub48 : !cir.int<u, 48>
53 changes: 53 additions & 0 deletions clang/test/Driver/frame-pointer-elim.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,5 +162,58 @@
// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s
// RUN: not %clang -### --target=riscv64-linux-android -mbig-endian -O1 -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s

// On ARM backend bare metal targets, frame pointer is omitted
// RUN: %clang -### --target=arm-arm-none-eabi -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NONE %s
// RUN: %clang -### --target=arm-arm-none-eabihf -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NONE %s
// RUN: %clang -### --target=arm-arm-none-eabi -S -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=arm-arm-none-eabihf -S -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=arm-arm-none-eabi -S -O1 %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NONE %s
// RUN: %clang -### --target=arm-arm-none-eabihf -S -O1 %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NONE %s
// RUN: %clang -### --target=arm-arm-none-eabi -S -O1 -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=arm-arm-none-eabihf -S -O1 -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=armeb-arm-none-eabi -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NONE %s
// RUN: %clang -### --target=thumb-arm-none-eabi -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NONE %s
// RUN: %clang -### --target=thumbeb-arm-none-eabi -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NONE %s

// Check that for Apple bare metal targets, we're keeping frame pointers by default
// RUN: %clang -### --target=thumbv6m-apple-none-macho -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=thumbv6m-apple-none-macho -S -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=arm-apple-none-macho -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=arm-apple-none-macho -S -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=thumbv6m-apple-none-macho -S -O1 %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=thumbv6m-apple-none-macho -S -O1 -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=arm-apple-none-macho -S -O1 %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s
// RUN: %clang -### --target=arm-apple-none-macho -S -O1 -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-ALL %s

// AArch64 bare metal targets behave like hosted targets
// RUN: %clang -### --target=aarch64-none-elf -S %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s
// RUN: %clang -### --target=aarch64-none-elf -S -O1 %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s
// RUN: %clang -### --target=aarch64-none-elf -S -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s
// RUN: %clang -### --target=aarch64-none-elf -S -O1 -fno-omit-frame-pointer %s 2>&1 | \
// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s

void f0() {}
void f1() { f0(); }
10 changes: 8 additions & 2 deletions clang/test/Driver/openmp-offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,15 @@

/// Check -Xopenmp-target triggers error when an option requiring arguments is passed to it.
// RUN: not %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu -Xopenmp-target -Xopenmp-target -mcpu=pwr8 %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHK-FOPENMP-TARGET-NESTED-ERROR %s
// RUN: | FileCheck -check-prefix=CHK-FOPENMP-TARGET-NESTED-ERROR_0 %s

// CHK-FOPENMP-TARGET-NESTED-ERROR: clang{{.*}} error: invalid -Xopenmp-target argument: '-Xopenmp-target -Xopenmp-target', options requiring arguments are unsupported
// CHK-FOPENMP-TARGET-NESTED-ERROR_0: error: invalid -Xopenmp-target argument: '-Xopenmp-target -Xopenmp-target', options requiring arguments are unsupported

/// Check -Xopenmp-target= triggers error when an option requiring arguments is passed to it.
// RUN: not %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu -Xopenmp-target=powerpc64le-ibm-linux-gnu -Xopenmp-target -mcpu=pwr8 %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHK-FOPENMP-TARGET-NESTED-ERROR_1 %s

// CHK-FOPENMP-TARGET-NESTED-ERROR_1: error: invalid -Xopenmp-target argument: '-Xopenmp-target=powerpc64le-ibm-linux-gnu -Xopenmp-target', options requiring arguments are unsupported

/// ###########################################################################

Expand Down
40 changes: 25 additions & 15 deletions clang/unittests/Basic/DiagnosticTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
Expand All @@ -20,6 +21,7 @@
#include "llvm/Support/VirtualFileSystem.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <memory>
#include <optional>
#include <vector>

Expand Down Expand Up @@ -196,7 +198,17 @@ class SuppressionMappingTest : public testing::Test {
return CaptureConsumer.StoredDiags;
}

SourceLocation locForFile(llvm::StringRef FileName) {
auto Buf = MemoryBuffer::getMemBuffer("", FileName);
SourceManager &SM = Diags.getSourceManager();
FileID FooID = SM.createFileID(std::move(Buf));
return SM.getLocForStartOfFile(FooID);
}

private:
FileManager FM{{}, FS};
SourceManager SM{Diags, FM};

class CaptureDiagnosticConsumer : public DiagnosticConsumer {
public:
std::vector<StoredDiagnostic> StoredDiags;
Expand Down Expand Up @@ -255,9 +267,9 @@ TEST_F(SuppressionMappingTest, SuppressesGroup) {
clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS);
EXPECT_THAT(diags(), IsEmpty());

EXPECT_TRUE(
Diags.isSuppressedViaMapping(diag::warn_unused_function, "foo.cpp"));
EXPECT_FALSE(Diags.isSuppressedViaMapping(diag::warn_deprecated, "foo.cpp"));
SourceLocation FooLoc = locForFile("foo.cpp");
EXPECT_TRUE(Diags.isSuppressedViaMapping(diag::warn_unused_function, FooLoc));
EXPECT_FALSE(Diags.isSuppressedViaMapping(diag::warn_deprecated, FooLoc));
}

TEST_F(SuppressionMappingTest, EmitCategoryIsExcluded) {
Expand All @@ -271,10 +283,10 @@ TEST_F(SuppressionMappingTest, EmitCategoryIsExcluded) {
clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS);
EXPECT_THAT(diags(), IsEmpty());

EXPECT_TRUE(
Diags.isSuppressedViaMapping(diag::warn_unused_function, "bar.cpp"));
EXPECT_FALSE(
Diags.isSuppressedViaMapping(diag::warn_unused_function, "foo.cpp"));
EXPECT_TRUE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
locForFile("bar.cpp")));
EXPECT_FALSE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
locForFile("foo.cpp")));
}

TEST_F(SuppressionMappingTest, LongestMatchWins) {
Expand All @@ -289,12 +301,12 @@ TEST_F(SuppressionMappingTest, LongestMatchWins) {
clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS);
EXPECT_THAT(diags(), IsEmpty());

EXPECT_TRUE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile("clang/lib/Basic/foo.h")));
EXPECT_FALSE(Diags.isSuppressedViaMapping(
diag::warn_unused_function, locForFile("clang/lib/Sema/bar.h")));
EXPECT_TRUE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
"clang/lib/Basic/foo.h"));
EXPECT_FALSE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
"clang/lib/Sema/bar.h"));
EXPECT_TRUE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
"clang/lib/Sema/foo.h"));
locForFile("clang/lib/Sema/foo.h")));
}

TEST_F(SuppressionMappingTest, IsIgnored) {
Expand All @@ -308,9 +320,7 @@ TEST_F(SuppressionMappingTest, IsIgnored) {
clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS);
ASSERT_THAT(diags(), IsEmpty());

FileManager FM({}, FS);
SourceManager SM(Diags, FM);

SourceManager &SM = Diags.getSourceManager();
auto ClangID =
SM.createFileID(llvm::MemoryBuffer::getMemBuffer("", "clang/foo.h"));
auto NonClangID =
Expand Down
1 change: 1 addition & 0 deletions flang-rt/lib/CufRuntime/descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "flang-rt/descriptor.h"
#include "../flang_rt/terminator.h"
#include "flang/Runtime/CUDA/common.h"
#include "flang/Runtime/descriptor.h"

#include "cuda_runtime.h"

Expand Down
10 changes: 10 additions & 0 deletions libcxx/Maintainers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# libc++ Maintainers

This file is a list of the
[maintainers](https://llvm.org/docs/DeveloperPolicy.html#maintainers) for
libc++.

# Lead maintainer

Louis Dionne \
ldionne.2@gmail.com (email), [ldionne](https://github.com/ldionne) (GitHub)
36 changes: 20 additions & 16 deletions libcxx/include/__memory/allocator_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD

// __pointer
template <class _Tp>
using __pointer_member = typename _Tp::pointer;
using __pointer_member _LIBCPP_NODEBUG = typename _Tp::pointer;

template <class _Tp, class _Alloc>
using __pointer = __detected_or_t<_Tp*, __pointer_member, __libcpp_remove_reference_t<_Alloc> >;
using __pointer _LIBCPP_NODEBUG = __detected_or_t<_Tp*, __pointer_member, __libcpp_remove_reference_t<_Alloc> >;

// __const_pointer
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_pointer, const_pointer);
Expand All @@ -58,7 +58,7 @@ struct __const_pointer {
template <class _Tp, class _Ptr, class _Alloc>
struct __const_pointer<_Tp, _Ptr, _Alloc, false> {
#ifdef _LIBCPP_CXX03_LANG
using type = typename pointer_traits<_Ptr>::template rebind<const _Tp>::other;
using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<const _Tp>::other;
#else
using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind<const _Tp>;
#endif
Expand Down Expand Up @@ -96,10 +96,10 @@ struct __const_void_pointer<_Ptr, _Alloc, false> {

// __size_type
template <class _Tp>
using __size_type_member = typename _Tp::size_type;
using __size_type_member _LIBCPP_NODEBUG = typename _Tp::size_type;

template <class _Alloc, class _DiffType>
using __size_type = __detected_or_t<__make_unsigned_t<_DiffType>, __size_type_member, _Alloc>;
using __size_type _LIBCPP_NODEBUG = __detected_or_t<__make_unsigned_t<_DiffType>, __size_type_member, _Alloc>;

// __alloc_traits_difference_type
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_alloc_traits_difference_type, difference_type);
Expand All @@ -114,33 +114,37 @@ struct __alloc_traits_difference_type<_Alloc, _Ptr, true> {

// __propagate_on_container_copy_assignment
template <class _Tp>
using __propagate_on_container_copy_assignment_member = typename _Tp::propagate_on_container_copy_assignment;
using __propagate_on_container_copy_assignment_member _LIBCPP_NODEBUG =
typename _Tp::propagate_on_container_copy_assignment;

template <class _Alloc>
using __propagate_on_container_copy_assignment =
using __propagate_on_container_copy_assignment _LIBCPP_NODEBUG =
__detected_or_t<false_type, __propagate_on_container_copy_assignment_member, _Alloc>;

// __propagate_on_container_move_assignment
template <class _Tp>
using __propagate_on_container_move_assignment_member = typename _Tp::propagate_on_container_move_assignment;
using __propagate_on_container_move_assignment_member _LIBCPP_NODEBUG =
typename _Tp::propagate_on_container_move_assignment;

template <class _Alloc>
using __propagate_on_container_move_assignment =
using __propagate_on_container_move_assignment _LIBCPP_NODEBUG =
__detected_or_t<false_type, __propagate_on_container_move_assignment_member, _Alloc>;

// __propagate_on_container_swap
template <class _Tp>
using __propagate_on_container_swap_member = typename _Tp::propagate_on_container_swap;
using __propagate_on_container_swap_member _LIBCPP_NODEBUG = typename _Tp::propagate_on_container_swap;

template <class _Alloc>
using __propagate_on_container_swap = __detected_or_t<false_type, __propagate_on_container_swap_member, _Alloc>;
using __propagate_on_container_swap _LIBCPP_NODEBUG =
__detected_or_t<false_type, __propagate_on_container_swap_member, _Alloc>;

// __is_always_equal
template <class _Tp>
using __is_always_equal_member = typename _Tp::is_always_equal;
using __is_always_equal_member _LIBCPP_NODEBUG = typename _Tp::is_always_equal;

template <class _Alloc>
using __is_always_equal = __detected_or_t<typename is_empty<_Alloc>::type, __is_always_equal_member, _Alloc>;
using __is_always_equal _LIBCPP_NODEBUG =
__detected_or_t<typename is_empty<_Alloc>::type, __is_always_equal_member, _Alloc>;

// __allocator_traits_rebind
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
Expand All @@ -165,7 +169,7 @@ struct __allocator_traits_rebind<_Alloc<_Tp, _Args...>, _Up, false> {
_LIBCPP_SUPPRESS_DEPRECATED_POP

template <class _Alloc, class _Tp>
using __allocator_traits_rebind_t = typename __allocator_traits_rebind<_Alloc, _Tp>::type;
using __allocator_traits_rebind_t _LIBCPP_NODEBUG = typename __allocator_traits_rebind<_Alloc, _Tp>::type;

_LIBCPP_SUPPRESS_DEPRECATED_PUSH

Expand Down Expand Up @@ -355,12 +359,12 @@ template <class _Traits, class _Tp>
using __rebind_alloc _LIBCPP_NODEBUG = typename _Traits::template rebind_alloc<_Tp>;
#else
template <class _Traits, class _Tp>
using __rebind_alloc = typename _Traits::template rebind_alloc<_Tp>::other;
using __rebind_alloc _LIBCPP_NODEBUG = typename _Traits::template rebind_alloc<_Tp>::other;
#endif

template <class _Alloc>
struct __check_valid_allocator : true_type {
using _Traits = std::allocator_traits<_Alloc>;
using _Traits _LIBCPP_NODEBUG = std::allocator_traits<_Alloc>;
static_assert(is_same<_Alloc, __rebind_alloc<_Traits, typename _Traits::value_type> >::value,
"[allocator.requirements] states that rebinding an allocator to the same type should result in the "
"original allocator");
Expand Down
6 changes: 3 additions & 3 deletions libcxx/include/__type_traits/detected_or.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD

template <class _Default, class _Void, template <class...> class _Op, class... _Args>
struct __detector {
using type = _Default;
using type _LIBCPP_NODEBUG = _Default;
};

template <class _Default, template <class...> class _Op, class... _Args>
struct __detector<_Default, __void_t<_Op<_Args...> >, _Op, _Args...> {
using type = _Op<_Args...>;
using type _LIBCPP_NODEBUG = _Op<_Args...>;
};

template <class _Default, template <class...> class _Op, class... _Args>
using __detected_or_t = typename __detector<_Default, void, _Op, _Args...>::type;
using __detected_or_t _LIBCPP_NODEBUG = typename __detector<_Default, void, _Op, _Args...>::type;

_LIBCPP_END_NAMESPACE_STD

Expand Down
35 changes: 33 additions & 2 deletions libcxx/test/std/containers/sequences/vector/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,41 @@

#include "count_new.h"

struct throwing_t {
int* throw_after_n_ = nullptr;
throwing_t() { throw 0; }

throwing_t(int& throw_after_n) : throw_after_n_(&throw_after_n) {
if (throw_after_n == 0)
throw 0;
--throw_after_n;
}

throwing_t(const throwing_t& rhs) : throw_after_n_(rhs.throw_after_n_) {
if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
throw 1;
--*throw_after_n_;
}

throwing_t& operator=(const throwing_t& rhs) {
throw_after_n_ = rhs.throw_after_n_;
if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
throw 1;
--*throw_after_n_;
return *this;
}

friend bool operator==(const throwing_t& lhs, const throwing_t& rhs) {
return lhs.throw_after_n_ == rhs.throw_after_n_;
}
friend bool operator!=(const throwing_t& lhs, const throwing_t& rhs) {
return lhs.throw_after_n_ != rhs.throw_after_n_;
}
};

template <class T>
struct throwing_allocator {
using value_type = T;
using is_always_equal = std::false_type;
using value_type = T;

bool throw_on_copy_ = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,149 +16,66 @@
#include <type_traits>
#include <vector>

#include "../common.h"
#include "count_new.h"
#include "test_allocator.h"
#include "test_iterators.h"

template <class T>
struct Allocator {
using value_type = T;
using is_always_equal = std::false_type;

template <class U>
Allocator(const Allocator<U>&) {}

Allocator(bool should_throw = true) {
if (should_throw)
throw 0;
}

T* allocate(std::size_t n) { return std::allocator<T>().allocate(n); }
void deallocate(T* ptr, std::size_t n) { std::allocator<T>().deallocate(ptr, n); }

template <class U>
friend bool operator==(const Allocator&, const Allocator<U>&) {
return true;
}
};

struct ThrowingT {
int* throw_after_n_ = nullptr;
ThrowingT() { throw 0; }

ThrowingT(int& throw_after_n) : throw_after_n_(&throw_after_n) {
if (throw_after_n == 0)
throw 0;
--throw_after_n;
}

ThrowingT(const ThrowingT& rhs) : throw_after_n_(rhs.throw_after_n_) {
if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
throw 1;
--*throw_after_n_;
}

ThrowingT& operator=(const ThrowingT& rhs) {
throw_after_n_ = rhs.throw_after_n_;
if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
throw 1;
--*throw_after_n_;
return *this;
}
};

template <class IterCat>
struct Iterator {
using iterator_category = IterCat;
using difference_type = std::ptrdiff_t;
using value_type = int;
using reference = int&;
using pointer = int*;

int i_;
Iterator(int i = 0) : i_(i) {}
int& operator*() {
if (i_ == 1)
throw 1;
return i_;
}

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

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

Iterator& operator++() {
++i_;
return *this;
}

Iterator operator++(int) {
auto tmp = *this;
++i_;
return tmp;
}
};

void check_new_delete_called() {
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
assert(globalMemCounter.new_array_called == globalMemCounter.delete_array_called);
assert(globalMemCounter.aligned_new_called == globalMemCounter.aligned_delete_called);
assert(globalMemCounter.aligned_new_array_called == globalMemCounter.aligned_delete_array_called);
}

int main(int, char**) {
using AllocVec = std::vector<int, Allocator<int> >;
using AllocVec = std::vector<int, throwing_allocator<int> >;
try { // vector()
AllocVec vec;
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(size_type) from type
std::vector<ThrowingT> get_alloc(1);
std::vector<throwing_t> get_alloc(1);
} catch (int) {
}
check_new_delete_called();

#if TEST_STD_VER >= 14
try { // Throw in vector(size_type, value_type) from type
int throw_after = 1;
ThrowingT v(throw_after);
std::vector<ThrowingT> get_alloc(1, v);
throwing_t v(throw_after);
std::vector<throwing_t> get_alloc(1, v);
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(size_type, const allocator_type&) from allocator
Allocator<int> alloc(false);
throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true);
AllocVec get_alloc(0, alloc);
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(size_type, const allocator_type&) from the type
std::vector<ThrowingT> vec(1, std::allocator<ThrowingT>());
std::vector<throwing_t> vec(1, std::allocator<throwing_t>());
} catch (int) {
}
check_new_delete_called();
#endif // TEST_STD_VER >= 14

try { // Throw in vector(size_type, value_type, const allocator_type&) from the type
int throw_after = 1;
ThrowingT v(throw_after);
std::vector<ThrowingT> vec(1, v, std::allocator<ThrowingT>());
throwing_t v(throw_after);
std::vector<throwing_t> vec(1, v, std::allocator<throwing_t>());
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(InputIterator, InputIterator) from input iterator
std::vector<int> vec((Iterator<std::input_iterator_tag>()), Iterator<std::input_iterator_tag>(2));
std::vector<int> vec(
(throwing_iterator<int, std::input_iterator_tag>()), throwing_iterator<int, std::input_iterator_tag>(2));
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(InputIterator, InputIterator) from forward iterator
std::vector<int> vec((Iterator<std::forward_iterator_tag>()), Iterator<std::forward_iterator_tag>(2));
std::vector<int> vec(
(throwing_iterator<int, std::forward_iterator_tag>()), throwing_iterator<int, std::forward_iterator_tag>(2));
} catch (int) {
}
check_new_delete_called();
Expand All @@ -172,75 +89,76 @@ int main(int, char**) {

try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator
std::allocator<int> alloc;
std::vector<int> vec(Iterator<std::input_iterator_tag>(), Iterator<std::input_iterator_tag>(2), alloc);
std::vector<int> vec(
throwing_iterator<int, std::input_iterator_tag>(), throwing_iterator<int, std::input_iterator_tag>(2), alloc);
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator
std::allocator<int> alloc;
std::vector<int> vec(Iterator<std::forward_iterator_tag>(), Iterator<std::forward_iterator_tag>(2), alloc);
std::vector<int> vec(throwing_iterator<int, std::forward_iterator_tag>(),
throwing_iterator<int, std::forward_iterator_tag>(2),
alloc);
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
int a[] = {1, 2};
Allocator<int> alloc(false);
throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true);
AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2), alloc);
} catch (int) {
// FIXME: never called.
}
check_new_delete_called();

try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
int a[] = {1, 2};
Allocator<int> alloc(false);
throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true);
AllocVec vec(forward_iterator<int*>(a), forward_iterator<int*>(a + 2), alloc);
} catch (int) {
// FIXME: never called.
}
check_new_delete_called();

try { // Throw in vector(const vector&) from type
std::vector<ThrowingT> vec;
int throw_after = 0;
std::vector<throwing_t> vec;
int throw_after = 1;
vec.emplace_back(throw_after);
auto vec2 = vec;
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(const vector&, const allocator_type&) from type
std::vector<ThrowingT> vec;
std::vector<throwing_t> vec;
int throw_after = 1;
vec.emplace_back(throw_after);
std::vector<ThrowingT> vec2(vec, std::allocator<int>());
std::vector<throwing_t> vec2(vec, std::allocator<int>());
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(vector&&, const allocator_type&) from type during element-wise move
std::vector<ThrowingT, test_allocator<ThrowingT> > vec(test_allocator<ThrowingT>(1));
std::vector<throwing_t, test_allocator<throwing_t> > vec(test_allocator<throwing_t>(1));
int throw_after = 10;
ThrowingT v(throw_after);
throwing_t v(throw_after);
vec.insert(vec.end(), 6, v);
std::vector<ThrowingT, test_allocator<ThrowingT> > vec2(std::move(vec), test_allocator<ThrowingT>(2));
std::vector<throwing_t, test_allocator<throwing_t> > vec2(std::move(vec), test_allocator<throwing_t>(2));
} catch (int) {
}
check_new_delete_called();

#if TEST_STD_VER >= 11
try { // Throw in vector(initializer_list<value_type>) from type
int throw_after = 1;
std::vector<ThrowingT> vec({ThrowingT(throw_after)});
std::vector<throwing_t> vec({throwing_t(throw_after)});
} catch (int) {
}
check_new_delete_called();

try { // Throw in vector(initializer_list<value_type>, const allocator_type&) constructor from type
int throw_after = 1;
std::vector<ThrowingT> vec({ThrowingT(throw_after)}, std::allocator<ThrowingT>());
std::vector<throwing_t> vec({throwing_t(throw_after)}, std::allocator<throwing_t>());
} catch (int) {
}
check_new_delete_called();
Expand Down
8 changes: 4 additions & 4 deletions lldb/source/Target/StackFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,8 @@ ValueObjectSP StackFrame::LegacyGetValueForVariableExpressionPath(
}
}

// If we have a non pointer type with a sythetic value then lets check if
// we have an sythetic dereference specified.
// If we have a non-pointer type with a synthetic value then lets check if
// we have a synthetic dereference specified.
if (!valobj_sp->IsPointerType() && valobj_sp->HasSyntheticValue()) {
Status deref_error;
if (valobj_sp->GetCompilerType().IsReferenceType()) {
Expand All @@ -686,13 +686,13 @@ ValueObjectSP StackFrame::LegacyGetValueForVariableExpressionPath(
valobj_sp = valobj_sp->Dereference(deref_error);
if (!valobj_sp || deref_error.Fail()) {
error = Status::FromErrorStringWithFormatv(
"Failed to dereference sythetic value: {0}", deref_error);
"Failed to dereference synthetic value: {0}", deref_error);
return ValueObjectSP();
}
// Some synthetic plug-ins fail to set the error in Dereference
if (!valobj_sp) {
error =
Status::FromErrorString("Failed to dereference sythetic value");
Status::FromErrorString("Failed to dereference synthetic value");
return ValueObjectSP();
}
expr_is_ptr = false;
Expand Down
7 changes: 2 additions & 5 deletions llvm/Maintainers.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,17 +434,14 @@ Others only have a lead maintainer listed here.

[Flang maintainers](https://github.com/llvm/llvm-project/blob/main/flang/Maintainers.txt)

[libc++ maintainers](https://github.com/llvm/llvm-project/blob/main/libcxx/Maintainers.md)

[LLD maintainers](https://github.com/llvm/llvm-project/blob/main/lld/Maintainers.md)

[LLDB maintainers](https://github.com/llvm/llvm-project/blob/main/lldb/Maintainers.rst)

[LLVM OpenMP Library maintainers](https://github.com/llvm/llvm-project/blob/main/openmp/Maintainers.md)

#### libc++

Louis Dionne \
ldionne.2@gmail.com (email), [ldionne](https://github.com/ldionne) (GitHub)

#### libclc

Tom Stellard \
Expand Down
14 changes: 12 additions & 2 deletions llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ static bool isPromotableLoadFromStore(MachineInstr &MI) {
}
}

static bool isMergeableLdStUpdate(MachineInstr &MI) {
static bool isMergeableLdStUpdate(MachineInstr &MI, AArch64FunctionInfo &AFI) {
unsigned Opc = MI.getOpcode();
switch (Opc) {
default:
Expand Down Expand Up @@ -785,6 +785,15 @@ static bool isMergeableLdStUpdate(MachineInstr &MI) {
if (!AArch64InstrInfo::getLdStOffsetOp(MI).isImm())
return false;

// When using stack tagging, simple sp+imm loads and stores are not
// tag-checked, but pre- and post-indexed versions of them are, so we can't
// replace the former with the latter. This transformation would be valid
// if the load/store accesses an untagged stack slot, but we don't have
// that information available after frame indices have been eliminated.
if (AFI.isMTETagged() &&
AArch64InstrInfo::getLdStBaseOp(MI).getReg() == AArch64::SP)
return false;

return true;
}
}
Expand Down Expand Up @@ -2772,6 +2781,7 @@ bool AArch64LoadStoreOpt::tryToMergeIndexLdSt(MachineBasicBlock::iterator &MBBI,

bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &MBB,
bool EnableNarrowZeroStOpt) {
AArch64FunctionInfo &AFI = *MBB.getParent()->getInfo<AArch64FunctionInfo>();

bool Modified = false;
// Four tranformations to do here:
Expand Down Expand Up @@ -2842,7 +2852,7 @@ bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &MBB,
// ldr x0, [x2], #4
for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
MBBI != E;) {
if (isMergeableLdStUpdate(*MBBI) && tryToMergeLdStUpdate(MBBI))
if (isMergeableLdStUpdate(*MBBI, AFI) && tryToMergeLdStUpdate(MBBI))
Modified = true;
else
++MBBI;
Expand Down
43 changes: 42 additions & 1 deletion llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,37 @@ static bool isTriviallyUniform(const Use &U) {
return false;
}

/// Simplify a lane index operand (e.g. llvm.amdgcn.readlane src1).
///
/// The instruction only reads the low 5 bits for wave32, and 6 bits for wave64.
bool GCNTTIImpl::simplifyDemandedLaneMaskArg(InstCombiner &IC,
IntrinsicInst &II,
unsigned LaneArgIdx) const {
unsigned MaskBits = ST->getWavefrontSizeLog2();
APInt DemandedMask(32, maskTrailingOnes<unsigned>(MaskBits));

KnownBits Known(32);
if (IC.SimplifyDemandedBits(&II, LaneArgIdx, DemandedMask, Known))
return true;

if (!Known.isConstant())
return false;

// Out of bounds indexes may appear in wave64 code compiled for wave32.
// Unlike the DAG version, SimplifyDemandedBits does not change constants, so
// manually fix it up.

Value *LaneArg = II.getArgOperand(LaneArgIdx);
Constant *MaskedConst =
ConstantInt::get(LaneArg->getType(), Known.getConstant() & DemandedMask);
if (MaskedConst != LaneArg) {
II.getOperandUse(LaneArgIdx).set(MaskedConst);
return true;
}

return false;
}

std::optional<Instruction *>
GCNTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
Intrinsic::ID IID = II.getIntrinsicID();
Expand Down Expand Up @@ -1092,7 +1123,17 @@ GCNTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
const Use &Src = II.getArgOperandUse(0);
if (isTriviallyUniform(Src))
return IC.replaceInstUsesWith(II, Src.get());
break;

if (IID == Intrinsic::amdgcn_readlane &&
simplifyDemandedLaneMaskArg(IC, II, 1))
return &II;

return std::nullopt;
}
case Intrinsic::amdgcn_writelane: {
if (simplifyDemandedLaneMaskArg(IC, II, 1))
return &II;
return std::nullopt;
}
case Intrinsic::amdgcn_trig_preop: {
// The intrinsic is declared with name mangling, but currently the
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ class GCNTTIImpl final : public BasicTTIImplBase<GCNTTIImpl> {

bool canSimplifyLegacyMulToMul(const Instruction &I, const Value *Op0,
const Value *Op1, InstCombiner &IC) const;

bool simplifyDemandedLaneMaskArg(InstCombiner &IC, IntrinsicInst &II,
unsigned LaneAgIdx) const;

std::optional<Instruction *> instCombineIntrinsic(InstCombiner &IC,
IntrinsicInst &II) const;
std::optional<Value *> simplifyDemandedVectorEltsIntrinsic(
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/AMDGPU/VINTERPInstructions.td
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,6 @@ defm V_INTERP_P10_F16_F32_inreg : VINTERP_Real_t16_and_fake16_gfx11_gfx12<0x002,
defm V_INTERP_P2_F16_F32_inreg : VINTERP_Real_t16_and_fake16_gfx11_gfx12<0x003, "v_interp_p2_f16_f32">;
defm V_INTERP_P10_RTZ_F16_F32_inreg : VINTERP_Real_t16_and_fake16_gfx11_gfx12<0x004, "v_interp_p10_rtz_f16_f32">;
defm V_INTERP_P2_RTZ_F16_F32_inreg : VINTERP_Real_t16_and_fake16_gfx11_gfx12<0x005, "v_interp_p2_rtz_f16_f32">;

let AssemblerPredicate = isGFX11Plus in
def : AMDGPUMnemonicAlias<"v_interp_p2_new_f32", "v_interp_p2_f32">;
5 changes: 5 additions & 0 deletions llvm/lib/Target/AMDGPU/VOP3Instructions.td
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,11 @@ defm V_OR_B16_fake16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x363, "v_or_b1
defm V_XOR_B16_t16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x364, "v_xor_b16">;
defm V_XOR_B16_fake16 : VOP3Only_Realtriple_t16_gfx11_gfx12<0x364, "v_xor_b16">;

let AssemblerPredicate = isGFX11Plus in {
def : AMDGPUMnemonicAlias<"v_add3_nc_u32", "v_add3_u32">;
def : AMDGPUMnemonicAlias<"v_xor_add_u32", "v_xad_u32">;
}

//===----------------------------------------------------------------------===//
// GFX10.
//===----------------------------------------------------------------------===//
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/AMDGPU/VOPCInstructions.td
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,17 @@ defm V_CMPX_CLASS_F16_fake16 : VOPCX_Real_t16_gfx11_gfx12<0x0fd, "v_cmpx_class_f
defm V_CMPX_CLASS_F32 : VOPCX_Real_gfx11_gfx12<0x0fe>;
defm V_CMPX_CLASS_F64 : VOPCX_Real_gfx11_gfx12<0x0ff>;

let AssemblerPredicate = isGFX11Only in {
def : AMDGPUMnemonicAlias<"v_cmp_tru_i32", "v_cmp_t_i32">;
def : AMDGPUMnemonicAlias<"v_cmp_tru_u32", "v_cmp_t_u32">;
def : AMDGPUMnemonicAlias<"v_cmp_tru_i64", "v_cmp_t_i64">;
def : AMDGPUMnemonicAlias<"v_cmp_tru_u64", "v_cmp_t_u64">;
def : AMDGPUMnemonicAlias<"v_cmpx_tru_i32", "v_cmpx_t_i32">;
def : AMDGPUMnemonicAlias<"v_cmpx_tru_u32", "v_cmpx_t_u32">;
def : AMDGPUMnemonicAlias<"v_cmpx_tru_i64", "v_cmpx_t_i64">;
def : AMDGPUMnemonicAlias<"v_cmpx_tru_u64", "v_cmpx_t_u64">;
}

//===----------------------------------------------------------------------===//
// GFX10.
//===----------------------------------------------------------------------===//
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5129,7 +5129,8 @@ ParseStatus ARMAsmParser::parseMemBarrierOptOperand(OperandVector &Operands) {

Opt = ARM_MB::RESERVED_0 + Val;
} else
return ParseStatus::Failure;
return Error(Parser.getTok().getLoc(),
"expected an immediate or barrier type");

Operands.push_back(
ARMOperand::CreateMemBarrierOpt((ARM_MB::MemBOpt)Opt, S, *this));
Expand Down Expand Up @@ -5193,7 +5194,8 @@ ARMAsmParser::parseInstSyncBarrierOptOperand(OperandVector &Operands) {

Opt = ARM_ISB::RESERVED_0 + Val;
} else
return ParseStatus::Failure;
return Error(Parser.getTok().getLoc(),
"expected an immediate or barrier type");

Operands.push_back(ARMOperand::CreateInstSyncBarrierOpt(
(ARM_ISB::InstSyncBOpt)Opt, S, *this));
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2423,11 +2423,11 @@ SDValue X86DAGToDAGISel::matchIndexRecursively(SDValue N,
if (CurDAG->isBaseWithConstantOffset(Src)) {
SDValue AddSrc = Src.getOperand(0);
auto *AddVal = cast<ConstantSDNode>(Src.getOperand(1));
uint64_t Offset = (uint64_t)AddVal->getSExtValue();
if (!foldOffsetIntoAddress(Offset * AM.Scale, AM)) {
int64_t Offset = AddVal->getSExtValue();
if (!foldOffsetIntoAddress((uint64_t)Offset * AM.Scale, AM)) {
SDLoc DL(N);
SDValue ExtSrc = CurDAG->getNode(Opc, DL, VT, AddSrc);
SDValue ExtVal = CurDAG->getConstant(Offset, DL, VT);
SDValue ExtVal = CurDAG->getSignedConstant(Offset, DL, VT);
SDValue ExtAdd = CurDAG->getNode(ISD::ADD, DL, VT, ExtSrc, ExtVal);
insertDAGNode(*CurDAG, N, ExtSrc);
insertDAGNode(*CurDAG, N, ExtVal);
Expand Down
36 changes: 27 additions & 9 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,13 +689,32 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
if (!isa<GetElementPtrInst>(RHS))
RHS = RHS->stripPointerCasts();

auto CanFold = [Cond](GEPNoWrapFlags NW) {
if (ICmpInst::isEquality(Cond))
return true;

// Unsigned predicates can be folded if the GEPs have *any* nowrap flags.
assert(ICmpInst::isUnsigned(Cond));
return NW != GEPNoWrapFlags::none();
};

auto NewICmp = [Cond](GEPNoWrapFlags NW, Value *Op1, Value *Op2) {
if (!NW.hasNoUnsignedWrap()) {
// Convert signed to unsigned comparison.
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), Op1, Op2);
}

auto *I = new ICmpInst(Cond, Op1, Op2);
I->setSameSign(NW.hasNoUnsignedSignedWrap());
return I;
};

Value *PtrBase = GEPLHS->getOperand(0);
if (PtrBase == RHS &&
(GEPLHS->hasNoUnsignedSignedWrap() || ICmpInst::isEquality(Cond))) {
if (PtrBase == RHS && CanFold(GEPLHS->getNoWrapFlags())) {
// ((gep Ptr, OFFSET) cmp Ptr) ---> (OFFSET cmp 0).
Value *Offset = EmitGEPOffset(GEPLHS);
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), Offset,
Constant::getNullValue(Offset->getType()));
return NewICmp(GEPLHS->getNoWrapFlags(), Offset,
Constant::getNullValue(Offset->getType()));
}

if (GEPLHS->isInBounds() && ICmpInst::isEquality(Cond) &&
Expand Down Expand Up @@ -813,19 +832,18 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
return replaceInstUsesWith(I, // No comparison is needed here.
ConstantInt::get(I.getType(), ICmpInst::isTrueWhenEqual(Cond)));

else if (NumDifferences == 1 && NW.hasNoUnsignedSignedWrap()) {
else if (NumDifferences == 1 && CanFold(NW)) {
Value *LHSV = GEPLHS->getOperand(DiffOperand);
Value *RHSV = GEPRHS->getOperand(DiffOperand);
// Make sure we do a signed comparison here.
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), LHSV, RHSV);
return NewICmp(NW, LHSV, RHSV);
}
}

if (NW.hasNoUnsignedSignedWrap() || CmpInst::isEquality(Cond)) {
if (CanFold(NW)) {
// ((gep Ptr, OFFSET1) cmp (gep Ptr, OFFSET2) ---> (OFFSET1 cmp OFFSET2)
Value *L = EmitGEPOffset(GEPLHS, /*RewriteGEP=*/true);
Value *R = EmitGEPOffset(GEPRHS, /*RewriteGEP=*/true);
return new ICmpInst(ICmpInst::getSignedPredicate(Cond), L, R);
return NewICmp(NW, L, R);
}
}

Expand Down
16 changes: 13 additions & 3 deletions llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,9 @@ static Decomposition decompose(Value *V,
else if (match(V, m_NNegZExt(m_Value(Op0)))) {
V = Op0;
IsKnownNonNegative = true;
} else if (match(V, m_NSWTrunc(m_Value(Op0)))) {
if (Op0->getType()->getScalarSizeInBits() <= 64)
V = Op0;
}

if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1))))
Expand Down Expand Up @@ -558,12 +561,19 @@ static Decomposition decompose(Value *V,
if (match(V, m_ZExt(m_Value(Op0)))) {
IsKnownNonNegative = true;
V = Op0;
}

if (match(V, m_SExt(m_Value(Op0)))) {
} else if (match(V, m_SExt(m_Value(Op0)))) {
V = Op0;
Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
ConstantInt::get(Op0->getType(), 0));
} else if (auto *Trunc = dyn_cast<TruncInst>(V)) {
if (Trunc->getSrcTy()->getScalarSizeInBits() <= 64) {
if (Trunc->hasNoUnsignedWrap() || Trunc->hasNoSignedWrap()) {
V = Trunc->getOperand(0);
if (!Trunc->hasNoUnsignedWrap())
Preconditions.emplace_back(CmpInst::ICMP_SGE, V,
ConstantInt::get(V->getType(), 0));
}
}
}

Value *Op1;
Expand Down
214 changes: 146 additions & 68 deletions llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp

Large diffs are not rendered by default.

142 changes: 142 additions & 0 deletions llvm/test/CodeGen/AArch64/memtag-merge-writeback.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
# RUN: llc -mtriple aarch64-none-elf -mattr=+mte --run-pass=aarch64-ldst-opt %s -o - | FileCheck %s

## When generating code with sanitize_memtag, we make use of the fact that the
## sp+imm forms of many load and store instructions are not tag-checked, so we
## can use SP directly instead of needing a register holding the tagged
## pointer. However, this isn't true for the writeback versions of the
## instructions, so we can't fold ADDs and SUBs into them in
## AArch64LoadStoreOptimizer. This would be possible in cases where the
## loads/stores only access untagged stack slots, but that information isn't
## easily available after frame index elimination.

--- |
define void @pre_index() {
entry:
ret void
}
define void @pre_index_memtag() sanitize_memtag {
entry:
ret void
}
define void @pre_index_memtag_not_sp() sanitize_memtag {
entry:
ret void
}
define void @post_index() {
entry:
ret void
}
define void @post_index_memtag() sanitize_memtag {
entry:
ret void
}
define void @post_index_memtag_not_sp() sanitize_memtag {
entry:
ret void
}
...
---
name: pre_index
body: |
bb.0.entry:
liveins: $x0

; CHECK-LABEL: name: pre_index
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: $sp = frame-setup SUBXri $sp, 16, 0
; CHECK-NEXT: early-clobber $sp = STRXpre killed renamable $x0, $sp, 16
; CHECK-NEXT: RET undef $lr
$sp = frame-setup SUBXri $sp, 16, 0
STRXui killed renamable $x0, $sp, 2
$sp = ADDXri $sp, 16, 0
RET undef $lr
...
---
name: pre_index_memtag
body: |
bb.0.entry:
liveins: $x0

; CHECK-LABEL: name: pre_index_memtag
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: $sp = frame-setup SUBXri $sp, 16, 0
; CHECK-NEXT: STRXui killed renamable $x0, $sp, 2
; CHECK-NEXT: $sp = ADDXri $sp, 16, 0
; CHECK-NEXT: RET undef $lr
$sp = frame-setup SUBXri $sp, 16, 0
STRXui killed renamable $x0, $sp, 2
$sp = ADDXri $sp, 16, 0
RET undef $lr
...
---
name: pre_index_memtag_not_sp
body: |
bb.0.entry:
liveins: $x0, $x1

; CHECK-LABEL: name: pre_index_memtag_not_sp
; CHECK: liveins: $x0, $x1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: $x1 = frame-setup SUBXri $x1, 16, 0
; CHECK-NEXT: early-clobber $x1 = STRXpre killed renamable $x0, $x1, 16
; CHECK-NEXT: RET undef $lr, implicit $x1
$x1 = frame-setup SUBXri $x1, 16, 0
STRXui killed renamable $x0, $x1, 2
$x1 = ADDXri $x1, 16, 0
RET undef $lr, implicit $x1
...
---
name: post_index
body: |
bb.0.entry:
liveins: $x0

; CHECK-LABEL: name: post_index
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: $sp = frame-setup SUBXri $sp, 16, 0
; CHECK-NEXT: early-clobber $sp = STRXpost killed renamable $x0, $sp, 16
; CHECK-NEXT: RET undef $lr
$sp = frame-setup SUBXri $sp, 16, 0
STRXui killed renamable $x0, $sp, 0
$sp = ADDXri $sp, 16, 0
RET undef $lr
...
---
name: post_index_memtag
body: |
bb.0.entry:
liveins: $x0

; CHECK-LABEL: name: post_index_memtag
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: $sp = frame-setup SUBXri $sp, 16, 0
; CHECK-NEXT: STRXui killed renamable $x0, $sp, 0
; CHECK-NEXT: $sp = ADDXri $sp, 16, 0
; CHECK-NEXT: RET undef $lr
$sp = frame-setup SUBXri $sp, 16, 0
STRXui killed renamable $x0, $sp, 0
$sp = ADDXri $sp, 16, 0
RET undef $lr
...
---
name: post_index_memtag_not_sp
body: |
bb.0.entry:
liveins: $x0, $x1

; CHECK-LABEL: name: post_index_memtag_not_sp
; CHECK: liveins: $x0, $x1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: $x1 = frame-setup SUBXri $x1, 16, 0
; CHECK-NEXT: early-clobber $x1 = STRXpost killed renamable $x0, $x1, 16
; CHECK-NEXT: RET undef $lr, implicit $x1
$x1 = frame-setup SUBXri $x1, 16, 0
STRXui killed renamable $x0, $x1, 0
$x1 = ADDXri $x1, 16, 0
RET undef $lr, implicit $x1
...
45 changes: 45 additions & 0 deletions llvm/test/CodeGen/X86/pr118934.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=i686-unknown | FileCheck %s --check-prefix=X86
; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s --check-prefix=X64

define void @PR118934(i1 %b, ptr %f, ptr %k) {
; X86-LABEL: PR118934:
; X86: # %bb.0: # %entry
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: movzbl {{[0-9]+}}(%esp), %edx
; X86-NEXT: andb $1, %dl
; X86-NEXT: addb %dl, %dl
; X86-NEXT: addb $-2, %dl
; X86-NEXT: movsbl %dl, %edx
; X86-NEXT: addl $-6, %edx
; X86-NEXT: addl $6, %edx
; X86-NEXT: movl %edx, (%ecx)
; X86-NEXT: addl %edx, %edx
; X86-NEXT: movl %edx, (%eax)
;
; X64-LABEL: PR118934:
; X64: # %bb.0: # %entry
; X64-NEXT: andb $1, %dil
; X64-NEXT: addb %dil, %dil
; X64-NEXT: addb $-2, %dil
; X64-NEXT: movsbl %dil, %eax
; X64-NEXT: addl $-6, %eax
; X64-NEXT: addl $6, %eax
; X64-NEXT: movl %eax, (%rsi)
; X64-NEXT: addl %eax, %eax
; X64-NEXT: movl %eax, (%rdx)
entry:
%0 = select i1 %b, i8 0, i8 -2
br label %for.end

for.end:
%n.i.i = select i1 poison, i32 6, i32 7
%narrow = add nsw i8 %0, -6
%add2.i = sext i8 %narrow to i32
%conv5.i = add nsw i32 %n.i.i, %add2.i
store i32 %conv5.i, ptr %f, align 4
%add = shl nsw i32 %conv5.i, 1
store i32 %add, ptr %k, align 4
unreachable
}
74 changes: 74 additions & 0 deletions llvm/test/MC/AMDGPU/gfx11_asm_vinterp.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 5
// RUN: llvm-mc -triple=amdgcn -mcpu=gfx1100 -show-encoding %s | FileCheck --check-prefix=GFX11 %s

v_interp_p10_f32 v0, v1, v2, v3 wait_exp:5
// GFX11: v_interp_p10_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x00,0xcd,0x01,0x05,0x0e,0x04]

v_interp_p10_f32 v0, -v1, v2, v3
// GFX11: v_interp_p10_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x24]

v_interp_p10_f32 v0, v1, -v2, v3
// GFX11: v_interp_p10_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x44]

v_interp_p10_f32 v0, v1, v2, -v3
// GFX11: v_interp_p10_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x84]

v_interp_p2_f32 v0, v1, v2, v3 wait_exp:5
// GFX11: v_interp_p2_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x01,0xcd,0x01,0x05,0x0e,0x04]

v_interp_p2_f32 v0, -v1, v2, v3
// GFX11: v_interp_p2_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x24]

v_interp_p2_f32 v0, v1, -v2, v3
// GFX11: v_interp_p2_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x44]

v_interp_p2_f32 v0, v1, v2, -v3
// GFX11: v_interp_p2_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x84]

v_interp_p10_f16_f32 v0, v1, v2, v3 wait_exp:5
// GFX11: v_interp_p10_f16_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x02,0xcd,0x01,0x05,0x0e,0x04]

v_interp_p10_f16_f32 v0, -v1, v2, v3
// GFX11: v_interp_p10_f16_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x24]

v_interp_p10_f16_f32 v0, v1, -v2, v3
// GFX11: v_interp_p10_f16_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x44]

v_interp_p10_f16_f32 v0, v1, v2, -v3
// GFX11: v_interp_p10_f16_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x84]

v_interp_p2_f16_f32 v0, v1, v2, v3 wait_exp:5
// GFX11: v_interp_p2_f16_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x03,0xcd,0x01,0x05,0x0e,0x04]

v_interp_p2_f16_f32 v0, -v1, v2, v3
// GFX11: v_interp_p2_f16_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x24]

v_interp_p2_f16_f32 v0, v1, -v2, v3
// GFX11: v_interp_p2_f16_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x44]

v_interp_p2_f16_f32 v0, v1, v2, -v3
// GFX11: v_interp_p2_f16_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x84]

v_interp_p10_rtz_f16_f32 v0, v1, v2, v3 wait_exp:5
// GFX11: v_interp_p10_rtz_f16_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x04,0xcd,0x01,0x05,0x0e,0x04]

v_interp_p10_rtz_f16_f32 v0, -v1, v2, v3
// GFX11: v_interp_p10_rtz_f16_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x24]

v_interp_p10_rtz_f16_f32 v0, v1, -v2, v3
// GFX11: v_interp_p10_rtz_f16_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x44]

v_interp_p10_rtz_f16_f32 v0, v1, v2, -v3
// GFX11: v_interp_p10_rtz_f16_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x84]

v_interp_p2_rtz_f16_f32 v0, v1, v2, v3 wait_exp:5
// GFX11: v_interp_p2_rtz_f16_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x05,0xcd,0x01,0x05,0x0e,0x04]

v_interp_p2_rtz_f16_f32 v0, -v1, v2, v3
// GFX11: v_interp_p2_rtz_f16_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x24]

v_interp_p2_rtz_f16_f32 v0, v1, -v2, v3
// GFX11: v_interp_p2_rtz_f16_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x44]

v_interp_p2_rtz_f16_f32 v0, v1, v2, -v3
// GFX11: v_interp_p2_rtz_f16_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x84]
5 changes: 5 additions & 0 deletions llvm/test/MC/AMDGPU/gfx11_asm_vinterp_alias.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 5
// RUN: llvm-mc -triple=amdgcn -mcpu=gfx1100 -show-encoding %s | FileCheck --check-prefix=GFX11 %s

v_interp_p2_new_f32 v0, v1, v2, v3
// GFX11: v_interp_p2_f32 v0, v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x04]
6 changes: 6 additions & 0 deletions llvm/test/MC/AMDGPU/gfx11_asm_vop3_alias.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ v_cvt_pknorm_i16_f16 v5, v1, v2

v_cvt_pknorm_u16_f16 v5, v1, v2
// GFX11: v_cvt_pk_norm_u16_f16 v5, v1, v2 ; encoding: [0x05,0x00,0x13,0xd7,0x01,0x05,0x02,0x00]

v_add3_nc_u32 v5, v1, v2, s3
// GFX11: v_add3_u32 v5, v1, v2, s3 ; encoding: [0x05,0x00,0x55,0xd6,0x01,0x05,0x0e,0x00]

v_xor_add_u32 v5, v1, v2, s3
// GFX11: v_xad_u32 v5, v1, v2, s3 ; encoding: [0x05,0x00,0x45,0xd6,0x01,0x05,0x0e,0x00]
14 changes: 14 additions & 0 deletions llvm/test/MC/AMDGPU/gfx11_asm_vopc_alias.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 5
// RUN: llvm-mc -triple=amdgcn -mcpu=gfx1100 -mattr=+wavefrontsize64 -show-encoding %s | FileCheck -check-prefix=GFX11 %s

v_cmp_tru_i32 vcc, v1, v2
// GFX11: v_cmp_t_i32_e32 vcc, v1, v2 ; encoding: [0x01,0x05,0x8e,0x7c]

v_cmp_tru_u32 vcc, v1, v2
// GFX11: v_cmp_t_u32_e32 vcc, v1, v2 ; encoding: [0x01,0x05,0x9e,0x7c]

v_cmp_tru_i64 vcc, v[1:2], v[2:3]
// GFX11: v_cmp_t_i64_e32 vcc, v[1:2], v[2:3] ; encoding: [0x01,0x05,0xae,0x7c]

v_cmp_tru_u64 vcc, v[1:2], v[2:3]
// GFX11: v_cmp_t_u64_e32 vcc, v[1:2], v[2:3] ; encoding: [0x01,0x05,0xbe,0x7c]
14 changes: 14 additions & 0 deletions llvm/test/MC/AMDGPU/gfx11_asm_vopcx_alias.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 5
// RUN: llvm-mc -triple=amdgcn -mcpu=gfx1100 -mattr=+wavefrontsize64 -show-encoding %s | FileCheck -check-prefix=GFX11 %s

v_cmpx_tru_i32 v1, v2
// GFX11: v_cmpx_t_i32_e32 v1, v2 ; encoding: [0x01,0x05,0x8e,0x7d]

v_cmpx_tru_u32 v1, v2
// GFX11: v_cmpx_t_u32_e32 v1, v2 ; encoding: [0x01,0x05,0x9e,0x7d]

v_cmpx_tru_i64 v[1:2], v[2:3]
// GFX11: v_cmpx_t_i64_e32 v[1:2], v[2:3] ; encoding: [0x01,0x05,0xae,0x7d]

v_cmpx_tru_u64 v[1:2], v[2:3]
// GFX11: v_cmpx_t_u64_e32 v[1:2], v[2:3] ; encoding: [0x01,0x05,0xbe,0x7d]
6 changes: 6 additions & 0 deletions llvm/test/MC/AMDGPU/gfx12_asm_vop3_aliases.s
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,9 @@ v_cvt_pknorm_i16_f16 v5, v1, v2

v_cvt_pknorm_u16_f16 v5, v1, v2
// GFX12: v_cvt_pk_norm_u16_f16 v5, v1, v2 ; encoding: [0x05,0x00,0x13,0xd7,0x01,0x05,0x02,0x00]

v_add3_nc_u32 v5, v1, v2, s3
// GFX12: v_add3_u32 v5, v1, v2, s3 ; encoding: [0x05,0x00,0x55,0xd6,0x01,0x05,0x0e,0x00]

v_xor_add_u32 v5, v1, v2, s3
// GFX12: v_xad_u32 v5, v1, v2, s3 ; encoding: [0x05,0x00,0x45,0xd6,0x01,0x05,0x0e,0x00]
38 changes: 30 additions & 8 deletions llvm/test/MC/ARM/invalid-barrier.s
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,46 @@
@ DMB
@------------------------------------------------------------------------------
dmb #0x10
@ CHECK: [[@LINE-1]]:{{.*}}: error: immediate value out of range
dmb imaginary_scope

@ CHECK: error: immediate value out of range
@ CHECK: error: invalid operand for instruction
@ CHECK: [[@LINE-1]]:{{.*}}: error: invalid operand for instruction
dmb [r0]
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
dmb [], @, -=_+
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
dmb ,,,,,
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
dmb 3.141
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type

@------------------------------------------------------------------------------
@ DSB
@------------------------------------------------------------------------------
dsb #0x10
@ CHECK: [[@LINE-1]]:{{.*}}: error: immediate value out of range
dsb imaginary_scope
@ CHECK: error: immediate value out of range
@ CHECK: error: invalid operand for instruction
@ CHECK: [[@LINE-1]]:{{.*}}: error: invalid operand for instruction
dsb [r0]
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
dsb [], @, -=_+
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
dsb ,,,,,
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
dsb 3.141
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type

@------------------------------------------------------------------------------
@ ISB
@------------------------------------------------------------------------------
isb #0x1f
@ CHECK: [[@LINE-1]]:{{.*}}: error: immediate value out of range
isb imaginary_domain

@ CHECK: error: immediate value out of range
@ CHECK: error: invalid operand for instruction
@ CHECK: [[@LINE-1]]:{{.*}}: error: invalid operand for instruction
isb [r0]
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
isb [], @, -=_+
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
isb ,,,,,
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
isb 3.141
@ CHECK: [[@LINE-1]]:{{.*}}: error: expected an immediate or barrier type
74 changes: 74 additions & 0 deletions llvm/test/MC/Disassembler/AMDGPU/gfx11_dasm_vinterp.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 5
# RUN: llvm-mc -triple=amdgcn -mcpu=gfx1100 -disassemble -show-encoding < %s | FileCheck -strict-whitespace -check-prefix=GFX11 %s

0x00,0x05,0x00,0xcd,0x01,0x05,0x0e,0x04
# GFX11: v_interp_p10_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x00,0xcd,0x01,0x05,0x0e,0x04]

0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x24
# GFX11: v_interp_p10_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x24]

0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x44
# GFX11: v_interp_p10_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x44]

0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x84
# GFX11: v_interp_p10_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x00,0xcd,0x01,0x05,0x0e,0x84]

0x00,0x05,0x01,0xcd,0x01,0x05,0x0e,0x04
# GFX11: v_interp_p2_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x01,0xcd,0x01,0x05,0x0e,0x04]

0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x24
# GFX11: v_interp_p2_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x24]

0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x44
# GFX11: v_interp_p2_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x44]

0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x84
# GFX11: v_interp_p2_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x01,0xcd,0x01,0x05,0x0e,0x84]

0x00,0x05,0x02,0xcd,0x01,0x05,0x0e,0x04
# GFX11: v_interp_p10_f16_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x02,0xcd,0x01,0x05,0x0e,0x04]

0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x24
# GFX11: v_interp_p10_f16_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x24]

0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x44
# GFX11: v_interp_p10_f16_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x44]

0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x84
# GFX11: v_interp_p10_f16_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x02,0xcd,0x01,0x05,0x0e,0x84]

0x00,0x05,0x03,0xcd,0x01,0x05,0x0e,0x04
# GFX11: v_interp_p2_f16_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x03,0xcd,0x01,0x05,0x0e,0x04]

0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x24
# GFX11: v_interp_p2_f16_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x24]

0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x44
# GFX11: v_interp_p2_f16_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x44]

0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x84
# GFX11: v_interp_p2_f16_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x03,0xcd,0x01,0x05,0x0e,0x84]

0x00,0x05,0x04,0xcd,0x01,0x05,0x0e,0x04
# GFX11: v_interp_p10_rtz_f16_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x04,0xcd,0x01,0x05,0x0e,0x04]

0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x24
# GFX11: v_interp_p10_rtz_f16_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x24]

0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x44
# GFX11: v_interp_p10_rtz_f16_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x44]

0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x84
# GFX11: v_interp_p10_rtz_f16_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x04,0xcd,0x01,0x05,0x0e,0x84]

0x00,0x05,0x05,0xcd,0x01,0x05,0x0e,0x04
# GFX11: v_interp_p2_rtz_f16_f32 v0, v1, v2, v3 wait_exp:5 ; encoding: [0x00,0x05,0x05,0xcd,0x01,0x05,0x0e,0x04]

0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x24
# GFX11: v_interp_p2_rtz_f16_f32 v0, -v1, v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x24]

0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x44
# GFX11: v_interp_p2_rtz_f16_f32 v0, v1, -v2, v3 wait_exp:0 ; encoding: [0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x44]

0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x84
# GFX11: v_interp_p2_rtz_f16_f32 v0, v1, v2, -v3 wait_exp:0 ; encoding: [0x00,0x00,0x05,0xcd,0x01,0x05,0x0e,0x84]
212 changes: 212 additions & 0 deletions llvm/test/Transforms/ConstraintElimination/trunc.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s

define i1 @test_icmp_ult_zext_icmp_trunc_nuw(i16 %x, i32 %y) {
; CHECK-LABEL: define i1 @test_icmp_ult_zext_icmp_trunc_nuw(
; CHECK-SAME: i16 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[EXT:%.*]] = zext i16 [[X]] to i32
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[Y]], [[EXT]]
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: [[CONV:%.*]] = trunc nuw i32 [[Y]] to i16
; CHECK-NEXT: ret i1 false
; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: ret i1 false
;
%ext = zext i16 %x to i32
%cond = icmp ult i32 %y, %ext
br i1 %cond, label %if.then, label %if.else

if.then:
%conv = trunc nuw i32 %y to i16
%cmp = icmp eq i16 %x, %conv
ret i1 %cmp

if.else:
ret i1 false
}

define i1 @test_icmp_slt_sext_icmp_trunc_nsw(i16 %x, i32 %y) {
; CHECK-LABEL: define i1 @test_icmp_slt_sext_icmp_trunc_nsw(
; CHECK-SAME: i16 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[EXT:%.*]] = sext i16 [[X]] to i32
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[Y]], [[EXT]]
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: [[CONV:%.*]] = trunc nsw i32 [[Y]] to i16
; CHECK-NEXT: ret i1 false
; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: ret i1 false
;
%ext = sext i16 %x to i32
%cond = icmp slt i32 %y, %ext
br i1 %cond, label %if.then, label %if.else

if.then:
%conv = trunc nsw i32 %y to i16
%cmp = icmp slt i16 %x, %conv
ret i1 %cmp

if.else:
ret i1 false
}

define i1 @test_icmp_ult_trunc_nsw_nneg_icmp_trunc_nuw(i64 %x, i32 %y) {
; CHECK-LABEL: define i1 @test_icmp_ult_trunc_nsw_nneg_icmp_trunc_nuw(
; CHECK-SAME: i64 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[EXT:%.*]] = trunc nsw i64 [[X]] to i32
; CHECK-NEXT: [[NNEG:%.*]] = icmp sgt i64 [[X]], -1
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[Y]], [[EXT]]
; CHECK-NEXT: [[AND:%.*]] = and i1 [[NNEG]], [[COND]]
; CHECK-NEXT: br i1 [[AND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: [[CONV:%.*]] = zext i32 [[Y]] to i64
; CHECK-NEXT: ret i1 false
; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: ret i1 false
;
%ext = trunc nsw i64 %x to i32
%nneg = icmp sgt i64 %x, -1
%cond = icmp ult i32 %y, %ext
%and = and i1 %nneg, %cond
br i1 %and, label %if.then, label %if.else

if.then:
%conv = zext i32 %y to i64
%cmp = icmp eq i64 %x, %conv
ret i1 %cmp

if.else:
ret i1 false
}

define i1 @test2(i32 %n) {
; CHECK-LABEL: define i1 @test2(
; CHECK-SAME: i32 [[N:%.*]]) {
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[N]], 0
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: [[EXT:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT: [[END:%.*]] = add nsw i64 [[EXT]], -1
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[INDVAR:%.*]] = phi i64 [ 0, %[[IF_THEN]] ], [ [[INDVAR_NEXT:%.*]], %[[FOR_NEXT:.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[INDVAR]], [[END]]
; CHECK-NEXT: br i1 [[CMP]], label %[[IF_ELSE]], label %[[FOR_NEXT]]
; CHECK: [[FOR_NEXT]]:
; CHECK-NEXT: [[INDVAR_NEXT]] = add nuw nsw i64 [[INDVAR]], 1
; CHECK-NEXT: [[COND2:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[COND2]], label %[[FOR_BODY]], label %[[FOR_END:.*]]
; CHECK: [[FOR_END]]:
; CHECK-NEXT: [[TRUNC:%.*]] = trunc nsw i64 [[INDVAR_NEXT]] to i32
; CHECK-NEXT: ret i1 true
; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: ret i1 false
;
%cond = icmp sgt i32 %n, 0
br i1 %cond, label %if.then, label %if.else

if.then:
%ext = zext nneg i32 %n to i64
%end = add nsw i64 %ext, -1
br label %for.body

for.body:
%indvar = phi i64 [ 0, %if.then ], [ %indvar.next, %for.next ]
%cmp = icmp eq i64 %indvar, %end
br i1 %cmp, label %if.else, label %for.next

for.next:
%indvar.next = add nuw nsw i64 %indvar, 1
%cond2 = call i1 @cond()
br i1 %cond2, label %for.body, label %for.end

for.end:
%trunc = trunc nsw i64 %indvar.next to i32
%res = icmp sgt i32 %n, %trunc
ret i1 %res

if.else:
ret i1 false
}

define i1 @test_icmp_ult_zext_icmp_trunc(i16 %x, i32 %y) {
; CHECK-LABEL: define i1 @test_icmp_ult_zext_icmp_trunc(
; CHECK-SAME: i16 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[EXT:%.*]] = zext i16 [[X]] to i32
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[Y]], [[EXT]]
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: [[CONV:%.*]] = trunc i32 [[Y]] to i16
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[X]], [[CONV]]
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: ret i1 false
;
%ext = zext i16 %x to i32
%cond = icmp ult i32 %y, %ext
br i1 %cond, label %if.then, label %if.else

if.then:
%conv = trunc i32 %y to i16
%cmp = icmp eq i16 %x, %conv
ret i1 %cmp

if.else:
ret i1 false
}

define i1 @test_icmp_ult_zext_icmp_trunc_nuw_i128(i16 %x, i128 %y) {
; CHECK-LABEL: define i1 @test_icmp_ult_zext_icmp_trunc_nuw_i128(
; CHECK-SAME: i16 [[X:%.*]], i128 [[Y:%.*]]) {
; CHECK-NEXT: [[EXT:%.*]] = zext i16 [[X]] to i128
; CHECK-NEXT: [[COND:%.*]] = icmp ult i128 [[Y]], [[EXT]]
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: [[CONV:%.*]] = trunc nuw i128 [[Y]] to i16
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[X]], [[CONV]]
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: ret i1 false
;
%ext = zext i16 %x to i128
%cond = icmp ult i128 %y, %ext
br i1 %cond, label %if.then, label %if.else

if.then:
%conv = trunc nuw i128 %y to i16
%cmp = icmp eq i16 %x, %conv
ret i1 %cmp

if.else:
ret i1 false
}

; We do not know the sign of %x, so we cannot infer nuw for %ext.
define i1 @test_icmp_ult_trunc_nsw_icmp_trunc_nuw(i64 %x, i32 %y) {
; CHECK-LABEL: define i1 @test_icmp_ult_trunc_nsw_icmp_trunc_nuw(
; CHECK-SAME: i64 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[EXT:%.*]] = trunc nsw i64 [[X]] to i32
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[Y]], [[EXT]]
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CHECK: [[IF_THEN]]:
; CHECK-NEXT: [[CONV:%.*]] = zext i32 [[Y]] to i64
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X]], [[CONV]]
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK: [[IF_ELSE]]:
; CHECK-NEXT: ret i1 false
;
%ext = trunc nsw i64 %x to i32
%cond = icmp ult i32 %y, %ext
br i1 %cond, label %if.then, label %if.else

if.then:
%conv = zext i32 %y to i64
%cmp = icmp eq i64 %x, %conv
ret i1 %cmp

if.else:
ret i1 false
}

declare void @cond()
Loading