From 00c113acf374d292de96871328bed981aae153a5 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sun, 16 Feb 2025 00:58:57 +0000 Subject: [PATCH 01/16] [MC] Rework .chericap to support expressions that can fold to sym+const Currently we require the expression to be sym+const, where the constant is a known parse-time constant. However, that prevents the use of symbol difference expressions for the constant, something which LLVM does itself emit and so cannot round-trip through assembly. Rework the implementation to look more like nromal data directives. At parse time, any expression can be used, which will then get folded as normal, giving an error later if it could not be folded into a relocatable expression. This also requires taking care to preserve the provenance within such expressions. --- llvm/include/llvm/MC/MCAsmBackend.h | 4 ++ llvm/include/llvm/MC/MCExpr.h | 9 +-- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 +- llvm/lib/MC/MCAsmInfo.cpp | 2 +- llvm/lib/MC/MCAssembler.cpp | 5 +- llvm/lib/MC/MCExpr.cpp | 62 +++++++++++++------ llvm/lib/MC/MCMachOStreamer.cpp | 2 +- llvm/lib/MC/MCObjectStreamer.cpp | 6 +- llvm/lib/MC/MCObjectWriter.cpp | 1 + llvm/lib/MC/MCParser/AsmParser.cpp | 18 +++--- llvm/lib/MC/MachObjectWriter.cpp | 2 +- .../AArch64/AsmParser/AArch64AsmParser.cpp | 2 +- .../AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp | 2 +- .../AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp | 10 +-- .../AMDGPU/Utils/AMDGPUDelayedMCExpr.cpp | 5 +- .../ARM/MCTargetDesc/ARMMachObjectWriter.cpp | 2 +- .../Target/AVR/MCTargetDesc/AVRMCAsmInfo.cpp | 5 +- .../Hexagon/AsmParser/HexagonAsmParser.cpp | 2 +- .../Hexagon/MCTargetDesc/HexagonMCExpr.cpp | 2 +- .../AsmParser/LoongArchAsmParser.cpp | 2 +- .../MCTargetDesc/LoongArchAsmBackend.cpp | 2 +- .../Target/Mips/AsmParser/MipsAsmParser.cpp | 12 ++-- .../Mips/MCTargetDesc/MipsAsmBackend.cpp | 4 +- .../Target/Mips/MCTargetDesc/MipsAsmBackend.h | 4 ++ .../Mips/MCTargetDesc/MipsMCAsmInfo.cpp | 8 +-- .../Target/Mips/MCTargetDesc/MipsMCAsmInfo.h | 1 - .../Mips/MCTargetDesc/MipsMCCodeEmitter.cpp | 4 -- .../PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp | 4 +- .../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 4 +- .../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 18 +++++- .../RISCV/MCTargetDesc/RISCVAsmBackend.h | 4 ++ .../SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp | 2 +- .../Target/VE/MCTargetDesc/VEMCAsmInfo.cpp | 2 +- .../X86/MCTargetDesc/X86MachObjectWriter.cpp | 2 +- .../CodeGen/Mips/cheri/exception-table.cpp | 4 +- .../MC/Mips/cheri/chericap-expr-invalid.s | 13 ++++ llvm/test/MC/Mips/cheri/chericap-expr.s | 32 ++++++++++ .../MC/RISCV/cheri/chericap-expr-invalid.s | 14 +++++ llvm/test/MC/RISCV/cheri/chericap-expr.s | 32 ++++++++++ 39 files changed, 225 insertions(+), 86 deletions(-) create mode 100644 llvm/test/MC/Mips/cheri/chericap-expr-invalid.s create mode 100644 llvm/test/MC/Mips/cheri/chericap-expr.s create mode 100644 llvm/test/MC/RISCV/cheri/chericap-expr-invalid.s create mode 100644 llvm/test/MC/RISCV/cheri/chericap-expr.s diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h index 6b81bdba25e67..833c2b9c0f801 100644 --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -85,6 +85,10 @@ class LLVM_ABI MCAsmBackend { /// lifetime management virtual void reset() {} + virtual bool fixupNeedsProvenance(const MCFixup *Fixup) const { + return false; + } + /// Create a new MCObjectWriter instance for use by the assembler backend to /// emit the final object file. std::unique_ptr diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h index d040fa337accf..bccea6c9bfd5c 100644 --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -71,7 +71,8 @@ class MCExpr { } LLVM_ABI bool evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, - bool InSet) const; + bool InSet, + bool FixupNeedsProvenance) const; unsigned getSubclassData() const { return SubclassData; } @@ -115,8 +116,8 @@ class MCExpr { /// \param Res - The relocatable value, if evaluation succeeds. /// \param Asm - The assembler object to use for evaluating values. /// \return - True on success. - LLVM_ABI bool evaluateAsRelocatable(MCValue &Res, - const MCAssembler *Asm) const; + LLVM_ABI bool evaluateAsRelocatable(MCValue &Res, const MCAssembler *Asm, + bool FixupNeedsProvenance) const; /// Try to evaluate the expression to the form (a - b + constant) where /// neither a nor b are variables. @@ -133,7 +134,7 @@ class MCExpr { /// @} - LLVM_ABI static bool evaluateSymbolicAdd(const MCAssembler *, bool, + LLVM_ABI static bool evaluateSymbolicAdd(const MCAssembler *, bool, bool, const MCValue &, const MCValue &, MCValue &); }; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index ccd8b7172de89..87ad6d4607f3c 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -4059,7 +4059,7 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME, // cstexpr := - + gotpcrelcst, where // gotpcrelcst := + MCValue MV; - if (!(*ME)->evaluateAsRelocatable(MV, nullptr) || MV.isAbsolute()) + if (!(*ME)->evaluateAsRelocatable(MV, nullptr, false) || MV.isAbsolute()) return; const MCSymbol *GOTEquivSym = MV.getAddSym(); if (!GOTEquivSym) diff --git a/llvm/lib/MC/MCAsmInfo.cpp b/llvm/lib/MC/MCAsmInfo.cpp index 19032634f43d7..0a5243397c6e5 100644 --- a/llvm/lib/MC/MCAsmInfo.cpp +++ b/llvm/lib/MC/MCAsmInfo.cpp @@ -160,7 +160,7 @@ void MCAsmInfo::printExpr(raw_ostream &OS, const MCExpr &Expr) const { bool MCAsmInfo::evaluateAsRelocatableImpl(const MCSpecifierExpr &E, MCValue &Res, const MCAssembler *Asm) const { - if (!E.getSubExpr()->evaluateAsRelocatable(Res, Asm)) + if (!E.getSubExpr()->evaluateAsRelocatable(Res, Asm, false)) return false; Res.setSpecifier(E.getSpecifier()); diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index fd8a8c3a79c9f..15b8500b68139 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -124,7 +124,7 @@ bool MCAssembler::isThumbFunc(const MCSymbol *Symbol) const { const MCExpr *Expr = Symbol->getVariableValue(); MCValue V; - if (!Expr->evaluateAsRelocatable(V, nullptr)) + if (!Expr->evaluateAsRelocatable(V, nullptr, false)) return false; if (V.getSubSym() || V.getSpecifier()) @@ -155,7 +155,8 @@ bool MCAssembler::evaluateFixup(const MCFragment &F, MCFixup &Fixup, // further processing from being done. const MCExpr *Expr = Fixup.getValue(); Value = 0; - if (!Expr->evaluateAsRelocatable(Target, this)) { + if (!Expr->evaluateAsRelocatable(Target, this, + getBackend().fixupNeedsProvenance(&Fixup))) { reportError(Fixup.getLoc(), "expected relocatable expression"); return true; } diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp index ae54ce87d5957..9a113c4ef7096 100644 --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -262,7 +262,8 @@ bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, return true; } - bool IsRelocatable = evaluateAsRelocatableImpl(Value, Asm, InSet); + bool IsRelocatable = evaluateAsRelocatableImpl( + Value, Asm, InSet, /*FixupNeedsProvenance=*/false); Res = Value.getConstant(); // Value with RefKind (e.g. %hi(0xdeadbeef) in MIPS) is not considered // absolute (the value is unknown at parse time), even if it might be resolved @@ -274,7 +275,8 @@ bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, bool InSet, const MCSymbol *&A, const MCSymbol *&B, - int64_t &Addend) { + int64_t &Addend, + bool FixupNeedsProvenance) { if (!A || !B) return; @@ -309,7 +311,7 @@ static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, // linker-relaxable instruction and InSet is false (not expressions in // directive like .size/.fill), disable the fast path. bool Layout = Asm->hasLayout(); - if (Layout && (InSet || !SecA.isLinkerRelaxable())) { + if (Layout && (InSet || !SecA.isLinkerRelaxable() || FixupNeedsProvenance)) { // If both symbols are in the same fragment, return the difference of their // offsets. canGetFragmentOffset(FA) may be false. if (FA == FB && !SA.isVariable() && !SB.isVariable()) { @@ -415,8 +417,8 @@ static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, // streamer for example) and having the Asm argument lets us avoid relaxations // early. bool MCExpr::evaluateSymbolicAdd(const MCAssembler *Asm, bool InSet, - const MCValue &LHS, const MCValue &RHS, - MCValue &Res) { + bool FixupNeedsProvenance, const MCValue &LHS, + const MCValue &RHS, MCValue &Res) { const MCSymbol *LHS_A = LHS.getAddSym(); const MCSymbol *LHS_B = LHS.getSubSym(); int64_t LHS_Cst = LHS.getConstant(); @@ -430,15 +432,31 @@ bool MCExpr::evaluateSymbolicAdd(const MCAssembler *Asm, bool InSet, // If we have a layout, we can fold resolved differences. if (Asm && !LHS.getSpecifier() && !RHS.getSpecifier()) { + // If we have exactly one symbol on one side then that side represents a + // pointer, otherwise it represents an integer (a constant and a possible + // symbol difference). Similarly, if exactly one side represents a pointer + // then the whole addition represents a pointer, otherwise it represents an + // integer. + bool LHS_Provenance = (LHS_A == nullptr) != (LHS_B == nullptr); + bool RHS_Provenance = (RHS_A == nullptr) != (RHS_B == nullptr); + bool FoldCrossTerms = + !FixupNeedsProvenance || LHS_Provenance == RHS_Provenance; + // While LHS_A-LHS_B and RHS_A-RHS_B from recursive calls have already been // folded, reassociating terms in // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). // might bring more opportunities. - if (LHS_A && RHS_B) { - attemptToFoldSymbolOffsetDifference(Asm, InSet, LHS_A, RHS_B, Result_Cst); + attemptToFoldSymbolOffsetDifference(Asm, InSet, LHS_A, LHS_B, Result_Cst, + FixupNeedsProvenance); + if (FoldCrossTerms && LHS_A && RHS_B) { + attemptToFoldSymbolOffsetDifference(Asm, InSet, LHS_A, RHS_B, Result_Cst, + FixupNeedsProvenance); } - if (RHS_A && LHS_B) { - attemptToFoldSymbolOffsetDifference(Asm, InSet, RHS_A, LHS_B, Result_Cst); + attemptToFoldSymbolOffsetDifference(Asm, InSet, RHS_A, LHS_B, Result_Cst, + FixupNeedsProvenance); + if (FoldCrossTerms && RHS_A && LHS_B) { + attemptToFoldSymbolOffsetDifference(Asm, InSet, RHS_A, RHS_B, Result_Cst, + FixupNeedsProvenance); } } @@ -457,15 +475,17 @@ bool MCExpr::evaluateSymbolicAdd(const MCAssembler *Asm, bool InSet, return true; } -bool MCExpr::evaluateAsRelocatable(MCValue &Res, const MCAssembler *Asm) const { - return evaluateAsRelocatableImpl(Res, Asm, false); +bool MCExpr::evaluateAsRelocatable(MCValue &Res, const MCAssembler *Asm, + bool FixupNeedsProvenance) const { + return evaluateAsRelocatableImpl(Res, Asm, false, FixupNeedsProvenance); } bool MCExpr::evaluateAsValue(MCValue &Res, const MCAssembler &Asm) const { - return evaluateAsRelocatableImpl(Res, &Asm, true); + return evaluateAsRelocatableImpl(Res, &Asm, true, false); } bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, - bool InSet) const { + bool InSet, + bool FixupNeedsProvenance) const { ++stats::MCExprEvaluate; switch (getKind()) { case Target: @@ -498,8 +518,8 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, auto _ = make_scope_exit([&] { Sym.setIsResolving(false); }); bool IsMachO = Asm && Asm->getContext().getAsmInfo()->hasSubsectionsViaSymbols(); - if (!Sym.getVariableValue()->evaluateAsRelocatableImpl(Res, Asm, - InSet || IsMachO)) + if (!Sym.getVariableValue()->evaluateAsRelocatableImpl( + Res, Asm, InSet || IsMachO, FixupNeedsProvenance)) return false; // When generating relocations, if Sym resolves to a symbol relative to a // section, relocations are generated against Sym. Treat label differences @@ -546,7 +566,8 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, const MCUnaryExpr *AUE = cast(this); MCValue Value; - if (!AUE->getSubExpr()->evaluateAsRelocatableImpl(Value, Asm, InSet)) + if (!AUE->getSubExpr()->evaluateAsRelocatableImpl(Value, Asm, InSet, + FixupNeedsProvenance)) return false; switch (AUE->getOpcode()) { case MCUnaryExpr::LNot: @@ -580,8 +601,10 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, const MCBinaryExpr *ABE = cast(this); MCValue LHSValue, RHSValue; - if (!ABE->getLHS()->evaluateAsRelocatableImpl(LHSValue, Asm, InSet) || - !ABE->getRHS()->evaluateAsRelocatableImpl(RHSValue, Asm, InSet)) { + if (!ABE->getLHS()->evaluateAsRelocatableImpl(LHSValue, Asm, InSet, + FixupNeedsProvenance) || + !ABE->getRHS()->evaluateAsRelocatableImpl(RHSValue, Asm, InSet, + FixupNeedsProvenance)) { // Check if both are Target Expressions, see if we can compare them. if (const MCTargetExpr *L = dyn_cast(ABE->getLHS())) { if (const MCTargetExpr *R = dyn_cast(ABE->getRHS())) { @@ -628,7 +651,8 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, return false; if (RHSValue.SymB && RHSValue.Specifier) return false; - return evaluateSymbolicAdd(Asm, InSet, LHSValue, RHSValue, Res); + return evaluateSymbolicAdd(Asm, InSet, FixupNeedsProvenance, LHSValue, + RHSValue, Res); } } diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index 1068365b283a4..664c59c99ba65 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -180,7 +180,7 @@ void MCMachOStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { void MCMachOStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) { MCValue Res; - if (Value->evaluateAsRelocatable(Res, nullptr)) { + if (Value->evaluateAsRelocatable(Res, nullptr, false)) { if (const auto *SymA = Res.getAddSym()) { if (!Res.getSubSym() && (SymA->getName().empty() || Res.getConstant() != 0)) diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index d9c39bbedf37c..ab1d25ebcc739 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -626,7 +626,8 @@ getOffsetAndDataFragment(const MCSymbol &Symbol, uint32_t &RelocOffset, if (Symbol.isVariable()) { const MCExpr *SymbolExpr = Symbol.getVariableValue(); MCValue OffsetVal; - if (!SymbolExpr->evaluateAsRelocatable(OffsetVal, nullptr)) + if (!SymbolExpr->evaluateAsRelocatable(OffsetVal, nullptr, + /*FixupNeedsProvenance=*/false)) return std::make_pair(false, std::string("symbol in .reloc offset is not " "relocatable")); @@ -700,7 +701,8 @@ MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name, MCDataFragment *DF = getOrCreateDataFragment(&STI); MCValue OffsetVal; - if (!Offset.evaluateAsRelocatable(OffsetVal, nullptr)) + if (!Offset.evaluateAsRelocatable(OffsetVal, nullptr, + /*FixupNeedsProvenance=*/false)) return std::make_pair(false, std::string(".reloc offset is not relocatable")); if (OffsetVal.isAbsolute()) { diff --git a/llvm/lib/MC/MCObjectWriter.cpp b/llvm/lib/MC/MCObjectWriter.cpp index 7cbd0b489d9f6..d6d0747da8433 100644 --- a/llvm/lib/MC/MCObjectWriter.cpp +++ b/llvm/lib/MC/MCObjectWriter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 3816d424a68bc..a7aea843aa3e6 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -3120,7 +3120,8 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { return true; MCValue Value; - if (!Expr->evaluateAsRelocatable(Value, nullptr)) + if (!Expr->evaluateAsRelocatable(Value, nullptr, + /*FixupNeedsProvenance=*/false)) return Error(ExprLoc, "expression must be relocatable"); } @@ -5835,27 +5836,28 @@ bool AsmParser::parseDirectiveAddrsigSym() { } /// parseDirectiveCheriCap -/// ::= .chericap sym[+off] +/// ::= .chericap expression bool AsmParser::parseDirectiveCheriCap(SMLoc DirectiveLoc) { - const MCExpr *SymExpr; + const MCExpr *Expr; SMLoc ExprLoc = getLexer().getLoc(); if (!getTargetParser().isCheri()) return Error(DirectiveLoc, "'.chericap' requires CHERI"); - if (parseExpression(SymExpr)) + if (parseExpression(Expr)) return true; - int64_t Offset = 0; + int64_t Value; unsigned CapSize = getTargetParser().getCheriCapabilitySize(); // Allow .chericap 0x123456 to create an untagged uintcap_t - if (SymExpr->evaluateAsAbsolute(Offset, getStreamer().getAssemblerPtr())) - getStreamer().emitCheriIntcap(Offset, CapSize, ExprLoc); + if (Expr->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) + getStreamer().emitCheriIntcap(Value, CapSize, ExprLoc); else - getStreamer().emitCheriCapability(SymExpr, CapSize, ExprLoc); + getStreamer().emitCheriCapability(Expr, CapSize, ExprLoc); if (parseToken(AsmToken::EndOfStatement, "expected end of statement")) return true; + return false; } diff --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp index fb8e1fdf62f50..3f12414681560 100644 --- a/llvm/lib/MC/MachObjectWriter.cpp +++ b/llvm/lib/MC/MachObjectWriter.cpp @@ -99,7 +99,7 @@ uint64_t MachObjectWriter::getSymbolAddress(const MCSymbol &S) const { return C->getValue(); MCValue Target; - if (!S.getVariableValue()->evaluateAsRelocatable(Target, Asm)) + if (!S.getVariableValue()->evaluateAsRelocatable(Target, Asm, false)) report_fatal_error("unable to evaluate offset for variable '" + S.getName() + "'"); diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 1ca61f5c6b349..1bf8a97f6d92e 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -8293,7 +8293,7 @@ bool AArch64AsmParser::classifySymbolRef(const MCExpr *Expr, // Check that it looks like a symbol + an addend MCValue Res; - bool Relocatable = Expr->evaluateAsRelocatable(Res, nullptr); + bool Relocatable = Expr->evaluateAsRelocatable(Res, nullptr, false); if (!Relocatable || Res.getSubSym()) return false; diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp index 828c5c5462407..979d02f7990f8 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp @@ -121,7 +121,7 @@ StringRef AArch64::getSpecifierName(const MCSpecifierExpr &Expr) { static bool evaluate(const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) { - if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm)) + if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm, false)) return false; Res.setSpecifier(Expr.getSpecifier()); return true; diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp index 6638fa2f687d8..acca2a628e1fc 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp @@ -99,7 +99,7 @@ bool AMDGPUMCExpr::evaluateExtraSGPRs(MCValue &Res, const MCAssembler *Asm) const { auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { MCValue MCVal; - if (!Arg->evaluateAsRelocatable(MCVal, Asm) || !MCVal.isAbsolute()) + if (!Arg->evaluateAsRelocatable(MCVal, Asm, false) || !MCVal.isAbsolute()) return false; ConstantValue = MCVal.getConstant(); @@ -128,7 +128,7 @@ bool AMDGPUMCExpr::evaluateTotalNumVGPR(MCValue &Res, const MCAssembler *Asm) const { auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { MCValue MCVal; - if (!Arg->evaluateAsRelocatable(MCVal, Asm) || !MCVal.isAbsolute()) + if (!Arg->evaluateAsRelocatable(MCVal, Asm, false) || !MCVal.isAbsolute()) return false; ConstantValue = MCVal.getConstant(); @@ -154,7 +154,7 @@ bool AMDGPUMCExpr::evaluateTotalNumVGPR(MCValue &Res, bool AMDGPUMCExpr::evaluateAlignTo(MCValue &Res, const MCAssembler *Asm) const { auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { MCValue MCVal; - if (!Arg->evaluateAsRelocatable(MCVal, Asm) || !MCVal.isAbsolute()) + if (!Arg->evaluateAsRelocatable(MCVal, Asm, false) || !MCVal.isAbsolute()) return false; ConstantValue = MCVal.getConstant(); @@ -175,7 +175,7 @@ bool AMDGPUMCExpr::evaluateOccupancy(MCValue &Res, const MCAssembler *Asm) const { auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) { MCValue MCVal; - if (!Arg->evaluateAsRelocatable(MCVal, Asm) || !MCVal.isAbsolute()) + if (!Arg->evaluateAsRelocatable(MCVal, Asm, false) || !MCVal.isAbsolute()) return false; ConstantValue = MCVal.getConstant(); @@ -263,7 +263,7 @@ bool AMDGPUMCExpr::evaluateAsRelocatableImpl(MCValue &Res, for (const MCExpr *Arg : Args) { MCValue ArgRes; - if (!Arg->evaluateAsRelocatable(ArgRes, Asm) || !ArgRes.isAbsolute()) + if (!Arg->evaluateAsRelocatable(ArgRes, Asm, false) || !ArgRes.isAbsolute()) return false; if (!Total.has_value()) diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUDelayedMCExpr.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUDelayedMCExpr.cpp index 6e37750380718..61cb1d255e7f9 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUDelayedMCExpr.cpp +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUDelayedMCExpr.cpp @@ -30,7 +30,7 @@ static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, void DelayedMCExprs::assignDocNode(msgpack::DocNode &DN, msgpack::Type Type, const MCExpr *ExprValue) { MCValue Res; - if (ExprValue->evaluateAsRelocatable(Res, nullptr)) { + if (ExprValue->evaluateAsRelocatable(Res, nullptr, false)) { if (Res.isAbsolute()) { DN = getNode(DN, Type, Res); return; @@ -45,7 +45,8 @@ bool DelayedMCExprs::resolveDelayedExpressions() { Expr DE = DelayedExprs.front(); MCValue Res; - if (!DE.ExprValue->evaluateAsRelocatable(Res, nullptr) || !Res.isAbsolute()) + if (!DE.ExprValue->evaluateAsRelocatable(Res, nullptr, false) || + !Res.isAbsolute()) return false; DelayedExprs.pop_front(); diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp index 354de8fd7b4bb..c1a51c4a24601 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp @@ -414,7 +414,7 @@ void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer, if (A->isVariable()) { MCValue Val; bool Relocatable = - A->getVariableValue()->evaluateAsRelocatable(Val, &Asm); + A->getVariableValue()->evaluateAsRelocatable(Val, &Asm, false); int64_t Res = Val.getConstant(); bool isAbs = Val.isAbsolute(); if (Relocatable && Val.getAddSym() && Val.getSubSym()) { diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCAsmInfo.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCAsmInfo.cpp index c2c1bb4e5baee..f1cdb1a9902e3 100644 --- a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCAsmInfo.cpp +++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCAsmInfo.cpp @@ -184,7 +184,7 @@ bool AVRMCAsmInfo::evaluateAsRelocatableImpl(const MCSpecifierExpr &Expr, const MCAssembler *Asm) const { auto &E = static_cast(Expr); MCValue Value; - bool isRelocatable = E.getSubExpr()->evaluateAsRelocatable(Value, Asm); + bool isRelocatable = E.getSubExpr()->evaluateAsRelocatable(Value, Asm, false); if (!isRelocatable) return false; @@ -211,7 +211,8 @@ bool AVRMCAsmInfo::evaluateAsRelocatableImpl(const MCSpecifierExpr &Expr, bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const { MCValue Value; - bool isRelocatable = getSubExpr()->evaluateAsRelocatable(Value, nullptr); + bool isRelocatable = + getSubExpr()->evaluateAsRelocatable(Value, nullptr, false); if (!isRelocatable) return false; diff --git a/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp b/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp index af60f24e626c8..042a485353130 100644 --- a/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp +++ b/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp @@ -1255,7 +1255,7 @@ bool HexagonAsmParser::parseInstruction(OperandVector &Operands) { Expr, MCConstantExpr::create(0xffff, Context), Context); } else { MCValue Value; - if (Expr->evaluateAsRelocatable(Value, nullptr)) { + if (Expr->evaluateAsRelocatable(Value, nullptr, false)) { if (!Value.isAbsolute()) { switch (HexagonMCExpr::VariantKind(Value.getSpecifier())) { case HexagonMCExpr::VK_TPREL: diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.cpp index d96e9601bf9e4..645f37e4c29ac 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.cpp @@ -24,7 +24,7 @@ HexagonMCExpr *HexagonMCExpr::create(MCExpr const *Expr, MCContext &Ctx) { bool HexagonMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm) const { - return Expr->evaluateAsRelocatable(Res, Asm); + return Expr->evaluateAsRelocatable(Res, Asm, /*FixupNeedsProvenance=*/false); } void HexagonMCExpr::visitUsedExpr(MCStreamer &Streamer) const { diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp index 5be4713b349ee..be311eefbb817 100644 --- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp +++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp @@ -690,7 +690,7 @@ bool LoongArchAsmParser::classifySymbolRef(const MCExpr *Expr, } MCValue Res; - if (Expr->evaluateAsRelocatable(Res, nullptr)) + if (Expr->evaluateAsRelocatable(Res, nullptr, false)) return Res.getSpecifier() == LoongArchMCExpr::VK_None; return false; } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp index 3dbf7683cdade..1d727647dea63 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp @@ -441,7 +441,7 @@ bool LoongArchAsmBackend::isPCRelFixupResolved(const MCSymbol *SymA, PCRelTemp = getContext().createTempSymbol(); PCRelTemp->setFragment(const_cast(&F)); MCValue Res; - MCExpr::evaluateSymbolicAdd(Asm, false, MCValue::get(SymA), + MCExpr::evaluateSymbolicAdd(Asm, false, false, MCValue::get(SymA), MCValue::get(nullptr, PCRelTemp), Res); return !Res.getSubSym(); } diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 766012bc1e038..14730664069ba 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -610,7 +610,7 @@ class MipsAsmParser : public MCTargetAsmParser { if (!EmitJalrReloc) return false; MCValue Res; - if (!JalExpr->evaluateAsRelocatable(Res, nullptr)) + if (!JalExpr->evaluateAsRelocatable(Res, nullptr, false)) return false; if (Res.getSubSym()) return false; @@ -1399,7 +1399,7 @@ class MipsOperand : public MCParsedAsmOperand { isShiftedInt(getConstantMemOff()))) return true; MCValue Res; - bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr); + bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, false); return IsReloc && isShiftedInt(Res.getConstant()); } @@ -1413,7 +1413,7 @@ class MipsOperand : public MCParsedAsmOperand { (isConstantMemOff() && isIntN(PtrBits, getConstantMemOff()))) return true; MCValue Res; - bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr); + bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, false); return IsReloc && isIntN(PtrBits, Res.getConstant()); } @@ -1457,7 +1457,7 @@ class MipsOperand : public MCParsedAsmOperand { MCValue Res; // FIXME: it would be nice to somehow get at the MCFixup here and check the // size using MCAsmBackend::getFixupKindInfo() - bool Success = getImm()->evaluateAsRelocatable(Res, nullptr); + bool Success = getImm()->evaluateAsRelocatable(Res, nullptr, false); // FIXME: how can we get at the MCFixup object (to check size generically)? if (auto Expr = dyn_cast(getImm())) { // HACK: Check that only %captab and %capcall are allowed in clc / csc @@ -3244,7 +3244,7 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr, if (inPicMode()) { MCValue Res; - if (!SymExpr->evaluateAsRelocatable(Res, nullptr)) { + if (!SymExpr->evaluateAsRelocatable(Res, nullptr, false)) { Error(IDLoc, "expected relocatable expression"); return true; } @@ -4101,7 +4101,7 @@ void MipsAsmParser::expandMem16Inst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, // of R_MIPS_GOT_DISP in appropriate cases to reduce number // of GOT entries. MCValue Res; - if (!OffsetOp.getExpr()->evaluateAsRelocatable(Res, nullptr)) { + if (!OffsetOp.getExpr()->evaluateAsRelocatable(Res, nullptr, false)) { Error(IDLoc, "expected relocatable expression"); return; } diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp index 2b1074d4dd83f..efe843cfe4ae2 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -558,7 +558,7 @@ MCFixupKindInfo MipsAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { { "fixup_CHERI_CAPTAB_TLSLDM_LO16", 0, 16, 0 }, { "fixup_CHERI_CAPTAB_TPREL_HI16", 0, 16, 0 }, { "fixup_CHERI_CAPTAB_TPREL_LO16", 0, 16, 0 }, - // clang-format on + // clang-format on }; static_assert(std::size(LittleEndianInfos) == Mips::NumTargetFixupKinds, "Not all MIPS little endian fixup kinds added!"); @@ -665,7 +665,7 @@ MCFixupKindInfo MipsAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { { "fixup_CHERI_CAPTAB_TLSLDM_LO16", 16, 16, 0 }, { "fixup_CHERI_CAPTAB_TPREL_HI16", 16, 16, 0 }, { "fixup_CHERI_CAPTAB_TPREL_LO16", 16, 16, 0 }, - // clang-format on + // clang-format on }; static_assert(std::size(BigEndianInfos) == Mips::NumTargetFixupKinds, "Not all MIPS big endian fixup kinds added!"); diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h index 816626da723af..6e4eac25daa96 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -48,6 +48,10 @@ class MipsAsmBackend : public MCAsmBackend { bool writeNopData(raw_ostream &OS, uint64_t Count, const MCSubtargetInfo *STI) const override; + + bool fixupNeedsProvenance(const MCFixup *Fixup) const override { + return Fixup->getKind() == Mips::fixup_CHERI_CAPABILITY; + } }; // class MipsAsmBackend } // namespace diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp index c596db6a8f287..33575507e29a8 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -187,10 +187,6 @@ static void printImpl(const MCAsmInfo &MAI, raw_ostream &OS, case Mips::S_CAPCALL_LO16: OS << "%capcall_lo"; break; - case Mips::S_CHERI_CAP: - // FIXME: should we really end up here? - OS << "%chericap"; - break; case Mips::S_CAPTABLEREL: OS << "%captab_rel"; break; @@ -255,14 +251,14 @@ static bool evaluate(const MCSpecifierExpr &Expr, MCValue &Res, cast( cast(Expr.getSubExpr())->getSubExpr()) ->getSubExpr(); - if (!SubExpr->evaluateAsRelocatable(Res, Asm)) + if (!SubExpr->evaluateAsRelocatable(Res, Asm, false)) return false; Res.setSpecifier(Mips::S_Special); return true; } - if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm)) + if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm, false)) return false; Res.setSpecifier(Expr.getSpecifier()); return !Res.getSubSym(); diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h index 667cad9bfb031..70ad315e2341b 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h @@ -82,7 +82,6 @@ enum { S_CAPCALL_LO16, S_CAPCALL20, - S_CHERI_CAP, // Like GPREL but the offset from _CHERI_CAPABILITY_TABLE_ to symbol S_CAPTABLEREL, diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index 0e85a368cf21d..efa06fbd7da12 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -752,10 +752,6 @@ getExprOpValue(const MCExpr *Expr, SmallVectorImpl &Fixups, case Mips::S_CAPTAB_TPREL_LO16: FixupKind = Mips::fixup_CHERI_CAPTAB_TPREL_LO16; break; - - case Mips::S_CHERI_CAP: - FixupKind = Mips::fixup_CHERI_CAPABILITY; - break; } addFixup(Fixups, 0, MipsExpr, MCFixupKind(FixupKind)); return 0; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp index 8baf866549e4e..d4c1a2ff2c23b 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp @@ -138,7 +138,7 @@ static std::optional evaluateAsInt64(uint16_t specifier, bool PPC::evaluateAsConstant(const MCSpecifierExpr &Expr, int64_t &Res) { MCValue Value; - if (!Expr.getSubExpr()->evaluateAsRelocatable(Value, nullptr)) + if (!Expr.getSubExpr()->evaluateAsRelocatable(Value, nullptr, false)) return false; if (!Value.isAbsolute()) @@ -152,7 +152,7 @@ bool PPC::evaluateAsConstant(const MCSpecifierExpr &Expr, int64_t &Res) { static bool evaluateAsRelocatable(const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) { - if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm)) + if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm, false)) return false; // The signedness of the result is dependent on the instruction operand. E.g. diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index abf85532fabf2..f62de7896b8eb 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -3215,14 +3215,14 @@ bool RISCVAsmParser::classifySymbolRef(const MCExpr *Expr, } MCValue Res; - if (Expr->evaluateAsRelocatable(Res, nullptr)) + if (Expr->evaluateAsRelocatable(Res, nullptr, false)) return Res.getSpecifier() == RISCV::S_None; return false; } bool RISCVAsmParser::isSymbolDiff(const MCExpr *Expr) { MCValue Res; - if (Expr->evaluateAsRelocatable(Res, nullptr)) { + if (Expr->evaluateAsRelocatable(Res, nullptr, false)) { return Res.getSpecifier() == RISCV::S_None && Res.getAddSym() && Res.getSubSym(); } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 04599d073bc58..f44b2ade0cfc8 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -655,7 +655,7 @@ bool RISCVAsmBackend::isPCRelFixupResolved(const MCSymbol *SymA, PCRelTemp = getContext().createTempSymbol(); PCRelTemp->setFragment(const_cast(&F)); MCValue Res; - MCExpr::evaluateSymbolicAdd(Asm, false, MCValue::get(SymA), + MCExpr::evaluateSymbolicAdd(Asm, false, false, MCValue::get(SymA), MCValue::get(nullptr, PCRelTemp), Res); return !Res.getSubSym(); } @@ -668,7 +668,7 @@ bool RISCVAsmBackend::isPCRelFixupResolved(const MCSymbol *SymA, static const MCFixup *getPCRelHiFixup(const MCSpecifierExpr &Expr, const MCFragment **DFOut) { MCValue AUIPCLoc; - if (!Expr.getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr)) + if (!Expr.getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, false)) return nullptr; const MCSymbol *AUIPCSymbol = AUIPCLoc.getAddSym(); @@ -735,7 +735,8 @@ std::optional RISCVAsmBackend::evaluateFixup(const MCFragment &, // MCAssembler::evaluateFixup will emit an error for this case when it sees // the %pcrel_hi, so don't duplicate it when also seeing the %pcrel_lo. const MCExpr *AUIPCExpr = AUIPCFixup->getValue(); - if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, Asm)) + if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, Asm, + fixupNeedsProvenance(&Fixup))) return true; break; } @@ -850,6 +851,17 @@ bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup, TA = ELF::R_RISCV_SET_ULEB128; TB = ELF::R_RISCV_SUB_ULEB128; break; + case RISCV::fixup_riscv_capability: + if (auto *RefB = Target.getSubSym()) { + const auto &SymB = cast(*RefB); + if (SymB.isUndefined()) { + getContext().reportError( + Fixup.getLoc(), + Twine("symbol '") + SymB.getName() + + "' can not be undefined in a subtraction expression"); + } + } + return false; default: llvm_unreachable("unsupported fixup size"); } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h index 1f1a6f5fe31a0..5e16f722d3abb 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -82,6 +82,10 @@ class RISCVAsmBackend : public MCAsmBackend { bool writeNopData(raw_ostream &OS, uint64_t Count, const MCSubtargetInfo *STI) const override; + bool fixupNeedsProvenance(const MCFixup *Fixup) const override { + return Fixup->getKind() == RISCV::fixup_riscv_capability; + } + const MCTargetOptions &getTargetOptions() const { return TargetOptions; } }; } diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp index 2933b4becba05..146606f160096 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp @@ -81,7 +81,7 @@ void SystemZMCAsmInfoGOFF::printSpecifierExpr( bool SystemZMCAsmInfoGOFF::evaluateAsRelocatableImpl( const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const { - if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm)) + if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm, false)) return false; Res.setSpecifier(Expr.getSpecifier()); return true; diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCAsmInfo.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEMCAsmInfo.cpp index 952838155c955..1955e5fb20089 100644 --- a/llvm/lib/Target/VE/MCTargetDesc/VEMCAsmInfo.cpp +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCAsmInfo.cpp @@ -105,7 +105,7 @@ void VEELFMCAsmInfo::printSpecifierExpr(raw_ostream &OS, bool VEELFMCAsmInfo::evaluateAsRelocatableImpl(const MCSpecifierExpr &Expr, MCValue &Res, const MCAssembler *Asm) const { - if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm)) + if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm, false)) return false; Res.setSpecifier(Expr.getSpecifier()); return true; diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp index 0dabd98a38f44..3b53b8e7ba164 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp @@ -532,7 +532,7 @@ void X86MachObjectWriter::RecordX86Relocation(MachObjectWriter *Writer, if (A->isVariable()) { MCValue Val; bool Relocatable = - A->getVariableValue()->evaluateAsRelocatable(Val, &Asm); + A->getVariableValue()->evaluateAsRelocatable(Val, &Asm, false); int64_t Res = Val.getConstant(); bool isAbs = Val.isAbsolute(); if (Relocatable && Val.getAddSym() && Val.getSubSym()) { diff --git a/llvm/test/CodeGen/Mips/cheri/exception-table.cpp b/llvm/test/CodeGen/Mips/cheri/exception-table.cpp index 464b65df56f73..0e872621b14fa 100644 --- a/llvm/test/CodeGen/Mips/cheri/exception-table.cpp +++ b/llvm/test/CodeGen/Mips/cheri/exception-table.cpp @@ -76,14 +76,14 @@ long test(long arg, long arg2) { /// Landing pads are not relative offsets but real capabilities: // MIPS-NEXT: .uleb128 .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 // PURECAP-NEXT: .byte 12 # (landing pad is a capability) -// PURECAP-NEXT: .chericap _Z4testll + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 +// PURECAP-NEXT: .chericap _Z4testll+(.Ltmp2-.Lfunc_begin0) # jumps to .Ltmp2 // CHECK-NEXT: .byte 1 # On action: 1 // CHECK-NEXT: .uleb128 .Ltmp3-.Lfunc_begin0 # >> Call Site 2 << // CHECK-NEXT: .uleb128 .Ltmp4-.Ltmp3 # Call between .Ltmp3 and .Ltmp4 // MIPS-NEXT: .uleb128 .Ltmp5-.Lfunc_begin0 # jumps to .Ltmp5 /// Landing pads are not relative offsets but real capabilities: // PURECAP-NEXT: .byte 12 # (landing pad is a capability) -// PURECAP-NEXT: .chericap _Z4testll + .Ltmp5-.Lfunc_begin0 # jumps to .Ltmp5 +// PURECAP-NEXT: .chericap _Z4testll+(.Ltmp5-.Lfunc_begin0) # jumps to .Ltmp5 // CHECK-NEXT: .byte 1 # On action: 1 // CHECK-NEXT: .uleb128 .Ltmp4-.Lfunc_begin0 # >> Call Site 3 << // CHECK-NEXT: .uleb128 .Lfunc_end0-.Ltmp4 # Call between .Ltmp4 and .Lfunc_end0 diff --git a/llvm/test/MC/Mips/cheri/chericap-expr-invalid.s b/llvm/test/MC/Mips/cheri/chericap-expr-invalid.s new file mode 100644 index 0000000000000..e0a7c2b96c67a --- /dev/null +++ b/llvm/test/MC/Mips/cheri/chericap-expr-invalid.s @@ -0,0 +1,13 @@ +# RUN: not llvm-mc -filetype=obj -triple=mips64 -mattr=+cheri128 -o /dev/null < %s 2>&1 \ +# RUN: | FileCheck %s + +foo: + +.data + +.chericap foo - bar +# CHECK: error: symbol 'bar' can not be undefined in a subtraction expression + +## Make sure we don't fold this to bar +.chericap foo + (bar - foo) +# CHECK: error: expected relocatable expression diff --git a/llvm/test/MC/Mips/cheri/chericap-expr.s b/llvm/test/MC/Mips/cheri/chericap-expr.s new file mode 100644 index 0000000000000..4362017e322a3 --- /dev/null +++ b/llvm/test/MC/Mips/cheri/chericap-expr.s @@ -0,0 +1,32 @@ +# RUN: llvm-mc -triple mips64-unknown-freebsd -mattr=+cheri128 %s -o - \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple mips64-unknown-freebsd -mattr=+cheri128 %s -o - \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix=CHECK-RELOC %s + +foo: + nop + nop +bar: + jr $ra + +.data + +# CHECK-INST: .chericap foo-foo +# CHECK-RELOC-NOT: R_MIPS_CHERI_CAPABILITY +.chericap foo - foo + +# CHECK-INST: .chericap foo-bar +# CHECK-RELOC-NOT: R_MIPS_CHERI_CAPABILITY +.chericap foo - bar + +# CHECK-INST: .chericap foo +# CHECK-RELOC: 0x20 R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +.chericap foo + +# CHECK-INST: .chericap foo+4 +# CHECK-RELOC: 0x30 R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE foo 0x4 +.chericap foo + 4 + +# CHECK-INST: .chericap foo+(bar-foo) +# CHECK-RELOC: 0x40 R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE foo 0x8 +.chericap foo + (bar - foo) diff --git a/llvm/test/MC/RISCV/cheri/chericap-expr-invalid.s b/llvm/test/MC/RISCV/cheri/chericap-expr-invalid.s new file mode 100644 index 0000000000000..dfafc420d6786 --- /dev/null +++ b/llvm/test/MC/RISCV/cheri/chericap-expr-invalid.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc -filetype=obj -triple=riscv64 -mattr=+xcheri -o /dev/null < %s 2>&1 \ +# RUN: | FileCheck %s + +foo: + +.data + +## No add/sub relocations +.chericap foo - bar +# CHECK: error: symbol 'bar' can not be undefined in a subtraction expression + +## Make sure we don't fold this to bar +.chericap foo + (bar - foo) +# CHECK: error: expected relocatable expression diff --git a/llvm/test/MC/RISCV/cheri/chericap-expr.s b/llvm/test/MC/RISCV/cheri/chericap-expr.s new file mode 100644 index 0000000000000..88d6a192f21a6 --- /dev/null +++ b/llvm/test/MC/RISCV/cheri/chericap-expr.s @@ -0,0 +1,32 @@ +# RUN: llvm-mc -triple=riscv64 -mattr=+xcheri < %s \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+xcheri < %s \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix=CHECK-RELOC %s + +foo: + nop + nop +bar: + ret + +.data + +# CHECK-INST: .chericap foo-foo +# CHECK-RELOC-NOT: R_RISCV_CHERI_CAPABILITY +.chericap foo - foo + +# CHECK-INST: .chericap foo-bar +# CHECK-RELOC-NOT: R_RISCV_CHERI_CAPABILITY +.chericap foo - bar + +# CHECK-INST: .chericap foo +# CHECK-RELOC: 0x20 R_RISCV_CHERI_CAPABILITY foo 0x0 +.chericap foo + +# CHECK-INST: .chericap foo+4 +# CHECK-RELOC: 0x30 R_RISCV_CHERI_CAPABILITY foo 0x4 +.chericap foo + 4 + +# CHECK-INST: .chericap foo+(bar-foo) +# CHECK-RELOC: 0x40 R_RISCV_CHERI_CAPABILITY foo 0x8 +.chericap foo + (bar - foo) From fb57325392b5f30a20faca8e16f5462f40a116a9 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sun, 16 Feb 2025 02:18:04 +0000 Subject: [PATCH 02/16] [MC] Add general FK_Cap_* fixup kinds rather than duplicating per target --- llvm/include/llvm/MC/MCAsmBackend.h | 10 +- llvm/include/llvm/MC/MCFixup.h | 16 +- llvm/lib/MC/MCAsmBackend.cpp | 2 + llvm/lib/MC/MCObjectStreamer.cpp | 2 +- llvm/lib/MC/WasmObjectWriter.cpp | 2 +- .../Mips/MCTargetDesc/MipsAsmBackend.cpp | 52 ++- .../Target/Mips/MCTargetDesc/MipsAsmBackend.h | 9 +- .../Mips/MCTargetDesc/MipsELFObjectWriter.cpp | 41 +- .../Mips/MCTargetDesc/MipsELFStreamer.cpp | 2 +- .../Target/Mips/MCTargetDesc/MipsFixupKinds.h | 6 +- .../Mips/MCTargetDesc/MipsMCTargetDesc.h | 2 +- .../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 8 +- .../RISCV/MCTargetDesc/RISCVAsmBackend.h | 4 - .../MCTargetDesc/RISCVELFObjectWriter.cpp | 16 +- .../RISCV/MCTargetDesc/RISCVELFStreamer.cpp | 2 +- .../RISCV/MCTargetDesc/RISCVFixupKinds.h | 3 - llvm/test/CodeGen/Mips/llvm-ir/load.ll | 432 +++++++++--------- llvm/test/CodeGen/Mips/llvm-ir/store.ll | 252 +++++----- llvm/test/CodeGen/Mips/setcc-se.ll | 48 +- llvm/test/MC/ELF/mc-dump.s | 8 +- llvm/test/MC/RISCV/Relocations/mc-dump.s | 2 +- 21 files changed, 490 insertions(+), 429 deletions(-) diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h index 833c2b9c0f801..bc6dc27e09350 100644 --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -85,7 +85,15 @@ class LLVM_ABI MCAsmBackend { /// lifetime management virtual void reset() {} - virtual bool fixupNeedsProvenance(const MCFixup *Fixup) const { + bool fixupNeedsProvenance(const MCFixup *Fixup) const { + switch (Fixup->getKind()) { + case FK_Cap_8: + case FK_Cap_16: + case FK_Cap_32: + return true; + default: + return false; + } return false; } diff --git a/llvm/include/llvm/MC/MCFixup.h b/llvm/include/llvm/MC/MCFixup.h index aaf75102fb9ed..bf002f3911826 100644 --- a/llvm/include/llvm/MC/MCFixup.h +++ b/llvm/include/llvm/MC/MCFixup.h @@ -40,6 +40,9 @@ enum { FK_SecRel_2, ///< A two-byte section relative fixup. FK_SecRel_4, ///< A four-byte section relative fixup. FK_SecRel_8, ///< A eight-byte section relative fixup. + FK_Cap_8, ///< A eight-byte capability fixup. + FK_Cap_16, ///< A sixteen-byte capability fixup. + FK_Cap_32, ///< A thirty-two-byte capability fixup. FirstTargetFixupKind, }; @@ -107,17 +110,26 @@ class MCFixup { /// Return the generic fixup kind for a value with the given size. It /// is an error to pass an unsupported size. - static MCFixupKind getDataKindForSize(unsigned Size) { + static MCFixupKind getDataKindForSize(unsigned Size, bool IsCap) { switch (Size) { default: llvm_unreachable("Invalid generic fixup size!"); case 1: + assert(!IsCap && "Invalid cap fixup size!"); return FK_Data_1; case 2: + assert(!IsCap && "Invalid cap fixup size!"); return FK_Data_2; case 4: + assert(!IsCap && "Invalid cap fixup size!"); return FK_Data_4; case 8: - return FK_Data_8; + return IsCap ? FK_Cap_8 : FK_Data_8; + case 16: + assert(IsCap && "Invalid integer fixup size!"); + return FK_Cap_16; + case 32: + assert(IsCap && "Invalid integer fixup size!"); + return FK_Cap_32; } } diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp index 39ef521031069..9ac4708643c34 100644 --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -98,6 +98,8 @@ MCFixupKindInfo MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { {"FK_SecRel_2", 0, 16, 0}, {"FK_SecRel_4", 0, 32, 0}, {"FK_SecRel_8", 0, 64, 0}, + {"FK_Cap_8", 0, 64, 0}, + {"FK_Cap_16", 0, 128, 0}, }; // clang-format on diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index ab1d25ebcc739..e4558bff5d0c6 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -189,7 +189,7 @@ void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, return; } DF->addFixup(MCFixup::create(DF->getContents().size(), Value, - MCFixup::getDataKindForSize(Size))); + MCFixup::getDataKindForSize(Size, false))); DF->appendContents(Size, 0); } diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index 4c226d4420e1d..1a19799536de5 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -1888,7 +1888,7 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm, assert(llvm::all_of(DataFrag.getContents(), [](char C) { return !C; })); for (const MCFixup &Fixup : DataFrag.getFixups()) { assert(Fixup.getKind() == - MCFixup::getDataKindForSize(is64Bit() ? 8 : 4)); + MCFixup::getDataKindForSize(is64Bit() ? 8 : 4, false)); const MCExpr *Expr = Fixup.getValue(); auto *SymRef = dyn_cast(Expr); if (!SymRef) diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp index efe843cfe4ae2..4cbde2060ce48 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -21,6 +21,7 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixup.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptions.h" @@ -41,9 +42,6 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, switch (Kind) { default: return 0; - case Mips::fixup_CHERI_CAPABILITY: - // This should never change anything, it is just a marker for the linker - return 0; case FK_Data_2: case Mips::fixup_Mips_LO16: case Mips::fixup_Mips_GPREL16: @@ -253,7 +251,7 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, std::unique_ptr MipsAsmBackend::createObjectTargetWriter() const { - return createMipsELFObjectWriter(TheTriple, IsN32); + return createMipsELFObjectWriter(TheTriple, IsN32, CapSize); } // Little-endian fixup data byte ordering: @@ -354,8 +352,10 @@ void MipsAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup, case Mips::fixup_Mips_64: FullSize = 8; break; - case Mips::fixup_CHERI_CAPABILITY: - llvm_unreachable("fixup_CHERI_CAPABILITY shouldn't happen here!"); + case FK_Cap_8: + case FK_Cap_16: + case FK_Cap_32: + llvm_unreachable("capability fixups shouldn't happen here!"); break; case FK_Data_4: default: @@ -398,6 +398,10 @@ std::optional MipsAsmBackend::getFixupKind(StringRef Name) const { if (Type != -1u) return static_cast(FirstLiteralRelocationKind + Type); + std::optional CapFixup; + if (CapSize != 0) + CapFixup = MCFixup::getDataKindForSize(CapSize, true); + return StringSwitch>(Name) .Case("R_MIPS_NONE", FK_NONE) .Case("R_MIPS_32", FK_Data_4) @@ -434,7 +438,7 @@ std::optional MipsAsmBackend::getFixupKind(StringRef Name) const { .Case("R_MIPS_JALR", Mips::fixup_Mips_JALR) .Case("R_MICROMIPS_JALR", Mips::fixup_MICROMIPS_JALR) - .Case("R_MIPS_CHERI_CAPABILITY", Mips::fixup_CHERI_CAPABILITY) + .Case("R_MIPS_CHERI_CAPABILITY", CapFixup) .Case("R_MIPS_CHERI_CAPCALL11", Mips::fixup_CHERI_CAPCALL11) .Case("R_MIPS_CHERI_CAPCALL20", Mips::fixup_CHERI_CAPCALL20) .Case("R_MIPS_CHERI_CAPCALL_HI16", Mips::fixup_CHERI_CAPCALL_HI16) @@ -444,13 +448,18 @@ std::optional MipsAsmBackend::getFixupKind(StringRef Name) const { .Case("R_MIPS_CHERI_CAPTABLE_HI16", Mips::fixup_CHERI_CAPTABLE_HI16) .Case("R_MIPS_CHERI_CAPTABLE_LO16", Mips::fixup_CHERI_CAPTABLE_LO16) // CHERI TLS: - .Case("R_MIPS_CHERI_CAPTAB_TLSGD_HI16", Mips::fixup_CHERI_CAPTAB_TLSGD_HI16) - .Case("R_MIPS_CHERI_CAPTAB_TLSGD_LO16", Mips::fixup_CHERI_CAPTAB_TLSGD_LO16) - .Case("R_MIPS_CHERI_CAPTAB_TLSDM_HI16", Mips::fixup_CHERI_CAPTAB_TLSLDM_HI16) - .Case("R_MIPS_CHERI_CAPTAB_TLSDM_LO16", Mips::fixup_CHERI_CAPTAB_TLSLDM_LO16) - .Case("R_MIPS_CHERI_CAPTAB_TPREL_HI16", Mips::fixup_CHERI_CAPTAB_TPREL_HI16) - .Case("R_MIPS_CHERI_CAPTAB_TPREL_LO16", Mips::fixup_CHERI_CAPTAB_TPREL_LO16) - + .Case("R_MIPS_CHERI_CAPTAB_TLSGD_HI16", + Mips::fixup_CHERI_CAPTAB_TLSGD_HI16) + .Case("R_MIPS_CHERI_CAPTAB_TLSGD_LO16", + Mips::fixup_CHERI_CAPTAB_TLSGD_LO16) + .Case("R_MIPS_CHERI_CAPTAB_TLSDM_HI16", + Mips::fixup_CHERI_CAPTAB_TLSLDM_HI16) + .Case("R_MIPS_CHERI_CAPTAB_TLSDM_LO16", + Mips::fixup_CHERI_CAPTAB_TLSLDM_LO16) + .Case("R_MIPS_CHERI_CAPTAB_TPREL_HI16", + Mips::fixup_CHERI_CAPTAB_TPREL_HI16) + .Case("R_MIPS_CHERI_CAPTAB_TPREL_LO16", + Mips::fixup_CHERI_CAPTAB_TPREL_LO16) .Default(MCAsmBackend::getFixupKind(Name)); } @@ -546,8 +555,7 @@ MCFixupKindInfo MipsAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { { "fixup_CHERI_CAPCALL20", 0, 16, 0 }, { "fixup_CHERI_CAPCALL_HI16", 0, 16, 0 }, { "fixup_CHERI_CAPCALL_LO16", 0, 16, 0 }, - { "fixup_CHERI_CAPABILITY", 0, 255, 0 }, - + { "fixup_Mips_CAPTABLEREL16", 0, 16, 0 }, // like GPREL16 { "fixup_Mips_CAPTABLEREL_HI", 0, 16, 0 }, // like GPOFF_HI { "fixup_Mips_CAPTABLEREL_LO", 0, 16, 0 }, // like GPOFF_LO @@ -653,8 +661,7 @@ MCFixupKindInfo MipsAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { { "fixup_CHERI_CAPCALL20", 16, 16, 0 }, { "fixup_CHERI_CAPCALL_HI16", 16, 16, 0 }, { "fixup_CHERI_CAPCALL_LO16", 16, 16, 0 }, - { "fixup_CHERI_CAPABILITY", 0, 255, 0 }, - + { "fixup_Mips_CAPTABLEREL16", 16, 16, 0 }, // like GPREL16 { "fixup_Mips_CAPTABLEREL_HI", 16, 16, 0 }, // like GPOFF_HI { "fixup_Mips_CAPTABLEREL_LO", 16, 16, 0 }, // like GPOFF_LO @@ -678,8 +685,6 @@ MCFixupKindInfo MipsAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { assert(unsigned(Kind - FirstTargetFixupKind) < Mips::NumTargetFixupKinds && "Invalid kind!"); - assert(Kind - FirstTargetFixupKind != Mips::fixup_CHERI_CAPABILITY); - if (Endian == llvm::endianness::little) return LittleEndianInfos[Kind - FirstTargetFixupKind]; return BigEndianInfos[Kind - FirstTargetFixupKind]; @@ -709,7 +714,7 @@ class WindowsMipsAsmBackend : public MipsAsmBackend { public: WindowsMipsAsmBackend(const Target &T, const MCRegisterInfo &MRI, const MCSubtargetInfo &STI) - : MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(), false) {} + : MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(), false, 0) {} std::unique_ptr createObjectTargetWriter() const override { @@ -727,8 +732,11 @@ MCAsmBackend *llvm::createMipsAsmBackend(const Target &T, if (TheTriple.isOSWindows() && TheTriple.isOSBinFormatCOFF()) return new WindowsMipsAsmBackend(T, MRI, STI); + unsigned CapSize = STI.getFeatureBits()[Mips::FeatureMipsCheri128] ? 16 + : STI.getFeatureBits()[Mips::FeatureMipsCheri64] ? 8 + : 0; MipsABIInfo ABI = MipsABIInfo::computeTargetABI(STI.getTargetTriple(), STI.getCPU(), Options); return new MipsAsmBackend(T, MRI, STI.getTargetTriple(), STI.getCPU(), - ABI.IsN32()); + ABI.IsN32(), CapSize); } diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h index 6e4eac25daa96..55a3cfe8ce987 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -28,13 +28,14 @@ class Target; class MipsAsmBackend : public MCAsmBackend { Triple TheTriple; bool IsN32; + unsigned CapSize; public: MipsAsmBackend(const Target &T, const MCRegisterInfo &MRI, const Triple &TT, - StringRef CPU, bool N32) + StringRef CPU, bool N32, unsigned CapSize) : MCAsmBackend(TT.isLittleEndian() ? llvm::endianness::little : llvm::endianness::big), - TheTriple(TT), IsN32(N32) {} + TheTriple(TT), IsN32(N32), CapSize(CapSize) {} std::unique_ptr createObjectTargetWriter() const override; @@ -48,10 +49,6 @@ class MipsAsmBackend : public MCAsmBackend { bool writeNopData(raw_ostream &OS, uint64_t Count, const MCSubtargetInfo *STI) const override; - - bool fixupNeedsProvenance(const MCFixup *Fixup) const override { - return Fixup->getKind() == Mips::fixup_CHERI_CAPABILITY; - } }; // class MipsAsmBackend } // namespace diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp index 636fb7236b00d..1492300a626ad 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -44,8 +44,11 @@ struct MipsRelocationEntry { }; class MipsELFObjectWriter : public MCELFObjectTargetWriter { + unsigned CapSize; + public: - MipsELFObjectWriter(uint8_t OSABI, bool HasRelocationAddend, bool Is64); + MipsELFObjectWriter(uint8_t OSABI, bool HasRelocationAddend, bool Is64, + unsigned CapSize); ~MipsELFObjectWriter() override = default; @@ -149,8 +152,10 @@ static bool isMatchingReloc(unsigned MatchingType, const ELFRelocationEntry &R, } MipsELFObjectWriter::MipsELFObjectWriter(uint8_t OSABI, - bool HasRelocationAddend, bool Is64) - : MCELFObjectTargetWriter(Is64, OSABI, ELF::EM_MIPS, HasRelocationAddend) {} + bool HasRelocationAddend, bool Is64, + unsigned CapSize) + : MCELFObjectTargetWriter(Is64, OSABI, ELF::EM_MIPS, HasRelocationAddend), + CapSize(CapSize) {} unsigned MipsELFObjectWriter::getRelocType(const MCFixup &Fixup, const MCValue &Target, @@ -375,7 +380,30 @@ unsigned MipsELFObjectWriter::getRelocType(const MCFixup &Fixup, case Mips::fixup_CHERI_CAPCALL_HI16: return ELF::R_MIPS_CHERI_CAPCALL_HI16; - case Mips::fixup_CHERI_CAPABILITY: { + case FK_Cap_8: + if (CapSize != 8) { + getContext().reportError( + Fixup.getLoc(), + "8-byte capability relocations not supported without CHERI64"); + return ELF::R_MIPS_NONE; + } + goto fixup_cap; + case FK_Cap_16: + if (CapSize != 16) { + getContext().reportError( + Fixup.getLoc(), + "16-byte capability relocations not supported without CHERI128"); + return ELF::R_MIPS_NONE; + } + goto fixup_cap; + case FK_Cap_32: + if (CapSize != 32) { + getContext().reportError( + Fixup.getLoc(), + "32-byte capability relocations not supported without CHERI256"); + return ELF::R_MIPS_NONE; + } + fixup_cap: { const auto ElfSym = cast(Target.getAddSym()); // Assert that we don't create .chericap relocations against temporary // symbols since those will result in wrong relocations (against sec+offset) @@ -684,10 +712,11 @@ bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCValue &V, } std::unique_ptr -llvm::createMipsELFObjectWriter(const Triple &TT, bool IsN32) { +llvm::createMipsELFObjectWriter(const Triple &TT, bool IsN32, + unsigned CapSize) { uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); bool IsN64 = TT.isArch64Bit() && !IsN32; bool HasRelocationAddend = TT.isArch64Bit(); return std::make_unique(OSABI, HasRelocationAddend, - IsN64); + IsN64, CapSize); } diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp index a235e68b4dc51..918e3b04845d3 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp @@ -113,7 +113,7 @@ void MipsELFStreamer::emitCheriCapability(const MCExpr *Value, unsigned CapSize, MCDataFragment *DF = new MCDataFragment(); insert(DF); MCFixup cheriFixup = - MCFixup::create(0, Value, MCFixupKind(Mips::fixup_CHERI_CAPABILITY)); + MCFixup::create(0, Value, MCFixup::getDataKindForSize(CapSize, true)); DF->addFixup(cheriFixup); DF->appendContents(CapSize, '\xca'); } diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h index fd9d063fe3f1a..740e8ba948d35 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -238,10 +238,8 @@ enum Fixups { fixup_CHERI_CAPCALL_HI16, fixup_CHERI_CAPCALL_LO16, - // resulting in - R_MIPS_CHERI_CAPABILITY - fixup_CHERI_CAPABILITY, - - // 16 bit fixup for _CHERI_CAPABILITY_TABLE offest resulting in - R_MIPS_CHERI_CAPTABLEREL16. + // 16 bit fixup for _CHERI_CAPABILITY_TABLE offest resulting in - + // R_MIPS_CHERI_CAPTABLEREL16. fixup_Mips_CAPTABLEREL16, // resulting in - R_MIPS_CHERI_CAPTABLEREL16/R_MIPS_SUB/R_MIPS_HI16 fixup_Mips_CAPTABLEOFF_HI, diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h index f3e3e6e8d1073..b2d51a7934662 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h @@ -52,7 +52,7 @@ MCStreamer *createMipsWinCOFFStreamer(MCContext &C, /// Construct a Mips ELF object writer. std::unique_ptr -createMipsELFObjectWriter(const Triple &TT, bool IsN32); +createMipsELFObjectWriter(const Triple &TT, bool IsN32, unsigned CapSize); /// Construct a Mips Win COFF object writer. std::unique_ptr createMipsWinCOFFObjectWriter(); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index f44b2ade0cfc8..be7d8beba93f8 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -88,8 +88,6 @@ MCFixupKindInfo RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { // Andes fixups {"fixup_riscv_nds_branch_10", 0, 32, 0}, - {"fixup_riscv_capability", 0, 0, 0}, - {"fixup_riscv_cheriot_compartment_hi", 0, 32, 0}, {"fixup_riscv_cheriot_compartment_lo_i", 0, 32, 0}, {"fixup_riscv_cheriot_compartment_lo_s", 0, 32, 0}, @@ -487,7 +485,8 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, switch (Fixup.getKind()) { default: llvm_unreachable("Unknown fixup kind!"); - case RISCV::fixup_riscv_capability: + case FK_Cap_8: + case FK_Cap_16: llvm_unreachable("Relocation should be unconditionally forced\n"); case FK_Data_1: case FK_Data_2: @@ -851,7 +850,8 @@ bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup, TA = ELF::R_RISCV_SET_ULEB128; TB = ELF::R_RISCV_SUB_ULEB128; break; - case RISCV::fixup_riscv_capability: + case llvm::FK_Cap_8: + case llvm::FK_Cap_16: if (auto *RefB = Target.getSubSym()) { const auto &SymB = cast(*RefB); if (SymB.isUndefined()) { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h index 5e16f722d3abb..1f1a6f5fe31a0 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -82,10 +82,6 @@ class RISCVAsmBackend : public MCAsmBackend { bool writeNopData(raw_ostream &OS, uint64_t Count, const MCSubtargetInfo *STI) const override; - bool fixupNeedsProvenance(const MCFixup *Fixup) const override { - return Fixup->getKind() == RISCV::fixup_riscv_capability; - } - const MCTargetOptions &getTargetOptions() const { return TargetOptions; } }; } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index b801cda15827e..4e6a1d4f8ad59 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -149,7 +149,21 @@ unsigned RISCVELFObjectWriter::getRelocType(const MCFixup &Fixup, return ELF::R_RISCV_QC_E_32; case RISCV::fixup_riscv_qc_abs20_u: return ELF::R_RISCV_QC_ABS20_U; - case RISCV::fixup_riscv_capability: + case FK_Cap_8: + if (is64Bit()) { + getContext().reportError( + Fixup.getLoc(), + "8-byte capability relocations not supported on RV64"); + return ELF::R_RISCV_NONE; + } + return ELF::R_RISCV_CHERI_CAPABILITY; + case FK_Cap_16: + if (!is64Bit()) { + getContext().reportError( + Fixup.getLoc(), + "16-byte capability relocations not supported on RV32"); + return ELF::R_RISCV_NONE; + } return ELF::R_RISCV_CHERI_CAPABILITY; case RISCV::fixup_riscv_cheriot_compartment_hi: return ELF::R_RISCV_CHERIOT_COMPARTMENT_HI; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp index 2f51d92df671e..97695d3662591 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -227,7 +227,7 @@ void RISCVELFStreamer::emitCheriCapability(const MCExpr *Value, MCDataFragment *DF = new MCDataFragment(); insert(DF); MCFixup CapFixup = - MCFixup::create(0, Value, MCFixupKind(RISCV::fixup_riscv_capability)); + MCFixup::create(0, Value, MCFixup::getDataKindForSize(CapSize, true)); DF->addFixup(CapFixup); DF->appendContents(CapSize, '\xca'); } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h index 83a98aa37817e..55d2bf59db37e 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -64,9 +64,6 @@ enum Fixups { // 10-bit fixup for symbol references in the xandesperf branch instruction fixup_riscv_nds_branch_10, - // fixup_riscv_capability - CLen-bit fixup corresponding to .chericap - fixup_riscv_capability, - // $cgp- or $pcc-relative global, used with auicgp / auipcc instructions fixup_riscv_cheriot_compartment_hi, // $cgp- or $pcc-relative global, used with RV32 I instructions diff --git a/llvm/test/CodeGen/Mips/llvm-ir/load.ll b/llvm/test/CodeGen/Mips/llvm-ir/load.ll index 3c5415da6fe2e..511f6358eb361 100644 --- a/llvm/test/CodeGen/Mips/llvm-ir/load.ll +++ b/llvm/test/CodeGen/Mips/llvm-ir/load.ll @@ -29,48 +29,48 @@ define i8 @f1() { ; MIPS32: # %bb.0: # %entry ; MIPS32-NEXT: lui $1, %hi(a) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: lbu $2, %lo(a)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f1: ; MMR3: # %bb.0: # %entry ; MMR3-NEXT: lui $1, %hi(a) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: lbu $2, %lo(a)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f1: ; MIPS32R6: # %bb.0: # %entry ; MIPS32R6-NEXT: lui $1, %hi(a) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: lbu $2, %lo(a)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f1: ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(a) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: lbu $2, %lo(a)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -78,11 +78,11 @@ define i8 @f1() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(a) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(a) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -90,7 +90,7 @@ define i8 @f1() { ; MIPS3-NEXT: daddiu $1, $1, %hi(a) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -100,17 +100,17 @@ define i8 @f1() { ; MIPS3-NEXT: lbu $2, %lo(a)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f1: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(a) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(a) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -118,7 +118,7 @@ define i8 @f1() { ; MIPS64-NEXT: daddiu $1, $1, %hi(a) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -128,17 +128,17 @@ define i8 @f1() { ; MIPS64-NEXT: lbu $2, %lo(a)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f1: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(a) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(a) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -146,7 +146,7 @@ define i8 @f1() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(a) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -157,31 +157,31 @@ define i8 @f1() { ; MIPS64R6-NEXT: lbu $2, %lo(a)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f1: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(a) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: lbu $2, %lo(a)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f1: ; MIPS32R5FP643: # %bb.0: # %entry ; MIPS32R5FP643-NEXT: lui $1, %hi(a) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: lbu $2, %lo(a)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > entry: %0 = load i8, ptr @a ret i8 %0 @@ -192,48 +192,48 @@ define i32 @f2() { ; MIPS32: # %bb.0: # %entry ; MIPS32-NEXT: lui $1, %hi(a) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: lb $2, %lo(a)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f2: ; MMR3: # %bb.0: # %entry ; MMR3-NEXT: lui $1, %hi(a) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: lb $2, %lo(a)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f2: ; MIPS32R6: # %bb.0: # %entry ; MIPS32R6-NEXT: lui $1, %hi(a) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: lb $2, %lo(a)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f2: ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(a) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: lb $2, %lo(a)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -241,11 +241,11 @@ define i32 @f2() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(a) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(a) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -253,7 +253,7 @@ define i32 @f2() { ; MIPS3-NEXT: daddiu $1, $1, %hi(a) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -263,17 +263,17 @@ define i32 @f2() { ; MIPS3-NEXT: lb $2, %lo(a)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f2: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(a) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(a) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -281,7 +281,7 @@ define i32 @f2() { ; MIPS64-NEXT: daddiu $1, $1, %hi(a) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -291,17 +291,17 @@ define i32 @f2() { ; MIPS64-NEXT: lb $2, %lo(a)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f2: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(a) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(a) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -309,7 +309,7 @@ define i32 @f2() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(a) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -320,31 +320,31 @@ define i32 @f2() { ; MIPS64R6-NEXT: lb $2, %lo(a)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f2: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(a) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: lb $2, %lo(a)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f2: ; MIPS32R5FP643: # %bb.0: # %entry ; MIPS32R5FP643-NEXT: lui $1, %hi(a) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: lb $2, %lo(a)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > entry: %0 = load i8, ptr @a %1 = sext i8 %0 to i32 @@ -356,48 +356,48 @@ define i16 @f3() { ; MIPS32: # %bb.0: # %entry ; MIPS32-NEXT: lui $1, %hi(b) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: lhu $2, %lo(b)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f3: ; MMR3: # %bb.0: # %entry ; MMR3-NEXT: lui $1, %hi(b) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: lhu $2, %lo(b)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f3: ; MIPS32R6: # %bb.0: # %entry ; MIPS32R6-NEXT: lui $1, %hi(b) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: lhu $2, %lo(b)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f3: ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(b) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: lhu $2, %lo(b)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -405,11 +405,11 @@ define i16 @f3() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(b) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(b) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -417,7 +417,7 @@ define i16 @f3() { ; MIPS3-NEXT: daddiu $1, $1, %hi(b) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -427,17 +427,17 @@ define i16 @f3() { ; MIPS3-NEXT: lhu $2, %lo(b)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f3: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(b) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(b) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -445,7 +445,7 @@ define i16 @f3() { ; MIPS64-NEXT: daddiu $1, $1, %hi(b) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -455,17 +455,17 @@ define i16 @f3() { ; MIPS64-NEXT: lhu $2, %lo(b)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f3: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(b) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(b) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -473,7 +473,7 @@ define i16 @f3() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(b) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -484,31 +484,31 @@ define i16 @f3() { ; MIPS64R6-NEXT: lhu $2, %lo(b)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f3: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(b) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: lhu $2, %lo(b)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f3: ; MIPS32R5FP643: # %bb.0: # %entry ; MIPS32R5FP643-NEXT: lui $1, %hi(b) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: lhu $2, %lo(b)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > entry: %0 = load i16, ptr @b ret i16 %0 @@ -519,48 +519,48 @@ define i32 @f4() { ; MIPS32: # %bb.0: # %entry ; MIPS32-NEXT: lui $1, %hi(b) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: lh $2, %lo(b)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f4: ; MMR3: # %bb.0: # %entry ; MMR3-NEXT: lui $1, %hi(b) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: lh $2, %lo(b)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f4: ; MIPS32R6: # %bb.0: # %entry ; MIPS32R6-NEXT: lui $1, %hi(b) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: lh $2, %lo(b)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f4: ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(b) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: lh $2, %lo(b)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -568,11 +568,11 @@ define i32 @f4() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(b) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(b) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -580,7 +580,7 @@ define i32 @f4() { ; MIPS3-NEXT: daddiu $1, $1, %hi(b) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -590,17 +590,17 @@ define i32 @f4() { ; MIPS3-NEXT: lh $2, %lo(b)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f4: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(b) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(b) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -608,7 +608,7 @@ define i32 @f4() { ; MIPS64-NEXT: daddiu $1, $1, %hi(b) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -618,17 +618,17 @@ define i32 @f4() { ; MIPS64-NEXT: lh $2, %lo(b)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f4: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(b) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(b) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -636,7 +636,7 @@ define i32 @f4() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(b) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -647,31 +647,31 @@ define i32 @f4() { ; MIPS64R6-NEXT: lh $2, %lo(b)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f4: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(b) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: lh $2, %lo(b)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f4: ; MIPS32R5FP643: # %bb.0: # %entry ; MIPS32R5FP643-NEXT: lui $1, %hi(b) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: lh $2, %lo(b)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > entry: %0 = load i16, ptr @b %1 = sext i16 %0 to i32 @@ -683,48 +683,48 @@ define i32 @f5() { ; MIPS32: # %bb.0: # %entry ; MIPS32-NEXT: lui $1, %hi(c) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: lw $2, %lo(c)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f5: ; MMR3: # %bb.0: # %entry ; MMR3-NEXT: lui $1, %hi(c) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: lw $2, %lo(c)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f5: ; MIPS32R6: # %bb.0: # %entry ; MIPS32R6-NEXT: lui $1, %hi(c) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: lw $2, %lo(c)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f5: ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(c) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: lw $2, %lo(c)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -732,11 +732,11 @@ define i32 @f5() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(c) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(c) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -744,7 +744,7 @@ define i32 @f5() { ; MIPS3-NEXT: daddiu $1, $1, %hi(c) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -754,17 +754,17 @@ define i32 @f5() { ; MIPS3-NEXT: lw $2, %lo(c)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f5: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(c) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(c) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -772,7 +772,7 @@ define i32 @f5() { ; MIPS64-NEXT: daddiu $1, $1, %hi(c) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -782,17 +782,17 @@ define i32 @f5() { ; MIPS64-NEXT: lw $2, %lo(c)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f5: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(c) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(c) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -800,7 +800,7 @@ define i32 @f5() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(c) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -811,31 +811,31 @@ define i32 @f5() { ; MIPS64R6-NEXT: lw $2, %lo(c)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f5: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(c) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: lw $2, %lo(c)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f5: ; MIPS32R5FP643: # %bb.0: # %entry ; MIPS32R5FP643-NEXT: lui $1, %hi(c) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: lw $2, %lo(c)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > entry: %0 = load i32, ptr @c ret i32 %0 @@ -846,11 +846,11 @@ define i64 @f6() { ; MIPS32: # %bb.0: # %entry ; MIPS32-NEXT: lui $1, %hi(c) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: lw $3, %lo(c)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: addiu $2, $zero, 0 # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: li16 $2, 0 # ; MMR3-NEXT: # > @@ -871,17 +871,17 @@ define i64 @f6() { ; MMR3-NEXT: lw $3, %lo(c)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f6: ; MIPS32R6: # %bb.0: # %entry ; MIPS32R6-NEXT: lui $1, %hi(c) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: lw $3, %lo(c)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > @@ -894,11 +894,11 @@ define i64 @f6() { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(c) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: lw $3, %lo(c)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: li16 $2, 0 # ; MMR6-NEXT: # > @@ -909,11 +909,11 @@ define i64 @f6() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(c) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(c) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -921,7 +921,7 @@ define i64 @f6() { ; MIPS3-NEXT: daddiu $1, $1, %hi(c) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -931,17 +931,17 @@ define i64 @f6() { ; MIPS3-NEXT: lwu $2, %lo(c)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f6: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(c) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(c) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -949,7 +949,7 @@ define i64 @f6() { ; MIPS64-NEXT: daddiu $1, $1, %hi(c) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -959,17 +959,17 @@ define i64 @f6() { ; MIPS64-NEXT: lwu $2, %lo(c)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f6: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(c) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(c) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -977,7 +977,7 @@ define i64 @f6() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(c) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -988,13 +988,13 @@ define i64 @f6() { ; MIPS64R6-NEXT: lwu $2, %lo(c)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f6: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(c) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: li16 $2, 0 # ; MMR5FP64-NEXT: # > @@ -1003,17 +1003,17 @@ define i64 @f6() { ; MMR5FP64-NEXT: lw $3, %lo(c)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f6: ; MIPS32R5FP643: # %bb.0: # %entry ; MIPS32R5FP643-NEXT: lui $1, %hi(c) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: lw $3, %lo(c)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: addiu $2, $zero, 0 # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: lw $3, %lo(c)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: sra $2, $3, 31 # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: lw $3, %lo(c)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: sra $2, $3, 31 # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: lw $3, %lo(c)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > @@ -1080,11 +1080,11 @@ define i64 @f7() { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(c) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: lw $3, %lo(c)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sra $2, $3, 31 # ; MMR6-NEXT: # @@ -1096,11 +1096,11 @@ define i64 @f7() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(c) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(c) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -1108,7 +1108,7 @@ define i64 @f7() { ; MIPS3-NEXT: daddiu $1, $1, %hi(c) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -1118,17 +1118,17 @@ define i64 @f7() { ; MIPS3-NEXT: lw $2, %lo(c)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f7: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(c) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(c) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -1136,7 +1136,7 @@ define i64 @f7() { ; MIPS64-NEXT: daddiu $1, $1, %hi(c) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -1146,17 +1146,17 @@ define i64 @f7() { ; MIPS64-NEXT: lw $2, %lo(c)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f7: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(c) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(c) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -1164,7 +1164,7 @@ define i64 @f7() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(c) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -1175,17 +1175,17 @@ define i64 @f7() { ; MIPS64R6-NEXT: lw $2, %lo(c)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f7: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(c) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: lw $3, %lo(c)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: sra $2, $3, 31 # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: lw $3, %lo(c)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: sra $2, $3, 31 # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: lwc1 $f0, %lo(e)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f8: ; MMR3: # %bb.0: # %entry ; MMR3-NEXT: lui $1, %hi(e) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: lwc1 $f0, %lo(e)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f8: ; MIPS32R6: # %bb.0: # %entry ; MIPS32R6-NEXT: lui $1, %hi(e) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: lwc1 $f0, %lo(e)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f8: ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(e) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: lwc1 $f0, %lo(e)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -1268,11 +1268,11 @@ define float @f8() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(e) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(e) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -1280,7 +1280,7 @@ define float @f8() { ; MIPS3-NEXT: daddiu $1, $1, %hi(e) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -1290,17 +1290,17 @@ define float @f8() { ; MIPS3-NEXT: lwc1 $f0, %lo(e)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f8: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(e) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(e) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -1308,7 +1308,7 @@ define float @f8() { ; MIPS64-NEXT: daddiu $1, $1, %hi(e) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -1318,17 +1318,17 @@ define float @f8() { ; MIPS64-NEXT: lwc1 $f0, %lo(e)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f8: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(e) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(e) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -1336,7 +1336,7 @@ define float @f8() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(e) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -1347,31 +1347,31 @@ define float @f8() { ; MIPS64R6-NEXT: lwc1 $f0, %lo(e)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f8: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(e) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: lwc1 $f0, %lo(e)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f8: ; MIPS32R5FP643: # %bb.0: # %entry ; MIPS32R5FP643-NEXT: lui $1, %hi(e) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: lwc1 $f0, %lo(e)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > entry: %0 = load float, ptr @e ret float %0 @@ -1382,48 +1382,48 @@ define double @f9() { ; MIPS32: # %bb.0: # %entry ; MIPS32-NEXT: lui $1, %hi(f) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: ldc1 $f0, %lo(f)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f9: ; MMR3: # %bb.0: # %entry ; MMR3-NEXT: lui $1, %hi(f) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: ldc1 $f0, %lo(f)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f9: ; MIPS32R6: # %bb.0: # %entry ; MIPS32R6-NEXT: lui $1, %hi(f) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: ldc1 $f0, %lo(f)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f9: ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $1, %hi(f) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: ldc1 $f0, %lo(f)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -1431,11 +1431,11 @@ define double @f9() { ; MIPS3: # %bb.0: # %entry ; MIPS3-NEXT: lui $1, %highest(f) # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: daddiu $1, $1, %higher(f) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -1443,7 +1443,7 @@ define double @f9() { ; MIPS3-NEXT: daddiu $1, $1, %hi(f) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; MIPS3-NEXT: dsll $1, $1, 16 # ; MIPS3-NEXT: # @@ -1453,17 +1453,17 @@ define double @f9() { ; MIPS3-NEXT: ldc1 $f0, %lo(f)($1) # ; MIPS3-NEXT: # -; MIPS3-NEXT: # > +; MIPS3-NEXT: # > ; ; MIPS64-LABEL: f9: ; MIPS64: # %bb.0: # %entry ; MIPS64-NEXT: lui $1, %highest(f) # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: daddiu $1, $1, %higher(f) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -1471,7 +1471,7 @@ define double @f9() { ; MIPS64-NEXT: daddiu $1, $1, %hi(f) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; MIPS64-NEXT: dsll $1, $1, 16 # ; MIPS64-NEXT: # @@ -1481,17 +1481,17 @@ define double @f9() { ; MIPS64-NEXT: ldc1 $f0, %lo(f)($1) # ; MIPS64-NEXT: # -; MIPS64-NEXT: # > +; MIPS64-NEXT: # > ; ; MIPS64R6-LABEL: f9: ; MIPS64R6: # %bb.0: # %entry ; MIPS64R6-NEXT: lui $1, %highest(f) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(f) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -1499,7 +1499,7 @@ define double @f9() { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(f) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -1510,31 +1510,31 @@ define double @f9() { ; MIPS64R6-NEXT: ldc1 $f0, %lo(f)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f9: ; MMR5FP64: # %bb.0: # %entry ; MMR5FP64-NEXT: lui $1, %hi(f) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: ldc1 $f0, %lo(f)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f9: ; MIPS32R5FP643: # %bb.0: # %entry ; MIPS32R5FP643-NEXT: lui $1, %hi(f) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: ldc1 $f0, %lo(f)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > entry: %0 = load double, ptr @f ret double %0 diff --git a/llvm/test/CodeGen/Mips/llvm-ir/store.ll b/llvm/test/CodeGen/Mips/llvm-ir/store.ll index 8b51c0939b8d4..bc7b6a9f84a5f 100644 --- a/llvm/test/CodeGen/Mips/llvm-ir/store.ll +++ b/llvm/test/CodeGen/Mips/llvm-ir/store.ll @@ -26,48 +26,48 @@ define void @f1(i8 %a) { ; MIPS32: # %bb.0: ; MIPS32-NEXT: lui $1, %hi(a) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: sb $4, %lo(a)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f1: ; MMR3: # %bb.0: ; MMR3-NEXT: lui $1, %hi(a) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: sb $4, %lo(a)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f1: ; MIPS32R6: # %bb.0: ; MIPS32R6-NEXT: lui $1, %hi(a) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: sb $4, %lo(a)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f1: ; MMR6: # %bb.0: ; MMR6-NEXT: lui $1, %hi(a) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sb $4, %lo(a)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -75,11 +75,11 @@ define void @f1(i8 %a) { ; MIPS4: # %bb.0: ; MIPS4-NEXT: lui $1, %highest(a) # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: daddiu $1, $1, %higher(a) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -87,7 +87,7 @@ define void @f1(i8 %a) { ; MIPS4-NEXT: daddiu $1, $1, %hi(a) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -97,17 +97,17 @@ define void @f1(i8 %a) { ; MIPS4-NEXT: sb $4, %lo(a)($1) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; ; MIPS64R6-LABEL: f1: ; MIPS64R6: # %bb.0: ; MIPS64R6-NEXT: lui $1, %highest(a) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(a) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -115,7 +115,7 @@ define void @f1(i8 %a) { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(a) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -126,31 +126,31 @@ define void @f1(i8 %a) { ; MIPS64R6-NEXT: sb $4, %lo(a)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f1: ; MMR5FP64: # %bb.0: ; MMR5FP64-NEXT: lui $1, %hi(a) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: sb $4, %lo(a)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f1: ; MIPS32R5FP643: # %bb.0: ; MIPS32R5FP643-NEXT: lui $1, %hi(a) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: sb $4, %lo(a)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > store i8 %a, ptr @a ret void } @@ -160,48 +160,48 @@ define void @f2(i16 %a) { ; MIPS32: # %bb.0: ; MIPS32-NEXT: lui $1, %hi(b) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: sh $4, %lo(b)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f2: ; MMR3: # %bb.0: ; MMR3-NEXT: lui $1, %hi(b) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: sh $4, %lo(b)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f2: ; MIPS32R6: # %bb.0: ; MIPS32R6-NEXT: lui $1, %hi(b) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: sh $4, %lo(b)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f2: ; MMR6: # %bb.0: ; MMR6-NEXT: lui $1, %hi(b) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sh $4, %lo(b)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -209,11 +209,11 @@ define void @f2(i16 %a) { ; MIPS4: # %bb.0: ; MIPS4-NEXT: lui $1, %highest(b) # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: daddiu $1, $1, %higher(b) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -221,7 +221,7 @@ define void @f2(i16 %a) { ; MIPS4-NEXT: daddiu $1, $1, %hi(b) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -231,17 +231,17 @@ define void @f2(i16 %a) { ; MIPS4-NEXT: sh $4, %lo(b)($1) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; ; MIPS64R6-LABEL: f2: ; MIPS64R6: # %bb.0: ; MIPS64R6-NEXT: lui $1, %highest(b) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(b) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -249,7 +249,7 @@ define void @f2(i16 %a) { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(b) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -260,31 +260,31 @@ define void @f2(i16 %a) { ; MIPS64R6-NEXT: sh $4, %lo(b)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f2: ; MMR5FP64: # %bb.0: ; MMR5FP64-NEXT: lui $1, %hi(b) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: sh $4, %lo(b)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f2: ; MIPS32R5FP643: # %bb.0: ; MIPS32R5FP643-NEXT: lui $1, %hi(b) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: sh $4, %lo(b)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > store i16 %a, ptr @b ret void } @@ -294,48 +294,48 @@ define void @f3(i32 %a) { ; MIPS32: # %bb.0: ; MIPS32-NEXT: lui $1, %hi(c) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: sw $4, %lo(c)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f3: ; MMR3: # %bb.0: ; MMR3-NEXT: lui $1, %hi(c) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: sw $4, %lo(c)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f3: ; MIPS32R6: # %bb.0: ; MIPS32R6-NEXT: lui $1, %hi(c) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: sw $4, %lo(c)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f3: ; MMR6: # %bb.0: ; MMR6-NEXT: lui $1, %hi(c) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw $4, %lo(c)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -343,11 +343,11 @@ define void @f3(i32 %a) { ; MIPS4: # %bb.0: ; MIPS4-NEXT: lui $1, %highest(c) # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: daddiu $1, $1, %higher(c) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -355,7 +355,7 @@ define void @f3(i32 %a) { ; MIPS4-NEXT: daddiu $1, $1, %hi(c) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -365,17 +365,17 @@ define void @f3(i32 %a) { ; MIPS4-NEXT: sw $4, %lo(c)($1) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; ; MIPS64R6-LABEL: f3: ; MIPS64R6: # %bb.0: ; MIPS64R6-NEXT: lui $1, %highest(c) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(c) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -383,7 +383,7 @@ define void @f3(i32 %a) { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(c) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -394,31 +394,31 @@ define void @f3(i32 %a) { ; MIPS64R6-NEXT: sw $4, %lo(c)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f3: ; MMR5FP64: # %bb.0: ; MMR5FP64-NEXT: lui $1, %hi(c) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: sw $4, %lo(c)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f3: ; MIPS32R5FP643: # %bb.0: ; MIPS32R5FP643-NEXT: lui $1, %hi(c) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: sw $4, %lo(c)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > store i32 %a, ptr @c ret void } @@ -428,15 +428,15 @@ define void @f4(i64 %a) { ; MIPS32: # %bb.0: ; MIPS32-NEXT: lui $1, %hi(d) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: sw $4, %lo(d)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: addiu $1, $1, %lo(d) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: sw $5, 4($1) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: sw $4, %lo(d)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: addiu $2, $1, %lo(d) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: sw16 $5, 4($2) # ; MMR3-NEXT: # @@ -468,15 +468,15 @@ define void @f4(i64 %a) { ; MIPS32R6: # %bb.0: ; MIPS32R6-NEXT: lui $1, %hi(d) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: sw $4, %lo(d)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: addiu $1, $1, %lo(d) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > @@ -489,15 +489,15 @@ define void @f4(i64 %a) { ; MMR6: # %bb.0: ; MMR6-NEXT: lui $1, %hi(d) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw $4, %lo(d)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $1, %lo(d) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $5, 4($2) # ; MMR6-NEXT: # @@ -509,11 +509,11 @@ define void @f4(i64 %a) { ; MIPS4: # %bb.0: ; MIPS4-NEXT: lui $1, %highest(d) # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: daddiu $1, $1, %higher(d) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -521,7 +521,7 @@ define void @f4(i64 %a) { ; MIPS4-NEXT: daddiu $1, $1, %hi(d) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -531,17 +531,17 @@ define void @f4(i64 %a) { ; MIPS4-NEXT: sd $4, %lo(d)($1) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; ; MIPS64R6-LABEL: f4: ; MIPS64R6: # %bb.0: ; MIPS64R6-NEXT: lui $1, %highest(d) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(d) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -549,7 +549,7 @@ define void @f4(i64 %a) { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(d) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -560,21 +560,21 @@ define void @f4(i64 %a) { ; MIPS64R6-NEXT: sd $4, %lo(d)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f4: ; MMR5FP64: # %bb.0: ; MMR5FP64-NEXT: lui $1, %hi(d) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: sw $4, %lo(d)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: addiu $2, $1, %lo(d) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: sw16 $5, 4($2) # ; MMR5FP64-NEXT: # @@ -586,15 +586,15 @@ define void @f4(i64 %a) { ; MIPS32R5FP643: # %bb.0: ; MIPS32R5FP643-NEXT: lui $1, %hi(d) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: sw $4, %lo(d)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: addiu $1, $1, %lo(d) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: sw $5, 4($1) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: swc1 $f12, %lo(e)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f5: ; MMR3: # %bb.0: ; MMR3-NEXT: lui $1, %hi(e) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: swc1 $f12, %lo(e)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f5: ; MIPS32R6: # %bb.0: ; MIPS32R6-NEXT: lui $1, %hi(e) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: swc1 $f12, %lo(e)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f5: ; MMR6: # %bb.0: ; MMR6-NEXT: lui $1, %hi(e) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: swc1 $f12, %lo(e)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -659,11 +659,11 @@ define void @f5(float %e) { ; MIPS4: # %bb.0: ; MIPS4-NEXT: lui $1, %highest(e) # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: daddiu $1, $1, %higher(e) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -671,7 +671,7 @@ define void @f5(float %e) { ; MIPS4-NEXT: daddiu $1, $1, %hi(e) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -681,17 +681,17 @@ define void @f5(float %e) { ; MIPS4-NEXT: swc1 $f12, %lo(e)($1) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; ; MIPS64R6-LABEL: f5: ; MIPS64R6: # %bb.0: ; MIPS64R6-NEXT: lui $1, %highest(e) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(e) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -699,7 +699,7 @@ define void @f5(float %e) { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(e) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -710,31 +710,31 @@ define void @f5(float %e) { ; MIPS64R6-NEXT: swc1 $f12, %lo(e)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f5: ; MMR5FP64: # %bb.0: ; MMR5FP64-NEXT: lui $1, %hi(e) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: swc1 $f12, %lo(e)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f5: ; MIPS32R5FP643: # %bb.0: ; MIPS32R5FP643-NEXT: lui $1, %hi(e) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: swc1 $f12, %lo(e)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > store float %e, ptr @e ret void } @@ -744,48 +744,48 @@ define void @f6(double %f) { ; MIPS32: # %bb.0: ; MIPS32-NEXT: lui $1, %hi(f) # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; MIPS32-NEXT: jr $ra # > ; MIPS32-NEXT: sdc1 $f12, %lo(f)($1) # ; MIPS32-NEXT: # -; MIPS32-NEXT: # > +; MIPS32-NEXT: # > ; ; MMR3-LABEL: f6: ; MMR3: # %bb.0: ; MMR3-NEXT: lui $1, %hi(f) # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; MMR3-NEXT: jr $ra # > ; MMR3-NEXT: sdc1 $f12, %lo(f)($1) # ; MMR3-NEXT: # -; MMR3-NEXT: # > +; MMR3-NEXT: # > ; ; MIPS32R6-LABEL: f6: ; MIPS32R6: # %bb.0: ; MIPS32R6-NEXT: lui $1, %hi(f) # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: jr $ra # ; MIPS32R6-NEXT: # > ; MIPS32R6-NEXT: sdc1 $f12, %lo(f)($1) # ; MIPS32R6-NEXT: # -; MIPS32R6-NEXT: # > +; MIPS32R6-NEXT: # > ; ; MMR6-LABEL: f6: ; MMR6: # %bb.0: ; MMR6-NEXT: lui $1, %hi(f) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sdc1 $f12, %lo(f)($1) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: jrc $ra # > ; @@ -793,11 +793,11 @@ define void @f6(double %f) { ; MIPS4: # %bb.0: ; MIPS4-NEXT: lui $1, %highest(f) # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: daddiu $1, $1, %higher(f) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -805,7 +805,7 @@ define void @f6(double %f) { ; MIPS4-NEXT: daddiu $1, $1, %hi(f) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; MIPS4-NEXT: dsll $1, $1, 16 # ; MIPS4-NEXT: # @@ -815,17 +815,17 @@ define void @f6(double %f) { ; MIPS4-NEXT: sdc1 $f12, %lo(f)($1) # ; MIPS4-NEXT: # -; MIPS4-NEXT: # > +; MIPS4-NEXT: # > ; ; MIPS64R6-LABEL: f6: ; MIPS64R6: # %bb.0: ; MIPS64R6-NEXT: lui $1, %highest(f) # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: daddiu $1, $1, %higher(f) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -833,7 +833,7 @@ define void @f6(double %f) { ; MIPS64R6-NEXT: daddiu $1, $1, %hi(f) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; MIPS64R6-NEXT: dsll $1, $1, 16 # ; MIPS64R6-NEXT: # @@ -844,31 +844,31 @@ define void @f6(double %f) { ; MIPS64R6-NEXT: sdc1 $f12, %lo(f)($1) # ; MIPS64R6-NEXT: # -; MIPS64R6-NEXT: # > +; MIPS64R6-NEXT: # > ; ; MMR5FP64-LABEL: f6: ; MMR5FP64: # %bb.0: ; MMR5FP64-NEXT: lui $1, %hi(f) # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; MMR5FP64-NEXT: jr $ra # > ; MMR5FP64-NEXT: sdc1 $f12, %lo(f)($1) # ; MMR5FP64-NEXT: # -; MMR5FP64-NEXT: # > +; MMR5FP64-NEXT: # > ; ; MIPS32R5FP643-LABEL: f6: ; MIPS32R5FP643: # %bb.0: ; MIPS32R5FP643-NEXT: lui $1, %hi(f) # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > ; MIPS32R5FP643-NEXT: jr $ra # > ; MIPS32R5FP643-NEXT: sdc1 $f12, %lo(f)($1) # ; MIPS32R5FP643-NEXT: # -; MIPS32R5FP643-NEXT: # > +; MIPS32R5FP643-NEXT: # > store double %f, ptr @f ret void } diff --git a/llvm/test/CodeGen/Mips/setcc-se.ll b/llvm/test/CodeGen/Mips/setcc-se.ll index c1054607d5e91..12bc4553fe1a3 100644 --- a/llvm/test/CodeGen/Mips/setcc-se.ll +++ b/llvm/test/CodeGen/Mips/setcc-se.ll @@ -61,11 +61,11 @@ define void @slti_beq0(i32 %a) { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $2, %hi(_gp_disp) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $2, %lo(_gp_disp) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addu $2, $2, $25 # ; MMR6-NEXT: # @@ -81,7 +81,7 @@ define void @slti_beq0(i32 %a) { ; MMR6-NEXT: lw $2, %got(g1)($2) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $4, 0($2) # ; MMR6-NEXT: # @@ -120,11 +120,11 @@ define void @slti_beq1(i32 %a) { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $2, %hi(_gp_disp) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $2, %lo(_gp_disp) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addu $2, $2, $25 # ; MMR6-NEXT: # @@ -147,7 +147,7 @@ define void @slti_beq1(i32 %a) { ; MMR6-NEXT: lw $2, %got(g1)($2) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $4, 0($2) # ; MMR6-NEXT: # @@ -184,11 +184,11 @@ define void @slti_beq2(i32 %a) { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $2, %hi(_gp_disp) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $2, %lo(_gp_disp) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addu $2, $2, $25 # ; MMR6-NEXT: # @@ -204,7 +204,7 @@ define void @slti_beq2(i32 %a) { ; MMR6-NEXT: lw $2, %got(g1)($2) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $4, 0($2) # ; MMR6-NEXT: # @@ -242,11 +242,11 @@ define void @slti_beq3(i32 %a) { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $2, %hi(_gp_disp) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $2, %lo(_gp_disp) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addu $2, $2, $25 # ; MMR6-NEXT: # @@ -266,7 +266,7 @@ define void @slti_beq3(i32 %a) { ; MMR6-NEXT: lw $2, %got(g1)($2) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $4, 0($2) # ; MMR6-NEXT: # @@ -303,11 +303,11 @@ define void @sltiu_beq0(i32 %a) { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $2, %hi(_gp_disp) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $2, %lo(_gp_disp) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addu $2, $2, $25 # ; MMR6-NEXT: # @@ -323,7 +323,7 @@ define void @sltiu_beq0(i32 %a) { ; MMR6-NEXT: lw $2, %got(g1)($2) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $4, 0($2) # ; MMR6-NEXT: # @@ -361,11 +361,11 @@ define void @sltiu_beq1(i32 %a) { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $2, %hi(_gp_disp) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $2, %lo(_gp_disp) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addu $2, $2, $25 # ; MMR6-NEXT: # @@ -385,7 +385,7 @@ define void @sltiu_beq1(i32 %a) { ; MMR6-NEXT: lw $2, %got(g1)($2) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $4, 0($2) # ; MMR6-NEXT: # @@ -422,11 +422,11 @@ define void @sltiu_beq2(i32 %a) { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $2, %hi(_gp_disp) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $2, %lo(_gp_disp) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addu $2, $2, $25 # ; MMR6-NEXT: # @@ -442,7 +442,7 @@ define void @sltiu_beq2(i32 %a) { ; MMR6-NEXT: lw $2, %got(g1)($2) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $4, 0($2) # ; MMR6-NEXT: # @@ -481,11 +481,11 @@ define void @sltiu_beq3(i32 %a) { ; MMR6: # %bb.0: # %entry ; MMR6-NEXT: lui $2, %hi(_gp_disp) # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addiu $2, $2, %lo(_gp_disp) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: addu $2, $2, $25 # ; MMR6-NEXT: # @@ -508,7 +508,7 @@ define void @sltiu_beq3(i32 %a) { ; MMR6-NEXT: lw $2, %got(g1)($2) # ; MMR6-NEXT: # -; MMR6-NEXT: # > +; MMR6-NEXT: # > ; MMR6-NEXT: sw16 $4, 0($2) # ; MMR6-NEXT: # diff --git a/llvm/test/MC/ELF/mc-dump.s b/llvm/test/MC/ELF/mc-dump.s index 9cf15a7ddee46..6a71965959631 100644 --- a/llvm/test/MC/ELF/mc-dump.s +++ b/llvm/test/MC/ELF/mc-dump.s @@ -15,8 +15,8 @@ # CHECK-NEXT:3 Relaxable Size:2 > # CHECK-NEXT: Fixup @1 Value:.Ltmp0 Kind:4001 # CHECK-NEXT:5 Data Size:16 [48,8b,04,25,00,00,00,00,48,8b,04,25,00,00,00,00] -# CHECK-NEXT: Fixup @4 Value:f0@ Kind:4017 -# CHECK-NEXT: Fixup @12 Value:_start@ Kind:4017 +# CHECK-NEXT: Fixup @4 Value:f0@ Kind:4020 +# CHECK-NEXT: Fixup @12 Value:_start@ Kind:4020 # CHECK-NEXT: Symbol @16 .Ltmp0 Temporary # CHECK-NEXT:MCSection Name:.data # CHECK-NEXT:0 Data Size:0 [] @@ -30,8 +30,8 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t -debug-only=mc-dump -save-temp-labels -g 2>&1 | FileCheck %s --check-prefix=CHECK2 # CHECK2:5 Data Size:16 [48,8b,04,25,00,00,00,00,48,8b,04,25,00,00,00,00] -# CHECK2-NEXT: Fixup @4 Value:f0@ Kind:4017 -# CHECK2-NEXT: Fixup @12 Value:_start@ Kind:4017 +# CHECK2-NEXT: Fixup @4 Value:f0@ Kind:4020 +# CHECK2-NEXT: Fixup @12 Value:_start@ Kind:4020 # CHECK2-NEXT: Symbol @16 .Ltmp1 # CHECK2-NEXT: Symbol @0 .Ltmp3 Temporary # CHECK2-NEXT: Symbol @8 .Ltmp4 Temporary diff --git a/llvm/test/MC/RISCV/Relocations/mc-dump.s b/llvm/test/MC/RISCV/Relocations/mc-dump.s index c646e6f54b261..1d55fa671a5ae 100644 --- a/llvm/test/MC/RISCV/Relocations/mc-dump.s +++ b/llvm/test/MC/RISCV/Relocations/mc-dump.s @@ -7,7 +7,7 @@ # CHECK-NEXT: Symbol @0 .text # CHECK-NEXT:0 Align Align:4 Fill:0 FillLen:1 MaxBytesToEmit:4 Nops # CHECK-NEXT:0 Data LinkerRelaxable Size:8 [97,00,00,00,e7,80,00,00] -# CHECK-NEXT: Fixup @0 Value:specifier(19,ext) Kind:4023 LinkerRelaxable +# CHECK-NEXT: Fixup @0 Value:specifier(19,ext) Kind:4026 LinkerRelaxable # CHECK-NEXT: Symbol @0 $x # CHECK-NEXT:8 Align Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops # CHECK-NEXT:12 Data Size:4 [13,05,30,00] From 067d62a5377915f82cdda7e59c3b5ae0734b6e1c Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Fri, 28 Feb 2025 22:28:38 +0000 Subject: [PATCH 03/16] [MC] Support folding capability offset label difference between fragments In LLVM 15, these expressions would first try and fold the RHS, which would succeed, and use that as a constant offset for the symbol. In LLVM 17, RISC-V no longer folds label difference expressions within a section that has instructions due to relaxation, so the RHS remains unfolded, but cross-term folding will cancel the same symbol if it appears on both sides with different signs. Ideally we'd have SET/ADD/SUB-like capability relocations to support relaxation, but for now just force the RHS folding to happen again for capability relocations. Note that when RVC is enabled branches trigger the same code paths as linker relaxation, even with -mno-relax. --- llvm/test/MC/RISCV/cheri/chericap-expr-relax.s | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 llvm/test/MC/RISCV/cheri/chericap-expr-relax.s diff --git a/llvm/test/MC/RISCV/cheri/chericap-expr-relax.s b/llvm/test/MC/RISCV/cheri/chericap-expr-relax.s new file mode 100644 index 0000000000000..b95d555330abd --- /dev/null +++ b/llvm/test/MC/RISCV/cheri/chericap-expr-relax.s @@ -0,0 +1,16 @@ +# RUN: llvm-mc -triple=riscv64 -mattr=+c,+xcheri < %s \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+xcheri < %s \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix=CHECK-RELOC %s + +foo: + nop + j bar +bar: + ret + +.data + +# CHECK-INST: .chericap foo+(bar-foo) +# CHECK-RELOC: 0x0 R_RISCV_CHERI_CAPABILITY foo 0x4 +.chericap foo + (bar - foo) From c11d8c26f042bcb051cce2f8ce7017a137e29a5e Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Fri, 28 Feb 2025 22:31:43 +0000 Subject: [PATCH 04/16] [CodeGen] Use non-preemptible symbol for BlockAddress global constants Just as with landing pads, which are basically a special form of BlockAddress, we should not use preemptible symbols here. --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 36 +++++++++++++++++-- .../CodeGen/Mips/cheri/cheri-blockaddress.ll | 4 +-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 87ad6d4607f3c..d978b6ebac277 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1107,6 +1107,35 @@ void AsmPrinter::emitFunctionHeader() { static bool needFuncLabels(const MachineFunction &MF, const AsmPrinter &Asm); +/// Returns true if function begin label should be emitted due to a +/// BlockAddress used as an initializer for a GlobalVariable. +static bool needFuncLabelForBlockAddress(const MachineFunction &MF) { + SmallVector Users; + + for (const auto &MBB : MF) { + if (!MBB.isIRBlockAddressTaken()) + continue; + + const auto *BB = MBB.getAddressTakenIRBlock(); + for (const auto &U : BB->users()) { + if (isa(U)) + Users.push_back(U); + } + } + + while (!Users.empty()) { + const Value *V = Users.pop_back_val(); + if (isa(V)) + return true; + if (isa(V)) + continue; + for (const auto &U : V->users()) + Users.push_back(U); + } + + return false; +} + /// EmitFunctionEntryLabel - Emit the label that is the entrypoint for the /// function. This can be overridden by targets as required to do custom stuff. void AsmPrinter::emitFunctionEntryLabel() { @@ -1116,7 +1145,9 @@ void AsmPrinter::emitFunctionEntryLabel() { if (TM.getTargetTriple().isOSBinFormatELF()) { // For CHERI purecap exception handling, we always have to use a local // alias even if the function is not dso_local. - bool ForceLocal = MAI->isCheriPurecapABI() && needFuncLabels(*MF, *this); + bool ForceLocal = + MAI->isCheriPurecapABI() && + (needFuncLabels(*MF, *this) || needFuncLabelForBlockAddress(*MF)); MCSymbol *Sym = getSymbolPreferLocal(MF->getFunction(), ForceLocal); if (Sym != CurrentFnSym) { CurrentFnBeginLocal = Sym; @@ -4163,7 +4194,8 @@ static void emitGlobalConstantCHERICap(const DataLayout &DL, const Constant *CV, } else if (const MCSymbolRefExpr *SRE = dyn_cast(Expr)) { if (auto BA = dyn_cast(CV)) { // For block addresses we emit `.chericap FN+(.LtmpN - FN)` - auto FnStart = AP.getSymbol(BA->getFunction()); + // NB: Must use a non-preemptible symbol + auto FnStart = AP.getSymbolPreferLocal(*BA->getFunction(), true); const MCExpr *Start = MCSymbolRefExpr::create(FnStart, Ctx); const MCExpr *DiffToStart = MCBinaryExpr::createSub(SRE, Start, Ctx); const MCExpr *CapExpr = MCBinaryExpr::createAdd(Start, DiffToStart, Ctx); diff --git a/llvm/test/CodeGen/Mips/cheri/cheri-blockaddress.ll b/llvm/test/CodeGen/Mips/cheri/cheri-blockaddress.ll index 52f7d0f5035c3..c8bb07ea27718 100644 --- a/llvm/test/CodeGen/Mips/cheri/cheri-blockaddress.ll +++ b/llvm/test/CodeGen/Mips/cheri/cheri-blockaddress.ll @@ -62,12 +62,12 @@ indirectgoto: ; preds = %entry ; ASM: .end addrof_label_in_local ; ASM-LABEL: addrof_label_in_static.b: -; ASM-NEXT: .chericap addrof_label_in_static+(.Ltmp0-addrof_label_in_static) +; ASM-NEXT: .chericap .Laddrof_label_in_static$local+(.Ltmp0-.Laddrof_label_in_static$local) ; ASM-NEXT: .size addrof_label_in_static.b, [[#CAP_SIZE]] ; The .o file should contain a relocation against the function with a constant addend (0x1c) ; OBJ: Section (8) .rela.data { -; OBJ-NEXT: 0x0 R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE addrof_label_in_static 0x1C +; OBJ-NEXT: 0x0 R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .Laddrof_label_in_static$local 0x1C ; OBJ-NEXT: } From 6df9b3848733c27b45a5a163da6b91471935b029 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Fri, 14 Mar 2025 22:39:32 +0000 Subject: [PATCH 05/16] [clang][RISCV] Return ISAInfo from getArchFeatures rather than recomputing --- clang/lib/Driver/ToolChains/Arch/RISCV.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 18d081b53b550..177af5473de7d 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -27,7 +27,8 @@ using namespace llvm::opt; // Returns false if an error is diagnosed. static bool getArchFeatures(const Driver &D, StringRef Arch, std::vector &Features, - const ArgList &Args) { + const ArgList &Args, + std::unique_ptr &ISAInfoOut) { bool EnableExperimentalExtensions = Args.hasArg(options::OPT_menable_experimental_extensions); auto ISAInfo = @@ -48,6 +49,7 @@ static bool getArchFeatures(const Driver &D, StringRef Arch, if (EnableExperimentalExtensions) Features.push_back(Args.MakeArgString("+experimental")); + ISAInfoOut = std::move(*ISAInfo); return true; } @@ -92,8 +94,9 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector &Features) { std::string MArch = getRISCVArch(Args, Triple); + std::unique_ptr ISAInfo; - if (!getArchFeatures(D, MArch, Features, Args)) + if (!getArchFeatures(D, MArch, Features, Args, ISAInfo)) return; bool CPUFastScalarUnaligned = false; @@ -210,14 +213,7 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, // +xcheriot implies both +xcheri and +xcheripurecap Features.push_back("+xcheriot"); } else if (IsPureCapability) { - auto ISAInfo = llvm::RISCVISAInfo::parseFeatures( - Triple.isArch32Bit() ? 32 : 64, - std::vector(Features.begin(), Features.end())); - if (!ISAInfo) { - handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) { - D.Diag(diag::err_invalid_feature_combination) << ErrMsg.getMessage(); - }); - } else if (!(*ISAInfo)->hasExtension("xcheri")) { + if (!ISAInfo->hasExtension("xcheri")) { D.Diag(diag::err_riscv_invalid_abi) << A->getValue() << "pure capability ABI requires xcheri extension to be specified"; From 1a7ac953f5f57c1e0b08ed1608a5b69c5472d4af Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Mon, 12 Aug 2024 13:37:10 +0100 Subject: [PATCH 06/16] [clangd][test] Account for downstream coroutines hack in isKeywords test --- clang-tools-extra/clangd/unittests/SourceCodeTests.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp index 640f2f9f2bd84..e9920e1b41cb7 100644 --- a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp +++ b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp @@ -808,6 +808,10 @@ TEST(SourceCodeTests, isKeywords) { LangOpts.Coroutines = true; EXPECT_TRUE(isKeyword("int", LangOpts)); EXPECT_TRUE(isKeyword("return", LangOpts)); + // CHERI-TODO: COROUTINES_KEYWORD is not included in CXX20_KEYWORD until + // https://github.com/CTSRD-CHERI/llvm-project/issues/717 has been fixed. + EXPECT_FALSE(isKeyword("co_await", LangOpts)); + LangOpts.Coroutines = true; EXPECT_TRUE(isKeyword("co_await", LangOpts)); // these are identifiers (not keywords!) with special meaning in some From e7fe64fb11165800067f9cf90d24f61035905fa9 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Feb 2025 18:00:40 +0000 Subject: [PATCH 07/16] tests: prefer __has_feature(capabilities) to defined(__CHERI__) --- clang/test/CodeGen/builtin-align.c | 2 +- clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/CodeGen/builtin-align.c b/clang/test/CodeGen/builtin-align.c index 6ad904863131e..dfe6e808f577d 100644 --- a/clang/test/CodeGen/builtin-align.c +++ b/clang/test/CodeGen/builtin-align.c @@ -40,7 +40,7 @@ #error MISSING TYPE #endif -#ifndef __CHERI__ +#if !__has_feature(capabilities) #define __capability #endif diff --git a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp index d50f71aa3d8a1..6a709cedc3e36 100644 --- a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp +++ b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp @@ -9,7 +9,7 @@ typedef unsigned long ulong; int foo; -#ifdef __CHERI__ +#if __has_feature(capabilities) #define CAP __capability #else #define CAP @@ -68,7 +68,7 @@ int main() { } // Check that we don't warn on dependent types -#ifdef __CHERI__ +#if __has_feature(capabilities) template long offset_get(T x) { return __builtin_cheri_offset_get(reinterpret_cast(x)); From 94e37d52a2df7152daea447107d421922d4f1682 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Feb 2025 18:00:40 +0000 Subject: [PATCH 08/16] libunwind: prefer __has_feature(capabilities) to defined(__CHERI__) --- libunwind/src/AddressSpace.hpp | 6 +++--- libunwind/src/DwarfInstructions.hpp | 2 +- libunwind/src/Registers.hpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 0ab42a25c7dfe..1db9f0a169f5a 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -174,7 +174,7 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace { public: typedef uintptr_t pint_t; typedef intptr_t sint_t; -#ifndef __CHERI__ +#if !__has_feature(capabilities) typedef libunwind::fake_capability_t capability_t; #else typedef ::uintcap_t capability_t; @@ -342,7 +342,7 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace { static pint_t to_pint_t(capability_t cap) { #ifdef __CHERI_PURE_CAPABILITY__ return (uintcap_t)cap; -#elif defined(__CHERI__) +#elif __has_feature(capabilities) return (__cheri_addr pint_t)cap; #else pint_t result; @@ -351,7 +351,7 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace { #endif } static capability_t to_capability_t(pint_t pint) { -#ifdef __CHERI__ +#if __has_feature(capabilities) return (uintcap_t)pint; #else capability_t result; diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index b5d376225e945..6565ee54302cf 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -495,7 +495,7 @@ DwarfInstructions::evaluateExpression(pint_t expression, A &addressSpace, // XXXAR: I am not entirely sure these operations should work on a uintcap_t // but if it's an untagged integer value it is fine #pragma clang diagnostic push -#ifdef __CHERI__ +#if __has_feature(capabilities) #pragma clang diagnostic ignored "-Wcheri-bitwise-operations" #endif const bool log = true; diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index 6be9a40b14e6c..4328bfbd602cb 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -24,7 +24,7 @@ namespace libunwind { // For emulating 128-bit registers struct v128 { uint32_t vec[4]; }; // For emulating CHERI capability -#ifndef __CHERI__ +#if !_has_feature(capabilities) struct __attribute__((aligned(16))) fake_capability { char bytes[16]; }; @@ -3308,7 +3308,7 @@ class _LIBUNWIND_HIDDEN Registers_mips_newabi { Registers_mips_newabi(); Registers_mips_newabi(const void *registers); CAPABILITIES_NOT_SUPPORTED -#ifdef __CHERI__ +#if __has_feature(capabilities) #pragma message("Should also handle capability registers here.") #endif From 97192f14c9d3b53d627e42182b8b19fa5e4d0acb Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Feb 2025 18:00:40 +0000 Subject: [PATCH 09/16] libcxx: prefer __has_feature(capabilities) to defined(__CHERI__) --- libcxx/include/limits | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/limits b/libcxx/include/limits index bf161659a83c8..09ff5af0f4e42 100644 --- a/libcxx/include/limits +++ b/libcxx/include/limits @@ -448,7 +448,7 @@ protected: static _LIBCPP_CONSTEXPR const float_round_style round_style = round_to_nearest; }; -#ifdef __CHERI__ +#if __has_feature(capabilities) template<> class __libcpp_numeric_limits<__intcap_t, true> : public __libcpp_numeric_limits { }; From 93f3ce83ece543223e8912814f2453b4fa8e72b8 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Mon, 3 Mar 2025 17:18:50 +0000 Subject: [PATCH 10/16] Add __has_feature(cheri) This is intended to replace __has_feature(capabilities) which is almost certainly too generic to upstream. We'll support them side by side for the long term in our tree, but projects should generally migrate to __has_feature(cheri) as their need for older compilers passes. --- clang/include/clang/Basic/Features.def | 1 + clang/test/Preprocessor/cheri-features.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index bf71b614fec75..5fe3739ea65bd 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -319,6 +319,7 @@ FEATURE(experimental_library, LangOpts.ExperimentalLibrary) // CHERI features: FEATURE(capabilities, PP.getTargetInfo().SupportsCapabilities()) +FEATURE(cheri, PP.getTargetInfo().SupportsCapabilities()) FEATURE(pointer_interpretation, PP.getTargetInfo().SupportsCapabilities()) FEATURE(cheri_casts, PP.getTargetInfo().SupportsCapabilities()) // CHERI typed sealed pointers diff --git a/clang/test/Preprocessor/cheri-features.c b/clang/test/Preprocessor/cheri-features.c index 10365e3d964f6..4ea8056d3fdec 100644 --- a/clang/test/Preprocessor/cheri-features.c +++ b/clang/test/Preprocessor/cheri-features.c @@ -5,6 +5,15 @@ // RUN: 2>&1 | FileCheck --check-prefix=CHECK-MIPS %s +#if __has_feature(cheri) +#pragma message("__has_feature(cheri)") +// CHECK-CHERI: warning: __has_feature(cheri) +void* __capability w = 0; +#else +#pragma message("no cheri") +// CHECK-MIPS: warning: no cheri +#endif + #if __has_feature(capabilities) #pragma message("__has_feature(capabilities)") // CHECK-CHERI: warning: __has_feature(capabilities) From 90f42abdac86476b98ad249a732c16f9ed7d0071 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Mon, 3 Mar 2025 18:43:27 +0000 Subject: [PATCH 11/16] Use __has_feature(cheri) in tests Migrate tests that aren't explicitly about __has_feature(capabilities) to __has_feature(cheri). --- clang/test/CodeGen/builtin-align.c | 2 +- .../CodeGen/cheri/warn-ctoptr-functions.c | 4 +- .../cheri/constinit-zero-to-pointer.cpp | 2 +- .../test/SemaCXX/cheri/cheri-pointer-cast.cpp | 4 +- .../SemaCXX/cheri/dependent-cast-crash.cpp | 2 +- .../implicit-cap-conversion-return-value.cpp | 2 +- .../overloaded-function-template-arg.cpp | 2 +- libcxx/test/support/charconv_test_helpers.h | 48 ++++++++++--------- 8 files changed, 34 insertions(+), 32 deletions(-) diff --git a/clang/test/CodeGen/builtin-align.c b/clang/test/CodeGen/builtin-align.c index dfe6e808f577d..735cc721b1277 100644 --- a/clang/test/CodeGen/builtin-align.c +++ b/clang/test/CodeGen/builtin-align.c @@ -40,7 +40,7 @@ #error MISSING TYPE #endif -#if !__has_feature(capabilities) +#if !__has_feature(cheri) #define __capability #endif diff --git a/clang/test/CodeGen/cheri/warn-ctoptr-functions.c b/clang/test/CodeGen/cheri/warn-ctoptr-functions.c index 0de2d0e97efd4..490ce1f9609ea 100644 --- a/clang/test/CodeGen/cheri/warn-ctoptr-functions.c +++ b/clang/test/CodeGen/cheri/warn-ctoptr-functions.c @@ -22,7 +22,7 @@ typedef __sighandler_t * __kerncap sig_t; /* type of pointer to a signal functio typedef long sigset_t; struct __siginfo; -#if __has_feature(capabilities) +#if __has_feature(cheri) struct sigaction_c { union { void (* __capability __sa_handler)(int); @@ -42,7 +42,7 @@ struct sigaction_native { sigset_t sa_mask; /* signal mask to apply */ }; -#if __has_feature(capabilities) +#if __has_feature(cheri) typedef struct sigaction_c ksigaction_t; #else typedef struct sigaction_native ksigaction_t; diff --git a/clang/test/CodeGenCXX/cheri/constinit-zero-to-pointer.cpp b/clang/test/CodeGenCXX/cheri/constinit-zero-to-pointer.cpp index 994e82fe4fcc5..0f9f564684508 100644 --- a/clang/test/CodeGenCXX/cheri/constinit-zero-to-pointer.cpp +++ b/clang/test/CodeGenCXX/cheri/constinit-zero-to-pointer.cpp @@ -24,7 +24,7 @@ const AttributeData kBarcodeAttributeData{ AttributeData test() { return kBarcodeAttributeData; } /// Also check enums with underlying type __intcap for CHERI targets: -#if __has_feature(capabilities) +#if __has_feature(cheri) enum class IntCapEnum : __intcap { Zero }; void *intcapEnumToPtrConstant = (void *)IntCapEnum::Zero; diff --git a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp index 6a709cedc3e36..a7d31fe6de3ad 100644 --- a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp +++ b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp @@ -9,7 +9,7 @@ typedef unsigned long ulong; int foo; -#if __has_feature(capabilities) +#if __has_feature(cheri) #define CAP __capability #else #define CAP @@ -68,7 +68,7 @@ int main() { } // Check that we don't warn on dependent types -#if __has_feature(capabilities) +#if __has_feature(cheri) template long offset_get(T x) { return __builtin_cheri_offset_get(reinterpret_cast(x)); diff --git a/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp b/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp index 0cb11821bed95..39103f1c31ad8 100644 --- a/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp +++ b/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only %s -verify // RUN: %cheri_cc1 -fsyntax-only %s -verify // RUN: %cheri_purecap_cc1 -fsyntax-only %s -verify -#if !__has_feature(capabilities) +#if !__has_feature(cheri) #define __capability #endif diff --git a/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp b/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp index 5e21df86b528b..0ac9add6c5f58 100644 --- a/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp +++ b/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp @@ -7,7 +7,7 @@ // RUN: %cheri_cc1 -Wall -Wcheri-pointer-conversion -verify=c,expected,hybrid,hybrid-c -x c -fsyntax-only %s // RUN: %cheri_purecap_cc1 -Wall -Wcheri-pointer-conversion -verify=c,expected,purecap,purecap-c -x c -fsyntax-only %s -#if __has_feature(capabilities) +#if __has_feature(cheri) typedef unsigned __intcap uintcap_t; #else typedef unsigned long uintcap_t; diff --git a/clang/test/SemaCXX/cheri/overloaded-function-template-arg.cpp b/clang/test/SemaCXX/cheri/overloaded-function-template-arg.cpp index 9b1bf25433641..dbec6059d527b 100644 --- a/clang/test/SemaCXX/cheri/overloaded-function-template-arg.cpp +++ b/clang/test/SemaCXX/cheri/overloaded-function-template-arg.cpp @@ -32,7 +32,7 @@ void instantiate() { c::function(1); // expected-error{{address of overloaded function 'a' does not match required type 'void (char)'}} } -#if __has_feature(capabilities) +#if __has_feature(cheri) template // hybrid-note@-1 3 {{template parameter is declared here}} struct c_cap { diff --git a/libcxx/test/support/charconv_test_helpers.h b/libcxx/test/support/charconv_test_helpers.h index da5f836cbb34b..0b8c344d70dd6 100644 --- a/libcxx/test/support/charconv_test_helpers.h +++ b/libcxx/test/support/charconv_test_helpers.h @@ -292,35 +292,37 @@ constexpr auto concat(L1, L2) -> concat_t return {}; } -auto all_signed = type_list< - char, - signed char, - short, - int, - long, - long long +auto all_signed = + type_list< char, + signed char, + short, + int, + long, + long long #ifndef TEST_HAS_NO_INT128 - , - __int128_t + , + __int128_t #endif -#if __has_feature(capabilities) - , __intcap +#if __has_feature(cheri) + , + __intcap #endif - >(); -auto all_unsigned = type_list< - unsigned char, - unsigned short, - unsigned int, - unsigned long, - unsigned long long + >(); +auto all_unsigned = + type_list< unsigned char, + unsigned short, + unsigned int, + unsigned long, + unsigned long long #ifndef TEST_HAS_NO_INT128 - , - __uint128_t + , + __uint128_t #endif -#if __has_feature(capabilities) - , unsigned __intcap +#if __has_feature(cheri) + , + unsigned __intcap #endif - >(); + >(); auto integrals = concat(all_signed, all_unsigned); auto all_floats = type_list< float, double >(); //TODO: Add long double From 6b1b1d0d44f7b2ec86fdb24c3d86be6ec987ebfe Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Wed, 26 Feb 2025 18:37:56 +0000 Subject: [PATCH 12/16] Introduce __CHERI_HYBRID__ macro This is meant to replace expressions like: __has_feature(capabilities) && !defined(__CHERI_PURE_CAPABILITY__) or (currently( __CHERI__ && !defined(__CHERI_PURE_CAPABILITY__) --- clang/lib/Frontend/InitPreprocessor.cpp | 2 ++ clang/test/Preprocessor/cheri-cap-sizes.c | 1 + clang/test/Preprocessor/cheri-features.c | 9 +++++++++ clang/test/Preprocessor/cheri-riscv-feature-flags.c | 1 + clang/test/Preprocessor/init.c | 1 + .../function.objects/unord.hash/integral.pass.cpp | 6 +++--- 6 files changed, 17 insertions(+), 3 deletions(-) diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index e1d246f4b1804..fd2f094b59b95 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1148,6 +1148,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.getCheriBounds() > LangOptions::CBM_Conservative) Builder.defineMacro("__CHERI_SUBOBJECT_BOUNDS__", Twine(LangOpts.getCheriBounds())); + } else { + Builder.defineMacro("__CHERI_HYBRID__"); } } diff --git a/clang/test/Preprocessor/cheri-cap-sizes.c b/clang/test/Preprocessor/cheri-cap-sizes.c index 2bf52173fb9ed..b7ebdf0aad6dd 100644 --- a/clang/test/Preprocessor/cheri-cap-sizes.c +++ b/clang/test/Preprocessor/cheri-cap-sizes.c @@ -39,6 +39,7 @@ // PURECAP: #define __CHERI_PURE_CAPABILITY__ 2 // MIPS-NOT: __CHERI_PURE_CAPABILITY__ // CHECK: #define __CHERI__ 1 +// MIPS: #define __CHERI_HYBRID__ 1 // Note: 64-bit range for intcap makes more sense than the full range for pointers // CHECK: #define __INTCAP_MAX__ 9223372036854775807L diff --git a/clang/test/Preprocessor/cheri-features.c b/clang/test/Preprocessor/cheri-features.c index 4ea8056d3fdec..1b75bf3de4968 100644 --- a/clang/test/Preprocessor/cheri-features.c +++ b/clang/test/Preprocessor/cheri-features.c @@ -32,6 +32,15 @@ void* __capability y = 0; // CHECK-MIPS: warning: __CHERI__ not defined #endif +#if defined(__CHERI_HYBRID__) +#pragma message("__CHERI_HYBRID__ defined") +// CHECK-CHERI: warning: __CHERI_HYBRID__ defined +void* __capability y = 0; +#else +#pragma message("__CHERI_HYBRID__ not defined") +// CHECK-MIPS: warning: __CHERI_HYBRID__ not defined +#endif + int main() { return 0; } diff --git a/clang/test/Preprocessor/cheri-riscv-feature-flags.c b/clang/test/Preprocessor/cheri-riscv-feature-flags.c index 886ede81e78f2..11b3701e01e73 100644 --- a/clang/test/Preprocessor/cheri-riscv-feature-flags.c +++ b/clang/test/Preprocessor/cheri-riscv-feature-flags.c @@ -19,6 +19,7 @@ // CHECK: #define __CHERI_CAP_PERMISSION_PERMIT_STORE__ 8 // CHECK: #define __CHERI_CAP_PERMISSION_PERMIT_UNSEAL__ 512 // CHECK: #define __CHERI__ 1 +// CHECK: #define __CHERI_HYBRID__ 1 // CHECK32: #define __SIZEOF_CHERI_CAPABILITY__ 8 // CHECK64: #define __SIZEOF_CHERI_CAPABILITY__ 16 // __VERSION__ and __clang_version__ could contain CHERI due to the Git URL. diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c index 7a75198816840..dc2f6df23c655 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -435,6 +435,7 @@ // CHERI-COMMON-NEXT: #define __CHERI_CAP_PERMISSION_PERMIT_STORE__ 8 // CHERI-COMMON-NEXT: #define __CHERI_CAP_PERMISSION_PERMIT_UNSEAL__ 512 // CHERI-COMMON-NEXT: #define __CHERI__ 1 +// CHERI-COMMON-NEXT: #define __CHERI_HYBRID__ 1 // CHERI64: #define __POINTER_WIDTH__ 32 // CHERI128: #define __POINTER_WIDTH__ 64 // CHERI-COMMON-NEXT: #define __PRAGMA_REDEFINE_EXTNAME 1 diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp index a3b23bb9550a8..1b42177a9ca37 100644 --- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp @@ -126,9 +126,9 @@ int main(int, char**) test<__uint128_t>(); #endif -#if defined(__CHERI__) && !defined(__CHERI_PURE_CAPABILITY__) - test<__intcap_t>(); - test<__uintcap_t>(); +#ifdef __CHERI_HYBRID__ + test<__intcap_t>(); + test<__uintcap_t>(); #endif return 0; From 87e65de8694b1928ccc8fd7cac864de956efa5f9 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Wed, 26 Feb 2025 18:39:20 +0000 Subject: [PATCH 13/16] Make __CHERI__ a synonym for __CHERI_PURE_CAPABILITY__ WARNING: This is a breaking change for hybrid + standard C/C++ code. Rationale: We strongly encourage all CHERI consumers to use a pure-capability ABI whenever possible. Therefore it should be the easiest thing to type and less preferred options should be longer. The existing macros date to the earliest compiler support which barely supported capability types. Before broad adoption of CHERI we should make the macros be sensible. We're past Stuart Feldman's too many users of make to change the tabs threshold (12), but few codebases will be effected, the required changes are simple can be safely performed without automatic review, and we shouldn't have to live with this aspect of history forever. Backwards compatible code transition: For purecap + standard C/C++ code (no hybrid): No change required. For hybrid + standard C/C++ (with or without purecap): defined(__CHERI__) -> __has_feature(capabilities) or defined(__CHERI__) -> defined(__CHERI__) || defined(__CHERI_HYBRID__) Once the need for compatability with old compilers is passed, further simplication is possible. For purecap + standard C/C++ code: __CHERI_PURE_CAPABILITY__ -> __CHERI__ For hybrid + standard C/C++ code: __has_feature(capabilities) && !defined(__CHERI_PURE_CAPABILITY__) -> defined(__CHERI_HYBRID__) --- clang/lib/Frontend/InitPreprocessor.cpp | 3 ++- clang/test/Driver/cheri/bounds-mode.c | 1 + clang/test/Preprocessor/cheri-cap-sizes.c | 3 ++- clang/test/Preprocessor/cheri-features.c | 2 +- clang/test/Preprocessor/cheri-riscv-feature-flags.c | 1 - clang/test/Preprocessor/init.c | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index fd2f094b59b95..152eebd0d7be1 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1122,7 +1122,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (TI.SupportsCapabilities()) { const uint64_t CapWidth = TI.getCHERICapabilityWidth(); const uint64_t CapRange = TI.getPointerRangeForCHERICapability(); - Builder.defineMacro("__CHERI__", "1"); // TODO: or define __CHERI__ to 128/256? Builder.defineMacro("__CHERI_CAPABILITY_WIDTH__", Twine(CapWidth)); DefineTypeSizeof("__SIZEOF_CHERI_CAPABILITY__", CapWidth, TI, Builder); Builder.defineMacro("__CHERI_ADDRESS_BITS__", Twine(CapRange)); @@ -1137,6 +1136,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineTypeSize("__UINTCAP_MAX__", TI.getIntTypeByWidth(CapRange, false), TI, Builder); if (TI.areAllPointersCapabilities()) { + Builder.defineMacro("__CHERI__"); + // XXXAR is there a reason we use two instead of just defining it? // I don't think we have any checks that rely on the value Builder.defineMacro("__CHERI_PURE_CAPABILITY__", "2"); diff --git a/clang/test/Driver/cheri/bounds-mode.c b/clang/test/Driver/cheri/bounds-mode.c index 1b66a0ce8fa91..5ac92acc644cb 100644 --- a/clang/test/Driver/cheri/bounds-mode.c +++ b/clang/test/Driver/cheri/bounds-mode.c @@ -17,3 +17,4 @@ // CHECK: #define __CHERI_PURE_CAPABILITY__ 2 // SUBOBJECT-DISABLED-NOT: __CHERI_SUBOBJECT_BOUNDS__ // SUBOBJECT-SAFE: #define __CHERI_SUBOBJECT_BOUNDS__ 2 +// CHECK: #define __CHERI__ 1 diff --git a/clang/test/Preprocessor/cheri-cap-sizes.c b/clang/test/Preprocessor/cheri-cap-sizes.c index b7ebdf0aad6dd..9436599ea00c3 100644 --- a/clang/test/Preprocessor/cheri-cap-sizes.c +++ b/clang/test/Preprocessor/cheri-cap-sizes.c @@ -37,8 +37,9 @@ // CHECK: #define __CHERI_ADDRESS_BITS__ 64 // CHERI128: #define __CHERI_CAPABILITY_WIDTH__ 128 // PURECAP: #define __CHERI_PURE_CAPABILITY__ 2 +// PURECAP: #define __CHERI__ 1 // MIPS-NOT: __CHERI_PURE_CAPABILITY__ -// CHECK: #define __CHERI__ 1 +// MIPS-NOT: __CHERI__ // MIPS: #define __CHERI_HYBRID__ 1 // Note: 64-bit range for intcap makes more sense than the full range for pointers // CHECK: #define __INTCAP_MAX__ 9223372036854775807L diff --git a/clang/test/Preprocessor/cheri-features.c b/clang/test/Preprocessor/cheri-features.c index 1b75bf3de4968..2d10f87f59ae1 100644 --- a/clang/test/Preprocessor/cheri-features.c +++ b/clang/test/Preprocessor/cheri-features.c @@ -25,10 +25,10 @@ void* __capability x = 0; #if defined(__CHERI__) #pragma message("__CHERI__ defined") -// CHECK-CHERI: warning: __CHERI__ defined void* __capability y = 0; #else #pragma message("__CHERI__ not defined") +// CHECK-CHERI: warning: __CHERI__ not defined // CHECK-MIPS: warning: __CHERI__ not defined #endif diff --git a/clang/test/Preprocessor/cheri-riscv-feature-flags.c b/clang/test/Preprocessor/cheri-riscv-feature-flags.c index 11b3701e01e73..9e73265ddad97 100644 --- a/clang/test/Preprocessor/cheri-riscv-feature-flags.c +++ b/clang/test/Preprocessor/cheri-riscv-feature-flags.c @@ -18,7 +18,6 @@ // CHECK: #define __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ 64 // CHECK: #define __CHERI_CAP_PERMISSION_PERMIT_STORE__ 8 // CHECK: #define __CHERI_CAP_PERMISSION_PERMIT_UNSEAL__ 512 -// CHECK: #define __CHERI__ 1 // CHECK: #define __CHERI_HYBRID__ 1 // CHECK32: #define __SIZEOF_CHERI_CAPABILITY__ 8 // CHECK64: #define __SIZEOF_CHERI_CAPABILITY__ 16 diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c index dc2f6df23c655..c04e8ee53fdda 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -434,7 +434,6 @@ // CHERI-COMMON-NEXT: #define __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ 64 // CHERI-COMMON-NEXT: #define __CHERI_CAP_PERMISSION_PERMIT_STORE__ 8 // CHERI-COMMON-NEXT: #define __CHERI_CAP_PERMISSION_PERMIT_UNSEAL__ 512 -// CHERI-COMMON-NEXT: #define __CHERI__ 1 // CHERI-COMMON-NEXT: #define __CHERI_HYBRID__ 1 // CHERI64: #define __POINTER_WIDTH__ 32 // CHERI128: #define __POINTER_WIDTH__ 64 @@ -487,6 +486,7 @@ // CHERI128-PURECAP: #define _MIPS_FPSET 32 // CHERI128-PURECAP: #define __CHERI_PURE_CAPABILITY__ 2 // CHERI128-PURECAP: #define __CHERI_SANDBOX__ 4 +// CHERI128-PURECAP: #define __CHERI__ 1 // CHERI128-PURECAP: #define __INTPTR_FMTd__ "Pd" // CHERI128-PURECAP: #define __INTPTR_FMTi__ "Pi" // CHERI128-PURECAP: #define __INTPTR_MAX__ 9223372036854775807L From 8d0672c07bd53aa57fb0300be6fd4da3046904e6 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sat, 3 Aug 2024 00:02:12 +0100 Subject: [PATCH 14/16] [Sema] Expose diagnoseAmbiguousProvenance for other uses This will be reused for __builtin__overflow, which gets checked in SemaChecking.cpp instead and so can't currently use this. --- clang/include/clang/Sema/Sema.h | 3 +++ clang/lib/Sema/SemaExpr.cpp | 34 ++++++++++++++++----------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f3fed2d59f1d4..e646cbd5a4e9b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2178,6 +2178,9 @@ class Sema final : public SemaBase { bool CheckCHERIAssignCompatible(QualType LHS, QualType RHS, Expr *&RHSExpr, bool InsertBitCast = true); + void DiagnoseAmbiguousProvenance(Expr *LHS, Expr *RHS, SourceLocation Loc, + bool IsCompAssign); + /// ActOnPragmaClangSection - Called on well formed \#pragma clang section void ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5e8f03412cba6..5ddaf28b331d1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10916,36 +10916,34 @@ static void DiagnoseDivisionSizeofPointerOrArray(Sema &S, Expr *LHS, Expr *RHS, } } -static void diagnoseAmbiguousProvenance(Sema &S, ExprResult &LHS, - ExprResult &RHS, SourceLocation Loc, - bool IsCompAssign) { +void Sema::DiagnoseAmbiguousProvenance(Expr *LHS, Expr *RHS, SourceLocation Loc, + bool IsCompAssign) { // For compound assignment the provenance source is obvious // TODO: for compound assignment, we should implement a warning that a // capability RHS with a non-cap LHS is potentially inefficient. if (IsCompAssign) return; - const QualType LHSType = LHS.get()->getType(); - const QualType RHSType = RHS.get()->getType(); - bool isLHSCap = LHSType->isCHERICapabilityType(S.Context); - bool isRHSCap = RHSType->isCHERICapabilityType(S.Context); + const QualType LHSType = LHS->getType(); + const QualType RHSType = RHS->getType(); + bool isLHSCap = LHSType->isCHERICapabilityType(Context); + bool isRHSCap = RHSType->isCHERICapabilityType(Context); // If both sides can carry provenance (i.e. not marked as non-provenance // carrying) we should emit a warning bool LHSProvenance = isLHSCap && !LHSType->hasAttr(attr::CHERINoProvenance); bool RHSProvenance = isRHSCap && !RHSType->hasAttr(attr::CHERINoProvenance); if (LHSProvenance && RHSProvenance) { - S.DiagRuntimeBehavior( - Loc, RHS.get(), - S.PDiag(diag::warn_ambiguous_provenance_capability_binop) - << LHSType << RHSType << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange()); + DiagRuntimeBehavior(Loc, RHS, + PDiag(diag::warn_ambiguous_provenance_capability_binop) + << LHSType << RHSType << LHS->getSourceRange() + << RHS->getSourceRange()); // In the case of ambiguous provenance we currently default to LHS-derived // values. To achieve this behaviour, flag the RHS as non-provenance // carrying for code-generation. // FIXME: in the future make this an error and require manual annotation. - RHS.get()->setType( - S.Context.getAttributedType(attr::CHERINoProvenance, RHSType, RHSType)); + RHS->setType( + Context.getAttributedType(attr::CHERINoProvenance, RHSType, RHSType)); } } @@ -11000,7 +10998,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv); DiagnoseDivisionSizeofPointerOrArray(*this, LHS.get(), RHS.get(), Loc); } else { - diagnoseAmbiguousProvenance(*this, LHS, RHS, Loc, IsCompAssign); + DiagnoseAmbiguousProvenance(LHS.get(), RHS.get(), Loc, IsCompAssign); } return compType; } @@ -11418,7 +11416,7 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, if (!compType.isNull() && compType->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; assert(Opc == BO_AddAssign || Opc == BO_Add); - diagnoseAmbiguousProvenance(*this, LHS, RHS, Loc, Opc == BO_AddAssign); + DiagnoseAmbiguousProvenance(LHS.get(), RHS.get(), Loc, Opc == BO_AddAssign); return compType; } @@ -13638,8 +13636,8 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, diagnoseXorMisusedAsPow(*this, LHS, RHS, Loc); if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType()) { -const bool UsingUIntCapOffset = getLangOpts().cheriUIntCapUsesOffset(); - diagnoseAmbiguousProvenance(*this, LHS, RHS, Loc, IsCompAssign); + const bool UsingUIntCapOffset = getLangOpts().cheriUIntCapUsesOffset(); + DiagnoseAmbiguousProvenance(LHS.get(), RHS.get(), Loc, IsCompAssign); const bool isLHSCap = LHS.get()->getType()->isCHERICapabilityType(Context); if (isLHSCap && (Opc == BO_And || Opc == BO_AndAssign)) { // Bitwise and can cause checking low pointer bits to be compiled to From db188831415b8689a3564e6b84e71d1d52ee6ee0 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sat, 3 Aug 2024 03:02:58 +0100 Subject: [PATCH 15/16] [Sema][CodeGen] Support __builtin__overflow with __intcap Morello LLVM has downstream support for this, but it's both incomplete (see https://git.morello-project.org/morello/llvm-project/-/issues/80) and incorrect with regards to provenance (in that it takes a naive type-based approach rather than considering the cheri_no_provenance attribute, meaning it differs from the binary operators in provenance semantics). This is a from-scratch implementation that aims to not have the same shortcomings. Fixes https://github.com/CTSRD-CHERI/llvm-project/issues/720 --- clang/lib/CodeGen/CGBuiltin.cpp | 136 +- clang/lib/Sema/SemaChecking.cpp | 15 + .../CodeGen/cheri/intcap-overflow-builtins.c | 5455 +++++++++++++++++ .../Sema/cheri/intcap-overflow-builtins.c | 77 + 4 files changed, 5668 insertions(+), 15 deletions(-) create mode 100644 clang/test/CodeGen/cheri/intcap-overflow-builtins.c create mode 100644 clang/test/Sema/cheri/intcap-overflow-builtins.c diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 217a4ada8de24..e1ad9926e525c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -29,6 +29,9 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" @@ -2321,14 +2324,40 @@ static RValue EmitCheckedUnsignedMultiplySignedResult( CodeGenFunction &CGF, const clang::Expr *Op1, WidthAndSignedness Op1Info, const clang::Expr *Op2, WidthAndSignedness Op2Info, const clang::Expr *ResultArg, QualType ResultQTy, - WidthAndSignedness ResultInfo) { + WidthAndSignedness ResultInfo, SourceLocation Loc) { assert(isSpecialUnsignedMultiplySignedResult( Builtin::BI__builtin_mul_overflow, Op1Info, Op2Info, ResultInfo) && "Cannot specialize this multiply"); + clang::QualType Op1QTy = Op1->getType(); + clang::QualType Op2QTy = Op2->getType(); + bool Op1IsCap = Op1QTy->isCHERICapabilityType(CGF.getContext()); + bool Op2IsCap = Op2QTy->isCHERICapabilityType(CGF.getContext()); + bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGF.getContext()); + llvm::Value *V1 = CGF.EmitScalarExpr(Op1); llvm::Value *V2 = CGF.EmitScalarExpr(Op2); + llvm::Value *ProvenanceCap = nullptr; + if (ResultIsCap) { + bool Op1NoProvenance = + !Op1IsCap || Op1QTy->hasAttr(attr::CHERINoProvenance); + bool Op2NoProvenance = + !Op2IsCap || Op2QTy->hasAttr(attr::CHERINoProvenance); + if (Op1NoProvenance && Op2NoProvenance) + ProvenanceCap = llvm::ConstantPointerNull::get(CGF.Int8CheriCapTy); + else if (Op1NoProvenance) + ProvenanceCap = V2; + else + ProvenanceCap = V1; + } + + if (Op1IsCap) + V1 = CGF.getCapabilityIntegerValue(V1); + + if (Op2IsCap) + V2 = CGF.getCapabilityIntegerValue(V2); + llvm::Value *HasOverflow; llvm::Value *Result = EmitOverflowIntrinsic( CGF, Intrinsic::umul_with_overflow, V1, V2, HasOverflow); @@ -2342,6 +2371,9 @@ static RValue EmitCheckedUnsignedMultiplySignedResult( llvm::Value *IntMaxOverflow = CGF.Builder.CreateICmpUGT(Result, IntMaxValue); HasOverflow = CGF.Builder.CreateOr(HasOverflow, IntMaxOverflow); + if (ResultIsCap) + Result = CGF.setCapabilityIntegerValue(ProvenanceCap, Result, Loc); + bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg); @@ -2362,16 +2394,21 @@ static bool isSpecialMixedSignMultiply(unsigned BuiltinID, /// Emit a checked mixed-sign multiply. This is a cheaper specialization of /// the generic checked-binop irgen. -static RValue -EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, - WidthAndSignedness Op1Info, const clang::Expr *Op2, - WidthAndSignedness Op2Info, - const clang::Expr *ResultArg, QualType ResultQTy, - WidthAndSignedness ResultInfo) { +static RValue EmitCheckedMixedSignMultiply( + CodeGenFunction &CGF, const clang::Expr *Op1, WidthAndSignedness Op1Info, + const clang::Expr *Op2, WidthAndSignedness Op2Info, + const clang::Expr *ResultArg, QualType ResultQTy, + WidthAndSignedness ResultInfo, SourceLocation Loc) { assert(isSpecialMixedSignMultiply(Builtin::BI__builtin_mul_overflow, Op1Info, Op2Info, ResultInfo) && "Not a mixed-sign multipliction we can specialize"); + QualType Op1QTy = Op1->getType(); + QualType Op2QTy = Op2->getType(); + bool Op1IsCap = Op1QTy->isCHERICapabilityType(CGF.getContext()); + bool Op2IsCap = Op2QTy->isCHERICapabilityType(CGF.getContext()); + bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGF.getContext()); + // Emit the signed and unsigned operands. const clang::Expr *SignedOp = Op1Info.Signed ? Op1 : Op2; const clang::Expr *UnsignedOp = Op1Info.Signed ? Op2 : Op1; @@ -2379,6 +2416,28 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp); unsigned SignedOpWidth = Op1Info.Signed ? Op1Info.Width : Op2Info.Width; unsigned UnsignedOpWidth = Op1Info.Signed ? Op2Info.Width : Op1Info.Width; + bool SignedIsCap = Op1Info.Signed ? Op1IsCap : Op2IsCap; + bool UnsignedIsCap = Op1Info.Signed ? Op2IsCap : Op1IsCap; + + llvm::Value *ProvenanceCap = nullptr; + if (ResultIsCap) { + bool Op1NoProvenance = + !Op1IsCap || Op1QTy->hasAttr(attr::CHERINoProvenance); + bool Op2NoProvenance = + !Op2IsCap || Op2QTy->hasAttr(attr::CHERINoProvenance); + if (Op1NoProvenance && Op2NoProvenance) + ProvenanceCap = llvm::ConstantPointerNull::get(CGF.Int8CheriCapTy); + else if (Op1NoProvenance) + ProvenanceCap = Op1Info.Signed ? Unsigned : Signed; + else + ProvenanceCap = Op1Info.Signed ? Signed : Unsigned; + } + + if (SignedIsCap) + Signed = CGF.getCapabilityIntegerValue(Signed); + + if (UnsignedIsCap) + Unsigned = CGF.getCapabilityIntegerValue(Unsigned); // One of the operands may be smaller than the other. If so, [s|z]ext it. if (SignedOpWidth < UnsignedOpWidth) @@ -2389,7 +2448,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, llvm::Type *OpTy = Signed->getType(); llvm::Value *Zero = llvm::Constant::getNullValue(OpTy); Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg); - llvm::Type *ResTy = CGF.getTypes().ConvertType(ResultQTy); + llvm::Type *ResTy = ResultIsCap ? llvm::IntegerType::get(CGF.getLLVMContext(), + ResultInfo.Width) + : CGF.getTypes().ConvertType(ResultQTy); unsigned OpWidth = std::max(Op1Info.Width, Op2Info.Width); // Take the absolute value of the signed operand. @@ -2428,8 +2489,7 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult)); Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow); if (ResultInfo.Width < OpWidth) { - auto IntMax = - llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth); + auto IntMax = llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth); llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT( UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax)); Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow); @@ -2443,6 +2503,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, } assert(Overflow && Result && "Missing overflow or result"); + if (ResultIsCap) + Result = CGF.setCapabilityIntegerValue(ProvenanceCap, Result, Loc); + bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); CGF.Builder.CreateStore(CGF.EmitToMemory(Result, ResultQTy), ResultPtr, @@ -5495,13 +5558,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const clang::Expr *RightArg = E->getArg(1); const clang::Expr *ResultArg = E->getArg(2); + clang::QualType LeftQTy = LeftArg->getType(); + clang::QualType RightQTy = RightArg->getType(); clang::QualType ResultQTy = ResultArg->getType()->castAs()->getPointeeType(); + bool LeftIsCap = LeftQTy->isCHERICapabilityType(CGM.getContext()); + bool RightIsCap = RightQTy->isCHERICapabilityType(CGM.getContext()); + bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGM.getContext()); WidthAndSignedness LeftInfo = - getIntegerWidthAndSignedness(CGM.getContext(), LeftArg->getType()); + getIntegerWidthAndSignedness(CGM.getContext(), LeftQTy); WidthAndSignedness RightInfo = - getIntegerWidthAndSignedness(CGM.getContext(), RightArg->getType()); + getIntegerWidthAndSignedness(CGM.getContext(), RightQTy); WidthAndSignedness ResultInfo = getIntegerWidthAndSignedness(CGM.getContext(), ResultQTy); @@ -5510,13 +5578,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, if (isSpecialMixedSignMultiply(BuiltinID, LeftInfo, RightInfo, ResultInfo)) return EmitCheckedMixedSignMultiply(*this, LeftArg, LeftInfo, RightArg, RightInfo, ResultArg, ResultQTy, - ResultInfo); + ResultInfo, E->getExprLoc()); if (isSpecialUnsignedMultiplySignedResult(BuiltinID, LeftInfo, RightInfo, ResultInfo)) return EmitCheckedUnsignedMultiplySignedResult( *this, LeftArg, LeftInfo, RightArg, RightInfo, ResultArg, ResultQTy, - ResultInfo); + ResultInfo, E->getExprLoc()); WidthAndSignedness EncompassingInfo = EncompassingIntegerType({LeftInfo, RightInfo, ResultInfo}); @@ -5524,23 +5592,30 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Type *EncompassingLLVMTy = llvm::IntegerType::get(CGM.getLLVMContext(), EncompassingInfo.Width); - llvm::Type *ResultLLVMTy = CGM.getTypes().ConvertType(ResultQTy); + llvm::Type *ResultLLVMTy = + ResultIsCap + ? llvm::IntegerType::get(CGM.getLLVMContext(), ResultInfo.Width) + : CGM.getTypes().ConvertType(ResultQTy); Intrinsic::ID IntrinsicId; + bool Commutative; switch (BuiltinID) { default: llvm_unreachable("Unknown overflow builtin id."); case Builtin::BI__builtin_add_overflow: IntrinsicId = EncompassingInfo.Signed ? Intrinsic::sadd_with_overflow : Intrinsic::uadd_with_overflow; + Commutative = true; break; case Builtin::BI__builtin_sub_overflow: IntrinsicId = EncompassingInfo.Signed ? Intrinsic::ssub_with_overflow : Intrinsic::usub_with_overflow; + Commutative = false; break; case Builtin::BI__builtin_mul_overflow: IntrinsicId = EncompassingInfo.Signed ? Intrinsic::smul_with_overflow : Intrinsic::umul_with_overflow; + Commutative = true; break; } @@ -5548,6 +5623,33 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Right = EmitScalarExpr(RightArg); Address ResultPtr = EmitPointerWithAlignment(ResultArg); + llvm::Value *ProvenanceCap = nullptr; + if (ResultIsCap) { + if (!Commutative) { + if (LeftIsCap) + ProvenanceCap = Left; + else + ProvenanceCap = llvm::ConstantPointerNull::get(Int8CheriCapTy); + } else { + bool LeftNoProvenance = + !LeftIsCap || LeftQTy->hasAttr(attr::CHERINoProvenance); + bool RightNoProvenance = + !RightIsCap || RightQTy->hasAttr(attr::CHERINoProvenance); + if (LeftNoProvenance && RightNoProvenance) + ProvenanceCap = llvm::ConstantPointerNull::get(Int8CheriCapTy); + else if (LeftNoProvenance) + ProvenanceCap = Right; + else + ProvenanceCap = Left; + } + } + + if (LeftIsCap) + Left = getCapabilityIntegerValue(Left); + + if (RightIsCap) + Right = getCapabilityIntegerValue(Right); + // Extend each operand to the encompassing type. Left = Builder.CreateIntCast(Left, EncompassingLLVMTy, LeftInfo.Signed); Right = Builder.CreateIntCast(Right, EncompassingLLVMTy, RightInfo.Signed); @@ -5572,6 +5674,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Result = ResultTrunc; } + if (ResultIsCap) + Result = + setCapabilityIntegerValue(ProvenanceCap, Result, E->getExprLoc()); + // Finally, store the result using the pointer. bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4e2213c0ac7fa..055a9d51bf8fe 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -39,7 +39,10 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -569,6 +572,18 @@ static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) { } } + // ScalarExprEmitter::EmitSub's diagnostics aren't included here since + // they're generally unhelpful, grouped under pedantic warnings, and would be + // confusing without also taking into account the type of the result. + if (BuiltinID != Builtin::BI__builtin_sub_overflow) { + assert((BuiltinID == Builtin::BI__builtin_add_overflow || + BuiltinID == Builtin::BI__builtin_mul_overflow) && + "Unexpected overflow builtin"); + + S.DiagnoseAmbiguousProvenance(TheCall->getArg(0), TheCall->getArg(1), + TheCall->getExprLoc(), false); + } + return false; } diff --git a/clang/test/CodeGen/cheri/intcap-overflow-builtins.c b/clang/test/CodeGen/cheri/intcap-overflow-builtins.c new file mode 100644 index 0000000000000..6d30d2d8ea247 --- /dev/null +++ b/clang/test/CodeGen/cheri/intcap-overflow-builtins.c @@ -0,0 +1,5455 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature +// RUN: %riscv32_cheri_cc1 -Wno-cheri-provenance -o - -emit-llvm -disable-O0-optnone %s \ +// RUN: | opt -S --passes=mem2reg | FileCheck %s --check-prefix=CHECK32 +// RUN: %cheri128_cc1 -Wno-cheri-provenance -o - -emit-llvm -disable-O0-optnone %s \ +// RUN: | opt -S --passes=mem2reg | FileCheck %s --check-prefix=CHECK64 +// RUN: %riscv64_cheri_cc1 -Wno-cheri-provenance -o - -emit-llvm -disable-O0-optnone %s \ +// RUN: | opt -S --passes=mem2reg | FileCheck %s --check-prefix=CHECK64 + +// CHECK32-LABEL: define {{[^@]+}}@ssadds +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ssadds(__intcap a, __intcap b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ssadds_lhs(__intcap a, int b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A]], i32 [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ssadds_rhs(int a, __intcap b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A]], i32 [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1 +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP2]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP3]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP1]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP4]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ssadds_promote(int a, int b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool ssadds_demote(__intcap a, __intcap b, int *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool ssadds_provenance(int a, __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssaddu(__intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool ssaddu_lhs(__intcap a, int b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssaddu_rhs(int a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssaddu_promote(int a, int b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool ssaddu_demote(__intcap a, __intcap b, unsigned int *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssaddu_provenance(int a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uuadds(unsigned __intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uuadds_lhs(unsigned __intcap a, unsigned int b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uuadds_rhs(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uuadds_promote(unsigned int a, unsigned int b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uuadds_demote(unsigned __intcap a, unsigned __intcap b, int *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uuadds_provenance(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uuaddu(unsigned __intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uuaddu_lhs(unsigned __intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uuaddu_rhs(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uuaddu_promote(unsigned int a, unsigned int b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool uuaddu_demote(unsigned __intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uuaddu_provenance(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suadds(__intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = sext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool suadds_lhs(__intcap a, unsigned int b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool suadds_rhs(int a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suadds_promote(int a, unsigned int b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suadds_demote(__intcap a, unsigned __intcap b, int *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool suadds_provenance(int a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suaddu(__intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool suaddu_lhs(__intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool suaddu_rhs(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suaddu_promote(int a, unsigned int b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suaddu_demote(__intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool suaddu_provenance(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool usadds(unsigned __intcap a, __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool usadds_lhs(unsigned __intcap a, int b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool usadds_rhs(unsigned int a, __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool usadds_promote(unsigned int a, int b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool usadds_demote(unsigned __intcap a, __intcap b, int *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usadds_provenance(unsigned int a, __intcap b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usaddu(unsigned __intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool usaddu_lhs(unsigned __intcap a, int b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usaddu_rhs(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usaddu_promote(unsigned int a, int b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usaddu_demote(unsigned __intcap a, __intcap b, unsigned int *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usaddu_provenance(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubs(__intcap a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = sext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool sssubs_lhs(__intcap a, int b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sssubs_rhs(int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubs_promote(int a, int b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubs_demote(__intcap a, __intcap b, int *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool sssubs_provenance(int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubu(__intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool sssubu_lhs(__intcap a, int b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sssubu_rhs(int a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubu_promote(int a, int b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool sssubu_demote(__intcap a, __intcap b, unsigned int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sssubu_provenance(int a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uusubs(unsigned __intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uusubs_lhs(unsigned __intcap a, unsigned int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uusubs_rhs(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uusubs_promote(unsigned int a, unsigned int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uusubs_demote(unsigned __intcap a, unsigned __intcap b, int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uusubs_provenance(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uusubu(unsigned __intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uusubu_lhs(unsigned __intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uusubu_rhs(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uusubu_promote(unsigned int a, unsigned int b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool uusubu_demote(unsigned __intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uusubu_provenance(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubs(__intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = sext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool susubs_lhs(__intcap a, unsigned int b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool susubs_rhs(int a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubs_promote(int a, unsigned int b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubs_demote(__intcap a, unsigned __intcap b, int *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool susubs_provenance(int a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubu(__intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool susubu_lhs(__intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool susubu_rhs(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubu_promote(int a, unsigned int b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubu_demote(__intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool susubu_provenance(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ussubs(unsigned __intcap a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ussubs_lhs(unsigned __intcap a, int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool ussubs_rhs(unsigned int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool ussubs_promote(unsigned int a, int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool ussubs_demote(unsigned __intcap a, __intcap b, int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ussubs_provenance(unsigned int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ussubu(unsigned __intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool ussubu_lhs(unsigned __intcap a, int b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ussubu_rhs(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ussubu_promote(unsigned int a, int b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ussubu_demote(unsigned __intcap a, __intcap b, unsigned int *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ussubu_provenance(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 9223372036854775807, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmuls(__intcap a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = icmp slt i32 [[B]], 0 +// CHECK32-NEXT: [[TMP2:%.*]] = sub i32 0, [[B]] +// CHECK32-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[TMP2]], i32 [[B]] +// CHECK32-NEXT: [[TMP4:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP3]], i32 [[TMP0]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i1 [[TMP1]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = add i32 2147483647, [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ugt i32 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP6]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i32 [[TMP11]], i32 [[TMP6]] +// CHECK32-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP12]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[OP_SEXT:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = icmp slt i64 [[OP_SEXT]], 0 +// CHECK64-NEXT: [[TMP2:%.*]] = sub i64 0, [[OP_SEXT]] +// CHECK64-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 [[OP_SEXT]] +// CHECK64-NEXT: [[TMP4:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP3]], i64 [[TMP0]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i1 [[TMP1]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = add i64 9223372036854775807, [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP6]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i64 [[TMP11]], i64 [[TMP6]] +// CHECK64-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP12]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssmuls_lhs(__intcap a, int b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK32-NEXT: [[TMP10:%.*]] = add i32 2147483647, [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = icmp ugt i32 [[TMP8]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK32-NEXT: [[TMP13:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i32 [[TMP13]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP14]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP12]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i64 +// CHECK64-NEXT: [[TMP10:%.*]] = add i64 9223372036854775807, [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP8]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i64 [[TMP13]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP14]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool ssmuls_rhs(int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[B]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[B]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[B]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP13]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[OP_SEXT:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[OP_SEXT]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[OP_SEXT]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[OP_SEXT]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 9223372036854775807, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP13]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmuls_promote(int a, int b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: store i32 [[TMP13]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 2147483647, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 +// CHECK64-NEXT: store i32 [[TMP14]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmuls_demote(__intcap a, __intcap b, int *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool ssmuls_provenance(int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssmulu(__intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool ssmulu_lhs(__intcap a, int b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmulu_rhs(int a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssmulu_promote(int a, int b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool ssmulu_demote(__intcap a, __intcap b, unsigned int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmulu_provenance(int a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 9223372036854775807, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uumuls(unsigned __intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP2:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[TMP2]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP3]], i32 [[B]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i1 [[TMP1]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = add i32 2147483647, [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ugt i32 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP6]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i32 [[TMP11]], i32 [[TMP6]] +// CHECK32-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP12]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[OP_ZEXT:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP3]], i64 [[OP_ZEXT]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i1 [[TMP1]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = add i64 9223372036854775807, [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP6]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i64 [[TMP11]], i64 [[TMP6]] +// CHECK64-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP12]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uumuls_lhs(unsigned __intcap a, unsigned int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK32-NEXT: [[TMP10:%.*]] = add i32 2147483647, [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = icmp ugt i32 [[TMP8]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK32-NEXT: [[TMP13:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i32 [[TMP13]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP14]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP12]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i64 +// CHECK64-NEXT: [[TMP10:%.*]] = add i64 9223372036854775807, [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP8]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i64 [[TMP13]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP14]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool uumuls_rhs(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[B]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP13]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[OP_ZEXT:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[OP_ZEXT]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 9223372036854775807, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP13]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uumuls_promote(unsigned int a, unsigned int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: store i32 [[TMP13]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 2147483647, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 +// CHECK64-NEXT: store i32 [[TMP14]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uumuls_demote(unsigned __intcap a, unsigned __intcap b, int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = icmp ugt i32 [[TMP5]], 2147483647 +// CHECK32-NEXT: [[TMP7:%.*]] = or i1 [[TMP4]], [[TMP6]] +// CHECK32-NEXT: [[TMP8:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP8]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP7]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = icmp ugt i64 [[TMP5]], 9223372036854775807 +// CHECK64-NEXT: [[TMP7:%.*]] = or i1 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP8]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP7]] +// +_Bool uumuls_provenance(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uumulu(unsigned __intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uumulu_lhs(unsigned __intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uumulu_rhs(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uumulu_promote(unsigned int a, unsigned int b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool uumulu_demote(unsigned __intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uumulu_provenance(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], 2147483647 +// CHECK32-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]] +// CHECK32-NEXT: [[TMP7:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP7]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP6]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = icmp ugt i64 [[TMP4]], 9223372036854775807 +// CHECK64-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]] +// CHECK64-NEXT: [[TMP7:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP7]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP6]] +// +_Bool sumuls(__intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = icmp ugt i32 [[TMP3]], 2147483647 +// CHECK32-NEXT: [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]] +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP5]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = sext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool sumuls_lhs(__intcap a, unsigned int b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = icmp ugt i32 [[TMP5]], 2147483647 +// CHECK32-NEXT: [[TMP7:%.*]] = or i1 [[TMP4]], [[TMP6]] +// CHECK32-NEXT: [[TMP8:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP8]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP7]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = icmp ugt i64 [[TMP5]], 9223372036854775807 +// CHECK64-NEXT: [[TMP7:%.*]] = or i1 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP8]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP7]] +// +_Bool sumuls_rhs(int a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], 2147483647 +// CHECK32-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]] +// CHECK32-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP7]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP6]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sumuls_promote(int a, unsigned int b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], 2147483647 +// CHECK32-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]] +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP6]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sumuls_demote(__intcap a, unsigned __intcap b, int *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK32-NEXT: [[TMP10:%.*]] = add i32 2147483647, [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = icmp ugt i32 [[TMP8]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK32-NEXT: [[TMP13:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i32 [[TMP13]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP14]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP12]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i64 +// CHECK64-NEXT: [[TMP10:%.*]] = add i64 9223372036854775807, [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP8]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i64 [[TMP13]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP14]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool sumuls_provenance(int a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP12]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i64 [[TMP11]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP12]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sumulu(__intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP2:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[TMP2]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP3]], i32 [[B]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = icmp ne i32 [[TMP6]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = and i1 [[TMP1]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP5]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = sub i32 0, [[TMP6]] +// CHECK32-NEXT: [[TMP11:%.*]] = select i1 [[TMP1]], i32 [[TMP10]], i32 [[TMP6]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP11]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[OP_ZEXT:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP3]], i64 [[OP_ZEXT]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP6]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = and i1 [[TMP1]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP5]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = sub i64 0, [[TMP6]] +// CHECK64-NEXT: [[TMP11:%.*]] = select i1 [[TMP1]], i64 [[TMP10]], i64 [[TMP6]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP11]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool sumulu_lhs(__intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i32 [[TMP8]], 0 +// CHECK32-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i32 [[TMP12]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i64 [[TMP8]], 0 +// CHECK64-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i64 [[TMP12]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sumulu_rhs(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[B]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP12]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[OP_ZEXT:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[OP_ZEXT]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i64 [[TMP11]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP12]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sumulu_promote(int a, unsigned int b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: store i32 [[TMP12]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP7]], 4294967295 +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP10]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP2]], i64 [[TMP13]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP15:%.*]] = trunc i64 [[TMP14]] to i32 +// CHECK64-NEXT: store i32 [[TMP15]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool sumulu_demote(__intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i32 [[TMP8]], 0 +// CHECK32-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i32 [[TMP12]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i64 [[TMP8]], 0 +// CHECK64-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i64 [[TMP12]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sumulu_provenance(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool usmuls(unsigned __intcap a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool usmuls_lhs(unsigned __intcap a, int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool usmuls_rhs(unsigned int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool usmuls_promote(unsigned int a, int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool usmuls_demote(unsigned __intcap a, __intcap b, int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK32-NEXT: [[TMP10:%.*]] = add i32 2147483647, [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = icmp ugt i32 [[TMP8]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK32-NEXT: [[TMP13:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i32 [[TMP13]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP14]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP12]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i64 +// CHECK64-NEXT: [[TMP10:%.*]] = add i64 9223372036854775807, [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP8]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i64 [[TMP13]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP14]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool usmuls_provenance(unsigned int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP12]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i64 [[TMP11]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP12]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usmulu(unsigned __intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = icmp slt i32 [[B]], 0 +// CHECK32-NEXT: [[TMP2:%.*]] = sub i32 0, [[B]] +// CHECK32-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[TMP2]], i32 [[B]] +// CHECK32-NEXT: [[TMP4:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP3]], i32 [[TMP0]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = icmp ne i32 [[TMP6]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = and i1 [[TMP1]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP5]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = sub i32 0, [[TMP6]] +// CHECK32-NEXT: [[TMP11:%.*]] = select i1 [[TMP1]], i32 [[TMP10]], i32 [[TMP6]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP11]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[OP_SEXT:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = icmp slt i64 [[OP_SEXT]], 0 +// CHECK64-NEXT: [[TMP2:%.*]] = sub i64 0, [[OP_SEXT]] +// CHECK64-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 [[OP_SEXT]] +// CHECK64-NEXT: [[TMP4:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP3]], i64 [[TMP0]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP6]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = and i1 [[TMP1]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP5]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = sub i64 0, [[TMP6]] +// CHECK64-NEXT: [[TMP11:%.*]] = select i1 [[TMP1]], i64 [[TMP10]], i64 [[TMP6]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP11]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool usmulu_lhs(unsigned __intcap a, int b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i32 [[TMP8]], 0 +// CHECK32-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i32 [[TMP12]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i64 [[TMP8]], 0 +// CHECK64-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i64 [[TMP12]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usmulu_rhs(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[B]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[B]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[B]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP12]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[OP_SEXT:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[OP_SEXT]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[OP_SEXT]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[OP_SEXT]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i64 [[TMP11]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP12]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usmulu_promote(unsigned int a, int b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: store i32 [[TMP12]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP7]], 4294967295 +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP10]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP2]], i64 [[TMP13]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP15:%.*]] = trunc i64 [[TMP14]] to i32 +// CHECK64-NEXT: store i32 [[TMP15]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool usmulu_demote(unsigned __intcap a, __intcap b, unsigned int *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i32 [[TMP8]], 0 +// CHECK32-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i32 [[TMP12]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i64 [[TMP8]], 0 +// CHECK64-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i64 [[TMP12]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usmulu_provenance(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} diff --git a/clang/test/Sema/cheri/intcap-overflow-builtins.c b/clang/test/Sema/cheri/intcap-overflow-builtins.c new file mode 100644 index 0000000000000..a77b4786e8224 --- /dev/null +++ b/clang/test/Sema/cheri/intcap-overflow-builtins.c @@ -0,0 +1,77 @@ +// RUN: %cheri_cc1 %s -Wcheri-provenance -Wcheri-provenance-pedantic -fsyntax-only -verify + +_Bool add(__intcap a, __intcap b, __intcap *c) { + return __builtin_add_overflow(a, b, c); + // expected-warning@-1 {{binary expression on capability types '__intcap' and '__intcap'; it is not clear which should be used as the source of provenance; currently provenance is inherited from the left-hand side}} +} + +_Bool add_lhs(__intcap a, int b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +_Bool add_rhs(int a, __intcap b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +_Bool add_promote(int a, int b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +_Bool add_demote(__intcap a, __intcap b, int *c) { + return __builtin_add_overflow(a, b, c); + // expected-warning@-1 {{binary expression on capability types '__intcap' and '__intcap'; it is not clear which should be used as the source of provenance; currently provenance is inherited from the left-hand side}} +} + +_Bool add_provenance(int a, __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +_Bool sub(__intcap a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +_Bool sub_lhs(__intcap a, int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +_Bool sub_rhs(int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +_Bool sub_promote(int a, int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +_Bool sub_demote(__intcap a, __intcap b, int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +_Bool sub_provenance(int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +_Bool mul(__intcap a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); + // expected-warning@-1 {{binary expression on capability types '__intcap' and '__intcap'; it is not clear which should be used as the source of provenance; currently provenance is inherited from the left-hand side}} +} + +_Bool mul_lhs(__intcap a, int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +_Bool mul_rhs(int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +_Bool mul_promote(int a, int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +_Bool mul_demote(__intcap a, __intcap b, int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); + // expected-warning@-1 {{binary expression on capability types '__intcap' and '__intcap'; it is not clear which should be used as the source of provenance; currently provenance is inherited from the left-hand side}} +} + +_Bool mul_provenance(int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} From b306de65fb9aeecb7655f6312be7cc32c2a80c70 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Tue, 18 Mar 2025 14:53:27 +0000 Subject: [PATCH 16/16] Add missing underscore in __has_feature --- libunwind/src/Registers.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index 4328bfbd602cb..04922211a9255 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -24,7 +24,7 @@ namespace libunwind { // For emulating 128-bit registers struct v128 { uint32_t vec[4]; }; // For emulating CHERI capability -#if !_has_feature(capabilities) +#if !__has_feature(capabilities) struct __attribute__((aligned(16))) fake_capability { char bytes[16]; };