Author: Craig Topper
Date: 2025-12-30T14:49:30-08:00
New Revision: 0bc6491da0c827ce94bd8fa852422eaafe6c39e7

URL: 
https://github.com/llvm/llvm-project/commit/0bc6491da0c827ce94bd8fa852422eaafe6c39e7
DIFF: 
https://github.com/llvm/llvm-project/commit/0bc6491da0c827ce94bd8fa852422eaafe6c39e7.diff

LOG: [Clang] Add NUW to the Sub in __builtin_clrsb expansion. (#174010)

The ctlz will produce a value in the range [1..bitwidth]. It can't
produce 0. This means the subtract of 1 will not have unsigned wrap.

It also has no signed wrap, but the optimizer can figure that out on its
own.

It's very likely InstCombine will just drop the NUW when it
canonicalizes to Add, but maybe it will be helpful in some case.

Added: 
    

Modified: 
    clang/lib/CodeGen/CGBuiltin.cpp
    clang/test/CodeGen/builtin_clrsb.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index d3abf6d2a1f2d..bd1ef267a7f22 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3292,7 +3292,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
     Value *Inverse = Builder.CreateNot(ArgValue, "not");
     Value *Tmp = Builder.CreateSelect(IsNeg, Inverse, ArgValue);
     Value *Ctlz = Builder.CreateCall(F, {Tmp, Builder.getFalse()});
-    Value *Result = Builder.CreateSub(Ctlz, llvm::ConstantInt::get(ArgType, 
1));
+    Value *Result =
+        Builder.CreateNUWSub(Ctlz, llvm::ConstantInt::get(ArgType, 1));
     Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
                                    "cast");
     return RValue::get(Result);

diff  --git a/clang/test/CodeGen/builtin_clrsb.c 
b/clang/test/CodeGen/builtin_clrsb.c
index c51777ed1222c..1f6c93ff4c570 100644
--- a/clang/test/CodeGen/builtin_clrsb.c
+++ b/clang/test/CodeGen/builtin_clrsb.c
@@ -6,7 +6,7 @@ int test__builtin_clrsb(int x) {
 // CHECK-NEXT: [[INV:%.*]] = xor i32 [[X]], -1
 // CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], i32 [[INV]], i32 [[X]]
 // CHECK-NEXT: [[CTLZ:%.*]] = call i32 @llvm.ctlz.i32(i32 [[SEL]], i1 false)
-// CHECK-NEXT: [[SUB:%.*]] = sub i32 [[CTLZ]], 1
+// CHECK-NEXT: [[SUB:%.*]] = sub nuw i32 [[CTLZ]], 1
   return __builtin_clrsb(x);
 }
 
@@ -16,7 +16,7 @@ int test__builtin_clrsbll(long long x) {
 // CHECK-NEXT: [[INV:%.*]] = xor i64 [[X]], -1
 // CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], i64 [[INV]], i64 [[X]]
 // CHECK-NEXT: [[CTLZ:%.*]] = call i64 @llvm.ctlz.i64(i64 [[SEL]], i1 false)
-// CHECK-NEXT: [[SUB:%.*]] = sub i64 [[CTLZ]], 1
+// CHECK-NEXT: [[SUB:%.*]] = sub nuw i64 [[CTLZ]], 1
 // CHECK-NEXT: trunc i64 [[SUB]] to i32
   return __builtin_clrsbll(x);
 }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to