Author: Sirui Mu
Date: 2025-07-03T23:08:49+08:00
New Revision: 4b9f622ca94d8f4c0102560cb15c99f4e0013f99

URL: 
https://github.com/llvm/llvm-project/commit/4b9f622ca94d8f4c0102560cb15c99f4e0013f99
DIFF: 
https://github.com/llvm/llvm-project/commit/4b9f622ca94d8f4c0102560cb15c99f4e0013f99.diff

LOG: [CIR] Bit manipulation builtin functions (#146529)

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`.

Added: 
    clang/test/CIR/CodeGen/builtin_bit.cpp

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIROps.td
    clang/include/clang/CIR/MissingFeatures.h
    clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
    clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
    clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7e0f3dba6fbe0..6529f1386599c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2521,6 +2521,146 @@ def ComplexImagOp : CIR_Op<"complex.imag", [Pure]> {
   let hasFolder = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// 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 b24e2ee2de86f..5ac42b6a63b09 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 {
@@ -1955,6 +2030,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 de4600f376e55..d9fb91066317b 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-LABEL: _Z17test_builtin_ctzlm
+// CIR:         [[TMP:%.+]] = cir.bit.ctz(%{{.+}} : !u64i) poison_zero : !u64i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u64i), !s32i
+
+// LLVM-LABEL: _Z17test_builtin_ctzlm
+// LLVM:         %{{.+}} = call i64 @llvm.cttz.i64(i64 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z17test_builtin_ctzlm
+// OGCG:         %{{.+}} = call i64 @llvm.cttz.i64(i64 %{{.+}}, i1 true)
+
+int test_builtin_ctzll(unsigned long long x) {
+  return __builtin_ctzll(x);
+}
+
+// CIR-LABEL: _Z18test_builtin_ctzlly
+// CIR:         [[TMP:%.+]] = cir.bit.ctz(%{{.+}} : !u64i) poison_zero : !u64i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u64i), !s32i
+
+// LLVM-LABEL: _Z18test_builtin_ctzlly
+// LLVM:         %{{.+}} = call i64 @llvm.cttz.i64(i64 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z18test_builtin_ctzlly
+// OGCG:         %{{.+}} = call i64 @llvm.cttz.i64(i64 %{{.+}}, i1 true)
+
+int test_builtin_ctzg(unsigned x) {
+  return __builtin_ctzg(x);
+}
+
+// CIR-LABEL: _Z17test_builtin_ctzgj
+// CIR:         [[TMP:%.+]] = cir.bit.ctz(%{{.+}} : !u32i) poison_zero : !u32i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u32i), !s32i
+
+// LLVM-LABEL: _Z17test_builtin_ctzgj
+// LLVM:         %{{.+}} = call i32 @llvm.cttz.i32(i32 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z17test_builtin_ctzgj
+// OGCG:         %{{.+}} = call i32 @llvm.cttz.i32(i32 %{{.+}}, i1 true)
+
+int test_builtin_clzs(unsigned short x) {
+  return __builtin_clzs(x);
+}
+
+// CIR-LABEL: _Z17test_builtin_clzst
+// CIR:         [[TMP:%.+]] = cir.bit.clz(%{{.+}} : !u16i) poison_zero : !u16i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u16i), !s32i
+
+// LLVM-LABEL: _Z17test_builtin_clzst
+// LLVM:         %{{.+}} = call i16 @llvm.ctlz.i16(i16 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z17test_builtin_clzst
+// OGCG:         %{{.+}} = call i16 @llvm.ctlz.i16(i16 %{{.+}}, i1 true)
+
+int test_builtin_clz(unsigned x) {
+  return __builtin_clz(x);
+}
+
+// CIR-LABEL: _Z16test_builtin_clzj
+// CIR:         [[TMP:%.+]] = cir.bit.clz(%{{.+}} : !u32i) poison_zero : !u32i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u32i), !s32i
+
+// LLVM-LABEL: _Z16test_builtin_clzj
+// LLVM:         %{{.+}} = call i32 @llvm.ctlz.i32(i32 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z16test_builtin_clzj
+// OGCG:         %{{.+}} = call i32 @llvm.ctlz.i32(i32 %{{.+}}, i1 true)
+
+int test_builtin_clzl(unsigned long x) {
+  return __builtin_clzl(x);
+}
+
+// CIR-LABEL: _Z17test_builtin_clzlm
+// CIR:         [[TMP:%.+]] = cir.bit.clz(%{{.+}} : !u64i) poison_zero : !u64i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u64i), !s32i
+
+// LLVM-LABEL: _Z17test_builtin_clzlm
+// LLVM:         %{{.+}} = call i64 @llvm.ctlz.i64(i64 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z17test_builtin_clzlm
+// OGCG:         %{{.+}} = call i64 @llvm.ctlz.i64(i64 %{{.+}}, i1 true)
+
+int test_builtin_clzll(unsigned long long x) {
+  return __builtin_clzll(x);
+}
+
+// CIR-LABEL: _Z18test_builtin_clzlly
+// CIR:         [[TMP:%.+]] = cir.bit.clz(%{{.+}} : !u64i) poison_zero : !u64i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u64i), !s32i
+
+// LLVM-LABEL: _Z18test_builtin_clzlly
+// LLVM:         %{{.+}} = call i64 @llvm.ctlz.i64(i64 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z18test_builtin_clzlly
+// OGCG:         %{{.+}} = call i64 @llvm.ctlz.i64(i64 %{{.+}}, i1 true)
+
+int test_builtin_clzg(unsigned x) {
+  return __builtin_clzg(x);
+}
+
+// CIR-LABEL: _Z17test_builtin_clzgj
+// CIR:         [[TMP:%.+]] = cir.bit.clz(%{{.+}} : !u32i) poison_zero : !u32i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u32i), !s32i
+
+// LLVM-LABEL: _Z17test_builtin_clzgj
+// LLVM:         %{{.+}} = call i32 @llvm.ctlz.i32(i32 %{{.+}}, i1 true)
+
+// OGCG-LABEL: _Z17test_builtin_clzgj
+// OGCG:         %{{.+}} = call i32 @llvm.ctlz.i32(i32 %{{.+}}, i1 true)
+
+int test_builtin_parity(unsigned x) {
+  return __builtin_parity(x);
+}
+
+// CIR-LABEL: _Z19test_builtin_parityj
+// CIR:         [[TMP:%.+]] = cir.bit.parity(%{{.+}} : !u32i) : !u32i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u32i), !s32i
+
+// LLVM-LABEL: _Z19test_builtin_parityj
+// LLVM:         %[[X:.+]] = load i32, ptr %{{.+}}, align 4
+// LLVM-NEXT:    %[[POPCNT:.+]] = call i32 @llvm.ctpop.i32(i32 %[[X]])
+// LLVM-NEXT:    %{{.+}} = and i32 %[[POPCNT]], 1
+
+// OGCG-LABEL: _Z19test_builtin_parityj
+// OGCG:         %[[X:.+]] = load i32, ptr %{{.+}}, align 4
+// OGCG-NEXT:    %[[POPCNT:.+]] = call i32 @llvm.ctpop.i32(i32 %[[X]])
+// OGCG-NEXT:    %{{.+}} = and i32 %[[POPCNT]], 1
+
+int test_builtin_parityl(unsigned long x) {
+  return __builtin_parityl(x);
+}
+
+// CIR-LABEL: _Z20test_builtin_paritylm
+// CIR:         [[TMP:%.+]] = cir.bit.parity(%{{.+}} : !u64i) : !u64i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u64i), !s32i
+
+// LLVM-LABEL: _Z20test_builtin_paritylm
+// LLVM:         %[[X:.+]] = load i64, ptr %{{.+}}, align 8
+// LLVM-NEXT:    %[[POPCNT:.+]] = call i64 @llvm.ctpop.i64(i64 %[[X]])
+// LLVM-NEXT:    %{{.+}} = and i64 %[[POPCNT]], 1
+
+// OGCG-LABEL: _Z20test_builtin_paritylm
+// OGCG:         %[[X:.+]] = load i64, ptr %{{.+}}, align 8
+// OGCG-NEXT:    %[[POPCNT:.+]] = call i64 @llvm.ctpop.i64(i64 %[[X]])
+// OGCG-NEXT:    %{{.+}} = and i64 %[[POPCNT]], 1
+
+int test_builtin_parityll(unsigned long long x) {
+  return __builtin_parityll(x);
+}
+
+// CIR-LABEL: _Z21test_builtin_paritylly
+// CIR:         [[TMP:%.+]] = cir.bit.parity(%{{.+}} : !u64i) : !u64i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u64i), !s32i
+
+// LLVM-LABEL: _Z21test_builtin_paritylly
+// LLVM:         %[[X:.+]] = load i64, ptr %{{.+}}, align 8
+// LLVM-NEXT:    %[[POPCNT:.+]] = call i64 @llvm.ctpop.i64(i64 %[[X]])
+// LLVM-NEXT:    %{{.+}} = and i64 %[[POPCNT]], 1
+
+// OGCG-LABEL: _Z21test_builtin_paritylly
+// OGCG:         %[[X:.+]] = load i64, ptr %{{.+}}, align 8
+// OGCG-NEXT:    %[[POPCNT:.+]] = call i64 @llvm.ctpop.i64(i64 %[[X]])
+// OGCG-NEXT:    %{{.+}} = and i64 %[[POPCNT]], 1
+
+int test_builtin_popcount(unsigned x) {
+  return __builtin_popcount(x);
+}
+
+// CIR-LABEL: _Z21test_builtin_popcountj
+// CIR:         [[TMP:%.+]] = cir.bit.popcnt(%{{.+}} : !u32i) : !u32i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u32i), !s32i
+
+// LLVM-LABEL: _Z21test_builtin_popcountj
+// LLVM:         %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}})
+
+// OGCG-LABEL: _Z21test_builtin_popcountj
+// OGCG:         %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}})
+
+int test_builtin_popcountl(unsigned long x) {
+  return __builtin_popcountl(x);
+}
+
+// CIR-LABEL: _Z22test_builtin_popcountlm
+// CIR:         [[TMP:%.+]] = cir.bit.popcnt(%{{.+}} : !u64i) : !u64i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u64i), !s32i
+
+// LLVM-LABEL: _Z22test_builtin_popcountlm
+// LLVM:         %{{.+}} = call i64 @llvm.ctpop.i64(i64 %{{.+}})
+
+// OGCG-LABEL: _Z22test_builtin_popcountlm
+// OGCG:         %{{.+}} = call i64 @llvm.ctpop.i64(i64 %{{.+}})
+
+int test_builtin_popcountll(unsigned long long x) {
+  return __builtin_popcountll(x);
+}
+
+// CIR-LABEL: _Z23test_builtin_popcountlly
+// CIR:         [[TMP:%.+]] = cir.bit.popcnt(%{{.+}} : !u64i) : !u64i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u64i), !s32i
+
+// LLVM-LABEL: _Z23test_builtin_popcountlly
+// LLVM:         %{{.+}} = call i64 @llvm.ctpop.i64(i64 %{{.+}})
+
+// OGCG-LABEL: _Z23test_builtin_popcountlly
+// OGCG:         %{{.+}} = call i64 @llvm.ctpop.i64(i64 %{{.+}})
+
+int test_builtin_popcountg(unsigned x) {
+  return __builtin_popcountg(x);
+}
+
+// CIR-LABEL: _Z22test_builtin_popcountgj
+// CIR:         [[TMP:%.+]] = cir.bit.popcnt(%{{.+}} : !u32i) : !u32i
+// CIR:         {{%.+}} = cir.cast(integral, [[TMP]] : !u32i), !s32i
+
+// LLVM-LABEL: _Z22test_builtin_popcountgj
+// LLVM:         %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}})
+
+// OGCG-LABEL: _Z22test_builtin_popcountgj
+// OGCG:         %{{.+}} = call i32 @llvm.ctpop.i32(i32 %{{.+}})


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to