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