[clang] [CIR] Bit manipulation builtin functions (PR #146529)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 1 06:35:11 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Sirui Mu (Lancern)
<details>
<summary>Changes</summary>
This patch adds CIR support for the following families of bit manipulation builtin functions:
- `__builtin_clrsb`, represented by the `cir.bit.clrsb` operation
- `__builtin_ctz`, represented by the `cir.bit.clz` operation
- `__builtin_clz`, represented by the `cir.bit.ctz` operation
- `__builtin_parity`, represented by the `cir.bit.parity` operation
- `__builtin_popcount`, represented by the `cir.bit.popcnt` operation
The `__builtin_ffs` builtin function is not included in this patch because the current CIRGen would emit it as a library call to `@<!-- -->ffs`.
---
Patch is 27.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/146529.diff
6 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+140)
- (modified) clang/include/clang/CIR/MissingFeatures.h (+1)
- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+64)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+80)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+50)
- (added) clang/test/CIR/CodeGen/builtin_bit.cpp (+327)
``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4daff74cbae5a..25a191165e9fe 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2481,6 +2481,146 @@ def ComplexEqualOp : CIR_Op<"complex.eq", [Pure, SameTypeOperands]> {
}];
}
+//===----------------------------------------------------------------------===//
+// Bit Manipulation Operations
+//===----------------------------------------------------------------------===//
+
+class CIR_BitOpBase<string mnemonic, TypeConstraint operandTy>
+ : CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]> {
+ let arguments = (ins operandTy:$input);
+ let results = (outs operandTy:$result);
+
+ let assemblyFormat = [{
+ `(` $input `:` type($input) `)` `:` type($result) attr-dict
+ }];
+}
+
+class CIR_BitZeroCountOpBase<string mnemonic, TypeConstraint operandTy>
+ : CIR_BitOpBase<mnemonic, operandTy> {
+ let arguments = (ins operandTy:$input, UnitAttr:$poison_zero);
+
+ let assemblyFormat = [{
+ `(` $input `:` type($input) `)` (`poison_zero` $poison_zero^)?
+ `:` type($result) attr-dict
+ }];
+}
+
+def BitClrsbOp : CIR_BitOpBase<"bit.clrsb", CIR_SIntOfWidths<[32, 64]>> {
+ let summary = "Get the number of leading redundant sign bits in the input";
+ let description = [{
+ Compute the number of leading redundant sign bits in the input integer.
+
+ The input integer must be a signed integer. The most significant bit of the
+ input integer is the sign bit. The `cir.bit.clrsb` operation returns the
+ number of consecutive bits following the sign bit that are identical to the
+ sign bit.
+
+ The bit width of the input integer must be either 32 or 64.
+
+ Examples:
+
+ ```mlir
+ // %0 = 0b1101_1110_1010_1101_1011_1110_1110_1111
+ %0 = cir.const #cir.int<3735928559> : !s32i
+ // %1 will be 1 because there is 1 bit following the most significant bit
+ // that is identical to it.
+ %1 = cir.bit.clrsb(%0 : !s32i) : !s32i
+
+ // %2 = 1, 0b0000_0000_0000_0000_0000_0000_0000_0001
+ %2 = cir.const #cir.int<1> : !s32i
+ // %3 will be 30 because there are 30 consecutive bits following the sign
+ // bit that are identical to the sign bit.
+ %3 = cir.bit.clrsb(%2 : !s32i) : !s32i
+ ```
+ }];
+}
+
+def BitClzOp : CIR_BitZeroCountOpBase<"bit.clz",
+ CIR_UIntOfWidths<[16, 32, 64]>> {
+ let summary = "Get the number of leading 0-bits in the input";
+ let description = [{
+ Compute the number of leading 0-bits in the input.
+
+ The input integer must be an unsigned integer. The `cir.bit.clz` operation
+ returns the number of consecutive 0-bits at the most significant bit
+ position in the input.
+
+ If the `poison_zero` attribute is present, this operation will have
+ undefined behavior if the input value is 0.
+
+ Example:
+
+ ```mlir
+ // %0 = 0b0000_0000_0000_0000_0000_0000_0000_1000
+ %0 = cir.const #cir.int<8> : !u32i
+ // %1 will be 28
+ %1 = cir.bit.clz(%0 : !u32i) poison_zero : !u32i
+ ```
+ }];
+}
+
+def BitCtzOp : CIR_BitZeroCountOpBase<"bit.ctz",
+ CIR_UIntOfWidths<[16, 32, 64]>> {
+ let summary = "Get the number of trailing 0-bits in the input";
+ let description = [{
+ Compute the number of trailing 0-bits in the input.
+
+ The input integer must be an unsigned integer. The `cir.bit.ctz` operation
+ counts the number of consecutive 0-bits starting from the least significant
+ bit.
+
+ If the `poison_zero` attribute is present, this operation will have
+ undefined behavior if the input value is 0.
+
+ Example:
+
+ ```mlir
+ // %0 = 0b1000
+ %0 = cir.const #cir.int<8> : !u32i
+ // %1 will be 3
+ %1 = cir.bit.ctz(%0 : !u32i) poison_zero : !u32i
+ ```
+ }];
+}
+
+def BitParityOp : CIR_BitOpBase<"bit.parity", CIR_UIntOfWidths<[32, 64]>> {
+ let summary = "Get the parity of input";
+ let description = [{
+ Compute the parity of the input. The parity of an integer is the number of
+ 1-bits in it modulo 2.
+
+ The input must be an unsigned integer.
+
+ Example:
+
+ ```mlir
+ // %0 = 0x0110_1000
+ %0 = cir.const #cir.int<104> : !u32i
+ // %1 will be 1 since there are three 1-bits in %0
+ %1 = cir.bit.parity(%0 : !u32i) : !u32i
+ ```
+ }];
+}
+
+def BitPopcountOp : CIR_BitOpBase<"bit.popcnt",
+ CIR_UIntOfWidths<[16, 32, 64]>> {
+ let summary = "Get the number of 1-bits in input";
+ let description = [{
+ Compute the number of 1-bits in the input.
+
+ The input must be an unsigned integer.
+
+ Example:
+
+ ```mlir
+ // %0 = 0x0110_1000
+ %0 = cir.const #cir.int<104> : !u32i
+ // %1 will be 3 since there are 3 1-bits in %0
+ %1 = cir.bit.popcnt(%0 : !u32i) : !u32i
+ ```
+ }];
+}
+
//===----------------------------------------------------------------------===//
// Assume Operations
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index c33d68fa5e730..c76737549a0fc 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -180,6 +180,7 @@ struct MissingFeatures {
static bool builtinCall() { return false; }
static bool builtinCallF128() { return false; }
static bool builtinCallMathErrno() { return false; }
+ static bool builtinCheckKind() { return false; }
static bool cgFPOptionsRAII() { return false; }
static bool cirgenABIInfo() { return false; }
static bool cleanupAfterErrorDiags() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 0943b5788b73a..fb046533a91b8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -34,6 +34,29 @@ static RValue emitLibraryCall(CIRGenFunction &cgf, const FunctionDecl *fd,
return cgf.emitCall(e->getCallee()->getType(), callee, e, ReturnValueSlot());
}
+template <typename Op>
+static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,
+ bool poisonZero = false) {
+ assert(!cir::MissingFeatures::builtinCheckKind());
+
+ mlir::Value arg = cgf.emitScalarExpr(e->getArg(0));
+ CIRGenBuilderTy &builder = cgf.getBuilder();
+
+ Op op;
+ if constexpr (std::is_same_v<Op, cir::BitClzOp> ||
+ std::is_same_v<Op, cir::BitCtzOp>)
+ op = builder.create<Op>(cgf.getLoc(e->getSourceRange()), arg, poisonZero);
+ else
+ op = builder.create<Op>(cgf.getLoc(e->getSourceRange()), arg);
+
+ mlir::Value result = op.getResult();
+ mlir::Type exprTy = cgf.convertType(e->getType());
+ if (exprTy != result.getType())
+ result = builder.createIntCast(result, exprTy);
+
+ return RValue::get(result);
+}
+
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
const CallExpr *e,
ReturnValueSlot returnValue) {
@@ -101,6 +124,47 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
return RValue::get(complex);
}
+ case Builtin::BI__builtin_clrsb:
+ case Builtin::BI__builtin_clrsbl:
+ case Builtin::BI__builtin_clrsbll:
+ return emitBuiltinBitOp<cir::BitClrsbOp>(*this, e);
+
+ case Builtin::BI__builtin_ctzs:
+ case Builtin::BI__builtin_ctz:
+ case Builtin::BI__builtin_ctzl:
+ case Builtin::BI__builtin_ctzll:
+ case Builtin::BI__builtin_ctzg:
+ assert(!cir::MissingFeatures::builtinCheckKind());
+ return emitBuiltinBitOp<cir::BitCtzOp>(*this, e, /*poisonZero=*/true);
+
+ case Builtin::BI__builtin_clzs:
+ case Builtin::BI__builtin_clz:
+ case Builtin::BI__builtin_clzl:
+ case Builtin::BI__builtin_clzll:
+ case Builtin::BI__builtin_clzg:
+ assert(!cir::MissingFeatures::builtinCheckKind());
+ return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/true);
+
+ case Builtin::BI__builtin_parity:
+ case Builtin::BI__builtin_parityl:
+ case Builtin::BI__builtin_parityll:
+ return emitBuiltinBitOp<cir::BitParityOp>(*this, e);
+
+ case Builtin::BI__lzcnt16:
+ case Builtin::BI__lzcnt:
+ case Builtin::BI__lzcnt64:
+ assert(!cir::MissingFeatures::builtinCheckKind());
+ return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/false);
+
+ case Builtin::BI__popcnt16:
+ case Builtin::BI__popcnt:
+ case Builtin::BI__popcnt64:
+ case Builtin::BI__builtin_popcount:
+ case Builtin::BI__builtin_popcountl:
+ case Builtin::BI__builtin_popcountll:
+ case Builtin::BI__builtin_popcountg:
+ return emitBuiltinBitOp<cir::BitPopcountOp>(*this, e);
+
case Builtin::BI__builtin_expect:
case Builtin::BI__builtin_expect_with_probability: {
mlir::Value argValue = emitScalarExpr(e->getArg(0));
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 1034b8780c03c..bf5b710a66d88 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -460,6 +460,81 @@ mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMBitClrsbOpLowering::matchAndRewrite(
+ cir::BitClrsbOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ auto zero = rewriter.create<mlir::LLVM::ConstantOp>(
+ op.getLoc(), adaptor.getInput().getType(), 0);
+ auto isNeg = rewriter.create<mlir::LLVM::ICmpOp>(
+ op.getLoc(),
+ mlir::LLVM::ICmpPredicateAttr::get(rewriter.getContext(),
+ mlir::LLVM::ICmpPredicate::slt),
+ adaptor.getInput(), zero);
+
+ auto negOne = rewriter.create<mlir::LLVM::ConstantOp>(
+ op.getLoc(), adaptor.getInput().getType(), -1);
+ auto flipped = rewriter.create<mlir::LLVM::XOrOp>(op.getLoc(),
+ adaptor.getInput(), negOne);
+
+ auto select = rewriter.create<mlir::LLVM::SelectOp>(
+ op.getLoc(), isNeg, flipped, adaptor.getInput());
+
+ auto resTy = getTypeConverter()->convertType(op.getType());
+ auto clz = rewriter.create<mlir::LLVM::CountLeadingZerosOp>(
+ op.getLoc(), resTy, select, /*is_zero_poison=*/false);
+
+ auto one = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(), resTy, 1);
+ auto res = rewriter.create<mlir::LLVM::SubOp>(op.getLoc(), clz, one);
+ rewriter.replaceOp(op, res);
+
+ return mlir::LogicalResult::success();
+}
+
+mlir::LogicalResult CIRToLLVMBitClzOpLowering::matchAndRewrite(
+ cir::BitClzOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ auto resTy = getTypeConverter()->convertType(op.getType());
+ auto llvmOp = rewriter.create<mlir::LLVM::CountLeadingZerosOp>(
+ op.getLoc(), resTy, adaptor.getInput(), op.getPoisonZero());
+ rewriter.replaceOp(op, llvmOp);
+ return mlir::LogicalResult::success();
+}
+
+mlir::LogicalResult CIRToLLVMBitCtzOpLowering::matchAndRewrite(
+ cir::BitCtzOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ auto resTy = getTypeConverter()->convertType(op.getType());
+ auto llvmOp = rewriter.create<mlir::LLVM::CountTrailingZerosOp>(
+ op.getLoc(), resTy, adaptor.getInput(), op.getPoisonZero());
+ rewriter.replaceOp(op, llvmOp);
+ return mlir::LogicalResult::success();
+}
+
+mlir::LogicalResult CIRToLLVMBitParityOpLowering::matchAndRewrite(
+ cir::BitParityOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ auto resTy = getTypeConverter()->convertType(op.getType());
+ auto popcnt = rewriter.create<mlir::LLVM::CtPopOp>(op.getLoc(), resTy,
+ adaptor.getInput());
+
+ auto one = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(), resTy, 1);
+ auto popcntMod2 =
+ rewriter.create<mlir::LLVM::AndOp>(op.getLoc(), popcnt, one);
+ rewriter.replaceOp(op, popcntMod2);
+
+ return mlir::LogicalResult::success();
+}
+
+mlir::LogicalResult CIRToLLVMBitPopcountOpLowering::matchAndRewrite(
+ cir::BitPopcountOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ auto resTy = getTypeConverter()->convertType(op.getType());
+ auto llvmOp = rewriter.create<mlir::LLVM::CtPopOp>(op.getLoc(), resTy,
+ adaptor.getInput());
+ rewriter.replaceOp(op, llvmOp);
+ return mlir::LogicalResult::success();
+}
+
mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(
cir::BrCondOp brOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -1896,6 +1971,11 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMAssumeOpLowering,
CIRToLLVMBaseClassAddrOpLowering,
CIRToLLVMBinOpLowering,
+ CIRToLLVMBitClrsbOpLowering,
+ CIRToLLVMBitClzOpLowering,
+ CIRToLLVMBitCtzOpLowering,
+ CIRToLLVMBitParityOpLowering,
+ CIRToLLVMBitPopcountOpLowering,
CIRToLLVMBrCondOpLowering,
CIRToLLVMBrOpLowering,
CIRToLLVMCallOpLowering,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 25cf218cf8b6c..532edf7a9028e 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -44,6 +44,56 @@ class CIRToLLVMAssumeOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMBitClrsbOpLowering
+ : public mlir::OpConversionPattern<cir::BitClrsbOp> {
+public:
+ using mlir::OpConversionPattern<cir::BitClrsbOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::BitClrsbOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMBitClzOpLowering
+ : public mlir::OpConversionPattern<cir::BitClzOp> {
+public:
+ using mlir::OpConversionPattern<cir::BitClzOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::BitClzOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMBitCtzOpLowering
+ : public mlir::OpConversionPattern<cir::BitCtzOp> {
+public:
+ using mlir::OpConversionPattern<cir::BitCtzOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::BitCtzOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMBitParityOpLowering
+ : public mlir::OpConversionPattern<cir::BitParityOp> {
+public:
+ using mlir::OpConversionPattern<cir::BitParityOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::BitParityOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMBitPopcountOpLowering
+ : public mlir::OpConversionPattern<cir::BitPopcountOp> {
+public:
+ using mlir::OpConversionPattern<cir::BitPopcountOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::BitPopcountOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMBrCondOpLowering
: public mlir::OpConversionPattern<cir::BrCondOp> {
public:
diff --git a/clang/test/CIR/CodeGen/builtin_bit.cpp b/clang/test/CIR/CodeGen/builtin_bit.cpp
new file mode 100644
index 0000000000000..ba56c91ce7401
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtin_bit.cpp
@@ -0,0 +1,327 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+int test_builtin_clrsb(int x) {
+ return __builtin_clrsb(x);
+}
+
+// CIR-LABEL: _Z18test_builtin_clrsbi
+// CIR: [[TMP:%.+]] = cir.bit.clrsb(%{{.+}} : !s32i) : !s32i
+
+// LLVM-LABEL: _Z18test_builtin_clrsbi
+// LLVM: %[[X:.+]] = load i32, ptr %{{.+}}, align 4
+// LLVM-NEXT: %[[X_NEG:.+]] = icmp slt i32 %[[X]], 0
+// LLVM-NEXT: %[[X_NOT:.+]] = xor i32 %[[X]], -1
+// LLVM-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i32 %[[X_NOT]], i32 %[[X]]
+// LLVM-NEXT: %[[LZ:.+]] = call i32 @llvm.ctlz.i32(i32 %[[P]], i1 false)
+// LLVM-NEXT: %{{.+}} = sub i32 %[[LZ]], 1
+
+// OGCG-LABEL: _Z18test_builtin_clrsbi
+// OGCG: %[[X:.+]] = load i32, ptr %{{.+}}, align 4
+// OGCG-NEXT: %[[X_NEG:.+]] = icmp slt i32 %[[X]], 0
+// OGCG-NEXT: %[[X_NOT:.+]] = xor i32 %[[X]], -1
+// OGCG-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i32 %[[X_NOT]], i32 %[[X]]
+// OGCG-NEXT: %[[LZ:.+]] = call i32 @llvm.ctlz.i32(i32 %[[P]], i1 false)
+// OGCG-NEXT: %{{.+}} = sub i32 %[[LZ]], 1
+
+int test_builtin_clrsbl(long x) {
+ return __builtin_clrsbl(x);
+}
+
+// CIR-LABEL: _Z19test_builtin_clrsbll
+// CIR: [[TMP:%.+]] = cir.bit.clrsb(%{{.+}} : !s64i) : !s64i
+// CIR: {{%.+}} = cir.cast(integral, [[TMP]] : !s64i), !s32i
+
+// LLVM-LABEL: _Z19test_builtin_clrsbll
+// LLVM: %[[X:.+]] = load i64, ptr %{{.+}}, align 8
+// LLVM-NEXT: %[[X_NEG:.+]] = icmp slt i64 %[[X]], 0
+// LLVM-NEXT: %[[X_NOT:.+]] = xor i64 %[[X]], -1
+// LLVM-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i64 %[[X_NOT]], i64 %[[X]]
+// LLVM-NEXT: %[[LZ:.+]] = call i64 @llvm.ctlz.i64(i64 %[[P]], i1 false)
+// LLVM-NEXT: %{{.+}} = sub i64 %[[LZ]], 1
+
+// OGCG-LABEL: _Z19test_builtin_clrsbll
+// OGCG: %[[X:.+]] = load i64, ptr %{{.+}}, align 8
+// OGCG-NEXT: %[[X_NEG:.+]] = icmp slt i64 %[[X]], 0
+// OGCG-NEXT: %[[X_NOT:.+]] = xor i64 %[[X]], -1
+// OGCG-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i64 %[[X_NOT]], i64 %[[X]]
+// OGCG-NEXT: %[[LZ:.+]] = call i64 @llvm.ctlz.i64(i64 %[[P]], i1 false)
+// OGCG-NEXT: %{{.+}} = sub i64 %[[LZ]], 1
+
+int test_builtin_clrsbll(long long x) {
+ return __builtin_clrsbll(x);
+}
+
+// CIR-LABEL: _Z20test_builtin_clrsbllx
+// CIR: [[TMP:%.+]] = cir.bit.clrsb(%{{.+}} : !s64i) : !s64i
+// CIR: {{%.+}} = cir.cast(integral, [[TMP]] : !s64i), !s32i
+
+// LLVM-LABEL: _Z20test_builtin_clrsbllx
+// LLVM: %[[X:.+]] = load i64, ptr %{{.+}}, align 8
+// LLVM-NEXT: %[[X_NEG:.+]] = icmp slt i64 %[[X]], 0
+// LLVM-NEXT: %[[X_NOT:.+]] = xor i64 %[[X]], -1
+// LLVM-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i64 %[[X_NOT]], i64 %[[X]]
+// LLVM-NEXT: %[[LZ:.+]] = call i64 @llvm.ctlz.i64(i64 %[[P]], i1 false)
+// LLVM-NEXT: %{{.+}} = sub i64 %[[LZ]], 1
+
+// OGCG-LABEL: _Z20test_builtin_clrsbllx
+// OGCG: %[[X:.+]] = load i64, ptr %{{.+}}, align 8
+// OGCG-NEXT: %[[X_NEG:.+]] = icmp slt i64 %[[X]], 0
+// OGCG-NEXT: %[[X_NOT:.+]] = xor i64 %[[X]], -1
+// OGCG-NEXT: %[[P:.+]] = select i1 %[[X_NEG]], i64 %[[X_NOT]], i64 %[[X]]
+// OGCG-NEXT: %[[LZ:.+]] = call i64 @llvm.ctlz.i64(i64 %[[P]], i1 false)
+// OGCG-NEXT: %{{.+}} = sub i64 %[[LZ]], 1
+
+int test_builtin_ctzs(unsigned short x) {
+ return __builtin_ctzs(x);
+}
+
+// CIR-LABEL: _Z17test_builtin_ctzst
+// CIR: [[TMP:%.+]] = cir.bit.ctz(%{{.+}} : !u16i) poison_zero : !u16i
+// CIR: {{%.+}} = cir.cast(integral, [[TMP]] : !u16i), !s32i
+
+// LLVM-LABEL: _Z17test_builtin_ctzst
+// LLVM: %{{.+}} = call i16 @llvm.cttz.i16(i16 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z17test_builtin_ctzst
+// OGCG: %{{.+}} = call i16 @llvm.cttz.i16(i16 %{{.+}}, i1 true)
+
+int test_builtin_ctz(unsigned x) {
+ return __builtin_ctz(x);
+}
+
+// CIR-LABEL: _Z16test_builtin_ctzj
+// CIR: [[TMP:%.+]] = cir.bit.ctz(%{{.+}} : !u32i) poison_zero : !u32i
+// CIR: {{%.+}} = cir.cast(integral, [[TMP]] : !u32i), !s32i
+
+// LLVM-LABEL: _Z16test_builtin_ctzj
+// LLVM: %{{.+}} = call i32 @llvm.cttz.i32(i32 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z16test_builtin_ctzj
+// OGCG: %{{.+}} = call i32 @llvm.cttz.i32(i32 %{{.+}}, i1 true)
+
+int test_builtin_ctzl(unsigned long x) {
+ return __builtin_ctzl(x);
+}
+
+// CIR-L...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/146529
More information about the cfe-commits
mailing list