[CIR] Split BinOpOverflowOp into separate overflow-checked ops (#186653)

Replace the monolithic cir.binop.overflow operation and its
BinOpOverflowKind enum with three individual operations:
cir.add.overflow, cir.sub.overflow, and cir.mul.overflow.

This follows the same pattern used when BinOp and UnaryOp were
previously split into per-operation ops (cir.add, cir.sub, etc.),
eliminating enum dispatch and enabling per-op traits like Commutative.
This commit is contained in:
Henrich Lauko 2026-03-17 18:57:23 +01:00 committed by GitHub
parent f28ef68996
commit 74a5efa331
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 184 additions and 173 deletions

View File

@ -2154,44 +2154,30 @@ def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
}
//===----------------------------------------------------------------------===//
// BinOpOverflowOp
// Checked Binary Arithmetic Operations (with overflow)
//===----------------------------------------------------------------------===//
def CIR_BinOpOverflowKind : CIR_I32EnumAttr<
"BinOpOverflowKind", "checked binary arithmetic operation kind", [
I32EnumAttrCase<"Add", 0, "add">,
I32EnumAttrCase<"Sub", 1, "sub">,
I32EnumAttrCase<"Mul", 2, "mul">
]>;
def CIR_BinOpOverflowOp : CIR_Op<"binop.overflow", [Pure, SameTypeOperands]> {
let summary = "Perform binary integral arithmetic with overflow checking";
let description = [{
`cir.binop.overflow` performs binary arithmetic operations with overflow
checking on integral operands.
The `kind` argument specifies the kind of arithmetic operation to perform.
It can be either `add`, `sub`, or `mul`. The `lhs` and `rhs` arguments
specify the input operands of the arithmetic operation. The types of `lhs`
and `rhs` must be the same.
`cir.binop.overflow` produces two SSA values. `result` is the result of the
arithmetic operation truncated to its specified type. `overflow` is a
boolean value indicating whether overflow happens during the operation.
The exact semantic of this operation is as follows:
- `lhs` and `rhs` are promoted to an imaginary integral type that has
infinite precision.
- The arithmetic operation is performed on the promoted operands.
- The infinite-precision result is truncated to the type of `result`. The
truncated result is assigned to `result`.
- If the truncated result is equal to the un-truncated result, `overflow`
is assigned to false. Otherwise, `overflow` is assigned to true.
}];
// Base class for binary arithmetic operations with overflow checking.
//
// Each op produces two SSA values: `result` is the arithmetic result truncated
// to its specified type, and `overflow` is a boolean indicating whether
// overflow occurred.
//
// The exact semantics are:
// - `lhs` and `rhs` are promoted to an imaginary infinite-precision
// integral type.
// - The arithmetic operation is performed on the promoted operands.
// - The infinite-precision result is truncated to the type of `result`.
// - `overflow` is true if the truncated result differs from the
// infinite-precision result.
//
// The type of `result` may differ from the operand type. This models C
// builtins like `__builtin_*_overflow` where operands and the result can
// have different widths or signedness.
class CIR_BinOpOverflow<string mnemonic, list<Trait> traits = []>
: CIR_Op<mnemonic, !listconcat([Pure, SameTypeOperands], traits)> {
let arguments = (ins
CIR_BinOpOverflowKind:$kind,
CIR_IntType:$lhs,
CIR_IntType:$rhs
);
@ -2199,32 +2185,61 @@ def CIR_BinOpOverflowOp : CIR_Op<"binop.overflow", [Pure, SameTypeOperands]> {
let results = (outs CIR_IntType:$result, CIR_BoolType:$overflow);
let assemblyFormat = [{
`(` $kind `,` $lhs `,` $rhs `)` `:` qualified(type($lhs)) `,`
`(` qualified(type($result)) `,` qualified(type($overflow)) `)`
$lhs `,` $rhs `:` qualified(type($lhs)) `->` qualified(type($result))
attr-dict
}];
let builders = [
OpBuilder<(ins "cir::IntType":$resultTy,
"cir::BinOpOverflowKind":$kind,
"mlir::Value":$lhs,
"mlir::Value":$rhs), [{
auto overflowTy = cir::BoolType::get($_builder.getContext());
build($_builder, $_state, resultTy, overflowTy, kind, lhs, rhs);
build($_builder, $_state, resultTy, overflowTy, lhs, rhs);
}]>
];
let extraLLVMLoweringPatternDecl = [{
static std::string getLLVMIntrinName(cir::BinOpOverflowKind opKind,
bool isSigned, unsigned width);
}
struct EncompassedTypeInfo {
bool sign;
unsigned width;
};
def CIR_AddOverflowOp : CIR_BinOpOverflow<"add.overflow", [Commutative]> {
let summary = "Integer addition with overflow checking";
let description = [{
`cir.add.overflow` performs addition with overflow checking on integral
operands. See `CIR_BinOpOverflow` for semantics.
static EncompassedTypeInfo computeEncompassedTypeWidth(cir::IntType operandTy,
cir::IntType resultTy);
Example:
```mlir
%result, %overflow = cir.add.overflow %a, %b : !u32i -> !u32i
%result, %overflow = cir.add.overflow %a, %b : !cir.int<s, 33> -> !s32i
```
}];
}
def CIR_SubOverflowOp : CIR_BinOpOverflow<"sub.overflow"> {
let summary = "Integer subtraction with overflow checking";
let description = [{
`cir.sub.overflow` performs subtraction with overflow checking on integral
operands. See `CIR_BinOpOverflow` for semantics.
Example:
```mlir
%result, %overflow = cir.sub.overflow %a, %b : !u32i -> !u32i
```
}];
}
def CIR_MulOverflowOp : CIR_BinOpOverflow<"mul.overflow", [Commutative]> {
let summary = "Integer multiplication with overflow checking";
let description = [{
`cir.mul.overflow` performs multiplication with overflow checking on
integral operands. See `CIR_BinOpOverflow` for semantics.
Example:
```mlir
%result, %overflow = cir.mul.overflow %a, %b : !u32i -> !u32i
```
}];
}

View File

@ -231,6 +231,16 @@ getIntegerWidthAndSignedness(const clang::ASTContext &astContext,
return {width, isSigned};
}
/// Create a checked overflow arithmetic op and return its result and overflow
/// flag.
template <typename OpTy>
static std::pair<mlir::Value, mlir::Value>
emitOverflowOp(CIRGenBuilderTy &builder, mlir::Location loc,
cir::IntType resultTy, mlir::Value lhs, mlir::Value rhs) {
auto op = OpTy::create(builder, loc, resultTy, lhs, rhs);
return {op.getResult(), op.getOverflow()};
}
// Given one or more integer types, this function produces an integer type that
// encompasses them: any value in one of the given types could be expressed in
// the encompassing type.
@ -1900,38 +1910,36 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
&getMLIRContext(), encompassingInfo.width, encompassingInfo.isSigned);
auto resultCIRTy = mlir::cast<cir::IntType>(cgm.convertType(resultQTy));
mlir::Value left = emitScalarExpr(leftArg);
mlir::Value right = emitScalarExpr(rightArg);
mlir::Value x = emitScalarExpr(leftArg);
mlir::Value y = emitScalarExpr(rightArg);
Address resultPtr = emitPointerWithAlignment(resultArg);
// Extend each operand to the encompassing type, if necessary.
if (left.getType() != encompassingCIRTy)
left =
builder.createCast(cir::CastKind::integral, left, encompassingCIRTy);
if (right.getType() != encompassingCIRTy)
right =
builder.createCast(cir::CastKind::integral, right, encompassingCIRTy);
if (x.getType() != encompassingCIRTy)
x = builder.createCast(cir::CastKind::integral, x, encompassingCIRTy);
if (y.getType() != encompassingCIRTy)
y = builder.createCast(cir::CastKind::integral, y, encompassingCIRTy);
// Perform the operation on the extended values.
cir::BinOpOverflowKind opKind;
mlir::Location loc = getLoc(e->getSourceRange());
mlir::Value result, overflow;
switch (builtinID) {
default:
llvm_unreachable("Unknown overflow builtin id.");
case Builtin::BI__builtin_add_overflow:
opKind = cir::BinOpOverflowKind::Add;
std::tie(result, overflow) =
emitOverflowOp<cir::AddOverflowOp>(builder, loc, resultCIRTy, x, y);
break;
case Builtin::BI__builtin_sub_overflow:
opKind = cir::BinOpOverflowKind::Sub;
std::tie(result, overflow) =
emitOverflowOp<cir::SubOverflowOp>(builder, loc, resultCIRTy, x, y);
break;
case Builtin::BI__builtin_mul_overflow:
opKind = cir::BinOpOverflowKind::Mul;
std::tie(result, overflow) =
emitOverflowOp<cir::MulOverflowOp>(builder, loc, resultCIRTy, x, y);
break;
}
mlir::Location loc = getLoc(e->getSourceRange());
auto arithOp = cir::BinOpOverflowOp::create(builder, loc, resultCIRTy,
opKind, left, right);
// Here is a slight difference from the original clang CodeGen:
// - In the original clang CodeGen, the checked arithmetic result is
// first computed as a value of the encompassing type, and then it is
@ -1944,9 +1952,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
// Finally, store the result using the pointer.
bool isVolatile =
resultArg->getType()->getPointeeType().isVolatileQualified();
builder.createStore(loc, arithOp.getResult(), resultPtr, isVolatile);
builder.createStore(loc, result, resultPtr, isVolatile);
return RValue::get(arithOp.getOverflow());
return RValue::get(overflow);
}
case Builtin::BI__builtin_uadd_overflow:
@ -1974,8 +1982,13 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
const clang::Expr *resultArg = e->getArg(2);
Address resultPtr = emitPointerWithAlignment(resultArg);
// Decide which of the arithmetic operation we are lowering to:
cir::BinOpOverflowKind arithKind;
clang::QualType resultQTy =
resultArg->getType()->castAs<clang::PointerType>()->getPointeeType();
auto resultCIRTy = mlir::cast<cir::IntType>(cgm.convertType(resultQTy));
// Create the appropriate overflow-checked arithmetic operation.
mlir::Location loc = getLoc(e->getSourceRange());
mlir::Value result, overflow;
switch (builtinID) {
default:
llvm_unreachable("Unknown overflow builtin id.");
@ -1985,7 +1998,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_sadd_overflow:
case Builtin::BI__builtin_saddl_overflow:
case Builtin::BI__builtin_saddll_overflow:
arithKind = cir::BinOpOverflowKind::Add;
std::tie(result, overflow) =
emitOverflowOp<cir::AddOverflowOp>(builder, loc, resultCIRTy, x, y);
break;
case Builtin::BI__builtin_usub_overflow:
case Builtin::BI__builtin_usubl_overflow:
@ -1993,7 +2007,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_ssub_overflow:
case Builtin::BI__builtin_ssubl_overflow:
case Builtin::BI__builtin_ssubll_overflow:
arithKind = cir::BinOpOverflowKind::Sub;
std::tie(result, overflow) =
emitOverflowOp<cir::SubOverflowOp>(builder, loc, resultCIRTy, x, y);
break;
case Builtin::BI__builtin_umul_overflow:
case Builtin::BI__builtin_umull_overflow:
@ -2001,24 +2016,17 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_smul_overflow:
case Builtin::BI__builtin_smull_overflow:
case Builtin::BI__builtin_smulll_overflow:
arithKind = cir::BinOpOverflowKind::Mul;
std::tie(result, overflow) =
emitOverflowOp<cir::MulOverflowOp>(builder, loc, resultCIRTy, x, y);
break;
}
clang::QualType resultQTy =
resultArg->getType()->castAs<clang::PointerType>()->getPointeeType();
auto resultCIRTy = mlir::cast<cir::IntType>(cgm.convertType(resultQTy));
mlir::Location loc = getLoc(e->getSourceRange());
cir::BinOpOverflowOp arithOp = cir::BinOpOverflowOp::create(
builder, loc, resultCIRTy, arithKind, x, y);
bool isVolatile =
resultArg->getType()->getPointeeType().isVolatileQualified();
builder.createStore(loc, emitToMemory(arithOp.getResult(), resultQTy),
resultPtr, isVolatile);
builder.createStore(loc, emitToMemory(result, resultQTy), resultPtr,
isVolatile);
return RValue::get(arithOp.getOverflow());
return RValue::get(overflow);
}
case Builtin::BIaddressof:

View File

@ -581,9 +581,9 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
// allocation fails.
if (typeSizeMultiplier != 1) {
mlir::Value tsmV = cgf.getBuilder().getConstInt(loc, typeSizeMultiplier);
auto mulOp = cir::BinOpOverflowOp::create(
cgf.getBuilder(), loc, mlir::cast<cir::IntType>(cgf.sizeTy),
cir::BinOpOverflowKind::Mul, size, tsmV);
auto mulOp = cir::MulOverflowOp::create(
cgf.getBuilder(), loc, mlir::cast<cir::IntType>(cgf.sizeTy), size,
tsmV);
if (hasOverflow)
hasOverflow =
@ -617,9 +617,9 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
if (cookieSize != 0) {
sizeWithoutCookie = size;
mlir::Value cookieSizeV = cgf.getBuilder().getConstInt(loc, cookieSize);
auto addOp = cir::BinOpOverflowOp::create(
cgf.getBuilder(), loc, mlir::cast<cir::IntType>(cgf.sizeTy),
cir::BinOpOverflowKind::Add, size, cookieSizeV);
auto addOp = cir::AddOverflowOp::create(
cgf.getBuilder(), loc, mlir::cast<cir::IntType>(cgf.sizeTy), size,
cookieSizeV);
if (hasOverflow)
hasOverflow =

View File

@ -3136,22 +3136,29 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(
return cmpOp.emitError() << "unsupported type for CmpOp: " << type;
}
mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(
cir::BinOpOverflowOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
/// Shared lowering logic for checked binary arithmetic overflow operations.
/// The \p opStr parameter specifies the arithmetic operation name used in the
/// LLVM intrinsic (e.g., "add", "sub", "mul").
template <typename OpTy>
static mlir::LogicalResult
lowerBinOpOverflow(OpTy op, typename OpTy::Adaptor adaptor,
mlir::ConversionPatternRewriter &rewriter,
const mlir::TypeConverter *typeConverter,
llvm::StringRef opStr) {
mlir::Location loc = op.getLoc();
cir::BinOpOverflowKind arithKind = op.getKind();
cir::IntType operandTy = op.getLhs().getType();
cir::IntType resultTy = op.getResult().getType();
EncompassedTypeInfo encompassedTyInfo =
computeEncompassedTypeWidth(operandTy, resultTy);
mlir::IntegerType encompassedLLVMTy =
rewriter.getIntegerType(encompassedTyInfo.width);
bool sign = operandTy.getIsSigned() || resultTy.getIsSigned();
unsigned width =
std::max(operandTy.getWidth() + (sign && operandTy.isUnsigned()),
resultTy.getWidth() + (sign && resultTy.isUnsigned()));
mlir::IntegerType encompassedLLVMTy = rewriter.getIntegerType(width);
mlir::Value lhs = adaptor.getLhs();
mlir::Value rhs = adaptor.getRhs();
if (operandTy.getWidth() < encompassedTyInfo.width) {
if (operandTy.getWidth() < width) {
if (operandTy.isSigned()) {
lhs = mlir::LLVM::SExtOp::create(rewriter, loc, encompassedLLVMTy, lhs);
rhs = mlir::LLVM::SExtOp::create(rewriter, loc, encompassedLLVMTy, rhs);
@ -3161,8 +3168,10 @@ mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(
}
}
std::string intrinName = getLLVMIntrinName(arithKind, encompassedTyInfo.sign,
encompassedTyInfo.width);
// The intrinsic name is `@llvm.{s|u}{op}.with.overflow.i{width}`
std::string intrinName = ("llvm." + llvm::Twine(sign ? 's' : 'u') + opStr +
".with.overflow.i" + llvm::Twine(width))
.str();
auto intrinNameAttr = mlir::StringAttr::get(op.getContext(), intrinName);
mlir::IntegerType overflowLLVMTy = rewriter.getI1Type();
@ -3180,8 +3189,8 @@ mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(
rewriter, loc, intrinRet, ArrayRef<int64_t>{1})
.getResult();
if (resultTy.getWidth() < encompassedTyInfo.width) {
mlir::Type resultLLVMTy = getTypeConverter()->convertType(resultTy);
if (resultTy.getWidth() < width) {
mlir::Type resultLLVMTy = typeConverter->convertType(resultTy);
auto truncResult =
mlir::LLVM::TruncOp::create(rewriter, loc, resultLLVMTy, result);
@ -3202,7 +3211,7 @@ mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(
}
mlir::Type boolLLVMTy =
getTypeConverter()->convertType(op.getOverflow().getType());
typeConverter->convertType(op.getOverflow().getType());
if (boolLLVMTy != rewriter.getI1Type())
overflow = mlir::LLVM::ZExtOp::create(rewriter, loc, boolLLVMTy, overflow);
@ -3211,43 +3220,22 @@ mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(
return mlir::success();
}
std::string CIRToLLVMBinOpOverflowOpLowering::getLLVMIntrinName(
cir::BinOpOverflowKind opKind, bool isSigned, unsigned width) {
// The intrinsic name is `@llvm.{s|u}{opKind}.with.overflow.i{width}`
std::string name = "llvm.";
if (isSigned)
name.push_back('s');
else
name.push_back('u');
switch (opKind) {
case cir::BinOpOverflowKind::Add:
name.append("add.");
break;
case cir::BinOpOverflowKind::Sub:
name.append("sub.");
break;
case cir::BinOpOverflowKind::Mul:
name.append("mul.");
break;
}
name.append("with.overflow.i");
name.append(std::to_string(width));
return name;
mlir::LogicalResult CIRToLLVMAddOverflowOpLowering::matchAndRewrite(
cir::AddOverflowOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
return lowerBinOpOverflow(op, adaptor, rewriter, getTypeConverter(), "add");
}
CIRToLLVMBinOpOverflowOpLowering::EncompassedTypeInfo
CIRToLLVMBinOpOverflowOpLowering::computeEncompassedTypeWidth(
cir::IntType operandTy, cir::IntType resultTy) {
bool sign = operandTy.getIsSigned() || resultTy.getIsSigned();
unsigned width =
std::max(operandTy.getWidth() + (sign && operandTy.isUnsigned()),
resultTy.getWidth() + (sign && resultTy.isUnsigned()));
return {sign, width};
mlir::LogicalResult CIRToLLVMSubOverflowOpLowering::matchAndRewrite(
cir::SubOverflowOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
return lowerBinOpOverflow(op, adaptor, rewriter, getTypeConverter(), "sub");
}
mlir::LogicalResult CIRToLLVMMulOverflowOpLowering::matchAndRewrite(
cir::MulOverflowOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
return lowerBinOpOverflow(op, adaptor, rewriter, getTypeConverter(), "mul");
}
mlir::LogicalResult CIRToLLVMShiftOpLowering::matchAndRewrite(

View File

@ -495,7 +495,7 @@ void t_new_var_size3(size_t n) {
// CHECK: cir.func {{.*}} @_Z15t_new_var_size3m
// CHECK: %[[N:.*]] = cir.load{{.*}} %[[ARG_ALLOCA:.*]]
// CHECK: %[[ELEMENT_SIZE:.*]] = cir.const #cir.int<8> : !u64i
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.binop.overflow(mul, %[[N]], %[[ELEMENT_SIZE]]) : !u64i, (!u64i, !cir.bool)
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.mul.overflow %[[N]], %[[ELEMENT_SIZE]] : !u64i -> !u64i
// CHECK: %[[ALL_ONES:.*]] = cir.const #cir.int<18446744073709551615> : !u64i
// CHECK: %[[ALLOC_SIZE:.*]] = cir.select if %[[OVERFLOW]] then %[[ALL_ONES]] else %[[RESULT]] : (!cir.bool, !u64i, !u64i)
// CHECK: %[[PTR:.*]] = cir.call @_Znam(%[[ALLOC_SIZE]]) {allocsize = array<i32: 0>, builtin} : (!u64i {llvm.noundef})
@ -524,7 +524,7 @@ void t_new_var_size4(int n) {
// CHECK: %[[N:.*]] = cir.load{{.*}} %[[ARG_ALLOCA:.*]]
// CHECK: %[[N_SIZE_T:.*]] = cir.cast integral %[[N]] : !s32i -> !u64i
// CHECK: %[[ELEMENT_SIZE:.*]] = cir.const #cir.int<8> : !u64i
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.binop.overflow(mul, %[[N_SIZE_T]], %[[ELEMENT_SIZE]]) : !u64i, (!u64i, !cir.bool)
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.mul.overflow %[[N_SIZE_T]], %[[ELEMENT_SIZE]] : !u64i -> !u64i
// CHECK: %[[ALL_ONES:.*]] = cir.const #cir.int<18446744073709551615> : !u64i
// CHECK: %[[ALLOC_SIZE:.*]] = cir.select if %[[OVERFLOW]] then %[[ALL_ONES]] else %[[RESULT]] : (!cir.bool, !u64i, !u64i)
// CHECK: %[[PTR:.*]] = cir.call @_Znam(%[[ALLOC_SIZE]]) {allocsize = array<i32: 0>, builtin} : (!u64i {llvm.noundef})
@ -558,7 +558,7 @@ void t_new_var_size5(int n) {
// CHECK: %[[N:.*]] = cir.load{{.*}} %[[ARG_ALLOCA:.*]]
// CHECK: %[[N_SIZE_T:.*]] = cir.cast integral %[[N]] : !s32i -> !u64i
// CHECK: %[[ELEMENT_SIZE:.*]] = cir.const #cir.int<48> : !u64i
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.binop.overflow(mul, %[[N_SIZE_T]], %[[ELEMENT_SIZE]]) : !u64i, (!u64i, !cir.bool)
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.mul.overflow %[[N_SIZE_T]], %[[ELEMENT_SIZE]] : !u64i -> !u64i
// CHECK: %[[ALL_ONES:.*]] = cir.const #cir.int<18446744073709551615> : !u64i
// CHECK: %[[ALLOC_SIZE:.*]] = cir.select if %[[OVERFLOW]] then %[[ALL_ONES]] else %[[RESULT]] : (!cir.bool, !u64i, !u64i)
// CHECK: %[[PTR:.*]] = cir.call @_Znam(%[[ALLOC_SIZE]]) {allocsize = array<i32: 0>, builtin} : (!u64i {llvm.noundef})
@ -591,7 +591,7 @@ void t_new_var_size6(int n) {
// CHECK: %[[MIN_SIZE:.*]] = cir.const #cir.int<3> : !u64i
// CHECK: %[[LT_MIN_SIZE:.*]] = cir.cmp lt %[[N_SIZE_T]], %[[MIN_SIZE]] : !u64i
// CHECK: %[[ELEMENT_SIZE:.*]] = cir.const #cir.int<8> : !u64i
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.binop.overflow(mul, %[[N_SIZE_T]], %[[ELEMENT_SIZE]]) : !u64i, (!u64i, !cir.bool)
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.mul.overflow %[[N_SIZE_T]], %[[ELEMENT_SIZE]] : !u64i -> !u64i
// CHECK: %[[ANY_OVERFLOW:.*]] = cir.or %[[LT_MIN_SIZE]], %[[OVERFLOW]] : !cir.bool
// CHECK: %[[ALL_ONES:.*]] = cir.const #cir.int<18446744073709551615> : !u64i
// CHECK: %[[ALLOC_SIZE:.*]] = cir.select if %[[ANY_OVERFLOW]] then %[[ALL_ONES]] else %[[RESULT]] : (!cir.bool, !u64i, !u64i)
@ -661,7 +661,7 @@ void t_new_var_size7(__int128 n) {
// CHECK: %[[N:.*]] = cir.load{{.*}} %[[ARG_ALLOCA:.*]]
// CHECK: %[[N_SIZE_T:.*]] = cir.cast integral %[[N]] : !s128i -> !u64i
// CHECK: %[[ELEMENT_SIZE:.*]] = cir.const #cir.int<8> : !u64i
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.binop.overflow(mul, %[[N_SIZE_T]], %[[ELEMENT_SIZE]]) : !u64i, (!u64i, !cir.bool)
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.mul.overflow %[[N_SIZE_T]], %[[ELEMENT_SIZE]] : !u64i -> !u64i
// CHECK: %[[ALL_ONES:.*]] = cir.const #cir.int<18446744073709551615> : !u64i
// CHECK: %[[ALLOC_SIZE:.*]] = cir.select if %[[OVERFLOW]] then %[[ALL_ONES]] else %[[RESULT]] : (!cir.bool, !u64i, !u64i)
// CHECK: %[[PTR:.*]] = cir.call @_Znam(%[[ALLOC_SIZE]]) {allocsize = array<i32: 0>, builtin} : (!u64i {llvm.noundef})
@ -691,9 +691,9 @@ void t_new_var_size_nontrivial(size_t n) {
// CHECK: cir.func {{.*}} @_Z25t_new_var_size_nontrivialm
// CHECK: %[[N:.*]] = cir.load{{.*}} %[[ARG_ALLOCA:.*]]
// CHECK: %[[ELEMENT_SIZE:.*]] = cir.const #cir.int<4> : !u64i
// CHECK: %[[SIZE_WITHOUT_COOKIE:.*]], %[[OVERFLOW:.*]] = cir.binop.overflow(mul, %[[N]], %[[ELEMENT_SIZE]]) : !u64i, (!u64i, !cir.bool)
// CHECK: %[[SIZE_WITHOUT_COOKIE:.*]], %[[OVERFLOW:.*]] = cir.mul.overflow %[[N]], %[[ELEMENT_SIZE]] : !u64i -> !u64i
// CHECK: %[[COOKIE_SIZE:.*]] = cir.const #cir.int<8> : !u64i
// CHECK: %[[SIZE:.*]], %[[OVERFLOW2:.*]] = cir.binop.overflow(add, %[[SIZE_WITHOUT_COOKIE]], %[[COOKIE_SIZE]]) : !u64i, (!u64i, !cir.bool)
// CHECK: %[[SIZE:.*]], %[[OVERFLOW2:.*]] = cir.add.overflow %[[SIZE_WITHOUT_COOKIE]], %[[COOKIE_SIZE]] : !u64i -> !u64i
// CHECK: %[[ANY_OVERFLOW:.*]] = cir.or %[[OVERFLOW]], %[[OVERFLOW2]] : !cir.bool
// CHECK: %[[ALL_ONES:.*]] = cir.const #cir.int<18446744073709551615> : !u64i
// CHECK: %[[ALLOC_SIZE:.*]] = cir.select if %[[ANY_OVERFLOW]] then %[[ALL_ONES]] else %[[SIZE]] : (!cir.bool, !u64i, !u64i)

View File

@ -13,7 +13,7 @@ bool test_add_overflow_uint_uint_uint(unsigned x, unsigned y, unsigned *res) {
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#LHS]], %[[#RHS]]) : !u32i, (!u32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#LHS]], %[[#RHS]] : !u32i -> !u32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u32i, !cir.ptr<!u32i>
// CIR: }
@ -31,7 +31,7 @@ bool test_add_overflow_int_int_int(int x, int y, int *res) {
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#LHS]], %[[#RHS]]) : !s32i, (!s32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#LHS]], %[[#RHS]] : !s32i -> !s32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: }
@ -43,7 +43,7 @@ bool test_add_overflow_xint31_xint31_xint31(_BitInt(31) x, _BitInt(31) y, _BitIn
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31>>, !cir.int<s, 31>
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31>>, !cir.int<s, 31>
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!cir.int<s, 31>>>, !cir.ptr<!cir.int<s, 31>>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#LHS]], %[[#RHS]]) : !cir.int<s, 31>, (!cir.int<s, 31>, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#LHS]], %[[#RHS]] : !cir.int<s, 31> -> !cir.int<s, 31>
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31>, !cir.ptr<!cir.int<s, 31>>
// CIR: }
@ -55,7 +55,7 @@ bool test_sub_overflow_uint_uint_uint(unsigned x, unsigned y, unsigned *res) {
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#LHS]], %[[#RHS]]) : !u32i, (!u32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#LHS]], %[[#RHS]] : !u32i -> !u32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u32i, !cir.ptr<!u32i>
// CIR: }
@ -67,7 +67,7 @@ bool test_sub_overflow_int_int_int(int x, int y, int *res) {
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#LHS]], %[[#RHS]]) : !s32i, (!s32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#LHS]], %[[#RHS]] : !s32i -> !s32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: }
@ -79,7 +79,7 @@ bool test_sub_overflow_xint31_xint31_xint31(_BitInt(31) x, _BitInt(31) y, _BitIn
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31>>, !cir.int<s, 31>
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31>>, !cir.int<s, 31>
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!cir.int<s, 31>>>, !cir.ptr<!cir.int<s, 31>>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#LHS]], %[[#RHS]]) : !cir.int<s, 31>, (!cir.int<s, 31>, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#LHS]], %[[#RHS]] : !cir.int<s, 31> -> !cir.int<s, 31>
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31>, !cir.ptr<!cir.int<s, 31>>
// CIR: }
@ -91,7 +91,7 @@ bool test_mul_overflow_uint_uint_uint(unsigned x, unsigned y, unsigned *res) {
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#LHS]], %[[#RHS]]) : !u32i, (!u32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#LHS]], %[[#RHS]] : !u32i -> !u32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u32i, !cir.ptr<!u32i>
// CIR: }
@ -103,7 +103,7 @@ bool test_mul_overflow_int_int_int(int x, int y, int *res) {
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#LHS]], %[[#RHS]]) : !s32i, (!s32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#LHS]], %[[#RHS]] : !s32i -> !s32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: }
@ -115,7 +115,7 @@ bool test_mul_overflow_xint31_xint31_xint31(_BitInt(31) x, _BitInt(31) y, _BitIn
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31>>, !cir.int<s, 31>
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31>>, !cir.int<s, 31>
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!cir.int<s, 31>>>, !cir.ptr<!cir.int<s, 31>>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#LHS]], %[[#RHS]]) : !cir.int<s, 31>, (!cir.int<s, 31>, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#LHS]], %[[#RHS]] : !cir.int<s, 31> -> !cir.int<s, 31>
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31>, !cir.ptr<!cir.int<s, 31>>
// CIR: }
@ -127,7 +127,7 @@ bool test_mul_overflow_ulong_ulong_long(unsigned long x, unsigned long y, unsign
// CIR: %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u64i>>, !cir.ptr<!u64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#LHS]], %[[#RHS]]) : !u64i, (!u64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#LHS]], %[[#RHS]] : !u64i -> !u64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u64i, !cir.ptr<!u64i>
// CIR: }
@ -141,7 +141,7 @@ bool test_add_overflow_uint_int_int(unsigned x, int y, int *res) {
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[#PROM_X:]] = cir.cast integral %[[#X]] : !u32i -> !cir.int<s, 33>
// CIR-NEXT: %[[#PROM_Y:]] = cir.cast integral %[[#Y]] : !s32i -> !cir.int<s, 33>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#PROM_X]], %[[#PROM_Y]]) : !cir.int<s, 33>, (!s32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#PROM_X]], %[[#PROM_Y]] : !cir.int<s, 33> -> !s32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: }
@ -153,7 +153,7 @@ bool test_add_overflow_volatile(int x, int y, volatile int *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#X]], %[[#Y]]) : !s32i, (!s32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#X]], %[[#Y]] : !s32i -> !s32i
// CIR-NEXT: cir.store volatile{{.*}} %[[RES]], %[[#RES_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: }
@ -165,7 +165,7 @@ bool test_uadd_overflow(unsigned x, unsigned y, unsigned *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#X]], %[[#Y]]) : !u32i, (!u32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#X]], %[[#Y]] : !u32i -> !u32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u32i, !cir.ptr<!u32i>
// CIR: }
@ -177,7 +177,7 @@ bool test_uaddl_overflow(unsigned long x, unsigned long y, unsigned long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u64i>>, !cir.ptr<!u64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#X]], %[[#Y]]) : !u64i, (!u64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#X]], %[[#Y]] : !u64i -> !u64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u64i, !cir.ptr<!u64i>
// CIR: }
@ -189,7 +189,7 @@ bool test_uaddll_overflow(unsigned long long x, unsigned long long y, unsigned l
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u64i>>, !cir.ptr<!u64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#X]], %[[#Y]]) : !u64i, (!u64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#X]], %[[#Y]] : !u64i -> !u64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u64i, !cir.ptr<!u64i>
// CIR: }
@ -201,7 +201,7 @@ bool test_usub_overflow(unsigned x, unsigned y, unsigned *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#X]], %[[#Y]]) : !u32i, (!u32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#X]], %[[#Y]] : !u32i -> !u32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u32i, !cir.ptr<!u32i>
// CIR: }
@ -213,7 +213,7 @@ bool test_usubl_overflow(unsigned long x, unsigned long y, unsigned long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u64i>>, !cir.ptr<!u64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#X]], %[[#Y]]) : !u64i, (!u64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#X]], %[[#Y]] : !u64i -> !u64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u64i, !cir.ptr<!u64i>
// CIR: }
@ -225,7 +225,7 @@ bool test_usubll_overflow(unsigned long long x, unsigned long long y, unsigned l
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u64i>>, !cir.ptr<!u64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#X]], %[[#Y]]) : !u64i, (!u64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#X]], %[[#Y]] : !u64i -> !u64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u64i, !cir.ptr<!u64i>
// CIR: }
@ -237,7 +237,7 @@ bool test_umul_overflow(unsigned x, unsigned y, unsigned *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#X]], %[[#Y]]) : !u32i, (!u32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#X]], %[[#Y]] : !u32i -> !u32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u32i, !cir.ptr<!u32i>
// CIR: }
@ -249,7 +249,7 @@ bool test_umull_overflow(unsigned long x, unsigned long y, unsigned long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u64i>>, !cir.ptr<!u64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#X]], %[[#Y]]) : !u64i, (!u64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#X]], %[[#Y]] : !u64i -> !u64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u64i, !cir.ptr<!u64i>
// CIR: }
@ -261,7 +261,7 @@ bool test_umulll_overflow(unsigned long long x, unsigned long long y, unsigned l
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!u64i>>, !cir.ptr<!u64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#X]], %[[#Y]]) : !u64i, (!u64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#X]], %[[#Y]] : !u64i -> !u64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !u64i, !cir.ptr<!u64i>
// CIR: }
@ -273,7 +273,7 @@ bool test_sadd_overflow(int x, int y, int *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#X]], %[[#Y]]) : !s32i, (!s32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#X]], %[[#Y]] : !s32i -> !s32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: }
@ -285,7 +285,7 @@ bool test_saddl_overflow(long x, long y, long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s64i>>, !cir.ptr<!s64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#X]], %[[#Y]]) : !s64i, (!s64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#X]], %[[#Y]] : !s64i -> !s64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s64i, !cir.ptr<!s64i>
// CIR: }
@ -297,7 +297,7 @@ bool test_saddll_overflow(long long x, long long y, long long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s64i>>, !cir.ptr<!s64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(add, %[[#X]], %[[#Y]]) : !s64i, (!s64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#X]], %[[#Y]] : !s64i -> !s64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s64i, !cir.ptr<!s64i>
// CIR: }
@ -309,7 +309,7 @@ bool test_ssub_overflow(int x, int y, int *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#X]], %[[#Y]]) : !s32i, (!s32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#X]], %[[#Y]] : !s32i -> !s32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: }
@ -321,7 +321,7 @@ bool test_ssubl_overflow(long x, long y, long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s64i>>, !cir.ptr<!s64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#X]], %[[#Y]]) : !s64i, (!s64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#X]], %[[#Y]] : !s64i -> !s64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s64i, !cir.ptr<!s64i>
// CIR: }
@ -333,7 +333,7 @@ bool test_ssubll_overflow(long long x, long long y, long long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s64i>>, !cir.ptr<!s64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(sub, %[[#X]], %[[#Y]]) : !s64i, (!s64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#X]], %[[#Y]] : !s64i -> !s64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s64i, !cir.ptr<!s64i>
// CIR: }
@ -345,7 +345,7 @@ bool test_smul_overflow(int x, int y, int *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#X]], %[[#Y]]) : !s32i, (!s32i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#X]], %[[#Y]] : !s32i -> !s32i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s32i, !cir.ptr<!s32i>
// CIR: }
@ -357,7 +357,7 @@ bool test_smull_overflow(long x, long y, long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s64i>>, !cir.ptr<!s64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#X]], %[[#Y]]) : !s64i, (!s64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#X]], %[[#Y]] : !s64i -> !s64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s64i, !cir.ptr<!s64i>
// CIR: }
@ -369,6 +369,6 @@ bool test_smulll_overflow(long long x, long long y, long long *res) {
// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s64i>, !s64i
// CIR-NEXT: %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s64i>>, !cir.ptr<!s64i>
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.binop.overflow(mul, %[[#X]], %[[#Y]]) : !s64i, (!s64i, !cir.bool)
// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#X]], %[[#Y]] : !s64i -> !s64i
// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !s64i, !cir.ptr<!s64i>
// CIR: }