[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
This revision was automatically updated to reflect the committed changes. Closed by commit rC339282: [Builtins] Implement __builtin_clrsb to be compatible with gcc (authored by ctopper, committed by ). Herald added a subscriber: kristina. Repository: rC Clang https://reviews.llvm.org/D50168 Files: include/clang/Basic/Builtins.def lib/CodeGen/CGBuiltin.cpp test/CodeGen/builtin_clrsb.c Index: include/clang/Basic/Builtins.def === --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -413,6 +413,9 @@ BUILTIN(__builtin_popcount , "iUi" , "nc") BUILTIN(__builtin_popcountl , "iULi" , "nc") BUILTIN(__builtin_popcountll, "iULLi", "nc") +BUILTIN(__builtin_clrsb , "ii" , "nc") +BUILTIN(__builtin_clrsbl , "iLi" , "nc") +BUILTIN(__builtin_clrsbll, "iLLi", "nc") // FIXME: These type signatures are not correct for targets with int != 32-bits // or with ULL != 64-bits. Index: test/CodeGen/builtin_clrsb.c === --- test/CodeGen/builtin_clrsb.c +++ test/CodeGen/builtin_clrsb.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +int test__builtin_clrsb(int x) { +// CHECK-LABEL: test__builtin_clrsb +// CHECK: [[C:%.*]] = icmp slt i32 [[X:%.*]], 0 +// 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 + return __builtin_clrsb(x); +} + +int test__builtin_clrsbll(long long x) { +// CHECK-LABEL: test__builtin_clrsbll +// CHECK: [[C:%.*]] = icmp slt i64 [[X:%.*]], 0 +// 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: trunc i64 [[SUB]] to i32 + return __builtin_clrsbll(x); +} Index: lib/CodeGen/CGBuiltin.cpp === --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1537,6 +1537,26 @@ return RValue::get(ComplexVal.second); } + case Builtin::BI__builtin_clrsb: + case Builtin::BI__builtin_clrsbl: + case Builtin::BI__builtin_clrsbll: { +// clrsb(x) -> clz(x < 0 ? ~x : x) - 1 or +Value *ArgValue = EmitScalarExpr(E->getArg(0)); + +llvm::Type *ArgType = ArgValue->getType(); +Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); + +llvm::Type *ResultType = ConvertType(E->getType()); +Value *Zero = llvm::Constant::getNullValue(ArgType); +Value *IsNeg = Builder.CreateICmpSLT(ArgValue, Zero, "isneg"); +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)); +Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); +return RValue::get(Result); + } case Builtin::BI__builtin_ctzs: case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: Index: include/clang/Basic/Builtins.def === --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -413,6 +413,9 @@ BUILTIN(__builtin_popcount , "iUi" , "nc") BUILTIN(__builtin_popcountl , "iULi" , "nc") BUILTIN(__builtin_popcountll, "iULLi", "nc") +BUILTIN(__builtin_clrsb , "ii" , "nc") +BUILTIN(__builtin_clrsbl , "iLi" , "nc") +BUILTIN(__builtin_clrsbll, "iLLi", "nc") // FIXME: These type signatures are not correct for targets with int != 32-bits // or with ULL != 64-bits. Index: test/CodeGen/builtin_clrsb.c === --- test/CodeGen/builtin_clrsb.c +++ test/CodeGen/builtin_clrsb.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +int test__builtin_clrsb(int x) { +// CHECK-LABEL: test__builtin_clrsb +// CHECK: [[C:%.*]] = icmp slt i32 [[X:%.*]], 0 +// 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 + return __builtin_clrsb(x); +} + +int test__builtin_clrsbll(long long x) { +// CHECK-LABEL: test__builtin_clrsbll +// CHECK: [[C:%.*]] = icmp slt i64 [[X:%.*]], 0 +// 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: trunc i64 [[SUB]] to i32 +
[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
bkramer accepted this revision. bkramer added a comment. This revision is now accepted and ready to land. lg https://reviews.llvm.org/D50168 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
craig.topper updated this revision to Diff 159753. craig.topper added a comment. Use ctlz(zero_undef=false) and sub https://reviews.llvm.org/D50168 Files: include/clang/Basic/Builtins.def lib/CodeGen/CGBuiltin.cpp test/CodeGen/builtin_clrsb.c Index: test/CodeGen/builtin_clrsb.c === --- /dev/null +++ test/CodeGen/builtin_clrsb.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +int test__builtin_clrsb(int x) { +// CHECK-LABEL: test__builtin_clrsb +// CHECK: [[C:%.*]] = icmp slt i32 [[X:%.*]], 0 +// 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 + return __builtin_clrsb(x); +} + +int test__builtin_clrsbll(long long x) { +// CHECK-LABEL: test__builtin_clrsbll +// CHECK: [[C:%.*]] = icmp slt i64 [[X:%.*]], 0 +// 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: trunc i64 [[SUB]] to i32 + return __builtin_clrsbll(x); +} Index: lib/CodeGen/CGBuiltin.cpp === --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1537,6 +1537,26 @@ return RValue::get(ComplexVal.second); } + case Builtin::BI__builtin_clrsb: + case Builtin::BI__builtin_clrsbl: + case Builtin::BI__builtin_clrsbll: { +// clrsb(x) -> clz(x < 0 ? ~x : x) - 1 or +Value *ArgValue = EmitScalarExpr(E->getArg(0)); + +llvm::Type *ArgType = ArgValue->getType(); +Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); + +llvm::Type *ResultType = ConvertType(E->getType()); +Value *Zero = llvm::Constant::getNullValue(ArgType); +Value *IsNeg = Builder.CreateICmpSLT(ArgValue, Zero, "isneg"); +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)); +Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); +return RValue::get(Result); + } case Builtin::BI__builtin_ctzs: case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: Index: include/clang/Basic/Builtins.def === --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -413,6 +413,9 @@ BUILTIN(__builtin_popcount , "iUi" , "nc") BUILTIN(__builtin_popcountl , "iULi" , "nc") BUILTIN(__builtin_popcountll, "iULLi", "nc") +BUILTIN(__builtin_clrsb , "ii" , "nc") +BUILTIN(__builtin_clrsbl , "iLi" , "nc") +BUILTIN(__builtin_clrsbll, "iLLi", "nc") // FIXME: These type signatures are not correct for targets with int != 32-bits // or with ULL != 64-bits. Index: test/CodeGen/builtin_clrsb.c === --- /dev/null +++ test/CodeGen/builtin_clrsb.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +int test__builtin_clrsb(int x) { +// CHECK-LABEL: test__builtin_clrsb +// CHECK: [[C:%.*]] = icmp slt i32 [[X:%.*]], 0 +// 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 + return __builtin_clrsb(x); +} + +int test__builtin_clrsbll(long long x) { +// CHECK-LABEL: test__builtin_clrsbll +// CHECK: [[C:%.*]] = icmp slt i64 [[X:%.*]], 0 +// 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: trunc i64 [[SUB]] to i32 + return __builtin_clrsbll(x); +} Index: lib/CodeGen/CGBuiltin.cpp === --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1537,6 +1537,26 @@ return RValue::get(ComplexVal.second); } + case Builtin::BI__builtin_clrsb: + case Builtin::BI__builtin_clrsbl: + case Builtin::BI__builtin_clrsbll: { +// clrsb(x) -> clz(x < 0 ? ~x : x) - 1 or +Value *ArgValue = EmitScalarExpr(E->getArg(0)); + +llvm::Type *ArgType = ArgValue->getType(); +Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); + +llvm::Type *ResultType = ConvertType(E->getType()); +Value *Zero = llvm::Constant::getNullValue(ArgType); +Value *IsNeg = Builder.CreateICmpSLT(ArgValue,
[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
spatel added a comment. About the bit hacking: I don't think clang should be in the optimization business. We should be able to take the most obvious/simple representation for this builtin and reduce it as needed (either in instcombine or the backend). So it would be better to use the version with the subtract rather than shift/or. That version corresponds more directly to the code in APInt::getMinSignedBits()? Comment at: include/clang/Basic/Builtins.def:416 BUILTIN(__builtin_popcountll, "iULLi", "nc") +BUILTIN(__builtin_clrsb , "ii" , "nc") +BUILTIN(__builtin_clrsbl , "iLi" , "nc") Is is intentional that clang doesn't document the behavior of the builtins that it copies from gcc? I'd think logic descriptions for all of these would be handy, but especially for less common ones like 'clrsb'. https://reviews.llvm.org/D50168 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
craig.topper updated this revision to Diff 159627. craig.topper added a comment. Add the test case that I failed to pick up in the original diff. https://reviews.llvm.org/D50168 Files: include/clang/Basic/Builtins.def lib/CodeGen/CGBuiltin.cpp test/CodeGen/builtin_clrsb.c Index: test/CodeGen/builtin_clrsb.c === --- /dev/null +++ test/CodeGen/builtin_clrsb.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +int test__builtin_clrsb(int x) { +// CHECK-LABEL: test__builtin_clrsb +// CHECK: [[C:%.*]] = icmp slt i32 [[X:%.*]], 0 +// CHECK: [[INV:%.*]] = xor i32 [[X]], -1 +// CHECK: [[SEL:%.*]] = select i1 [[C]], i32 [[INV]], i32 [[X]] +// CHECK: [[SHL:%.*]] = shl i32 [[SEL]], 1 +// CHECK: [[OR:%.*]] = or i32 [[SHL]], 1 +// CHECK: call i32 @llvm.ctlz.i32(i32 [[OR]], i1 true) + return __builtin_clrsb(x); +} + +int test__builtin_clrsbll(long long x) { +// CHECK-LABEL: test__builtin_clrsbll +// CHECK: [[C:%.*]] = icmp slt i64 [[X:%.*]], 0 +// CHECK-NEXT: [[INV:%.*]] = xor i64 [[X]], -1 +// CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], i64 [[INV]], i64 [[X]] +// CHECK-NEXT: [[SHL:%.*]] = shl i64 [[SEL]], 1 +// CHECK-NEXT: [[OR:%.*]] = or i64 [[SHL]], 1 +// CHECK-NEXT: [[CTLZ:%.*]] = call i64 @llvm.ctlz.i64(i64 [[OR]], i1 true) +// CHECK-NEXT: trunc i64 [[CTLZ]] to i32 + return __builtin_clrsbll(x); +} Index: lib/CodeGen/CGBuiltin.cpp === --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1537,6 +1537,33 @@ return RValue::get(ComplexVal.second); } + case Builtin::BI__builtin_clrsb: + case Builtin::BI__builtin_clrsbl: + case Builtin::BI__builtin_clrsbll: { +// clrsb(x) -> clz(x < 0 ? ~x : x) - 1 or +// -> clz(((x < 0 ? ~x : x) << 1) | 1) +Value *ArgValue = EmitScalarExpr(E->getArg(0)); + +llvm::Type *ArgType = ArgValue->getType(); +Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); + +llvm::Type *ResultType = ConvertType(E->getType()); +Value *Zero = llvm::Constant::getNullValue(ArgType); +Value *IsNeg = Builder.CreateICmpSLT(ArgValue, Zero, "isneg"); +Value *Inverse = Builder.CreateNot(ArgValue, "not"); +Value *Tmp = Builder.CreateSelect(IsNeg, Inverse, ArgValue); +// Now we need to calculate ctlz(Tmp)-1, but Tmp might be zero. We know +// the sign bit is zero, so we can shift it out. Then put a 1 in the LSB. +// This removes one leading zero like the subtract does, and replaces it +// with a guaranteed one to prevent the value being 0. +Value *One = llvm::ConstantInt::get(ArgType, 1); +Tmp = Builder.CreateShl(Tmp, One); +Tmp = Builder.CreateOr(Tmp, One); +Value *Result = Builder.CreateCall(F, {Tmp, Builder.getTrue()}); +Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); +return RValue::get(Result); + } case Builtin::BI__builtin_ctzs: case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: Index: include/clang/Basic/Builtins.def === --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -413,6 +413,9 @@ BUILTIN(__builtin_popcount , "iUi" , "nc") BUILTIN(__builtin_popcountl , "iULi" , "nc") BUILTIN(__builtin_popcountll, "iULLi", "nc") +BUILTIN(__builtin_clrsb , "ii" , "nc") +BUILTIN(__builtin_clrsbl , "iLi" , "nc") +BUILTIN(__builtin_clrsbll, "iLLi", "nc") // FIXME: These type signatures are not correct for targets with int != 32-bits // or with ULL != 64-bits. Index: test/CodeGen/builtin_clrsb.c === --- /dev/null +++ test/CodeGen/builtin_clrsb.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +int test__builtin_clrsb(int x) { +// CHECK-LABEL: test__builtin_clrsb +// CHECK: [[C:%.*]] = icmp slt i32 [[X:%.*]], 0 +// CHECK: [[INV:%.*]] = xor i32 [[X]], -1 +// CHECK: [[SEL:%.*]] = select i1 [[C]], i32 [[INV]], i32 [[X]] +// CHECK: [[SHL:%.*]] = shl i32 [[SEL]], 1 +// CHECK: [[OR:%.*]] = or i32 [[SHL]], 1 +// CHECK: call i32 @llvm.ctlz.i32(i32 [[OR]], i1 true) + return __builtin_clrsb(x); +} + +int test__builtin_clrsbll(long long x) { +// CHECK-LABEL: test__builtin_clrsbll +// CHECK: [[C:%.*]] = icmp slt i64 [[X:%.*]], 0 +// CHECK-NEXT: [[INV:%.*]] = xor i64 [[X]], -1 +// CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], i64 [[INV]], i64 [[X]] +// CHECK-NEXT: [[SHL:%.*]] = shl i64 [[SEL]], 1 +// CHECK-NEXT: [[OR:%.*]] = or i64 [[SHL]], 1 +// CHECK-NEXT: [[CTLZ:%.*]] = call i64 @llvm.ctlz.i64(i64 [[OR]], i1 true) +// CHECK-NEXT: trunc i64 [[CTLZ]] to i32 + return __builtin_clrsbll(x); +} Index: lib/CodeGen/CGBuiltin.cpp === --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1537,6 +1537,33 @@ return
[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
bkramer added a comment. Test case? Comment at: lib/CodeGen/CGBuiltin.cpp:1563 +Value *Result = Builder.CreateCall(F, {Tmp, Builder.getTrue()}); +if (Result->getType() != ResultType) + Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, CreateIntCast just does nothing if the types match, so this check isn't needed. https://reviews.llvm.org/D50168 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
craig.topper added a comment. Ping https://reviews.llvm.org/D50168 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
craig.topper created this revision. craig.topper added reviewers: bkramer, efriedma, spatel. Herald added a reviewer: javed.absar. Herald added a subscriber: kristof.beyls. gcc defines an intrinsic called __builtin_clrsb which counts the number of extra sign bits on a number. This is equivalent to counting the number of leading zeros on a positive number or the number of leading ones on a negative number and subtracting one from the result. Since we can't count leading ones we need to invert negative numbers to count zeros. The emitted sequence contains a bit of trickery stolen from an LLVM AArch64 test arm64-clrsb.ll to prevent passing a value of 0 to ctlz. I used a icmp slt and a select to conditionally negate, but InstCombine will turn that into an ashr+xor. I can emit that directly if that's prefered. I know @spatel has been trying to remove some of the bit tricks from InstCombine so I'm not sure if the ashr+xor form will be canonical going forward. This patch will cause the builtin to be expanded inline while gcc uses a call to a function like __clrsbdi2 that is implemented in libgcc. But this is similar to what we already do for popcnt. And I don't think compiler-rt supports __clrsbdi2. https://reviews.llvm.org/D50168 Files: include/clang/Basic/Builtins.def lib/CodeGen/CGBuiltin.cpp Index: lib/CodeGen/CGBuiltin.cpp === --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1537,6 +1537,34 @@ return RValue::get(ComplexVal.second); } + case Builtin::BI__builtin_clrsb: + case Builtin::BI__builtin_clrsbl: + case Builtin::BI__builtin_clrsbll: { +// clrsb(x) -> clz(x < 0 ? ~x : x) - 1 or +// -> clz(((x < 0 ? ~x : x) << 1) | 1) +Value *ArgValue = EmitScalarExpr(E->getArg(0)); + +llvm::Type *ArgType = ArgValue->getType(); +Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); + +llvm::Type *ResultType = ConvertType(E->getType()); +Value *Zero = llvm::Constant::getNullValue(ArgType); +Value *IsNeg = Builder.CreateICmpSLT(ArgValue, Zero, "isneg"); +Value *Inverse = Builder.CreateNot(ArgValue, "not"); +Value *Tmp = Builder.CreateSelect(IsNeg, Inverse, ArgValue); +// Now we need to calculate ctlz(Tmp)-1, but Tmp might be zero. We know +// the sign bit is zero, so we can shift it out. Then put a 1 in the LSB. +// This removes one leading zero like the subtract does, and replaces it +// with a guaranteed one to prevent the value being 0. +Value *One = llvm::ConstantInt::get(ArgType, 1); +Tmp = Builder.CreateShl(Tmp, One); +Tmp = Builder.CreateOr(Tmp, One); +Value *Result = Builder.CreateCall(F, {Tmp, Builder.getTrue()}); +if (Result->getType() != ResultType) + Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); +return RValue::get(Result); + } case Builtin::BI__builtin_ctzs: case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: Index: include/clang/Basic/Builtins.def === --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -413,6 +413,9 @@ BUILTIN(__builtin_popcount , "iUi" , "nc") BUILTIN(__builtin_popcountl , "iULi" , "nc") BUILTIN(__builtin_popcountll, "iULLi", "nc") +BUILTIN(__builtin_clrsb , "ii" , "nc") +BUILTIN(__builtin_clrsbl , "iLi" , "nc") +BUILTIN(__builtin_clrsbll, "iLLi", "nc") // FIXME: These type signatures are not correct for targets with int != 32-bits // or with ULL != 64-bits. Index: lib/CodeGen/CGBuiltin.cpp === --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1537,6 +1537,34 @@ return RValue::get(ComplexVal.second); } + case Builtin::BI__builtin_clrsb: + case Builtin::BI__builtin_clrsbl: + case Builtin::BI__builtin_clrsbll: { +// clrsb(x) -> clz(x < 0 ? ~x : x) - 1 or +// -> clz(((x < 0 ? ~x : x) << 1) | 1) +Value *ArgValue = EmitScalarExpr(E->getArg(0)); + +llvm::Type *ArgType = ArgValue->getType(); +Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); + +llvm::Type *ResultType = ConvertType(E->getType()); +Value *Zero = llvm::Constant::getNullValue(ArgType); +Value *IsNeg = Builder.CreateICmpSLT(ArgValue, Zero, "isneg"); +Value *Inverse = Builder.CreateNot(ArgValue, "not"); +Value *Tmp = Builder.CreateSelect(IsNeg, Inverse, ArgValue); +// Now we need to calculate ctlz(Tmp)-1, but Tmp might be zero. We know +// the sign bit is zero, so we can shift it out. Then put a 1 in the LSB. +// This removes one leading zero like the subtract does, and replaces it +// with a guaranteed one to prevent the value being 0. +Value *One = llvm::ConstantInt::get(ArgType, 1); +Tmp = Builder.CreateShl(Tmp, One); +Tmp = Builder.CreateOr(Tmp, One); +Value