diff options
| -rw-r--r-- | clang/include/clang/Basic/Builtins.def | 3 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 20 | ||||
| -rw-r--r-- | clang/test/CodeGen/builtin_clrsb.c | 22 |
3 files changed, 45 insertions, 0 deletions
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index c4d11cd827c..2d69bbf0c67 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -413,6 +413,9 @@ BUILTIN(__builtin_parityll, "iULLi", "nc") 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. diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 2060630c386..4c59286291b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1537,6 +1537,26 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, 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: diff --git a/clang/test/CodeGen/builtin_clrsb.c b/clang/test/CodeGen/builtin_clrsb.c new file mode 100644 index 00000000000..c51777ed122 --- /dev/null +++ b/clang/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); +} |

