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

Reply via email to