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 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/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/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/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"; diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index e1d246f4b1804..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"); @@ -1148,6 +1149,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/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/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 diff --git a/clang/test/CodeGen/builtin-align.c b/clang/test/CodeGen/builtin-align.c index 6ad904863131e..735cc721b1277 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(cheri) #define __capability #endif 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/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/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 2bf52173fb9ed..9436599ea00c3 100644 --- a/clang/test/Preprocessor/cheri-cap-sizes.c +++ b/clang/test/Preprocessor/cheri-cap-sizes.c @@ -37,8 +37,10 @@ // 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 10365e3d964f6..2d10f87f59ae1 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) @@ -16,13 +25,22 @@ 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 +#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..9e73265ddad97 100644 --- a/clang/test/Preprocessor/cheri-riscv-feature-flags.c +++ b/clang/test/Preprocessor/cheri-riscv-feature-flags.c @@ -18,7 +18,7 @@ // 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 // __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..c04e8ee53fdda 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -434,7 +434,7 @@ // 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 // CHERI-COMMON-NEXT: #define __PRAGMA_REDEFINE_EXTNAME 1 @@ -486,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 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); +} diff --git a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp index d50f71aa3d8a1..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; -#ifdef __CHERI__ +#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 -#ifdef __CHERI__ +#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/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 { }; 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; 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 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..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 -#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 diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h index 6b81bdba25e67..bc6dc27e09350 100644 --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -85,6 +85,18 @@ class LLVM_ABI MCAsmBackend { /// lifetime management virtual void reset() {} + 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; + } + /// 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/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/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index ccd8b7172de89..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; @@ -4059,7 +4090,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) @@ -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/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/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..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); } @@ -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/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/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..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 @@ -558,7 +566,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!"); @@ -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 @@ -665,7 +672,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!"); @@ -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 816626da723af..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; 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/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/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/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..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: @@ -655,7 +654,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 +667,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 +734,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 +850,18 @@ bool RISCVAsmBackend::addReloc(const MCFragment &F, const MCFixup &Fixup, TA = ELF::R_RISCV_SET_ULEB128; TB = ELF::R_RISCV_SUB_ULEB128; break; + case llvm::FK_Cap_8: + case llvm::FK_Cap_16: + 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/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/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/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: } 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/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/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/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] 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-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) 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)