diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d04a69869abf..cd30f60de522 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -688,28 +688,26 @@ static Value *emitRangedBuiltin(CodeGenFunction &CGF, } namespace { - struct WidthAndSignedness { - unsigned Width; + struct RangeAndSignedness { + unsigned Range; bool Signed; }; } -static WidthAndSignedness -getIntegerWidthAndSignedness(const clang::ASTContext &context, +static RangeAndSignedness +getIntegerRangeAndSignedness(const clang::ASTContext &context, const clang::QualType Type) { assert(Type->isIntegerType() && "Given type is not an integer."); - unsigned Width = Type->isBooleanType() ? 1 - : Type->isBitIntType() ? context.getIntWidth(Type) - : context.getTypeInfo(Type).Width; + unsigned Range = context.getIntRange(Type); bool Signed = Type->isSignedIntegerType(); - return {Width, Signed}; + return {Range, Signed}; } // Given one or more integer types, this function produces an integer type that // encompasses them: any value in one of the given types could be expressed in // the encompassing type. -static struct WidthAndSignedness -EncompassingIntegerType(ArrayRef Types) { +static struct RangeAndSignedness +EncompassingIntegerType(ArrayRef Types) { assert(Types.size() > 0 && "Empty list of types."); // If any of the given types is signed, we must return a signed type. @@ -722,15 +720,15 @@ EncompassingIntegerType(ArrayRef Types) { // of the specified types. Additionally, if the encompassing type is signed, // its width must be strictly greater than the width of any unsigned types // given. - unsigned Width = 0; + unsigned Range = 0; for (const auto &Type : Types) { - unsigned MinWidth = Type.Width + (Signed && !Type.Signed); - if (Width < MinWidth) { - Width = MinWidth; + unsigned MinRange = Type.Range + (Signed && !Type.Signed); + if (Range < MinRange) { + Range = MinRange; } } - return {Width, Signed}; + return {Range, Signed}; } Value *CodeGenFunction::EmitVAStartEnd(Value *ArgValue, bool IsStart) { @@ -1914,25 +1912,52 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) { } static bool isSpecialUnsignedMultiplySignedResult( - unsigned BuiltinID, WidthAndSignedness Op1Info, WidthAndSignedness Op2Info, - WidthAndSignedness ResultInfo) { + unsigned BuiltinID, RangeAndSignedness Op1Info, RangeAndSignedness Op2Info, + RangeAndSignedness ResultInfo) { return BuiltinID == Builtin::BI__builtin_mul_overflow && - Op1Info.Width == Op2Info.Width && Op2Info.Width == ResultInfo.Width && + Op1Info.Range == Op2Info.Range && Op2Info.Range == ResultInfo.Range && !Op1Info.Signed && !Op2Info.Signed && ResultInfo.Signed; } static RValue EmitCheckedUnsignedMultiplySignedResult( - CodeGenFunction &CGF, const clang::Expr *Op1, WidthAndSignedness Op1Info, - const clang::Expr *Op2, WidthAndSignedness Op2Info, + CodeGenFunction &CGF, const clang::Expr *Op1, RangeAndSignedness Op1Info, + const clang::Expr *Op2, RangeAndSignedness Op2Info, const clang::Expr *ResultArg, QualType ResultQTy, - WidthAndSignedness ResultInfo) { + RangeAndSignedness 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; + if (ResultIsCap && (Op1IsCap || Op2IsCap)) { + bool Op1NoProvenance = + !Op1IsCap || Op1QTy->hasAttr(attr::CHERINoProvenance); + bool Op2NoProvenance = + !Op2IsCap || Op2QTy->hasAttr(attr::CHERINoProvenance); + if (Op1NoProvenance && Op2NoProvenance) + ProvenanceCap = nullptr; + else if (Op1NoProvenance) + ProvenanceCap = V2; + else + ProvenanceCap = V1; + } else + ProvenanceCap = nullptr; + + if (Op1IsCap) + V1 = CGF.getCapabilityIntegerValue(V1); + + if (Op2IsCap) + V2 = CGF.getCapabilityIntegerValue(V2); + llvm::Value *HasOverflow; llvm::Value *Result = EmitOverflowIntrinsic( CGF, llvm::Intrinsic::umul_with_overflow, V1, V2, HasOverflow); @@ -1940,12 +1965,18 @@ static RValue EmitCheckedUnsignedMultiplySignedResult( // The intrinsic call will detect overflow when the value is > UINT_MAX, // however, since the original builtin had a signed result, we need to report // an overflow when the result is greater than INT_MAX. - auto IntMax = llvm::APInt::getSignedMaxValue(ResultInfo.Width); + auto IntMax = llvm::APInt::getSignedMaxValue(ResultInfo.Range); llvm::Value *IntMaxValue = llvm::ConstantInt::get(Result->getType(), IntMax); llvm::Value *IntMaxOverflow = CGF.Builder.CreateICmpUGT(Result, IntMaxValue); HasOverflow = CGF.Builder.CreateOr(HasOverflow, IntMaxOverflow); + if (ResultIsCap) + Result = ProvenanceCap + ? CGF.setCapabilityIntegerValue(ProvenanceCap, Result, Loc) + : CGF.getNullDerivedCapability( + CGF.CGM.getTypes().ConvertType(ResultQTy), Result); + bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg); @@ -1956,11 +1987,11 @@ static RValue EmitCheckedUnsignedMultiplySignedResult( /// Determine if a binop is a checked mixed-sign multiply we can specialize. static bool isSpecialMixedSignMultiply(unsigned BuiltinID, - WidthAndSignedness Op1Info, - WidthAndSignedness Op2Info, - WidthAndSignedness ResultInfo) { + RangeAndSignedness Op1Info, + RangeAndSignedness Op2Info, + RangeAndSignedness ResultInfo) { return BuiltinID == Builtin::BI__builtin_mul_overflow && - std::max(Op1Info.Width, Op2Info.Width) >= ResultInfo.Width && + std::max(Op1Info.Range, Op2Info.Range) >= ResultInfo.Range && Op1Info.Signed != Op2Info.Signed; } @@ -1968,33 +1999,65 @@ static bool isSpecialMixedSignMultiply(unsigned BuiltinID, /// the generic checked-binop irgen. static RValue EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, - WidthAndSignedness Op1Info, const clang::Expr *Op2, - WidthAndSignedness Op2Info, + RangeAndSignedness Op1Info, const clang::Expr *Op2, + RangeAndSignedness Op2Info, const clang::Expr *ResultArg, QualType ResultQTy, - WidthAndSignedness ResultInfo) { + RangeAndSignedness 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; llvm::Value *Signed = CGF.EmitScalarExpr(SignedOp); llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp); - unsigned SignedOpWidth = Op1Info.Signed ? Op1Info.Width : Op2Info.Width; - unsigned UnsignedOpWidth = Op1Info.Signed ? Op2Info.Width : Op1Info.Width; + unsigned SignedOpRange = Op1Info.Signed ? Op1Info.Range : Op2Info.Range; + unsigned UnsignedOpRange = Op1Info.Signed ? Op2Info.Range : Op1Info.Range; + bool SignedIsCap = Op1Info.Signed ? Op1IsCap : Op2IsCap; + bool UnsignedIsCap = Op1Info.Signed ? Op2IsCap : Op1IsCap; + + llvm::Value *ProvenanceCap; + if (ResultIsCap && (Op1IsCap || Op2IsCap)) { + bool Op1NoProvenance = + !Op1IsCap || Op1QTy->hasAttr(attr::CHERINoProvenance); + bool Op2NoProvenance = + !Op2IsCap || Op2QTy->hasAttr(attr::CHERINoProvenance); + if (Op1NoProvenance && Op2NoProvenance) + ProvenanceCap = nullptr; + else if (Op1NoProvenance) + ProvenanceCap = Op1Info.Signed ? Unsigned : Signed; + else + ProvenanceCap = Op1Info.Signed ? Signed : Unsigned; + } else + ProvenanceCap = nullptr; + + 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) + if (SignedOpRange < UnsignedOpRange) Signed = CGF.Builder.CreateSExt(Signed, Unsigned->getType(), "op.sext"); - if (UnsignedOpWidth < SignedOpWidth) + if (UnsignedOpRange < SignedOpRange) Unsigned = CGF.Builder.CreateZExt(Unsigned, Signed->getType(), "op.zext"); llvm::Type *OpTy = Signed->getType(); llvm::Value *Zero = llvm::Constant::getNullValue(OpTy); Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg); - llvm::Type *ResTy = ResultPtr.getElementType(); - unsigned OpWidth = std::max(Op1Info.Width, Op2Info.Width); + llvm::Type *ResTy = ResultIsCap ? llvm::IntegerType::get(CGF.getLLVMContext(), + ResultInfo.Range) + : ResultPtr.getElementType(); + unsigned OpRange = std::max(Op1Info.Range, Op2Info.Range); // Take the absolute value of the signed operand. llvm::Value *IsNegative = CGF.Builder.CreateICmpSLT(Signed, Zero); @@ -2013,7 +2076,7 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, // Signed overflow occurs if the result is greater than INT_MAX or lesser // than INT_MIN, i.e when |Result| > (INT_MAX + IsNegative). auto IntMax = - llvm::APInt::getSignedMaxValue(ResultInfo.Width).zext(OpWidth); + llvm::APInt::getSignedMaxValue(ResultInfo.Range).zext(OpRange); llvm::Value *MaxResult = CGF.Builder.CreateAdd(llvm::ConstantInt::get(OpTy, IntMax), CGF.Builder.CreateZExt(IsNegative, OpTy)); @@ -2031,9 +2094,8 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, llvm::Value *Underflow = CGF.Builder.CreateAnd( IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult)); Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow); - if (ResultInfo.Width < OpWidth) { - auto IntMax = - llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth); + if (ResultInfo.Range < OpRange) { + auto IntMax = llvm::APInt::getMaxValue(ResultInfo.Range).zext(OpRange); llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT( UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax)); Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow); @@ -2047,6 +2109,12 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, } assert(Overflow && Result && "Missing overflow or result"); + if (ResultIsCap) + Result = ProvenanceCap + ? CGF.setCapabilityIntegerValue(ProvenanceCap, Result, Loc) + : CGF.getNullDerivedCapability( + CGF.CGM.getTypes().ConvertType(ResultQTy), Result); + bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); CGF.Builder.CreateStore(CGF.EmitToMemory(Result, ResultQTy), ResultPtr, @@ -4493,52 +4561,64 @@ 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(); - WidthAndSignedness LeftInfo = - getIntegerWidthAndSignedness(CGM.getContext(), LeftArg->getType()); - WidthAndSignedness RightInfo = - getIntegerWidthAndSignedness(CGM.getContext(), RightArg->getType()); - WidthAndSignedness ResultInfo = - getIntegerWidthAndSignedness(CGM.getContext(), ResultQTy); + bool LeftIsCap = LeftQTy->isCHERICapabilityType(CGM.getContext()); + bool RightIsCap = RightQTy->isCHERICapabilityType(CGM.getContext()); + bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGM.getContext()); + RangeAndSignedness LeftInfo = + getIntegerRangeAndSignedness(CGM.getContext(), LeftQTy); + RangeAndSignedness RightInfo = + getIntegerRangeAndSignedness(CGM.getContext(), RightQTy); + RangeAndSignedness ResultInfo = + getIntegerRangeAndSignedness(CGM.getContext(), ResultQTy); // Handle mixed-sign multiplication as a special case, because adding // runtime or backend support for our generic irgen would be too expensive. 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 = + RangeAndSignedness EncompassingInfo = EncompassingIntegerType({LeftInfo, RightInfo, ResultInfo}); llvm::Type *EncompassingLLVMTy = - llvm::IntegerType::get(CGM.getLLVMContext(), EncompassingInfo.Width); + llvm::IntegerType::get(CGM.getLLVMContext(), EncompassingInfo.Range); - llvm::Type *ResultLLVMTy = CGM.getTypes().ConvertType(ResultQTy); + llvm::Type *ResultLLVMTy = + ResultIsCap + ? llvm::IntegerType::get(CGM.getLLVMContext(), ResultInfo.Range) + : CGM.getTypes().ConvertType(ResultQTy); llvm::Intrinsic::ID IntrinsicId; + bool Commutative; switch (BuiltinID) { default: llvm_unreachable("Unknown overflow builtin id."); case Builtin::BI__builtin_add_overflow: + Commutative = true; IntrinsicId = EncompassingInfo.Signed ? llvm::Intrinsic::sadd_with_overflow : llvm::Intrinsic::uadd_with_overflow; break; case Builtin::BI__builtin_sub_overflow: + Commutative = false; IntrinsicId = EncompassingInfo.Signed ? llvm::Intrinsic::ssub_with_overflow : llvm::Intrinsic::usub_with_overflow; break; case Builtin::BI__builtin_mul_overflow: + Commutative = true; IntrinsicId = EncompassingInfo.Signed ? llvm::Intrinsic::smul_with_overflow : llvm::Intrinsic::umul_with_overflow; @@ -4549,6 +4629,34 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Right = EmitScalarExpr(RightArg); Address ResultPtr = EmitPointerWithAlignment(ResultArg); + llvm::Value *ProvenanceCap; + if (ResultIsCap && (LeftIsCap || RightIsCap)) { + if (!Commutative) { + if (LeftIsCap) + ProvenanceCap = Left; + else + ProvenanceCap = nullptr; + } else { + bool LeftNoProvenance = + !LeftIsCap || LeftQTy->hasAttr(attr::CHERINoProvenance); + bool RightNoProvenance = + !RightIsCap || RightQTy->hasAttr(attr::CHERINoProvenance); + if (LeftNoProvenance && RightNoProvenance) + ProvenanceCap = nullptr; + else if (LeftNoProvenance) + ProvenanceCap = Right; + else + ProvenanceCap = Left; + } + } else + ProvenanceCap = nullptr; + + 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); @@ -4557,7 +4665,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Overflow, *Result; Result = EmitOverflowIntrinsic(*this, IntrinsicId, Left, Right, Overflow); - if (EncompassingInfo.Width > ResultInfo.Width) { + if (EncompassingInfo.Range > ResultInfo.Range) { // The encompassing type is wider than the result type, so we need to // truncate it. llvm::Value *ResultTrunc = Builder.CreateTrunc(Result, ResultLLVMTy); @@ -4573,6 +4681,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Result = ResultTrunc; } + if (ResultIsCap) + Result = ProvenanceCap + ? setCapabilityIntegerValue(ProvenanceCap, Result, + E->getExprLoc()) + : getNullDerivedCapability( + CGM.getTypes().ConvertType(ResultQTy), Result); + // Finally, store the result using the pointer. bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e41e47fdca5b..8b10cb2cdf44 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -37,8 +37,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" @@ -439,6 +441,39 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall, } } + // Mirror diagnostics from SemaExpr.cpp's diagnoseAmbiguousProvenance. + // + // 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 the type of the result. + const auto LHSExpr = TheCall->getArg(0); + const auto RHSExpr = TheCall->getArg(1); + if (BuiltinID != Builtin::BI__builtin_sub_overflow) { + assert((BuiltinID == Builtin::BI__builtin_add_overflow || + BuiltinID == Builtin::BI__builtin_mul_overflow) && + "Unexpected overflow builtin"); + + QualType LHSType = TheCall->getArg(0)->getType(); + QualType RHSType = TheCall->getArg(1)->getType(); + bool LHSIsCap = LHSType->isCHERICapabilityType(S.getASTContext()); + bool RHSIsCap = RHSType->isCHERICapabilityType(S.getASTContext()); + bool LHSProvenance = LHSIsCap && !LHSType->hasAttr(attr::CHERINoProvenance); + bool RHSProvenance = RHSIsCap && !RHSType->hasAttr(attr::CHERINoProvenance); + if (LHSProvenance && RHSProvenance) { + S.DiagRuntimeBehavior( + TheCall->getExprLoc(), RHSExpr, + S.PDiag(diag::warn_ambiguous_provenance_capability_binop) + << LHSType << RHSType << LHSExpr->getSourceRange() + << RHSExpr->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. + RHSExpr->setType(S.Context.getAttributedType(attr::CHERINoProvenance, + RHSType, RHSType)); + } + } + return false; } diff --git a/clang/test/CodeGen/cheri/intcap-overflow-builtins.c b/clang/test/CodeGen/cheri/intcap-overflow-builtins.c new file mode 100644 index 000000000000..b786781e0c9e --- /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 -mem2reg | FileCheck %s --check-prefix=CHECK32 +// RUN: %cheri128_cc1 -Wno-cheri-provenance -o - -emit-llvm -disable-O0-optnone %s \ +// RUN: | opt -S -mem2reg | FileCheck %s --check-prefix=CHECK64 +// RUN: %riscv64_cheri_cc1 -Wno-cheri-provenance -o - -emit-llvm -disable-O0-optnone %s \ +// RUN: | opt -S -mem2reg | FileCheck %s --check-prefix=CHECK64 + +// CHECK32-LABEL: define {{[^@]+}}@ssadds +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ssadds(__intcap a, __intcap b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ssadds_lhs(__intcap a, int b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A]], i32 [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ssadds_rhs(int a, __intcap b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A]], i32 [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1 +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP2]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP3]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP1]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP4]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ssadds_promote(int a, int b, __intcap *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool ssadds_demote(__intcap a, __intcap b, int *c) { + return __builtin_add_overflow(a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssadds_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssadds_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool ssadds_provenance(int a, __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssaddu(__intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool ssaddu_lhs(__intcap a, int b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssaddu_rhs(int a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssaddu_promote(int a, int b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool ssaddu_demote(__intcap a, __intcap b, unsigned int *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssaddu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssaddu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssaddu_provenance(int a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uuadds(unsigned __intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uuadds_lhs(unsigned __intcap a, unsigned int b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uuadds_rhs(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uuadds_promote(unsigned int a, unsigned int b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uuadds_demote(unsigned __intcap a, unsigned __intcap b, int *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuadds_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuadds_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uuadds_provenance(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uuaddu(unsigned __intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uuaddu_lhs(unsigned __intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uuaddu_rhs(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uuaddu_promote(unsigned int a, unsigned int b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool uuaddu_demote(unsigned __intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uuaddu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uuaddu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uuaddu_provenance(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suadds(__intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = sext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool suadds_lhs(__intcap a, unsigned int b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool suadds_rhs(int a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suadds_promote(int a, unsigned int b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suadds_demote(__intcap a, unsigned __intcap b, int *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suadds_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@suadds_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool suadds_provenance(int a, unsigned __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suaddu(__intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool suaddu_lhs(__intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool suaddu_rhs(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suaddu_promote(int a, unsigned int b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool suaddu_demote(__intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@suaddu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@suaddu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool suaddu_provenance(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool usadds(unsigned __intcap a, __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool usadds_lhs(unsigned __intcap a, int b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool usadds_rhs(unsigned int a, __intcap b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool usadds_promote(unsigned int a, int b, __intcap *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool usadds_demote(unsigned __intcap a, __intcap b, int *c) { + return __builtin_add_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usadds_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usadds_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usadds_provenance(unsigned int a, __intcap b, __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usaddu(unsigned __intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool usaddu_lhs(unsigned __intcap a, int b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usaddu_rhs(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usaddu_promote(unsigned int a, int b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usaddu_demote(unsigned __intcap a, __intcap b, unsigned int *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usaddu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usaddu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.sadd.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usaddu_provenance(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_add_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubs(__intcap a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = sext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool sssubs_lhs(__intcap a, int b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sssubs_rhs(int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubs_promote(int a, int b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubs_demote(__intcap a, __intcap b, int *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubs_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubs_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool sssubs_provenance(int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubu(__intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool sssubu_lhs(__intcap a, int b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sssubu_rhs(int a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sssubu_promote(int a, int b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool sssubu_demote(__intcap a, __intcap b, unsigned int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sssubu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sssubu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sssubu_provenance(int a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uusubs(unsigned __intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uusubs_lhs(unsigned __intcap a, unsigned int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uusubs_rhs(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uusubs_promote(unsigned int a, unsigned int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uusubs_demote(unsigned __intcap a, unsigned __intcap b, int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubs_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubs_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uusubs_provenance(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uusubu(unsigned __intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uusubu_lhs(unsigned __intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uusubu_rhs(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uusubu_promote(unsigned int a, unsigned int b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool uusubu_demote(unsigned __intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uusubu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uusubu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uusubu_provenance(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubs(__intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = sext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool susubs_lhs(__intcap a, unsigned int b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool susubs_rhs(int a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubs_promote(int a, unsigned int b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubs_demote(__intcap a, unsigned __intcap b, int *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubs_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubs_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool susubs_provenance(int a, unsigned __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubu(__intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool susubu_lhs(__intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool susubu_rhs(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubu_promote(int a, unsigned int b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool susubu_demote(__intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@susubu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = zext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@susubu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = zext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool susubu_provenance(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ussubs(unsigned __intcap a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool ussubs_lhs(unsigned __intcap a, int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool ussubs_rhs(unsigned int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool ussubs_promote(unsigned int a, int b, __intcap *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool ussubs_demote(unsigned __intcap a, __intcap b, int *c) { + return __builtin_sub_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubs_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubs_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = sext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ussubs_provenance(unsigned int a, __intcap b, __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ussubu(unsigned __intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool ussubu_lhs(unsigned __intcap a, int b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ussubu_rhs(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ussubu_promote(unsigned int a, int b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ussubu_demote(unsigned __intcap a, __intcap b, unsigned int *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ussubu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.ssub.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[TMP0]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ussubu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.ssub.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[TMP0]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ussubu_provenance(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_sub_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 9223372036854775807, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmuls(__intcap a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = icmp slt i32 [[B]], 0 +// CHECK32-NEXT: [[TMP2:%.*]] = sub i32 0, [[B]] +// CHECK32-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[TMP2]], i32 [[B]] +// CHECK32-NEXT: [[TMP4:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP3]], i32 [[TMP0]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i1 [[TMP1]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = add i32 2147483647, [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ugt i32 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP6]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i32 [[TMP11]], i32 [[TMP6]] +// CHECK32-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP12]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[OP_SEXT:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = icmp slt i64 [[OP_SEXT]], 0 +// CHECK64-NEXT: [[TMP2:%.*]] = sub i64 0, [[OP_SEXT]] +// CHECK64-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 [[OP_SEXT]] +// CHECK64-NEXT: [[TMP4:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP3]], i64 [[TMP0]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i1 [[TMP1]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = add i64 9223372036854775807, [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP6]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i64 [[TMP11]], i64 [[TMP6]] +// CHECK64-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP12]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssmuls_lhs(__intcap a, int b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK32-NEXT: [[TMP10:%.*]] = add i32 2147483647, [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = icmp ugt i32 [[TMP8]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK32-NEXT: [[TMP13:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i32 [[TMP13]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP14]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP12]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i64 +// CHECK64-NEXT: [[TMP10:%.*]] = add i64 9223372036854775807, [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP8]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i64 [[TMP13]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP14]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool ssmuls_rhs(int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[B]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[B]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[B]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP13]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[OP_SEXT:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[OP_SEXT]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[OP_SEXT]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[OP_SEXT]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 9223372036854775807, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP13]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmuls_promote(int a, int b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: store i32 [[TMP13]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 2147483647, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 +// CHECK64-NEXT: store i32 [[TMP14]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmuls_demote(__intcap a, __intcap b, int *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmuls_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmuls_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool ssmuls_provenance(int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP7]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP7]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssmulu(__intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP1]], i33 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i33, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i33 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i33 [[TMP5]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP6]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool ssmulu_lhs(__intcap a, int b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmulu_rhs(int a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP7]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = sext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool ssmulu_promote(int a, int b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = sext i32 [[TMP0]] to i33 +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP2]], i33 [[TMP3]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i33, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = trunc i33 [[TMP6]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i33 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i33 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool ssmulu_demote(__intcap a, __intcap b, unsigned int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@ssmulu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = sext i32 [[TMP1]] to i33 +// CHECK32-NEXT: [[TMP4:%.*]] = sext i32 [[TMP2]] to i33 +// CHECK32-NEXT: [[TMP5:%.*]] = call { i33, i1 } @llvm.smul.with.overflow.i33(i33 [[TMP3]], i33 [[TMP4]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i33, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i33, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = trunc i33 [[TMP7]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i33 +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ne i33 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP8]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@ssmulu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = sext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = sext i64 [[TMP2]] to i65 +// CHECK64-NEXT: [[TMP5:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP3]], i65 [[TMP4]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i65, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = trunc i65 [[TMP7]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i64 [[TMP8]] to i65 +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ne i65 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP8]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool ssmulu_provenance(int a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 9223372036854775807, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uumuls(unsigned __intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP2:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[TMP2]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP3]], i32 [[B]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = zext i1 [[TMP1]] to i32 +// CHECK32-NEXT: [[TMP8:%.*]] = add i32 2147483647, [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ugt i32 [[TMP6]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP6]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i32 [[TMP11]], i32 [[TMP6]] +// CHECK32-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP12]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[OP_ZEXT:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP3]], i64 [[OP_ZEXT]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = zext i1 [[TMP1]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = add i64 9223372036854775807, [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP6]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP1]], i64 [[TMP11]], i64 [[TMP6]] +// CHECK64-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP12]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool uumuls_lhs(unsigned __intcap a, unsigned int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK32-NEXT: [[TMP10:%.*]] = add i32 2147483647, [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = icmp ugt i32 [[TMP8]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK32-NEXT: [[TMP13:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i32 [[TMP13]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP14]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP12]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i64 +// CHECK64-NEXT: [[TMP10:%.*]] = add i64 9223372036854775807, [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP8]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i64 [[TMP13]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP14]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool uumuls_rhs(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[B]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP13]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[OP_ZEXT:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[OP_ZEXT]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 9223372036854775807, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP13]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uumuls_promote(unsigned int a, unsigned int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK32-NEXT: [[TMP9:%.*]] = add i32 2147483647, [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP7]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i32 [[TMP12]], i32 [[TMP7]] +// CHECK32-NEXT: store i32 [[TMP13]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = zext i1 [[TMP2]] to i64 +// CHECK64-NEXT: [[TMP9:%.*]] = add i64 2147483647, [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = icmp ugt i64 [[TMP7]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP6]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP2]], i64 [[TMP12]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 +// CHECK64-NEXT: store i32 [[TMP14]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool uumuls_demote(unsigned __intcap a, unsigned __intcap b, int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumuls_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = icmp ugt i32 [[TMP5]], 2147483647 +// CHECK32-NEXT: [[TMP7:%.*]] = or i1 [[TMP4]], [[TMP6]] +// CHECK32-NEXT: [[TMP8:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP8]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP7]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumuls_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = icmp ugt i64 [[TMP5]], 9223372036854775807 +// CHECK64-NEXT: [[TMP7:%.*]] = or i1 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP8]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP7]] +// +_Bool uumuls_provenance(unsigned int a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uumulu(unsigned __intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool uumulu_lhs(unsigned __intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uumulu_rhs(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uumulu_promote(unsigned int a, unsigned int b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool uumulu_demote(unsigned __intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@uumulu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@uumulu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool uumulu_provenance(unsigned int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], 2147483647 +// CHECK32-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]] +// CHECK32-NEXT: [[TMP7:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP7]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP6]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = icmp ugt i64 [[TMP4]], 9223372036854775807 +// CHECK64-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]] +// CHECK64-NEXT: [[TMP7:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP7]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP6]] +// +_Bool sumuls(__intcap a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = icmp ugt i32 [[TMP3]], 2147483647 +// CHECK32-NEXT: [[TMP5:%.*]] = or i1 [[TMP2]], [[TMP4]] +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP5]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP2:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP1]], i65 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i65, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = trunc i65 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = sext i64 [[TMP6]] to i65 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i65 [[TMP5]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP4]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP6]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP10]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool sumuls_lhs(__intcap a, unsigned int b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = icmp ugt i32 [[TMP5]], 2147483647 +// CHECK32-NEXT: [[TMP7:%.*]] = or i1 [[TMP4]], [[TMP6]] +// CHECK32-NEXT: [[TMP8:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP8]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP7]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = icmp ugt i64 [[TMP5]], 9223372036854775807 +// CHECK64-NEXT: [[TMP7:%.*]] = or i1 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP8]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP7]] +// +_Bool sumuls_rhs(int a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], 2147483647 +// CHECK32-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]] +// CHECK32-NEXT: [[TMP7:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP7]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP6]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i32 [[B]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i64 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i64 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP7]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP11]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sumuls_promote(int a, unsigned int b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], 2147483647 +// CHECK32-NEXT: [[TMP6:%.*]] = or i1 [[TMP3]], [[TMP5]] +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP6]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = zext i64 [[TMP0]] to i65 +// CHECK64-NEXT: [[TMP3:%.*]] = zext i64 [[TMP1]] to i65 +// CHECK64-NEXT: [[TMP4:%.*]] = call { i65, i1 } @llvm.smul.with.overflow.i65(i65 [[TMP2]], i65 [[TMP3]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i65, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i65, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = trunc i65 [[TMP6]] to i32 +// CHECK64-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i65 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i65 [[TMP6]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP5]], [[TMP9]] +// CHECK64-NEXT: store i32 [[TMP7]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sumuls_demote(__intcap a, unsigned __intcap b, int *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumuls_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK32-NEXT: [[TMP10:%.*]] = add i32 2147483647, [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = icmp ugt i32 [[TMP8]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK32-NEXT: [[TMP13:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i32 [[TMP13]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP14]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP12]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumuls_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i64 +// CHECK64-NEXT: [[TMP10:%.*]] = add i64 9223372036854775807, [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP8]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i64 [[TMP13]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP14]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool sumuls_provenance(int a, unsigned __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP12]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i64 [[TMP11]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP12]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sumulu(__intcap a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP2:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[TMP2]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP3]], i32 [[B]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = icmp ne i32 [[TMP6]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = and i1 [[TMP1]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP5]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = sub i32 0, [[TMP6]] +// CHECK32-NEXT: [[TMP11:%.*]] = select i1 [[TMP1]], i32 [[TMP10]], i32 [[TMP6]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP11]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[OP_ZEXT:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP3]], i64 [[OP_ZEXT]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP6]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = and i1 [[TMP1]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP5]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = sub i64 0, [[TMP6]] +// CHECK64-NEXT: [[TMP11:%.*]] = select i1 [[TMP1]], i64 [[TMP10]], i64 [[TMP6]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP11]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool sumulu_lhs(__intcap a, unsigned int b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i32 [[TMP8]], 0 +// CHECK32-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i32 [[TMP12]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i64 [[TMP8]], 0 +// CHECK64-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i64 [[TMP12]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sumulu_rhs(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[B]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP12]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[OP_ZEXT:%.*]] = zext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[OP_ZEXT]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i64 [[TMP11]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP12]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool sumulu_promote(int a, unsigned int b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: store i32 [[TMP12]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP7]], 4294967295 +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP10]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP2]], i64 [[TMP13]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP15:%.*]] = trunc i64 [[TMP14]] to i32 +// CHECK64-NEXT: store i32 [[TMP15]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool sumulu_demote(__intcap a, unsigned __intcap b, unsigned int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@sumulu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i32 [[TMP8]], 0 +// CHECK32-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i32 [[TMP12]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@sumulu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = sext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i64 [[TMP8]], 0 +// CHECK64-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i64 [[TMP12]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool sumulu_provenance(int a, unsigned __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP4]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool usmuls(unsigned __intcap a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP0]], i32 [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP3]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP4]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP2]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP4]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP3]] +// +_Bool usmuls_lhs(unsigned __intcap a, int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1 +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0 +// CHECK32-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP5]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP4]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP5]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool usmuls_rhs(unsigned int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP1]], i32 [[B]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP4]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP5]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP2:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP3:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP1]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP3]], 1 +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP3]], 0 +// CHECK64-NEXT: [[TMP6:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP5]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP6]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP4]] +// +_Bool usmuls_promote(unsigned int a, int b, __intcap *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[TMP0]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1 +// CHECK32-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0 +// CHECK32-NEXT: store i32 [[TMP4]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP3]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[TMP0]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP3:%.*]] = extractvalue { i64, i1 } [[TMP2]], 1 +// CHECK64-NEXT: [[TMP4:%.*]] = extractvalue { i64, i1 } [[TMP2]], 0 +// CHECK64-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32 +// CHECK64-NEXT: [[TMP6:%.*]] = sext i32 [[TMP5]] to i64 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP4]], [[TMP6]] +// CHECK64-NEXT: [[TMP8:%.*]] = or i1 [[TMP3]], [[TMP7]] +// CHECK64-NEXT: store i32 [[TMP5]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP8]] +// +_Bool usmuls_demote(unsigned __intcap a, __intcap b, int *c) { + return __builtin_mul_overflow((__intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmuls_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK32-NEXT: [[TMP10:%.*]] = add i32 2147483647, [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = icmp ugt i32 [[TMP8]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK32-NEXT: [[TMP13:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i32 [[TMP13]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP14]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP12]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmuls_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = zext i1 [[TMP3]] to i64 +// CHECK64-NEXT: [[TMP10:%.*]] = add i64 9223372036854775807, [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP8]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP3]], i64 [[TMP13]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP15:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP14]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP15]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool usmuls_provenance(unsigned int a, __intcap b, __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP12]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i64 [[TMP11]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP12]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usmulu(unsigned __intcap a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_lhs +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP1:%.*]] = icmp slt i32 [[B]], 0 +// CHECK32-NEXT: [[TMP2:%.*]] = sub i32 0, [[B]] +// CHECK32-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i32 [[TMP2]], i32 [[B]] +// CHECK32-NEXT: [[TMP4:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP3]], i32 [[TMP0]]) +// CHECK32-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1 +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0 +// CHECK32-NEXT: [[TMP7:%.*]] = icmp ne i32 [[TMP6]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = and i1 [[TMP1]], [[TMP7]] +// CHECK32-NEXT: [[TMP9:%.*]] = or i1 [[TMP5]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = sub i32 0, [[TMP6]] +// CHECK32-NEXT: [[TMP11:%.*]] = select i1 [[TMP1]], i32 [[TMP10]], i32 [[TMP6]] +// CHECK32-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[A]], i32 [[TMP11]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP9]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_lhs +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[OP_SEXT:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP1:%.*]] = icmp slt i64 [[OP_SEXT]], 0 +// CHECK64-NEXT: [[TMP2:%.*]] = sub i64 0, [[OP_SEXT]] +// CHECK64-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i64 [[TMP2]], i64 [[OP_SEXT]] +// CHECK64-NEXT: [[TMP4:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP3]], i64 [[TMP0]]) +// CHECK64-NEXT: [[TMP5:%.*]] = extractvalue { i64, i1 } [[TMP4]], 1 +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP4]], 0 +// CHECK64-NEXT: [[TMP7:%.*]] = icmp ne i64 [[TMP6]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = and i1 [[TMP1]], [[TMP7]] +// CHECK64-NEXT: [[TMP9:%.*]] = or i1 [[TMP5]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = sub i64 0, [[TMP6]] +// CHECK64-NEXT: [[TMP11:%.*]] = select i1 [[TMP1]], i64 [[TMP10]], i64 [[TMP6]] +// CHECK64-NEXT: [[TMP12:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[A]], i64 [[TMP11]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP12]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP9]] +// +_Bool usmulu_lhs(unsigned __intcap a, int b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_rhs +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i32 [[TMP8]], 0 +// CHECK32-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i32 [[TMP12]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_rhs +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i64 [[TMP8]], 0 +// CHECK64-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i64 [[TMP12]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usmulu_rhs(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_promote +// CHECK32-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[B]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[B]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[B]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[TMP12]] +// CHECK32-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_promote +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[OP_SEXT:%.*]] = sext i32 [[B]] to i64 +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[OP_SEXT]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[OP_SEXT]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[OP_SEXT]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i64 [[TMP11]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[TMP12]] +// CHECK64-NEXT: store ptr addrspace(200) [[TMP13]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP10]] +// +_Bool usmulu_promote(unsigned int a, int b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_demote +// CHECK32-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[A]]) +// CHECK32-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 0 +// CHECK32-NEXT: [[TMP3:%.*]] = sub i32 0, [[TMP0]] +// CHECK32-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 [[TMP0]] +// CHECK32-NEXT: [[TMP5:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP4]], i32 [[TMP1]]) +// CHECK32-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0 +// CHECK32-NEXT: [[TMP8:%.*]] = icmp ne i32 [[TMP7]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK32-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = sub i32 0, [[TMP7]] +// CHECK32-NEXT: [[TMP12:%.*]] = select i1 [[TMP2]], i32 [[TMP11]], i32 [[TMP7]] +// CHECK32-NEXT: store i32 [[TMP12]], ptr [[C]], align 4 +// CHECK32-NEXT: ret i1 [[TMP10]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_demote +// CHECK64-SAME: (ptr addrspace(200) noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[TMP0:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[A]]) +// CHECK64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP0]], 0 +// CHECK64-NEXT: [[TMP3:%.*]] = sub i64 0, [[TMP0]] +// CHECK64-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i64 [[TMP3]], i64 [[TMP0]] +// CHECK64-NEXT: [[TMP5:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP4]], i64 [[TMP1]]) +// CHECK64-NEXT: [[TMP6:%.*]] = extractvalue { i64, i1 } [[TMP5]], 1 +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP5]], 0 +// CHECK64-NEXT: [[TMP8:%.*]] = icmp ne i64 [[TMP7]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = and i1 [[TMP2]], [[TMP8]] +// CHECK64-NEXT: [[TMP10:%.*]] = or i1 [[TMP6]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[TMP7]], 4294967295 +// CHECK64-NEXT: [[TMP12:%.*]] = or i1 [[TMP10]], [[TMP11]] +// CHECK64-NEXT: [[TMP13:%.*]] = sub i64 0, [[TMP7]] +// CHECK64-NEXT: [[TMP14:%.*]] = select i1 [[TMP2]], i64 [[TMP13]], i64 [[TMP7]] +// CHECK64-NEXT: [[TMP15:%.*]] = trunc i64 [[TMP14]] to i32 +// CHECK64-NEXT: store i32 [[TMP15]], ptr [[C]], align 4 +// CHECK64-NEXT: ret i1 [[TMP12]] +// +_Bool usmulu_demote(unsigned __intcap a, __intcap b, unsigned int *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} + +// CHECK32-LABEL: define {{[^@]+}}@usmulu_provenance +// CHECK32-SAME: (i32 noundef [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i32 [[A]] +// CHECK32-NEXT: [[TMP1:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[B]]) +// CHECK32-NEXT: [[TMP2:%.*]] = call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) [[TMP0]]) +// CHECK32-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// CHECK32-NEXT: [[TMP4:%.*]] = sub i32 0, [[TMP1]] +// CHECK32-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i32 [[TMP4]], i32 [[TMP1]] +// CHECK32-NEXT: [[TMP6:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[TMP5]], i32 [[TMP2]]) +// CHECK32-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1 +// CHECK32-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0 +// CHECK32-NEXT: [[TMP9:%.*]] = icmp ne i32 [[TMP8]], 0 +// CHECK32-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK32-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK32-NEXT: [[TMP12:%.*]] = sub i32 0, [[TMP8]] +// CHECK32-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i32 [[TMP12]], i32 [[TMP8]] +// CHECK32-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i32(ptr addrspace(200) [[B]], i32 [[TMP13]]) +// CHECK32-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 8 +// CHECK32-NEXT: ret i1 [[TMP11]] +// +// CHECK64-LABEL: define {{[^@]+}}@usmulu_provenance +// CHECK64-SAME: (i32 noundef signext [[A:%.*]], ptr addrspace(200) noundef [[B:%.*]], ptr noundef [[C:%.*]]) #[[ATTR0]] { +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[CONV:%.*]] = zext i32 [[A]] to i64 +// CHECK64-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr addrspace(200) null, i64 [[CONV]] +// CHECK64-NEXT: [[TMP1:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[B]]) +// CHECK64-NEXT: [[TMP2:%.*]] = call i64 @llvm.cheri.cap.address.get.i64(ptr addrspace(200) [[TMP0]]) +// CHECK64-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP1]], 0 +// CHECK64-NEXT: [[TMP4:%.*]] = sub i64 0, [[TMP1]] +// CHECK64-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i64 [[TMP4]], i64 [[TMP1]] +// CHECK64-NEXT: [[TMP6:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[TMP5]], i64 [[TMP2]]) +// CHECK64-NEXT: [[TMP7:%.*]] = extractvalue { i64, i1 } [[TMP6]], 1 +// CHECK64-NEXT: [[TMP8:%.*]] = extractvalue { i64, i1 } [[TMP6]], 0 +// CHECK64-NEXT: [[TMP9:%.*]] = icmp ne i64 [[TMP8]], 0 +// CHECK64-NEXT: [[TMP10:%.*]] = and i1 [[TMP3]], [[TMP9]] +// CHECK64-NEXT: [[TMP11:%.*]] = or i1 [[TMP7]], [[TMP10]] +// CHECK64-NEXT: [[TMP12:%.*]] = sub i64 0, [[TMP8]] +// CHECK64-NEXT: [[TMP13:%.*]] = select i1 [[TMP3]], i64 [[TMP12]], i64 [[TMP8]] +// CHECK64-NEXT: [[TMP14:%.*]] = call ptr addrspace(200) @llvm.cheri.cap.address.set.i64(ptr addrspace(200) [[B]], i64 [[TMP13]]) +// CHECK64-NEXT: store ptr addrspace(200) [[TMP14]], ptr [[C]], align 16 +// CHECK64-NEXT: ret i1 [[TMP11]] +// +_Bool usmulu_provenance(unsigned int a, __intcap b, unsigned __intcap *c) { + return __builtin_mul_overflow((unsigned __intcap)a, b, c); +} diff --git a/clang/test/Sema/cheri/intcap-overflow-builtins.c b/clang/test/Sema/cheri/intcap-overflow-builtins.c new file mode 100644 index 000000000000..a77b4786e822 --- /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); +}