diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 0ea10462c265..7d4296ab30fc 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -985,6 +985,167 @@ def CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> { let hasVerifier = 0; } +//===----------------------------------------------------------------------===// +// BitsOp +//===----------------------------------------------------------------------===// + +class CIR_BitOp + : CIR_Op { + let arguments = (ins inputTy:$input); + let results = (outs SInt32:$result); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` `:` type($result) attr-dict + }]; +} + +def BitClrsbOp : CIR_BitOp<"bit.clrsb", 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 redundant sign bits in the input, that is, the number of bits + following the most significant bit that are identical to it. + + The bit width of the input integer must be either 32 or 64. + + Examples: + + ```mlir + !s32i = !cir.int + + // %0 = 0xDEADBEEF, 0b1101_1110_1010_1101_1011_1110_1110_1111 + %0 = cir.const(#cir.int<3735928559> : !s32i) : !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) : !s32i + // %3 will be 30 + %3 = cir.bit.clrsb(%2 : !s32i) : !s32i + ``` + }]; +} + +def BitClzOp : CIR_BitOp<"bit.clz", 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. + + This operation invokes undefined behavior if the input value is 0. + + Example: + + ```mlir + !s32i = !cir.int + !u32i = !cir.int + + // %0 = 0b0000_0000_0000_0000_0000_0000_0000_1000 + %0 = cir.const(#cir.int<8> : !u32i) : !u32i + // %1 will be 28 + %1 = cir.bit.clz(%0 : !u32i) : !s32i + ``` + }]; +} + +def BitCtzOp : CIR_BitOp<"bit.ctz", 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 + returns the number of consecutive 0-bits at the least significant bit + position in the input. + + This operation invokes undefined behavior if the input value is 0. + + Example: + + ```mlir + !s32i = !cir.int + !u32i = !cir.int + + // %0 = 0b1000 + %0 = cir.const(#cir.int<8> : !u32i) : !u32i + // %1 will be 3 + %1 = cir.bit.ctz(%0 : !u32i) : !s32i + ``` + }]; +} + +def BitFfsOp : CIR_BitOp<"bit.ffs", SIntOfWidths<[32, 64]>> { + let summary = "Get the position of the least significant 1-bit of input"; + let description = [{ + Compute the position of the least significant 1-bit of the input. + + The input integer must be a signed integer. The `cir.bit.ffs` operation + returns one plus the index of the least significant 1-bit of the input + signed integer. As a special case, if the input integer is 0, `cir.bit.ffs` + returns 0. + + Example: + + ```mlir + !s32i = !cir.int + + // %0 = 0x0010_1000 + %0 = cir.const(#cir.int<40> : !s32i) : !s32i + // #1 will be 4 since the 4th least significant bit is 1. + %1 = cir.bit.ffs(%0 : !s32i) : !s32i + ``` + }]; +} + +def BitParityOp : CIR_BitOp<"bit.parity", 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 + !s32i = !cir.int + !u32i = !cir.int + + // %0 = 0x0110_1000 + %0 = cir.const(#cir.int<104> : !u32i) : !s32i + // %1 will be 1 since there are 3 1-bits in %0 + %1 = cir.bit.parity(%0 : !u32i) : !s32i + ``` + }]; +} + +def BitPopcountOp : CIR_BitOp<"bit.popcount", 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 + !s32i = !cir.int + !u32i = !cir.int + + // %0 = 0x0110_1000 + %0 = cir.const(#cir.int<104> : !u32i) : !s32i + // %1 will be 3 since there are 3 1-bits in %0 + %1 = cir.bit.popcount(%0 : !u32i) : !s32i + ``` + }]; +} + //===----------------------------------------------------------------------===// // SwitchOp //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 1501cd1122ea..c02ee1bef916 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -97,6 +97,36 @@ def SInt16 : SInt<16>; def SInt32 : SInt<32>; def SInt64 : SInt<64>; +// A type constraint that allows unsigned integer type whose width is among the +// specified list of possible widths. +class UIntOfWidths widths> + : Type()">, + CPred<"$_self.cast<::mlir::cir::IntType>().isUnsigned()">, + Or().getWidth() == " # w> + )> + ]>, + !interleave(!foreach(w, widths, w # "-bit"), " or ") # " uint", + "::mlir::cir::IntType" + > {} + +// A type constraint that allows unsigned integer type whose width is among the +// specified list of possible widths. +class SIntOfWidths widths> + : Type()">, + CPred<"$_self.cast<::mlir::cir::IntType>().isSigned()">, + Or().getWidth() == " # w> + )> + ]>, + !interleave(!foreach(w, widths, w # "-bit"), " or ") # " sint", + "::mlir::cir::IntType" + > {} + //===----------------------------------------------------------------------===// // FloatType //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 0c351c7ea1b7..bee275371318 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -55,6 +55,22 @@ static RValue buildUnaryFPBuiltin(CIRGenFunction &CGF, const CallExpr &E) { return RValue::get(Call->getResult(0)); } +template +static RValue +buildBuiltinBitOp(CIRGenFunction &CGF, const CallExpr *E, + std::optional CK) { + mlir::Value arg; + if (CK.has_value()) + arg = CGF.buildCheckedArgForBuiltin(E->getArg(0), *CK); + else + arg = CGF.buildScalarExpr(E->getArg(0)); + + auto resultTy = CGF.ConvertType(E->getType()); + auto op = + CGF.getBuilder().create(CGF.getLoc(E->getExprLoc()), resultTy, arg); + return RValue::get(op); +} + RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -462,7 +478,7 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BImemcpy: case Builtin::BI__builtin_memcpy: case Builtin::BImempcpy: - case Builtin::BI__builtin_mempcpy: + case Builtin::BI__builtin_mempcpy: { Address Dest = buildPointerWithAlignment(E->getArg(0)); Address Src = buildPointerWithAlignment(E->getArg(1)); mlir::Value SizeVal = buildScalarExpr(E->getArg(2)); @@ -480,6 +496,42 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(Dest.getPointer()); } + case Builtin::BI__builtin_clrsb: + case Builtin::BI__builtin_clrsbl: + case Builtin::BI__builtin_clrsbll: + return buildBuiltinBitOp(*this, E, std::nullopt); + + case Builtin::BI__builtin_ctzs: + case Builtin::BI__builtin_ctz: + case Builtin::BI__builtin_ctzl: + case Builtin::BI__builtin_ctzll: + return buildBuiltinBitOp(*this, E, BCK_CTZPassedZero); + + case Builtin::BI__builtin_clzs: + case Builtin::BI__builtin_clz: + case Builtin::BI__builtin_clzl: + case Builtin::BI__builtin_clzll: + return buildBuiltinBitOp(*this, E, BCK_CLZPassedZero); + + case Builtin::BI__builtin_ffs: + case Builtin::BI__builtin_ffsl: + case Builtin::BI__builtin_ffsll: + return buildBuiltinBitOp(*this, E, std::nullopt); + + case Builtin::BI__builtin_parity: + case Builtin::BI__builtin_parityl: + case Builtin::BI__builtin_parityll: + return buildBuiltinBitOp(*this, E, std::nullopt); + + 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: + return buildBuiltinBitOp(*this, E, std::nullopt); + } + // If this is an alias for a lib function (e.g. __builtin_sin), emit // the call using the normal call path, but using the unmangled // version of the function name. @@ -543,6 +595,19 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return GetUndefRValue(E->getType()); } +mlir::Value CIRGenFunction::buildCheckedArgForBuiltin(const Expr *E, + BuiltinCheckKind Kind) { + assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero) && + "Unsupported builtin check kind"); + + auto value = buildScalarExpr(E); + if (!SanOpts.has(SanitizerKind::Builtin)) + return value; + + assert(!UnimplementedFeature::sanitizerBuiltin()); + llvm_unreachable("NYI"); +} + static mlir::Value buildTargetArchBuiltinExpr(CIRGenFunction *CGF, unsigned BuiltinID, const CallExpr *E, diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 056fe393d191..ed09b12b1eae 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1509,6 +1509,17 @@ class CIRGenFunction : public CIRGenTypeCache { LValue buildCheckedLValue(const Expr *E, TypeCheckKind TCK); LValue buildMemberExpr(const MemberExpr *E); + /// Specifies which type of sanitizer check to apply when handling a + /// particular builtin. + enum BuiltinCheckKind { + BCK_CTZPassedZero, + BCK_CLZPassedZero, + }; + + /// Emits an argument for a call to a builtin. If the builtin sanitizer is + /// enabled, a runtime check specified by \p Kind is also emitted. + mlir::Value buildCheckedArgForBuiltin(const Expr *E, BuiltinCheckKind Kind); + /// returns true if aggregate type has a volatile member. /// TODO(cir): this could be a common AST helper between LLVM / CIR. bool hasVolatileMember(QualType T) { diff --git a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h index 1b75451d9174..dd28c31d4d59 100644 --- a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h +++ b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h @@ -58,6 +58,7 @@ struct UnimplementedFeature { static bool pointerOverflowSanitizer() { return false; } static bool sanitizeDtor() { return false; } static bool sanitizeVLABound() { return false; } + static bool sanitizerBuiltin() { return false; } static bool sanitizerReturn() { return false; } // ObjC diff --git a/clang/test/CIR/CodeGen/builtin-bits.cpp b/clang/test/CIR/CodeGen/builtin-bits.cpp new file mode 100644 index 000000000000..f7a33a072bff --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin-bits.cpp @@ -0,0 +1,162 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir-enable -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +int test_builtin_clrsb(int x) { + return __builtin_clrsb(x); +} + +// CHECK: cir.func @_Z18test_builtin_clrsbi +// CHECK: %{{.+}} = cir.bit.clrsb(%{{.+}} : !s32i) : !s32i +// CHECK: } + +int test_builtin_clrsbl(long x) { + return __builtin_clrsbl(x); +} + +// CHECK: cir.func @_Z19test_builtin_clrsbll +// CHECK: %{{.+}} = cir.bit.clrsb(%{{.+}} : !s64i) : !s32i +// CHECK: } + +int test_builtin_clrsbll(long long x) { + return __builtin_clrsbll(x); +} + +// CHECK: cir.func @_Z20test_builtin_clrsbllx +// CHECK: %{{.+}} = cir.bit.clrsb(%{{.+}} : !s64i) : !s32i +// CHECK: } + +int test_builtin_ctzs(unsigned short x) { + return __builtin_ctzs(x); +} + +// CHECK: cir.func @_Z17test_builtin_ctzst +// CHECK: %{{.+}} = cir.bit.ctz(%{{.+}} : !u16i) : !s32i +// CHEKC: } + +int test_builtin_ctz(unsigned x) { + return __builtin_ctz(x); +} + +// CHECK: cir.func @_Z16test_builtin_ctzj +// CHECK: %{{.+}} = cir.bit.ctz(%{{.+}} : !u32i) : !s32i +// CHECK: } + +int test_builtin_ctzl(unsigned long x) { + return __builtin_ctzl(x); +} + +// CHECK: cir.func @_Z17test_builtin_ctzlm +// CHECK: %{{.+}} = cir.bit.ctz(%{{.+}} : !u64i) : !s32i +// CHECK: } + +int test_builtin_ctzll(unsigned long long x) { + return __builtin_ctzll(x); +} + +// CHECK: cir.func @_Z18test_builtin_ctzlly +// CHECK: %{{.+}} = cir.bit.ctz(%{{.+}} : !u64i) : !s32i +// CHECK: } + +int test_builtin_clzs(unsigned short x) { + return __builtin_clzs(x); +} + +// CHECK: cir.func @_Z17test_builtin_clzst +// CHECK: %{{.+}} = cir.bit.clz(%{{.+}} : !u16i) : !s32i +// CHECK: } + +int test_builtin_clz(unsigned x) { + return __builtin_clz(x); +} + +// CHECK: cir.func @_Z16test_builtin_clzj +// CHECK: %{{.+}} = cir.bit.clz(%{{.+}} : !u32i) : !s32i +// CHECK: } + +int test_builtin_clzl(unsigned long x) { + return __builtin_clzl(x); +} + +// CHECK: cir.func @_Z17test_builtin_clzlm +// CHECK: %{{.+}} = cir.bit.clz(%{{.+}} : !u64i) : !s32i +// CHECK: } + +int test_builtin_clzll(unsigned long long x) { + return __builtin_clzll(x); +} + +// CHECK: cir.func @_Z18test_builtin_clzlly +// CHECK: %{{.+}} = cir.bit.clz(%{{.+}} : !u64i) : !s32i +// CHECK: } + +int test_builtin_ffs(int x) { + return __builtin_ffs(x); +} + +// CHECK: cir.func @_Z16test_builtin_ffsi +// CHECK: %{{.+}} = cir.bit.ffs(%{{.+}} : !s32i) : !s32i +// CHECK: } + +int test_builtin_ffsl(long x) { + return __builtin_ffsl(x); +} + +// CHECK: cir.func @_Z17test_builtin_ffsll +// CHECK: %{{.+}} = cir.bit.ffs(%{{.+}} : !s64i) : !s32i +// CHECK: } + +int test_builtin_ffsll(long long x) { + return __builtin_ffsll(x); +} + +// CHECK: cir.func @_Z18test_builtin_ffsllx +// CHECK: %{{.+}} = cir.bit.ffs(%{{.+}} : !s64i) : !s32i +// CHECK: } + +int test_builtin_parity(unsigned x) { + return __builtin_parity(x); +} + +// CHECK: cir.func @_Z19test_builtin_parityj +// CHECK: %{{.+}} = cir.bit.parity(%{{.+}} : !u32i) : !s32i +// CHECK: } + +int test_builtin_parityl(unsigned long x) { + return __builtin_parityl(x); +} + +// CHECK: cir.func @_Z20test_builtin_paritylm +// CHECK: %{{.+}} = cir.bit.parity(%{{.+}} : !u64i) : !s32i +// CHECK: } + +int test_builtin_parityll(unsigned long long x) { + return __builtin_parityll(x); +} + +// CHECK: cir.func @_Z21test_builtin_paritylly +// CHECK: %{{.+}} = cir.bit.parity(%{{.+}} : !u64i) : !s32i +// CHECK: } + +int test_builtin_popcount(unsigned x) { + return __builtin_popcount(x); +} + +// CHECK: cir.func @_Z21test_builtin_popcountj +// CHECK: %{{.+}} = cir.bit.popcount(%{{.+}} : !u32i) : !s32i +// CHECK: } + +int test_builtin_popcountl(unsigned long x) { + return __builtin_popcountl(x); +} + +// CHECK: cir.func @_Z22test_builtin_popcountlm +// CHECK: %{{.+}} = cir.bit.popcount(%{{.+}} : !u64i) : !s32i +// CHECK: } + +int test_builtin_popcountll(unsigned long long x) { + return __builtin_popcountll(x); +} + +// CHECK: cir.func @_Z23test_builtin_popcountlly +// CHECK: %{{.+}} = cir.bit.popcount(%{{.+}} : !u64i) : !s32i +// CHECK: } diff --git a/clang/test/CIR/IR/bit.cir b/clang/test/CIR/IR/bit.cir new file mode 100644 index 000000000000..974f22606cdc --- /dev/null +++ b/clang/test/CIR/IR/bit.cir @@ -0,0 +1,75 @@ +// RUN: cir-opt %s | cir-opt | FileCheck %s + +!s8i = !cir.int +!s16i = !cir.int +!s32i = !cir.int +!s64i = !cir.int +!u8i = !cir.int +!u16i = !cir.int +!u32i = !cir.int +!u64i = !cir.int + +module { + cir.func @test() { + %s8 = cir.const(#cir.int<1> : !s8i) : !s8i + %s16 = cir.const(#cir.int<1> : !s16i) : !s16i + %s32 = cir.const(#cir.int<1> : !s32i) : !s32i + %s64 = cir.const(#cir.int<1> : !s64i) : !s64i + %u8 = cir.const(#cir.int<1> : !u8i) : !u8i + %u16 = cir.const(#cir.int<1> : !u16i) : !u16i + %u32 = cir.const(#cir.int<1> : !u32i) : !u32i + %u64 = cir.const(#cir.int<1> : !u64i) : !u64i + + %2 = cir.bit.clrsb(%s32 : !s32i) : !s32i + %3 = cir.bit.clrsb(%s64 : !s64i) : !s32i + + %4 = cir.bit.clz(%u16 : !u16i) : !s32i + %5 = cir.bit.clz(%u32 : !u32i) : !s32i + %6 = cir.bit.clz(%u64 : !u64i) : !s32i + + %7 = cir.bit.ctz(%u16 : !u16i) : !s32i + %8 = cir.bit.ctz(%u32 : !u32i) : !s32i + %9 = cir.bit.ctz(%u64 : !u64i) : !s32i + + %10 = cir.bit.ffs(%s32 : !s32i) : !s32i + %11 = cir.bit.ffs(%s64 : !s64i) : !s32i + + %12 = cir.bit.parity(%u32 : !u32i) : !s32i + %13 = cir.bit.parity(%u64 : !u64i) : !s32i + + %14 = cir.bit.popcount(%u16 : !u16i) : !s32i + %15 = cir.bit.popcount(%u32 : !u32i) : !s32i + %16 = cir.bit.popcount(%u64 : !u64i) : !s32i + + cir.return + } +} + +// CHECK: module { +// CHECK-NEXT: cir.func @test() { +// CHECK-NEXT: %0 = cir.const(#cir.int<1> : !s8i) : !s8i +// CHECK-NEXT: %1 = cir.const(#cir.int<1> : !s16i) : !s16i +// CHECK-NEXT: %2 = cir.const(#cir.int<1> : !s32i) : !s32i +// CHECK-NEXT: %3 = cir.const(#cir.int<1> : !s64i) : !s64i +// CHECK-NEXT: %4 = cir.const(#cir.int<1> : !u8i) : !u8i +// CHECK-NEXT: %5 = cir.const(#cir.int<1> : !u16i) : !u16i +// CHECK-NEXT: %6 = cir.const(#cir.int<1> : !u32i) : !u32i +// CHECK-NEXT: %7 = cir.const(#cir.int<1> : !u64i) : !u64i +// CHECK-NEXT: %8 = cir.bit.clrsb(%2 : !s32i) : !s32i +// CHECK-NEXT: %9 = cir.bit.clrsb(%3 : !s64i) : !s32i +// CHECK-NEXT: %10 = cir.bit.clz(%5 : !u16i) : !s32i +// CHECK-NEXT: %11 = cir.bit.clz(%6 : !u32i) : !s32i +// CHECK-NEXT: %12 = cir.bit.clz(%7 : !u64i) : !s32i +// CHECK-NEXT: %13 = cir.bit.ctz(%5 : !u16i) : !s32i +// CHECK-NEXT: %14 = cir.bit.ctz(%6 : !u32i) : !s32i +// CHECK-NEXT: %15 = cir.bit.ctz(%7 : !u64i) : !s32i +// CHECK-NEXT: %16 = cir.bit.ffs(%2 : !s32i) : !s32i +// CHECK-NEXT: %17 = cir.bit.ffs(%3 : !s64i) : !s32i +// CHECK-NEXT: %18 = cir.bit.parity(%6 : !u32i) : !s32i +// CHECK-NEXT: %19 = cir.bit.parity(%7 : !u64i) : !s32i +// CHECK-NEXT: %20 = cir.bit.popcount(%5 : !u16i) : !s32i +// CHECK-NEXT: %21 = cir.bit.popcount(%6 : !u32i) : !s32i +// CHECK-NEXT: %22 = cir.bit.popcount(%7 : !u64i) : !s32i +// CHECK-NEXT: cir.return +// CHECK-NEXT: } +// CHECK-NEXT: } diff --git a/clang/test/CIR/IR/invalid.cir b/clang/test/CIR/IR/invalid.cir index 986353e83447..2ff17558d866 100644 --- a/clang/test/CIR/IR/invalid.cir +++ b/clang/test/CIR/IR/invalid.cir @@ -834,3 +834,128 @@ module { // expected-error@+1 {{incomplete 'cir.struct' cannot be used to build a non-null data member pointer}} #incomplete_cls_member = #cir.data_member<0> : !cir.data_member + + +// ----- + +!s32i = !cir.int +!u32i = !cir.int + +cir.func @clrsb_invalid_input_ty(%arg0 : !u32i) -> () { + // expected-error@+1 {{'cir.bit.clrsb' op operand #0 must be 32-bit or 64-bit sint, but got '!cir.int'}} + %0 = cir.bit.clrsb(%arg0 : !u32i) : !s32i + cir.return +} + +// ----- + +!s32i = !cir.int +!u32i = !cir.int + +cir.func @clrsb_invalid_result_ty(%arg0 : !s32i) -> () { + // expected-error@+1 {{'cir.bit.clrsb' op result #0 must be 32-bit signed integer, but got '!cir.int'}} + %0 = cir.bit.clrsb(%arg0 : !s32i) : !u32i + cir.return +} + +// ----- + +!s32i = !cir.int + +cir.func @clz_invalid_input_ty(%arg0 : !s32i) -> () { + // expected-error@+1 {{'cir.bit.clz' op operand #0 must be 16-bit or 32-bit or 64-bit uint, but got '!cir.int'}} + %0 = cir.bit.clz(%arg0 : !s32i) : !s32i + cir.return +} + +// ----- + +!u32i = !cir.int + +cir.func @clz_invalid_result_ty(%arg0 : !u32i) -> () { + // expected-error@+1 {{'cir.bit.clz' op result #0 must be 32-bit signed integer, but got '!cir.int}} + %0 = cir.bit.clz(%arg0 : !u32i) : !u32i + cir.return +} + +// ----- + +!s32i = !cir.int + +cir.func @ctz_invalid_input_ty(%arg0 : !s32i) -> () { + // expected-error@+1 {{'cir.bit.ctz' op operand #0 must be 16-bit or 32-bit or 64-bit uint, but got '!cir.int'}} + %0 = cir.bit.ctz(%arg0 : !s32i) : !s32i + cir.return +} + +// ----- + +!u32i = !cir.int + +cir.func @ctz_invalid_result_ty(%arg0 : !u32i) -> () { + // expected-error@+1 {{'cir.bit.ctz' op result #0 must be 32-bit signed integer, but got '!cir.int'}} + %0 = cir.bit.ctz(%arg0 : !u32i) : !u32i + cir.return +} + +// ----- + +!s32i = !cir.int +!u32i = !cir.int + +cir.func @ffs_invalid_input_ty(%arg0 : !u32i) -> () { + // expected-error@+1 {{'cir.bit.ffs' op operand #0 must be 32-bit or 64-bit sint, but got '!cir.int'}} + %0 = cir.bit.ffs(%arg0 : !u32i) : !s32i + cir.return +} + +// ----- + +!s32i = !cir.int +!u32i = !cir.int + +cir.func @ffs_invalid_result_ty(%arg0 : !s32i) -> () { + // expected-error@+1 {{'cir.bit.ffs' op result #0 must be 32-bit signed integer, but got '!cir.int'}} + %0 = cir.bit.ffs(%arg0 : !s32i) : !u32i + cir.return +} + +// ----- + +!s32i = !cir.int + +cir.func @parity_invalid_input_ty(%arg0 : !s32i) -> () { + // expected-error@+1 {{'cir.bit.parity' op operand #0 must be 32-bit or 64-bit uint, but got '!cir.int'}} + %0 = cir.bit.parity(%arg0 : !s32i) : !s32i + cir.return +} + +// ----- + +!u32i = !cir.int + +cir.func @parity_invalid_result_ty(%arg0 : !u32i) -> () { + // expected-error@+1 {{'cir.bit.parity' op result #0 must be 32-bit signed integer, but got '!cir.int}} + %0 = cir.bit.parity(%arg0 : !u32i) : !u32i + cir.return +} + +// ----- + +!s32i = !cir.int + +cir.func @popcount_invalid_input_ty(%arg0 : !s32i) -> () { + // expected-error@+1 {{'cir.bit.popcount' op operand #0 must be 16-bit or 32-bit or 64-bit uint, but got '!cir.int'}} + %0 = cir.bit.popcount(%arg0 : !s32i) : !s32i + cir.return +} + +// ----- + +!u32i = !cir.int + +cir.func @popcount_invalid_result_ty(%arg0 : !u32i) -> () { + // expected-error@+1 {{'cir.bit.popcount' op result #0 must be 32-bit signed integer, but got '!cir.int'}} + %0 = cir.bit.popcount(%arg0 : !u32i) : !u32i + cir.return +}