From def11ee1f27d100b40226f783b16f3ef11806ebd Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sat, 3 Aug 2024 00:08:27 +0100 Subject: [PATCH] [Sema][CodeGen] Support __builtin__overflow with __intcap Morello LLVM has downstream support for this, but it's both incomplete (see https://git.morello-project.org/morello/llvm-project/-/issues/80) and incorrect with regards to provenance (in that it takes a naive type-based approach rather than considering the cheri_no_provenance attribute, meaning it differs from the binary operators in provenance semantics). This is a from-scratch implementation that aims to not have the same shortcomings. --- clang/lib/CodeGen/CGBuiltin.cpp | 130 +- clang/lib/Sema/SemaChecking.cpp | 14 + .../CodeGen/cheri/intcap-overflow-builtins.c | 5455 +++++++++++++++++ .../Sema/cheri/intcap-overflow-builtins.c | 77 + 4 files changed, 5663 insertions(+), 13 deletions(-) create mode 100644 clang/test/CodeGen/cheri/intcap-overflow-builtins.c create mode 100644 clang/test/Sema/cheri/intcap-overflow-builtins.c diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d04a69869abf..23338ac6796a 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -35,6 +35,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/IntrinsicInst.h" @@ -698,9 +699,7 @@ static WidthAndSignedness getIntegerWidthAndSignedness(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 Width = context.getIntWidth(Type); bool Signed = Type->isSignedIntegerType(); return {Width, Signed}; } @@ -1925,14 +1924,40 @@ static RValue EmitCheckedUnsignedMultiplySignedResult( CodeGenFunction &CGF, const clang::Expr *Op1, WidthAndSignedness Op1Info, const clang::Expr *Op2, WidthAndSignedness Op2Info, const clang::Expr *ResultArg, QualType ResultQTy, - WidthAndSignedness ResultInfo) { + WidthAndSignedness ResultInfo, SourceLocation Loc) { assert(isSpecialUnsignedMultiplySignedResult( Builtin::BI__builtin_mul_overflow, Op1Info, Op2Info, ResultInfo) && "Cannot specialize this multiply"); + clang::QualType Op1QTy = Op1->getType(); + clang::QualType Op2QTy = Op2->getType(); + bool Op1IsCap = Op1QTy->isCHERICapabilityType(CGF.getContext()); + bool Op2IsCap = Op2QTy->isCHERICapabilityType(CGF.getContext()); + bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGF.getContext()); + llvm::Value *V1 = CGF.EmitScalarExpr(Op1); llvm::Value *V2 = CGF.EmitScalarExpr(Op2); + llvm::Value *ProvenanceCap = nullptr; + if (ResultIsCap) { + bool Op1NoProvenance = + !Op1IsCap || Op1QTy->hasAttr(attr::CHERINoProvenance); + bool Op2NoProvenance = + !Op2IsCap || Op2QTy->hasAttr(attr::CHERINoProvenance); + if (Op1NoProvenance && Op2NoProvenance) + ProvenanceCap = llvm::ConstantPointerNull::get(CGF.Int8CheriCapTy); + else if (Op1NoProvenance) + ProvenanceCap = V2; + else + ProvenanceCap = V1; + } + + if (Op1IsCap) + V1 = CGF.getCapabilityIntegerValue(V1); + + if (Op2IsCap) + V2 = CGF.getCapabilityIntegerValue(V2); + llvm::Value *HasOverflow; llvm::Value *Result = EmitOverflowIntrinsic( CGF, llvm::Intrinsic::umul_with_overflow, V1, V2, HasOverflow); @@ -1946,6 +1971,9 @@ static RValue EmitCheckedUnsignedMultiplySignedResult( llvm::Value *IntMaxOverflow = CGF.Builder.CreateICmpUGT(Result, IntMaxValue); HasOverflow = CGF.Builder.CreateOr(HasOverflow, IntMaxOverflow); + if (ResultIsCap) + Result = CGF.setCapabilityIntegerValue(ProvenanceCap, Result, Loc); + bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg); @@ -1971,11 +1999,18 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, WidthAndSignedness Op1Info, const clang::Expr *Op2, WidthAndSignedness Op2Info, const clang::Expr *ResultArg, QualType ResultQTy, - WidthAndSignedness ResultInfo) { + WidthAndSignedness ResultInfo, + SourceLocation Loc) { assert(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; @@ -1983,6 +2018,28 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp); unsigned SignedOpWidth = Op1Info.Signed ? Op1Info.Width : Op2Info.Width; unsigned UnsignedOpWidth = Op1Info.Signed ? Op2Info.Width : Op1Info.Width; + bool SignedIsCap = Op1Info.Signed ? Op1IsCap : Op2IsCap; + bool UnsignedIsCap = Op1Info.Signed ? Op2IsCap : Op1IsCap; + + llvm::Value *ProvenanceCap = nullptr; + if (ResultIsCap) { + bool Op1NoProvenance = + !Op1IsCap || Op1QTy->hasAttr(attr::CHERINoProvenance); + bool Op2NoProvenance = + !Op2IsCap || Op2QTy->hasAttr(attr::CHERINoProvenance); + if (Op1NoProvenance && Op2NoProvenance) + ProvenanceCap = llvm::ConstantPointerNull::get(CGF.Int8CheriCapTy); + else if (Op1NoProvenance) + ProvenanceCap = Op1Info.Signed ? Unsigned : Signed; + else + ProvenanceCap = Op1Info.Signed ? Signed : Unsigned; + } + + if (SignedIsCap) + Signed = CGF.getCapabilityIntegerValue(Signed); + + if (UnsignedIsCap) + Unsigned = CGF.getCapabilityIntegerValue(Unsigned); // One of the operands may be smaller than the other. If so, [s|z]ext it. if (SignedOpWidth < UnsignedOpWidth) @@ -1993,7 +2050,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, llvm::Type *OpTy = Signed->getType(); llvm::Value *Zero = llvm::Constant::getNullValue(OpTy); Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg); - llvm::Type *ResTy = ResultPtr.getElementType(); + llvm::Type *ResTy = ResultIsCap ? llvm::IntegerType::get(CGF.getLLVMContext(), + ResultInfo.Width) + : ResultPtr.getElementType(); unsigned OpWidth = std::max(Op1Info.Width, Op2Info.Width); // Take the absolute value of the signed operand. @@ -2032,8 +2091,7 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult)); Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow); if (ResultInfo.Width < OpWidth) { - auto IntMax = - llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth); + auto IntMax = llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth); llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT( UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax)); Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow); @@ -2047,6 +2105,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1, } assert(Overflow && Result && "Missing overflow or result"); + if (ResultIsCap) + Result = CGF.setCapabilityIntegerValue(ProvenanceCap, Result, Loc); + bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); CGF.Builder.CreateStore(CGF.EmitToMemory(Result, ResultQTy), ResultPtr, @@ -4493,13 +4554,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const clang::Expr *RightArg = E->getArg(1); const clang::Expr *ResultArg = E->getArg(2); + clang::QualType LeftQTy = LeftArg->getType(); + clang::QualType RightQTy = RightArg->getType(); clang::QualType ResultQTy = ResultArg->getType()->castAs()->getPointeeType(); + bool LeftIsCap = LeftQTy->isCHERICapabilityType(CGM.getContext()); + bool RightIsCap = RightQTy->isCHERICapabilityType(CGM.getContext()); + bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGM.getContext()); WidthAndSignedness LeftInfo = - getIntegerWidthAndSignedness(CGM.getContext(), LeftArg->getType()); + getIntegerWidthAndSignedness(CGM.getContext(), LeftQTy); WidthAndSignedness RightInfo = - getIntegerWidthAndSignedness(CGM.getContext(), RightArg->getType()); + getIntegerWidthAndSignedness(CGM.getContext(), RightQTy); WidthAndSignedness ResultInfo = getIntegerWidthAndSignedness(CGM.getContext(), ResultQTy); @@ -4508,13 +4574,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, if (isSpecialMixedSignMultiply(BuiltinID, LeftInfo, RightInfo, ResultInfo)) return EmitCheckedMixedSignMultiply(*this, LeftArg, LeftInfo, RightArg, RightInfo, ResultArg, ResultQTy, - ResultInfo); + ResultInfo, E->getExprLoc()); if (isSpecialUnsignedMultiplySignedResult(BuiltinID, LeftInfo, RightInfo, ResultInfo)) return EmitCheckedUnsignedMultiplySignedResult( *this, LeftArg, LeftInfo, RightArg, RightInfo, ResultArg, ResultQTy, - ResultInfo); + ResultInfo, E->getExprLoc()); WidthAndSignedness EncompassingInfo = EncompassingIntegerType({LeftInfo, RightInfo, ResultInfo}); @@ -4522,23 +4588,30 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Type *EncompassingLLVMTy = llvm::IntegerType::get(CGM.getLLVMContext(), EncompassingInfo.Width); - llvm::Type *ResultLLVMTy = CGM.getTypes().ConvertType(ResultQTy); + llvm::Type *ResultLLVMTy = + ResultIsCap + ? llvm::IntegerType::get(CGM.getLLVMContext(), ResultInfo.Width) + : CGM.getTypes().ConvertType(ResultQTy); 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 +4622,33 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Right = EmitScalarExpr(RightArg); Address ResultPtr = EmitPointerWithAlignment(ResultArg); + llvm::Value *ProvenanceCap = nullptr; + if (ResultIsCap) { + if (!Commutative) { + if (LeftIsCap) + ProvenanceCap = Left; + else + ProvenanceCap = llvm::ConstantPointerNull::get(Int8CheriCapTy); + } else { + bool LeftNoProvenance = + !LeftIsCap || LeftQTy->hasAttr(attr::CHERINoProvenance); + bool RightNoProvenance = + !RightIsCap || RightQTy->hasAttr(attr::CHERINoProvenance); + if (LeftNoProvenance && RightNoProvenance) + ProvenanceCap = llvm::ConstantPointerNull::get(Int8CheriCapTy); + else if (LeftNoProvenance) + ProvenanceCap = Right; + else + ProvenanceCap = Left; + } + } + + if (LeftIsCap) + Left = getCapabilityIntegerValue(Left); + + if (RightIsCap) + Right = getCapabilityIntegerValue(Right); + // Extend each operand to the encompassing type. Left = Builder.CreateIntCast(Left, EncompassingLLVMTy, LeftInfo.Signed); Right = Builder.CreateIntCast(Right, EncompassingLLVMTy, RightInfo.Signed); @@ -4573,6 +4673,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Result = ResultTrunc; } + if (ResultIsCap) + Result = + setCapabilityIntegerValue(ProvenanceCap, Result, E->getExprLoc()); + // Finally, store the result using the pointer. bool isVolatile = ResultArg->getType()->getPointeeType().isVolatileQualified(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e41e47fdca5b..2cf9a9bb7efe 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,18 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall, } } + // 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. + if (BuiltinID != Builtin::BI__builtin_sub_overflow) { + assert((BuiltinID == Builtin::BI__builtin_add_overflow || + BuiltinID == Builtin::BI__builtin_mul_overflow) && + "Unexpected overflow builtin"); + + S.DiagnoseAmbiguousProvenance(TheCall->getArg(0), TheCall->getArg(1), + TheCall->getExprLoc(), false); + } + return false; } diff --git a/clang/test/CodeGen/cheri/intcap-overflow-builtins.c b/clang/test/CodeGen/cheri/intcap-overflow-builtins.c new file mode 100644 index 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); +}