[PATCH] D50168: [Builtins] Implement __builtin_clrsb to be compatible with gcc
Craig Topper via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 7 16:56:09 PDT 2018
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.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D50168.159627.patch
Type: text/x-patch
Size: 3381 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180807/2dd4b951/attachment.bin>
More information about the cfe-commits
mailing list