https://github.com/topperc created https://github.com/llvm/llvm-project/pull/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. >From cda1fcac9cbaeb7e6f75fdcaa3dbe850acab50be Mon Sep 17 00:00:00 2001 From: Craig Topper <[email protected]> Date: Tue, 30 Dec 2025 10:15:59 -0800 Subject: [PATCH] [Clang] Add NUW to the Sub in __builtin_clrsb expansion. 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. --- clang/lib/CodeGen/CGBuiltin.cpp | 3 ++- clang/test/CodeGen/builtin_clrsb.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) 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
