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 *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: