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,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: 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); +}