Author: widberg Date: 2026-06-26T11:01:53-07:00 New Revision: 2c59ef4d88cce89bccf26ebbdea530f98bfe8002
URL: https://github.com/llvm/llvm-project/commit/2c59ef4d88cce89bccf26ebbdea530f98bfe8002 DIFF: https://github.com/llvm/llvm-project/commit/2c59ef4d88cce89bccf26ebbdea530f98bfe8002.diff LOG: [CIR] Fix CIR __builtin_(add|sub|mul)_overflow bug (#192569) This fixes a problem with CIR failing to handle boolean result types for the __builtin_(add|sub|mul)_overflow functions. We were trying to lower to operations derived from CIR_BinOpOverflow, but these operations required an integer type for the return value. This change relaxes that requirement to allow integer or boolean types. related non-CIR PR #192568. Added: Modified: clang/include/clang/CIR/Dialect/IR/CIROps.td clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 9c226556c8a6d..7d1c48b994b27 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2383,7 +2383,7 @@ class CIR_BinOpOverflow<string mnemonic, list<Trait> traits = []> CIR_IntType:$rhs ); - let results = (outs CIR_IntType:$result, CIR_BoolType:$overflow); + let results = (outs CIR_AnyIntOrBoolType:$result, CIR_BoolType:$overflow); let assemblyFormat = [{ $lhs `,` $rhs `:` qualified(type($lhs)) `->` qualified(type($result)) @@ -2391,7 +2391,7 @@ class CIR_BinOpOverflow<string mnemonic, list<Trait> traits = []> }]; let builders = [ - OpBuilder<(ins "cir::IntType":$resultTy, + OpBuilder<(ins "mlir::Type":$resultTy, "mlir::Value":$lhs, "mlir::Value":$rhs), [{ auto overflowTy = cir::BoolType::get($_builder.getContext()); @@ -2412,6 +2412,7 @@ def CIR_AddOverflowOp : CIR_BinOpOverflow<"add.overflow", [Commutative]> { ``` %result, %overflow = cir.add.overflow %a, %b : !u32i -> !u32i %result, %overflow = cir.add.overflow %a, %b : !cir.int<s, 33> -> !s32i + %result, %overflow = cir.add.overflow %a, %b : !s32i -> !cir.bool ``` }]; } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index ba2dd2dccc63b..3b8149411e7c4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -308,7 +308,7 @@ getIntegerWidthAndSignedness(const clang::ASTContext &astContext, 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) { + mlir::Type resultTy, mlir::Value lhs, mlir::Value rhs) { auto op = OpTy::create(builder, loc, resultTy, lhs, rhs); return {op.getResult(), op.getOverflow()}; } @@ -2273,7 +2273,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, auto encompassingCIRTy = cir::IntType::get( &getMLIRContext(), encompassingInfo.width, encompassingInfo.isSigned); - auto resultCIRTy = mlir::cast<cir::IntType>(cgm.convertType(resultQTy)); + mlir::Type resultCIRTy = cgm.convertType(resultQTy); mlir::Value x = emitScalarExpr(leftArg); mlir::Value y = emitScalarExpr(rightArg); @@ -2319,7 +2319,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, // first computed as a value of the encompassing type, and then it is // truncated to the actual result type with a second overflow checking. // - In CIRGen, the checked arithmetic operation directly produce the - // checked arithmetic result in its expected type. + // checked arithmetic result in its expected type, which may be a + // `cir.bool`. // // So we don't need a truncation and a second overflow checking here. diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 3018aee70dea1..e0fc9e58ed4b7 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3044,12 +3044,17 @@ lowerBinOpOverflow(OpTy op, typename OpTy::Adaptor adaptor, llvm::StringRef opStr) { mlir::Location loc = op.getLoc(); cir::IntType operandTy = op.getLhs().getType(); - cir::IntType resultTy = op.getResult().getType(); - - bool sign = operandTy.getIsSigned() || resultTy.getIsSigned(); + // The result type may be a `cir.bool`, which behaves as a 1-bit unsigned + // integer for the purposes of the checked arithmetic. + mlir::Type resultTy = op.getResult().getType(); + auto resultIntTy = mlir::dyn_cast<cir::IntType>(resultTy); + unsigned resultWidth = resultIntTy ? resultIntTy.getWidth() : 1; + bool resultSigned = resultIntTy && resultIntTy.getIsSigned(); + + bool sign = operandTy.getIsSigned() || resultSigned; unsigned width = std::max(operandTy.getWidth() + (sign && operandTy.isUnsigned()), - resultTy.getWidth() + (sign && resultTy.isUnsigned())); + resultWidth + (sign && !resultSigned)); mlir::IntegerType encompassedLLVMTy = rewriter.getIntegerType(width); @@ -3086,7 +3091,7 @@ lowerBinOpOverflow(OpTy op, typename OpTy::Adaptor adaptor, rewriter, loc, intrinRet, ArrayRef<int64_t>{1}) .getResult(); - if (resultTy.getWidth() < width) { + if (resultWidth < width) { mlir::Type resultLLVMTy = typeConverter->convertType(resultTy); auto truncResult = mlir::LLVM::TruncOp::create(rewriter, loc, resultLLVMTy, result); @@ -3094,7 +3099,7 @@ lowerBinOpOverflow(OpTy op, typename OpTy::Adaptor adaptor, // Extend the truncated result back to the encompassing type to check for // any overflows during the truncation. mlir::Value truncResultExt; - if (resultTy.isSigned()) + if (resultSigned) truncResultExt = mlir::LLVM::SExtOp::create( rewriter, loc, encompassedLLVMTy, truncResult); else diff --git a/clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp b/clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp index 33dd4bb733059..c22a3644715e1 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp +++ b/clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp @@ -388,3 +388,19 @@ bool test_bool_math_overflow(bool x, bool y, int *res) { // LLVM: call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %[[X_CAST]], i32 %[[Y_CAST]]) } +bool f(int x, int y, bool *r) { + return __builtin_add_overflow(x, y, r); +} + +// CIR: cir.func {{.*}} @_Z1fiiPb +// CIR: %[[#X:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: %[[#Y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: %[[#R_PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!cir.bool>>, !cir.ptr<!cir.bool> +// CIR-NEXT: %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#X]], %[[#Y]] : !s32i -> !cir.bool +// CIR-NEXT: cir.store{{.*}} %[[RES]], %[[#R_PTR]] : !cir.bool, !cir.ptr<!cir.bool> +// CIR: } + +// LLVM-LABEL: @_Z1fiiPb( +// LLVM: call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) +// LLVM: trunc i32 %{{.+}} to i1 +// LLVM: store i8 %{{.+}}, ptr %{{.+}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
