https://github.com/xakep8 updated https://github.com/llvm/llvm-project/pull/214931
>From 23168137fd397e589f03922ba0216061fdc9faf1 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Sat, 8 Aug 2026 10:19:23 +0530 Subject: [PATCH 01/11] [CIR] Lowering __builtin_stdc_trailing_zeros Added CIRGen support for __builtin_stdc_trailing_zeros by lowering it to cir.ctz with zero behaviour defined, matching with the C23 stdbit semantics. Added CodeGen test for the same. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 7 +++++++ clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 1efe2b81d5cae..2eb9d6c3bb661 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1247,6 +1247,13 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, getTarget().isCLZForZeroUndef()); case Builtin::BI__builtin_ctzg: return emitBuiltinBitOpWithFallback<cir::BitCtzOp>(*this, e); + case Builtin::BIstdc_trailing_zeros_uc: + case Builtin::BIstdc_trailing_zeros_us: + case Builtin::BIstdc_trailiing_zeros_ui: + case Builtin::BIstdc_trailing_zeros_ul: + case Builtin::BIstdc_trailing_zeros_ull: + case Builtin::BI__builtin_stdc_trailing_zeros: + return emitBuiltinBitOp<cir::BitCtzOp>(*this, e, /*poisonZero=*/false); case Builtin::BI__builtin_clzs: case Builtin::BI__builtin_clz: diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c new file mode 100644 index 0000000000000..6d285c259a96f --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s + +void test_stdc_trailing_zeros(unsigned long long x) { + int cnt = __builtin_stdc_trailing_zeros(x); + (void)cnt; +} + +// CHECK-LABEL: test_stdc_trailing_zeros +// CHECK: cir.ctz +// CHECK-NOT: poison_zero >From 7f6b40a228b9c986c4af24b1327aa5c9e47dbac6 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Sat, 8 Aug 2026 11:31:41 +0530 Subject: [PATCH 02/11] [CIR] Lowering __builtin_stdc_leading_zeros Added CIRGen support for __builtin_stdc_leading_zeros by lowering to cir.clz with zero behaviour defined, matching C23 stdbit semantics. Added CodeGen test for the same. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 8 ++++++++ .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 2eb9d6c3bb661..bbc82f33571d4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1255,6 +1255,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__builtin_stdc_trailing_zeros: return emitBuiltinBitOp<cir::BitCtzOp>(*this, e, /*poisonZero=*/false); + case Builtin::BIstdc_leading_zeros_uc: + case Builtin::BIstdc_leading_zeros_us: + case Builtin::BIstdc_leading_zeros_ui: + case Builtin::BIstdc_leading_zeros_ul: + case Builtin::BIstdc_leading_zeros_ull: + case Builtin::BI__builtin_stdc_leading_zeros: + return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/false); + case Builtin::BI__builtin_clzs: case Builtin::BI__builtin_clz: case Builtin::BI__builtin_clzl: diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index 6d285c259a96f..1f127821673d2 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -8,3 +8,22 @@ void test_stdc_trailing_zeros(unsigned long long x) { // CHECK-LABEL: test_stdc_trailing_zeros // CHECK: cir.ctz // CHECK-NOT: poison_zero +// CHECK: cir.return + +void test_stdc_leading_zeros(unsigned x) { + return __builtin_stdc_trailing_zeros(x); +} + +// CHECK-LABEL: test_stdc_leading_zeros +// CHECK: cir.clz +// CHECK-NOT: poison_zero +// CHECK: cir.return + +void test_stdc_leading_zeros_ui(unsigned x) { + return stdc_leading_zeros_ui(x); +} + +// CHECK-LABEL: test_stdc_leading_zeros_ui +// CHECK: cir.clz +// CHECK-NOT: poison_zero +// CHECK: cir.return >From f7059f999f678712d76ef1057914c92cbae71036 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Sun, 9 Aug 2026 16:33:16 +0530 Subject: [PATCH 03/11] [CIR] Lowering __builtin_stdc_count_ones Added CIRGen support for lowering of __builtin_stdc_count_ones by lowering to cir.popcount, matching with the C23 stdbit semantics. Added test for the same. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 10 ++++++++- .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 22 ++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index bbc82f33571d4..d27ace31cef78 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1249,7 +1249,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return emitBuiltinBitOpWithFallback<cir::BitCtzOp>(*this, e); case Builtin::BIstdc_trailing_zeros_uc: case Builtin::BIstdc_trailing_zeros_us: - case Builtin::BIstdc_trailiing_zeros_ui: + case Builtin::BIstdc_trailing_zeros_ui: case Builtin::BIstdc_trailing_zeros_ul: case Builtin::BIstdc_trailing_zeros_ull: case Builtin::BI__builtin_stdc_trailing_zeros: @@ -1263,6 +1263,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__builtin_stdc_leading_zeros: return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/false); + case Builtin::BIstdc_count_ones_uc: + case Builtin::BIstdc_count_ones_us: + case Builtin::BIstdc_count_ones_ui: + case Builtin::BIstdc_count_ones_ul: + case Builtin::BIstdc_count_ones_ull: + case Builtin::BI__builtin_stdc_count_ones: + return emitBuiltinBitOp<cir::BitPopcountOp>(*this, e); + case Builtin::BI__builtin_clzs: case Builtin::BI__builtin_clz: case Builtin::BI__builtin_clzl: diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index 1f127821673d2..e9d5b25a10f0e 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -10,8 +10,8 @@ void test_stdc_trailing_zeros(unsigned long long x) { // CHECK-NOT: poison_zero // CHECK: cir.return -void test_stdc_leading_zeros(unsigned x) { - return __builtin_stdc_trailing_zeros(x); +unsigned test_stdc_leading_zeros(unsigned x) { + return __builtin_stdc_leading_zeros(x); } // CHECK-LABEL: test_stdc_leading_zeros @@ -19,7 +19,7 @@ void test_stdc_leading_zeros(unsigned x) { // CHECK-NOT: poison_zero // CHECK: cir.return -void test_stdc_leading_zeros_ui(unsigned x) { +unsigned test_stdc_leading_zeros_ui(unsigned x) { return stdc_leading_zeros_ui(x); } @@ -27,3 +27,19 @@ void test_stdc_leading_zeros_ui(unsigned x) { // CHECK: cir.clz // CHECK-NOT: poison_zero // CHECK: cir.return + +unsigned test_stdc_count_ones(unsigned x) { + return __builtin_stdc_count_ones(x); +} + +// CHECK-LABEL: test_stdc_count_ones +// CHECK: cir.popcount +// CHECK: cir.return + +unsigned test_stdc_count_ones_ui(unsigned x) { + return stdc_count_ones_ui(x); +} + +// CHECK-LABEL: test_stdc_count_ones_ui +// CHECK: cir.popcount +// CHECK: cir.return >From 08a059d8c8de71c2cbf959cbcab8043ccebf17ff Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Mon, 10 Aug 2026 18:21:43 +0530 Subject: [PATCH 04/11] [CIR] Lowering __builtin_stdc_bit_width Added lowering for __builtin_stdc_bit_width by addition of helper emitStdcBitWidth that does integer type width minus leading zero count. Added tests for the same. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 28 +++++++++++++++++++ .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 24 +++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index d27ace31cef78..aef5818084bc4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -111,6 +111,26 @@ static RValue emitBuiltinBitOpWithFallback(CIRGenFunction &cgf, return RValue::get(builder.createSelect(loc, isZero, fallbackValue, result)); } +static RValue emitStdcBitWidth(CIRGenFunction &cfg, const CallExpr *e) { + CIRGenBuilderTy &builder = cfg.getBuilder(); + mlir::Location loc = cfg.getLoc(e->getSourceRange()); + + mlir::Value arg = cfg.emitScalarExpr(e->getArg(0)); + auto argTy = mlir::cast<cir::IntType>(arg.getType()); + + mlir::Value lz = + createBuiltinBitOp<cir::BitClzOp>(cfg, e, arg, /*poisonZero=*/false); + + mlir::Value width = builder.getConstInt(loc, argTy, argTy.getWidth()); + mlir::Value result = builder.createSub(loc, width, lz); + + mlir::Type resultTy = cfg.convertType(e->getType()); + if (result.getType() != resultTy) + result = builder.createIntCast(result, resultTy); + + return RValue::get(result); +} + /// Emit the conversions required to turn the given value into an /// integer of the given size. static mlir::Value emitToInt(CIRGenFunction &cgf, mlir::Value v, QualType t, @@ -1263,6 +1283,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__builtin_stdc_leading_zeros: return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/false); + case Builtin::BIstdc_bit_width_uc: + case Builtin::BIstdc_bit_width_us: + case Builtin::BIstdc_bit_width_ui: + case Builtin::BIstdc_bit_width_ul: + case Builtin::BIstdc_bit_width_ull: + case Builtin::BI__builtin_stdc_bit_width: + return emitStdcBitWidth(*this, e); + case Builtin::BIstdc_count_ones_uc: case Builtin::BIstdc_count_ones_us: case Builtin::BIstdc_count_ones_ui: diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index e9d5b25a10f0e..56632e70761ef 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c23 -I%S/../../CodeGen/Inputs -fclangir -emit-cir %s -o - | FileCheck %s + +#include <stdbit.h> void test_stdc_trailing_zeros(unsigned long long x) { int cnt = __builtin_stdc_trailing_zeros(x); @@ -43,3 +45,23 @@ unsigned test_stdc_count_ones_ui(unsigned x) { // CHECK-LABEL: test_stdc_count_ones_ui // CHECK: cir.popcount // CHECK: cir.return + +unsigned test_stdc_bit_width(unsigned x) { + return __builtin_stdc_bit_width(x); +} + +// CHECK-LABEL: test_stdc_bit_width +// CHECK: cir.clz +// CHECK-NOT: poison_zero +// CHECK: cir.sub +// CHECK: cir.return + +unsigned test_stdc_bit_width_ui(unsigned x) { + return stdc_bit_width_ui(x); +} + +// CHECK-LABEL: test_stdc_bit_width_ui +// CHECK: cir.clz +// CHECK-NOT: poison_zero +// CHECK: cir.sub +// CHECK: cir.return >From 39676dc2974588426269931c4402d6dafce1be06 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Tue, 11 Aug 2026 12:57:31 +0530 Subject: [PATCH 05/11] [CIR] Lower __builting_stdc_* functions Added helpers and fixed shape for the previously added builtin functions to mirror the same as the Classic CodeGen code style and OGCG test style for the tests. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 56 +++- .../test/CIR/CodeGenBuiltins/Inputs/stdbit.h | 16 ++ .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 271 +++++++++++++++--- 3 files changed, 286 insertions(+), 57 deletions(-) create mode 100644 clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index aef5818084bc4..98f18111945b6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -111,20 +111,38 @@ static RValue emitBuiltinBitOpWithFallback(CIRGenFunction &cgf, return RValue::get(builder.createSelect(loc, isZero, fallbackValue, result)); } -static RValue emitStdcBitWidth(CIRGenFunction &cfg, const CallExpr *e) { - CIRGenBuilderTy &builder = cfg.getBuilder(); - mlir::Location loc = cfg.getLoc(e->getSourceRange()); +// stdc_{leading,trailing}_zeros and stdc_count_ones: counts bits using clz, +// ctz, or popcount. InvertArg flips the input to count the opposite bit value. +template <typename Op, typename... Args> +static RValue emitStdcCountOp(CIRGenFunction &cgf, const CallExpr *e, + bool invertArg, Args... args) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location loc = cgf.getLoc(e->getSourceRange()); + mlir::Value arg = cgf.emitScalarExpr(e->getArg(0)); + mlir::Value actualArg = invertArg ? builder.createNot(loc, arg) : arg; + mlir::Value result = Op::create(builder, loc, actualArg, args...).getResult(); - mlir::Value arg = cfg.emitScalarExpr(e->getArg(0)); - auto argTy = mlir::cast<cir::IntType>(arg.getType()); + mlir::Type resultTy = cgf.convertType(e->getType()); + if (result.getType() != resultTy) + result = builder.createIntCast(result, resultTy); + return RValue::get(result); +} - mlir::Value lz = - createBuiltinBitOp<cir::BitClzOp>(cfg, e, arg, /*poisonZero=*/false); +// stdc_count_zeros (BitWidth - popcount) and stdc_bit_width (BitWidth - clz). +// The subtract is performed in the argument type and cast once at the end. +template <typename Op, typename... Args> +static RValue emitStdcBitWidthMinus(CIRGenFunction &cgf, const CallExpr *e, + Args... args) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location loc = cgf.getLoc(e->getSourceRange()); + mlir::Value arg = cgf.emitScalarExpr(e->getArg(0)); + auto argTy = mlir::cast<cir::IntType>(arg.getType()); + mlir::Value cnt = Op::create(builder, loc, arg, args...).getResult(); mlir::Value width = builder.getConstInt(loc, argTy, argTy.getWidth()); - mlir::Value result = builder.createSub(loc, width, lz); + mlir::Value result = builder.createSub(loc, width, cnt); - mlir::Type resultTy = cfg.convertType(e->getType()); + mlir::Type resultTy = cgf.convertType(e->getType()); if (result.getType() != resultTy) result = builder.createIntCast(result, resultTy); @@ -1273,7 +1291,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_trailing_zeros_ul: case Builtin::BIstdc_trailing_zeros_ull: case Builtin::BI__builtin_stdc_trailing_zeros: - return emitBuiltinBitOp<cir::BitCtzOp>(*this, e, /*poisonZero=*/false); + return emitStdcCountOp<cir::BitCtzOp>(*this, e, /*invertArg=*/false, + /*poisonZero=*/false); case Builtin::BIstdc_leading_zeros_uc: case Builtin::BIstdc_leading_zeros_us: @@ -1281,7 +1300,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_leading_zeros_ul: case Builtin::BIstdc_leading_zeros_ull: case Builtin::BI__builtin_stdc_leading_zeros: - return emitBuiltinBitOp<cir::BitClzOp>(*this, e, /*poisonZero=*/false); + return emitStdcCountOp<cir::BitClzOp>(*this, e, /*invertArg=*/false, + /*poisonZero=*/false); case Builtin::BIstdc_bit_width_uc: case Builtin::BIstdc_bit_width_us: @@ -1289,7 +1309,16 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_bit_width_ul: case Builtin::BIstdc_bit_width_ull: case Builtin::BI__builtin_stdc_bit_width: - return emitStdcBitWidth(*this, e); + return emitStdcBitWidthMinus<cir::BitClzOp>(*this, e, + /*poisonZero=*/false); + + case Builtin::BIstdc_count_zeros_uc: + case Builtin::BIstdc_count_zeros_us: + case Builtin::BIstdc_count_zeros_ui: + case Builtin::BIstdc_count_zeros_ul: + case Builtin::BIstdc_count_zeros_ull: + case Builtin::BI__builtin_stdc_count_zeros: + return emitStdcBitWidthMinus<cir::BitPopcountOp>(*this, e); case Builtin::BIstdc_count_ones_uc: case Builtin::BIstdc_count_ones_us: @@ -1297,7 +1326,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_count_ones_ul: case Builtin::BIstdc_count_ones_ull: case Builtin::BI__builtin_stdc_count_ones: - return emitBuiltinBitOp<cir::BitPopcountOp>(*this, e); + return emitStdcCountOp<cir::BitPopcountOp>(*this, e, + /*invertArg=*/false); case Builtin::BI__builtin_clzs: case Builtin::BI__builtin_clz: diff --git a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h new file mode 100644 index 0000000000000..e61d333b221bd --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h @@ -0,0 +1,16 @@ +#ifndef LLVM_CLANG_TEST_CIR_STDBIT_H +#define LLVM_CLANG_TEST_CIR_STDBIT_H + +unsigned int stdc_count_zeros_uc(unsigned char); +unsigned int stdc_count_zeros_us(unsigned short); +unsigned int stdc_count_zeros_ui(unsigned int); +unsigned int stdc_count_zeros_ul(unsigned long); +unsigned int stdc_count_zeros_ull(unsigned long long); + +unsigned int stdc_bit_width_uc(unsigned char); +unsigned int stdc_bit_width_us(unsigned short); +unsigned int stdc_bit_width_ui(unsigned int); +unsigned int stdc_bit_width_ul(unsigned long); +unsigned int stdc_bit_width_ull(unsigned long long); + +#endif diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index 56632e70761ef..ffb9f43f58a31 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -1,67 +1,250 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c23 -I%S/../../CodeGen/Inputs -fclangir -emit-cir %s -o - | FileCheck %s +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-linux-gnu -std=c23 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-linux-gnu -std=c23 -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-linux-gnu -std=c23 -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c23 -isystem %S/Inputs -DTEST_LIB_SPELLINGS -fclangir -emit-cir %s -o %t-lib.cir +// RUN: FileCheck --input-file=%t-lib.cir %s --check-prefix=LIB-CIR +#ifdef TEST_LIB_SPELLINGS #include <stdbit.h> +#endif -void test_stdc_trailing_zeros(unsigned long long x) { - int cnt = __builtin_stdc_trailing_zeros(x); - (void)cnt; +#ifndef TEST_LIB_SPELLINGS + +void test_stdc_trailing_zeros(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_trailing_zeros(uc); + r = __builtin_stdc_trailing_zeros(us); + r = __builtin_stdc_trailing_zeros(ui); + r = __builtin_stdc_trailing_zeros(ul); + r = __builtin_stdc_trailing_zeros(ull); } -// CHECK-LABEL: test_stdc_trailing_zeros -// CHECK: cir.ctz -// CHECK-NOT: poison_zero -// CHECK: cir.return +// CIR-LABEL: @test_stdc_trailing_zeros( +// CIR: cir.ctz %{{.+}} : !u8i +// CIR: cir.ctz %{{.+}} : !u16i +// CIR: cir.ctz %{{.+}} : !u32i +// CIR: cir.ctz %{{.+}} : !u64i +// CIR: cir.ctz %{{.+}} : !u64i +// LLVM-LABEL: @test_stdc_trailing_zeros( +// LLVM: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// LLVM: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// LLVM: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +// LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG-LABEL: @test_stdc_trailing_zeros( +// OGCG: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// OGCG: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// OGCG: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +// OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) -unsigned test_stdc_leading_zeros(unsigned x) { - return __builtin_stdc_leading_zeros(x); +unsigned int test_stdc_leading_zeros(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_leading_zeros(uc); + r = __builtin_stdc_leading_zeros(us); + r = __builtin_stdc_leading_zeros(ui); + r = __builtin_stdc_leading_zeros(ul); + r = __builtin_stdc_leading_zeros(ull); + return r; } -// CHECK-LABEL: test_stdc_leading_zeros -// CHECK: cir.clz -// CHECK-NOT: poison_zero -// CHECK: cir.return +// CIR-LABEL: @test_stdc_leading_zeros( +// CIR: cir.clz %{{.+}} : !u8i +// CIR: cir.clz %{{.+}} : !u16i +// CIR: cir.clz %{{.+}} : !u32i +// CIR: cir.clz %{{.+}} : !u64i +// CIR: cir.clz %{{.+}} : !u64i +// LLVM-LABEL: @test_stdc_leading_zeros( +// LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG-LABEL: @test_stdc_leading_zeros( +// OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) -unsigned test_stdc_leading_zeros_ui(unsigned x) { - return stdc_leading_zeros_ui(x); +unsigned int test_stdc_count_ones(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_count_ones(uc); + r = __builtin_stdc_count_ones(us); + r = __builtin_stdc_count_ones(ui); + r = __builtin_stdc_count_ones(ul); + r = __builtin_stdc_count_ones(ull); + return r; } -// CHECK-LABEL: test_stdc_leading_zeros_ui -// CHECK: cir.clz -// CHECK-NOT: poison_zero -// CHECK: cir.return +// CIR-LABEL: @test_stdc_count_ones( +// CIR: cir.popcount %{{.+}} : !u8i +// CIR: cir.popcount %{{.+}} : !u16i +// CIR: cir.popcount %{{.+}} : !u32i +// CIR: cir.popcount %{{.+}} : !u64i +// CIR: cir.popcount %{{.+}} : !u64i +// LLVM-LABEL: @test_stdc_count_ones( +// LLVM: call i8 @llvm.ctpop.i8(i8 %{{.*}}) +// LLVM: call i16 @llvm.ctpop.i16(i16 %{{.*}}) +// LLVM: call i32 @llvm.ctpop.i32(i32 %{{.*}}) +// LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// OGCG-LABEL: @test_stdc_count_ones( +// OGCG: call i8 @llvm.ctpop.i8(i8 %{{.*}}) +// OGCG: call i16 @llvm.ctpop.i16(i16 %{{.*}}) +// OGCG: call i32 @llvm.ctpop.i32(i32 %{{.*}}) +// OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) -unsigned test_stdc_count_ones(unsigned x) { - return __builtin_stdc_count_ones(x); +unsigned int test_stdc_count_zeros(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_count_zeros(uc); + r = __builtin_stdc_count_zeros(us); + r = __builtin_stdc_count_zeros(ui); + r = __builtin_stdc_count_zeros(ul); + r = __builtin_stdc_count_zeros(ull); + return r; } -// CHECK-LABEL: test_stdc_count_ones -// CHECK: cir.popcount -// CHECK: cir.return +// CIR-LABEL: @test_stdc_count_zeros( +// CIR: cir.popcount %{{.+}} : !u8i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u8i +// CIR: cir.popcount %{{.+}} : !u16i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u16i +// CIR: cir.popcount %{{.+}} : !u32i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u32i +// CIR: cir.popcount %{{.+}} : !u64i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// CIR: cir.popcount %{{.+}} : !u64i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// LLVM-LABEL: @test_stdc_count_zeros( +// LLVM: call i8 @llvm.ctpop.i8(i8 %{{.*}}) +// LLVM: sub i8 8, %{{.*}} +// LLVM: call i16 @llvm.ctpop.i16(i16 %{{.*}}) +// LLVM: sub i16 16, %{{.*}} +// LLVM: call i32 @llvm.ctpop.i32(i32 %{{.*}}) +// LLVM: sub i32 32, %{{.*}} +// LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// LLVM: sub i64 64, %{{.*}} +// LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// LLVM: sub i64 64, %{{.*}} +// OGCG-LABEL: @test_stdc_count_zeros( +// OGCG: call i8 @llvm.ctpop.i8(i8 %{{.*}}) +// OGCG: sub i8 8, %{{.*}} +// OGCG: call i16 @llvm.ctpop.i16(i16 %{{.*}}) +// OGCG: sub i16 16, %{{.*}} +// OGCG: call i32 @llvm.ctpop.i32(i32 %{{.*}}) +// OGCG: sub i32 32, %{{.*}} +// OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// OGCG: sub i64 64, %{{.*}} +// OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// OGCG: sub i64 64, %{{.*}} -unsigned test_stdc_count_ones_ui(unsigned x) { - return stdc_count_ones_ui(x); +unsigned int test_stdc_bit_width(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_bit_width(uc); + r = __builtin_stdc_bit_width(us); + r = __builtin_stdc_bit_width(ui); + r = __builtin_stdc_bit_width(ul); + r = __builtin_stdc_bit_width(ull); + return r; } -// CHECK-LABEL: test_stdc_count_ones_ui -// CHECK: cir.popcount -// CHECK: cir.return +// CIR-LABEL: @test_stdc_bit_width( +// CIR: cir.clz %{{.+}} : !u8i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u8i +// CIR: cir.clz %{{.+}} : !u16i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u16i +// CIR: cir.clz %{{.+}} : !u32i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u32i +// CIR: cir.clz %{{.+}} : !u64i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// CIR: cir.clz %{{.+}} : !u64i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// LLVM-LABEL: @test_stdc_bit_width( +// LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// LLVM: sub i8 8, %{{.*}} +// LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// LLVM: sub i16 16, %{{.*}} +// LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// LLVM: sub i32 32, %{{.*}} +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: sub i64 64, %{{.*}} +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: sub i64 64, %{{.*}} +// OGCG-LABEL: @test_stdc_bit_width( +// OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// OGCG: sub i8 8, %{{.*}} +// OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// OGCG: sub i16 16, %{{.*}} +// OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// OGCG: sub i32 32, %{{.*}} +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: sub i64 64, %{{.*}} +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: sub i64 64, %{{.*}} + +#else -unsigned test_stdc_bit_width(unsigned x) { - return __builtin_stdc_bit_width(x); +unsigned int test_stdc_count_zeros_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_count_zeros_uc(uc); + r = stdc_count_zeros_us(us); + r = stdc_count_zeros_ui(ui); + r = stdc_count_zeros_ul(ul); + r = stdc_count_zeros_ull(ull); + return r; } -// CHECK-LABEL: test_stdc_bit_width -// CHECK: cir.clz -// CHECK-NOT: poison_zero -// CHECK: cir.sub -// CHECK: cir.return +// LIB-CIR-LABEL: @test_stdc_count_zeros_lib( +// LIB-CIR: cir.popcount %{{.+}} : !u8i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u8i +// LIB-CIR: cir.popcount %{{.+}} : !u16i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u16i +// LIB-CIR: cir.popcount %{{.+}} : !u32i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u32i +// LIB-CIR: cir.popcount %{{.+}} : !u64i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// LIB-CIR: cir.popcount %{{.+}} : !u64i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u64i -unsigned test_stdc_bit_width_ui(unsigned x) { - return stdc_bit_width_ui(x); +unsigned int test_stdc_bit_width_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_bit_width_uc(uc); + r = stdc_bit_width_us(us); + r = stdc_bit_width_ui(ui); + r = stdc_bit_width_ul(ul); + r = stdc_bit_width_ull(ull); + return r; } -// CHECK-LABEL: test_stdc_bit_width_ui -// CHECK: cir.clz -// CHECK-NOT: poison_zero -// CHECK: cir.sub -// CHECK: cir.return +// LIB-CIR-LABEL: @test_stdc_bit_width_lib( +// LIB-CIR: cir.clz %{{.+}} : !u8i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u8i +// LIB-CIR: cir.clz %{{.+}} : !u16i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u16i +// LIB-CIR: cir.clz %{{.+}} : !u32i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u32i +// LIB-CIR: cir.clz %{{.+}} : !u64i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// LIB-CIR: cir.clz %{{.+}} : !u64i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u64i + +#endif >From 56cd327d466edbf03606d1e80d2988e666b97e61 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Tue, 11 Aug 2026 15:46:50 +0530 Subject: [PATCH 06/11] [CIR] Lowering for __builtin_stdc_trailing and _leading_ones Added lowerin for the __builting_stdc_trailing and __builin_stdc_leading_ones by lowering to by inverted BitCtzOp and inverted BitCtzOp respectively, matching the C23 stdbit semantics. Added errorBuiltinNYI for the other Builtins that are not implemented. Added OGCG style test suite for the same. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 47 +++++- .../test/CIR/CodeGenBuiltins/Inputs/stdbit.h | 12 ++ .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 139 ++++++++++++++++++ 3 files changed, 196 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 98f18111945b6..43d62b964944d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -111,8 +111,9 @@ static RValue emitBuiltinBitOpWithFallback(CIRGenFunction &cgf, return RValue::get(builder.createSelect(loc, isZero, fallbackValue, result)); } -// stdc_{leading,trailing}_zeros and stdc_count_ones: counts bits using clz, -// ctz, or popcount. InvertArg flips the input to count the opposite bit value. +// stdc_{leading,trailing}_{zeros,ones} and stdc_count_ones: counts bits using +// clz, ctz, or popcount. InvertArg flips the input to count the opposite bit +// value. template <typename Op, typename... Args> static RValue emitStdcCountOp(CIRGenFunction &cgf, const CallExpr *e, bool invertArg, Args... args) { @@ -1303,6 +1304,24 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return emitStdcCountOp<cir::BitClzOp>(*this, e, /*invertArg=*/false, /*poisonZero=*/false); + case Builtin::BIstdc_trailing_ones_uc: + case Builtin::BIstdc_trailing_ones_us: + case Builtin::BIstdc_trailing_ones_ui: + case Builtin::BIstdc_trailing_ones_ul: + case Builtin::BIstdc_trailing_ones_ull: + case Builtin::BI__builtin_stdc_trailing_ones: + return emitStdcCountOp<cir::BitCtzOp>(*this, e, /*invertArg=*/true, + /*poisonZero=*/false); + + case Builtin::BIstdc_leading_ones_uc: + case Builtin::BIstdc_leading_ones_us: + case Builtin::BIstdc_leading_ones_ui: + case Builtin::BIstdc_leading_ones_ul: + case Builtin::BIstdc_leading_ones_ull: + case Builtin::BI__builtin_stdc_leading_ones: + return emitStdcCountOp<cir::BitClzOp>(*this, e, /*invertArg=*/true, + /*poisonZero=*/false); + case Builtin::BIstdc_bit_width_uc: case Builtin::BIstdc_bit_width_us: case Builtin::BIstdc_bit_width_ui: @@ -1329,6 +1348,30 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return emitStdcCountOp<cir::BitPopcountOp>(*this, e, /*invertArg=*/false); + case Builtin::BIstdc_has_single_bit_uc: + case Builtin::BIstdc_has_single_bit_us: + case Builtin::BIstdc_has_single_bit_ui: + case Builtin::BIstdc_has_single_bit_ul: + case Builtin::BIstdc_has_single_bit_ull: + case Builtin::BI__builtin_stdc_has_single_bit: + return errorBuiltinNYI(*this, e, builtinID); + + case Builtin::BIstdc_bit_ceil_uc: + case Builtin::BIstdc_bit_ceil_us: + case Builtin::BIstdc_bit_ceil_ui: + case Builtin::BIstdc_bit_ceil_ul: + case Builtin::BIstdc_bit_ceil_ull: + case Builtin::BI__builtin_stdc_bit_ceil: + return errorBuiltinNYI(*this, e, builtinID); + + case Builtin::BIstdc_bit_floor_uc: + case Builtin::BIstdc_bit_floor_us: + case Builtin::BIstdc_bit_floor_ui: + case Builtin::BIstdc_bit_floor_ul: + case Builtin::BIstdc_bit_floor_ull: + case Builtin::BI__builtin_stdc_bit_floor: + return errorBuiltinNYI(*this, e, builtinID); + case Builtin::BI__builtin_clzs: case Builtin::BI__builtin_clz: case Builtin::BI__builtin_clzl: diff --git a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h index e61d333b221bd..f4ee39e486558 100644 --- a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h +++ b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h @@ -1,6 +1,18 @@ #ifndef LLVM_CLANG_TEST_CIR_STDBIT_H #define LLVM_CLANG_TEST_CIR_STDBIT_H +unsigned int stdc_leading_ones_uc(unsigned char); +unsigned int stdc_leading_ones_us(unsigned short); +unsigned int stdc_leading_ones_ui(unsigned int); +unsigned int stdc_leading_ones_ul(unsigned long); +unsigned int stdc_leading_ones_ull(unsigned long long); + +unsigned int stdc_trailing_ones_uc(unsigned char); +unsigned int stdc_trailing_ones_us(unsigned short); +unsigned int stdc_trailing_ones_ui(unsigned int); +unsigned int stdc_trailing_ones_ul(unsigned long); +unsigned int stdc_trailing_ones_ull(unsigned long long); + unsigned int stdc_count_zeros_uc(unsigned char); unsigned int stdc_count_zeros_us(unsigned short); unsigned int stdc_count_zeros_ui(unsigned int); diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index ffb9f43f58a31..b7024af2475e5 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -43,6 +43,51 @@ void test_stdc_trailing_zeros(unsigned char uc, unsigned short us, // OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) // OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +void test_stdc_trailing_ones(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_trailing_ones(uc); + r = __builtin_stdc_trailing_ones(us); + r = __builtin_stdc_trailing_ones(ui); + r = __builtin_stdc_trailing_ones(ul); + r = __builtin_stdc_trailing_ones(ull); +} + +// CIR-LABEL: @test_stdc_trailing_ones( +// CIR: cir.not %{{.+}} : !u8i +// CIR: cir.ctz %{{.+}} : !u8i +// CIR: cir.not %{{.+}} : !u16i +// CIR: cir.ctz %{{.+}} : !u16i +// CIR: cir.not %{{.+}} : !u32i +// CIR: cir.ctz %{{.+}} : !u32i +// CIR: cir.not %{{.+}} : !u64i +// CIR: cir.ctz %{{.+}} : !u64i +// CIR: cir.not %{{.+}} : !u64i +// CIR: cir.ctz %{{.+}} : !u64i +// LLVM-LABEL: @test_stdc_trailing_ones( +// LLVM: xor i8 %{{.*}}, -1 +// LLVM: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// LLVM: xor i16 %{{.*}}, -1 +// LLVM: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// LLVM: xor i32 %{{.*}}, -1 +// LLVM: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +// LLVM: xor i64 %{{.*}}, -1 +// LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: xor i64 %{{.*}}, -1 +// LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG-LABEL: @test_stdc_trailing_ones( +// OGCG: xor i8 %{{.*}}, -1 +// OGCG: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// OGCG: xor i16 %{{.*}}, -1 +// OGCG: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// OGCG: xor i32 %{{.*}}, -1 +// OGCG: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +// OGCG: xor i64 %{{.*}}, -1 +// OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: xor i64 %{{.*}}, -1 +// OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) + unsigned int test_stdc_leading_zeros(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, unsigned long long ull) { @@ -74,6 +119,52 @@ unsigned int test_stdc_leading_zeros(unsigned char uc, unsigned short us, // OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) // OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +unsigned int test_stdc_leading_ones(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_leading_ones(uc); + r = __builtin_stdc_leading_ones(us); + r = __builtin_stdc_leading_ones(ui); + r = __builtin_stdc_leading_ones(ul); + r = __builtin_stdc_leading_ones(ull); + return r; +} + +// CIR-LABEL: @test_stdc_leading_ones( +// CIR: cir.not %{{.+}} : !u8i +// CIR: cir.clz %{{.+}} : !u8i +// CIR: cir.not %{{.+}} : !u16i +// CIR: cir.clz %{{.+}} : !u16i +// CIR: cir.not %{{.+}} : !u32i +// CIR: cir.clz %{{.+}} : !u32i +// CIR: cir.not %{{.+}} : !u64i +// CIR: cir.clz %{{.+}} : !u64i +// CIR: cir.not %{{.+}} : !u64i +// CIR: cir.clz %{{.+}} : !u64i +// LLVM-LABEL: @test_stdc_leading_ones( +// LLVM: xor i8 %{{.*}}, -1 +// LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// LLVM: xor i16 %{{.*}}, -1 +// LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// LLVM: xor i32 %{{.*}}, -1 +// LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// LLVM: xor i64 %{{.*}}, -1 +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: xor i64 %{{.*}}, -1 +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG-LABEL: @test_stdc_leading_ones( +// OGCG: xor i8 %{{.*}}, -1 +// OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// OGCG: xor i16 %{{.*}}, -1 +// OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// OGCG: xor i32 %{{.*}}, -1 +// OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// OGCG: xor i64 %{{.*}}, -1 +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: xor i64 %{{.*}}, -1 +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) + unsigned int test_stdc_count_ones(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, unsigned long long ull) { @@ -199,6 +290,54 @@ unsigned int test_stdc_bit_width(unsigned char uc, unsigned short us, #else +unsigned int test_stdc_trailing_ones_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_trailing_ones_uc(uc); + r = stdc_trailing_ones_us(us); + r = stdc_trailing_ones_ui(ui); + r = stdc_trailing_ones_ul(ul); + r = stdc_trailing_ones_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_trailing_ones_lib( +// LIB-CIR: cir.not %{{.+}} : !u8i +// LIB-CIR: cir.ctz %{{.+}} : !u8i +// LIB-CIR: cir.not %{{.+}} : !u16i +// LIB-CIR: cir.ctz %{{.+}} : !u16i +// LIB-CIR: cir.not %{{.+}} : !u32i +// LIB-CIR: cir.ctz %{{.+}} : !u32i +// LIB-CIR: cir.not %{{.+}} : !u64i +// LIB-CIR: cir.ctz %{{.+}} : !u64i +// LIB-CIR: cir.not %{{.+}} : !u64i +// LIB-CIR: cir.ctz %{{.+}} : !u64i + +unsigned int test_stdc_leading_ones_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_leading_ones_uc(uc); + r = stdc_leading_ones_us(us); + r = stdc_leading_ones_ui(ui); + r = stdc_leading_ones_ul(ul); + r = stdc_leading_ones_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_leading_ones_lib( +// LIB-CIR: cir.not %{{.+}} : !u8i +// LIB-CIR: cir.clz %{{.+}} : !u8i +// LIB-CIR: cir.not %{{.+}} : !u16i +// LIB-CIR: cir.clz %{{.+}} : !u16i +// LIB-CIR: cir.not %{{.+}} : !u32i +// LIB-CIR: cir.clz %{{.+}} : !u32i +// LIB-CIR: cir.not %{{.+}} : !u64i +// LIB-CIR: cir.clz %{{.+}} : !u64i +// LIB-CIR: cir.not %{{.+}} : !u64i +// LIB-CIR: cir.clz %{{.+}} : !u64i + unsigned int test_stdc_count_zeros_lib(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, unsigned long long ull) { >From a74543dd20691063598edbb659d231efc1086d8b Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Wed, 12 Aug 2026 01:17:56 +0530 Subject: [PATCH 07/11] [CIR] Lowering for more C23 stdbit builtins Lowered stdc_has_single_bit to popcount == 1 and added explicit NYI for stdc_first_* and the remaining builtins instead of letting stdbit spellings fall through to library calls. Added rejection for unsupported _BitInt widths before CIR bitops and tests now cover narrow and wide arguments. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 78 ++++++++++++++- .../test/CIR/CodeGenBuiltins/Inputs/stdbit.h | 14 +++ .../CodeGenBuiltins/builtin-stdc-bit-nyi.c | 32 +++++++ .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 96 +++++++++++++++++++ 4 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 43d62b964944d..d345b65d271b7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -111,6 +111,33 @@ static RValue emitBuiltinBitOpWithFallback(CIRGenFunction &cgf, return RValue::get(builder.createSelect(loc, isZero, fallbackValue, result)); } +static bool isStdcBitOpWidthSupported(cir::IntType intTy) { + switch (intTy.getWidth()) { + case 8: + case 16: + case 32: + case 64: + case 128: + return true; + default: + return false; + } +} + +static RValue errorStdcBitOpWidthNYI(CIRGenFunction &cgf, const CallExpr *e) { + cgf.cgm.errorNYI(e->getSourceRange(), + "stdc bit builtin with unsupported argument integer width"); + return cgf.getUndefRValue(e->getType()); +} + +static RValue errorBuiltinCallNYI(CIRGenFunction &cgf, const CallExpr *e, + unsigned builtinID) { + cgf.cgm.errorNYI(e->getSourceRange(), + std::string("unimplemented builtin call: ") + + cgf.getContext().BuiltinInfo.getName(builtinID)); + return cgf.getUndefRValue(e->getType()); +} + // stdc_{leading,trailing}_{zeros,ones} and stdc_count_ones: counts bits using // clz, ctz, or popcount. InvertArg flips the input to count the opposite bit // value. @@ -120,6 +147,8 @@ static RValue emitStdcCountOp(CIRGenFunction &cgf, const CallExpr *e, CIRGenBuilderTy &builder = cgf.getBuilder(); mlir::Location loc = cgf.getLoc(e->getSourceRange()); mlir::Value arg = cgf.emitScalarExpr(e->getArg(0)); + if (!isStdcBitOpWidthSupported(mlir::cast<cir::IntType>(arg.getType()))) + return errorStdcBitOpWidthNYI(cgf, e); mlir::Value actualArg = invertArg ? builder.createNot(loc, arg) : arg; mlir::Value result = Op::create(builder, loc, actualArg, args...).getResult(); @@ -138,6 +167,8 @@ static RValue emitStdcBitWidthMinus(CIRGenFunction &cgf, const CallExpr *e, mlir::Location loc = cgf.getLoc(e->getSourceRange()); mlir::Value arg = cgf.emitScalarExpr(e->getArg(0)); auto argTy = mlir::cast<cir::IntType>(arg.getType()); + if (!isStdcBitOpWidthSupported(argTy)) + return errorStdcBitOpWidthNYI(cgf, e); mlir::Value cnt = Op::create(builder, loc, arg, args...).getResult(); mlir::Value width = builder.getConstInt(loc, argTy, argTy.getWidth()); @@ -150,6 +181,21 @@ static RValue emitStdcBitWidthMinus(CIRGenFunction &cgf, const CallExpr *e, return RValue::get(result); } +static RValue emitStdcHasSingleBit(CIRGenFunction &cgf, const CallExpr *e) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location loc = cgf.getLoc(e->getSourceRange()); + mlir::Value arg = cgf.emitScalarExpr(e->getArg(0)); + if (!isStdcBitOpWidthSupported(mlir::cast<cir::IntType>(arg.getType()))) + return errorStdcBitOpWidthNYI(cgf, e); + + mlir::Value popCount = + cir::BitPopcountOp::create(builder, loc, arg).getResult(); + mlir::Value one = builder.getConstInt(loc, popCount.getType(), 1); + mlir::Value result = + builder.createCompare(loc, cir::CmpOpKind::eq, popCount, one); + return RValue::get(result); +} + /// Emit the conversions required to turn the given value into an /// integer of the given size. static mlir::Value emitToInt(CIRGenFunction &cgf, mlir::Value v, QualType t, @@ -1354,7 +1400,33 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_has_single_bit_ul: case Builtin::BIstdc_has_single_bit_ull: case Builtin::BI__builtin_stdc_has_single_bit: - return errorBuiltinNYI(*this, e, builtinID); + return emitStdcHasSingleBit(*this, e); + + case Builtin::BIstdc_first_leading_zero_uc: + case Builtin::BIstdc_first_leading_zero_us: + case Builtin::BIstdc_first_leading_zero_ui: + case Builtin::BIstdc_first_leading_zero_ul: + case Builtin::BIstdc_first_leading_zero_ull: + case Builtin::BI__builtin_stdc_first_leading_zero: + case Builtin::BIstdc_first_leading_one_uc: + case Builtin::BIstdc_first_leading_one_us: + case Builtin::BIstdc_first_leading_one_ui: + case Builtin::BIstdc_first_leading_one_ul: + case Builtin::BIstdc_first_leading_one_ull: + case Builtin::BI__builtin_stdc_first_leading_one: + case Builtin::BIstdc_first_trailing_zero_uc: + case Builtin::BIstdc_first_trailing_zero_us: + case Builtin::BIstdc_first_trailing_zero_ui: + case Builtin::BIstdc_first_trailing_zero_ul: + case Builtin::BIstdc_first_trailing_zero_ull: + case Builtin::BI__builtin_stdc_first_trailing_zero: + case Builtin::BIstdc_first_trailing_one_uc: + case Builtin::BIstdc_first_trailing_one_us: + case Builtin::BIstdc_first_trailing_one_ui: + case Builtin::BIstdc_first_trailing_one_ul: + case Builtin::BIstdc_first_trailing_one_ull: + case Builtin::BI__builtin_stdc_first_trailing_one: + return errorBuiltinCallNYI(*this, e, builtinID); case Builtin::BIstdc_bit_ceil_uc: case Builtin::BIstdc_bit_ceil_us: @@ -1362,7 +1434,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_bit_ceil_ul: case Builtin::BIstdc_bit_ceil_ull: case Builtin::BI__builtin_stdc_bit_ceil: - return errorBuiltinNYI(*this, e, builtinID); + return errorBuiltinCallNYI(*this, e, builtinID); case Builtin::BIstdc_bit_floor_uc: case Builtin::BIstdc_bit_floor_us: @@ -1370,7 +1442,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_bit_floor_ul: case Builtin::BIstdc_bit_floor_ull: case Builtin::BI__builtin_stdc_bit_floor: - return errorBuiltinNYI(*this, e, builtinID); + return errorBuiltinCallNYI(*this, e, builtinID); case Builtin::BI__builtin_clzs: case Builtin::BI__builtin_clz: diff --git a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h index f4ee39e486558..1146a4ee59c8f 100644 --- a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h +++ b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h @@ -19,10 +19,24 @@ unsigned int stdc_count_zeros_ui(unsigned int); unsigned int stdc_count_zeros_ul(unsigned long); unsigned int stdc_count_zeros_ull(unsigned long long); +_Bool stdc_has_single_bit_uc(unsigned char); +_Bool stdc_has_single_bit_us(unsigned short); +_Bool stdc_has_single_bit_ui(unsigned int); +_Bool stdc_has_single_bit_ul(unsigned long); +_Bool stdc_has_single_bit_ull(unsigned long long); + +unsigned int stdc_first_leading_zero_ui(unsigned int); +unsigned int stdc_first_leading_one_ui(unsigned int); +unsigned int stdc_first_trailing_zero_ui(unsigned int); +unsigned int stdc_first_trailing_one_ui(unsigned int); + unsigned int stdc_bit_width_uc(unsigned char); unsigned int stdc_bit_width_us(unsigned short); unsigned int stdc_bit_width_ui(unsigned int); unsigned int stdc_bit_width_ul(unsigned long); unsigned int stdc_bit_width_ull(unsigned long long); +unsigned int stdc_bit_ceil_ui(unsigned int); +unsigned int stdc_bit_floor_ui(unsigned int); + #endif diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c new file mode 100644 index 0000000000000..c425e3f84b947 --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-linux-gnu -std=c23 -fclangir -emit-cir -verify %s -o - +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c23 -isystem %S/Inputs -DTEST_LIB_SPELLINGS -fclangir -emit-cir -verify %s -o - + +#ifdef TEST_LIB_SPELLINGS +#include <stdbit.h> +#endif + +#ifndef TEST_LIB_SPELLINGS + +void test_unimplemented_builtin_stdc_bit(unsigned int ui, + unsigned _BitInt(37) bi) { + volatile unsigned int r; + r = __builtin_stdc_bit_ceil(ui); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: __builtin_stdc_bit_ceil}} + r = __builtin_stdc_bit_floor(ui); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: __builtin_stdc_bit_floor}} + (void)__builtin_stdc_leading_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin on unsupported integer width}} + (void)__builtin_stdc_count_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin on unsupported integer width}} + (void)__builtin_stdc_has_single_bit(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin on unsupported integer width}} +} + +#else + +void test_unimplemented_stdc_first(unsigned int x) { + volatile unsigned int r; + r = stdc_bit_ceil_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_bit_ceil_ui}} + r = stdc_bit_floor_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_bit_floor_ui}} + (void)stdc_first_leading_zero_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_leading_zero_ui}} + (void)stdc_first_leading_one_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_leading_one_ui}} + (void)stdc_first_trailing_zero_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_trailing_zero_ui}} + (void)stdc_first_trailing_one_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_trailing_one_ui}} +} + +#endif diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index b7024af2475e5..a08832ac7c168 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -185,16 +185,75 @@ unsigned int test_stdc_count_ones(unsigned char uc, unsigned short us, // CIR: cir.popcount %{{.+}} : !u64i // LLVM-LABEL: @test_stdc_count_ones( // LLVM: call i8 @llvm.ctpop.i8(i8 %{{.*}}) +// LLVM: zext i8 %{{.*}} to i32 // LLVM: call i16 @llvm.ctpop.i16(i16 %{{.*}}) +// LLVM: zext i16 %{{.*}} to i32 // LLVM: call i32 @llvm.ctpop.i32(i32 %{{.*}}) // LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// LLVM: trunc i64 %{{.*}} to i32 // LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// LLVM: trunc i64 %{{.*}} to i32 // OGCG-LABEL: @test_stdc_count_ones( // OGCG: call i8 @llvm.ctpop.i8(i8 %{{.*}}) +// OGCG: zext i8 %{{.*}} to i32 // OGCG: call i16 @llvm.ctpop.i16(i16 %{{.*}}) +// OGCG: zext i16 %{{.*}} to i32 // OGCG: call i32 @llvm.ctpop.i32(i32 %{{.*}}) // OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// OGCG: trunc i64 %{{.*}} to i32 // OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// OGCG: trunc i64 %{{.*}} to i32 + +_Bool test_stdc_has_single_bit(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile _Bool r; + r = __builtin_stdc_has_single_bit(uc); + r = __builtin_stdc_has_single_bit(us); + r = __builtin_stdc_has_single_bit(ui); + r = __builtin_stdc_has_single_bit(ul); + r = __builtin_stdc_has_single_bit(ull); + return r; +} + +// CIR-LABEL: @test_stdc_has_single_bit( +// CIR: %[[POPCOUNT_UC:.+]] = cir.popcount %{{.+}} : !u8i +// CIR: %[[ONE_UC:.+]] = cir.const #cir.int<1> : !u8i +// CIR: cir.cmp eq %[[POPCOUNT_UC]], %[[ONE_UC]] : !u8i +// CIR: %[[POPCOUNT_US:.+]] = cir.popcount %{{.+}} : !u16i +// CIR: %[[ONE_US:.+]] = cir.const #cir.int<1> : !u16i +// CIR: cir.cmp eq %[[POPCOUNT_US]], %[[ONE_US]] : !u16i +// CIR: %[[POPCOUNT_UI:.+]] = cir.popcount %{{.+}} : !u32i +// CIR: %[[ONE_UI:.+]] = cir.const #cir.int<1> : !u32i +// CIR: cir.cmp eq %[[POPCOUNT_UI]], %[[ONE_UI]] : !u32i +// CIR: %[[POPCOUNT_UL:.+]] = cir.popcount %{{.+}} : !u64i +// CIR: %[[ONE_UL:.+]] = cir.const #cir.int<1> : !u64i +// CIR: cir.cmp eq %[[POPCOUNT_UL]], %[[ONE_UL]] : !u64i +// CIR: %[[POPCOUNT_ULL:.+]] = cir.popcount %{{.+}} : !u64i +// CIR: %[[ONE_ULL:.+]] = cir.const #cir.int<1> : !u64i +// CIR: cir.cmp eq %[[POPCOUNT_ULL]], %[[ONE_ULL]] : !u64i +// LLVM-LABEL: @test_stdc_has_single_bit( +// LLVM: call i8 @llvm.ctpop.i8(i8 %{{.*}}) +// LLVM: icmp eq i8 %{{.*}}, 1 +// LLVM: call i16 @llvm.ctpop.i16(i16 %{{.*}}) +// LLVM: icmp eq i16 %{{.*}}, 1 +// LLVM: call i32 @llvm.ctpop.i32(i32 %{{.*}}) +// LLVM: icmp eq i32 %{{.*}}, 1 +// LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// LLVM: icmp eq i64 %{{.*}}, 1 +// LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// LLVM: icmp eq i64 %{{.*}}, 1 +// OGCG-LABEL: @test_stdc_has_single_bit( +// OGCG: call i8 @llvm.ctpop.i8(i8 %{{.*}}) +// OGCG: icmp eq i8 %{{.*}}, 1 +// OGCG: call i16 @llvm.ctpop.i16(i16 %{{.*}}) +// OGCG: icmp eq i16 %{{.*}}, 1 +// OGCG: call i32 @llvm.ctpop.i32(i32 %{{.*}}) +// OGCG: icmp eq i32 %{{.*}}, 1 +// OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// OGCG: icmp eq i64 %{{.*}}, 1 +// OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) +// OGCG: icmp eq i64 %{{.*}}, 1 unsigned int test_stdc_count_zeros(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, @@ -268,25 +327,33 @@ unsigned int test_stdc_bit_width(unsigned char uc, unsigned short us, // LLVM-LABEL: @test_stdc_bit_width( // LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) // LLVM: sub i8 8, %{{.*}} +// LLVM: zext i8 %{{.*}} to i32 // LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) // LLVM: sub i16 16, %{{.*}} +// LLVM: zext i16 %{{.*}} to i32 // LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) // LLVM: sub i32 32, %{{.*}} // LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) // LLVM: sub i64 64, %{{.*}} +// LLVM: trunc i64 %{{.*}} to i32 // LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) // LLVM: sub i64 64, %{{.*}} +// LLVM: trunc i64 %{{.*}} to i32 // OGCG-LABEL: @test_stdc_bit_width( // OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) // OGCG: sub i8 8, %{{.*}} +// OGCG: zext i8 %{{.*}} to i32 // OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) // OGCG: sub i16 16, %{{.*}} +// OGCG: zext i16 %{{.*}} to i32 // OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) // OGCG: sub i32 32, %{{.*}} // OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) // OGCG: sub i64 64, %{{.*}} +// OGCG: trunc i64 %{{.*}} to i32 // OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) // OGCG: sub i64 64, %{{.*}} +// OGCG: trunc i64 %{{.*}} to i32 #else @@ -338,6 +405,35 @@ unsigned int test_stdc_leading_ones_lib(unsigned char uc, unsigned short us, // LIB-CIR: cir.not %{{.+}} : !u64i // LIB-CIR: cir.clz %{{.+}} : !u64i +_Bool test_stdc_has_single_bit_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile _Bool r; + r = stdc_has_single_bit_uc(uc); + r = stdc_has_single_bit_us(us); + r = stdc_has_single_bit_ui(ui); + r = stdc_has_single_bit_ul(ul); + r = stdc_has_single_bit_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_has_single_bit_lib( +// LIB-CIR: %[[LIB_POPCOUNT_UC:.+]] = cir.popcount %{{.+}} : !u8i +// LIB-CIR: %[[LIB_ONE_UC:.+]] = cir.const #cir.int<1> : !u8i +// LIB-CIR: cir.cmp eq %[[LIB_POPCOUNT_UC]], %[[LIB_ONE_UC]] : !u8i +// LIB-CIR: %[[LIB_POPCOUNT_US:.+]] = cir.popcount %{{.+}} : !u16i +// LIB-CIR: %[[LIB_ONE_US:.+]] = cir.const #cir.int<1> : !u16i +// LIB-CIR: cir.cmp eq %[[LIB_POPCOUNT_US]], %[[LIB_ONE_US]] : !u16i +// LIB-CIR: %[[LIB_POPCOUNT_UI:.+]] = cir.popcount %{{.+}} : !u32i +// LIB-CIR: %[[LIB_ONE_UI:.+]] = cir.const #cir.int<1> : !u32i +// LIB-CIR: cir.cmp eq %[[LIB_POPCOUNT_UI]], %[[LIB_ONE_UI]] : !u32i +// LIB-CIR: %[[LIB_POPCOUNT_UL:.+]] = cir.popcount %{{.+}} : !u64i +// LIB-CIR: %[[LIB_ONE_UL:.+]] = cir.const #cir.int<1> : !u64i +// LIB-CIR: cir.cmp eq %[[LIB_POPCOUNT_UL]], %[[LIB_ONE_UL]] : !u64i +// LIB-CIR: %[[LIB_POPCOUNT_ULL:.+]] = cir.popcount %{{.+}} : !u64i +// LIB-CIR: %[[LIB_ONE_ULL:.+]] = cir.const #cir.int<1> : !u64i +// LIB-CIR: cir.cmp eq %[[LIB_POPCOUNT_ULL]], %[[LIB_ONE_ULL]] : !u64i + unsigned int test_stdc_count_zeros_lib(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, unsigned long long ull) { >From 1e056af20c5d52661f49654521fa42caaebd0278 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Wed, 12 Aug 2026 08:44:48 +0530 Subject: [PATCH 08/11] [CIR] fix stale test wording The failing tests were due to stale wording in the test expectation. --- clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c index c425e3f84b947..48cfe9d2e4571 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c @@ -12,9 +12,9 @@ void test_unimplemented_builtin_stdc_bit(unsigned int ui, volatile unsigned int r; r = __builtin_stdc_bit_ceil(ui); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: __builtin_stdc_bit_ceil}} r = __builtin_stdc_bit_floor(ui); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: __builtin_stdc_bit_floor}} - (void)__builtin_stdc_leading_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin on unsupported integer width}} - (void)__builtin_stdc_count_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin on unsupported integer width}} - (void)__builtin_stdc_has_single_bit(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin on unsupported integer width}} + (void)__builtin_stdc_leading_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} + (void)__builtin_stdc_count_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} + (void)__builtin_stdc_has_single_bit(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} } #else >From 5d955d2a3230b635fd470c28c1a8cc3fc3012917 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Wed, 12 Aug 2026 23:50:43 +0530 Subject: [PATCH 09/11] [CIR] Lowering __builtin_stdc_bit_floor Lowering __builtin_stdc_bit_floor using the same (width-1-ctlz)->left_shift->zero_select shape as the classic codegen. Added test for the same. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 24 +++- .../test/CIR/CodeGenBuiltins/Inputs/stdbit.h | 4 + .../CodeGenBuiltins/builtin-stdc-bit-nyi.c | 3 +- .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 113 ++++++++++++++++++ 4 files changed, 141 insertions(+), 3 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index d345b65d271b7..d62d50415aa77 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -196,6 +196,28 @@ static RValue emitStdcHasSingleBit(CIRGenFunction &cgf, const CallExpr *e) { return RValue::get(result); } +static RValue emitStdcBitFloor(CIRGenFunction &cgf, const CallExpr *e) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location loc = cgf.getLoc(e->getSourceRange()); + mlir::Value arg = cgf.emitScalarExpr(e->getArg(0)); + auto argTy = mlir::cast<cir::IntType>(arg.getType()); + if (!isStdcBitOpWidthSupported(argTy)) + return errorStdcBitOpWidthNYI(cgf, e); + + mlir::Value widthMinusOne = + builder.getConstInt(loc, argTy, argTy.getWidth() - 1); + mlir::Value one = builder.getConstInt(loc, argTy, 1); + mlir::Value lz = + cir::BitClzOp::create(builder, loc, arg, /*poisonZero=*/true).getResult(); + mlir::Value shiftAmt = builder.createSub(loc, widthMinusOne, lz); + mlir::Value zero = builder.getNullValue(argTy, loc); + mlir::Value isZero = + builder.createCompare(loc, cir::CmpOpKind::eq, arg, zero); + mlir::Value floor = builder.createShiftLeft(loc, one, shiftAmt); + mlir::Value result = builder.createSelect(loc, isZero, zero, floor); + return RValue::get(result); +} + /// Emit the conversions required to turn the given value into an /// integer of the given size. static mlir::Value emitToInt(CIRGenFunction &cgf, mlir::Value v, QualType t, @@ -1442,7 +1464,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_bit_floor_ul: case Builtin::BIstdc_bit_floor_ull: case Builtin::BI__builtin_stdc_bit_floor: - return errorBuiltinCallNYI(*this, e, builtinID); + return emitStdcBitFloor(*this, e); case Builtin::BI__builtin_clzs: case Builtin::BI__builtin_clz: diff --git a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h index 1146a4ee59c8f..0e39daf17aeb1 100644 --- a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h +++ b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h @@ -37,6 +37,10 @@ unsigned int stdc_bit_width_ul(unsigned long); unsigned int stdc_bit_width_ull(unsigned long long); unsigned int stdc_bit_ceil_ui(unsigned int); +unsigned char stdc_bit_floor_uc(unsigned char); +unsigned short stdc_bit_floor_us(unsigned short); unsigned int stdc_bit_floor_ui(unsigned int); +unsigned long stdc_bit_floor_ul(unsigned long); +unsigned long long stdc_bit_floor_ull(unsigned long long); #endif diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c index 48cfe9d2e4571..34cd7ae103de7 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c @@ -11,10 +11,10 @@ void test_unimplemented_builtin_stdc_bit(unsigned int ui, unsigned _BitInt(37) bi) { volatile unsigned int r; r = __builtin_stdc_bit_ceil(ui); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: __builtin_stdc_bit_ceil}} - r = __builtin_stdc_bit_floor(ui); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: __builtin_stdc_bit_floor}} (void)__builtin_stdc_leading_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} (void)__builtin_stdc_count_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} (void)__builtin_stdc_has_single_bit(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} + (void)__builtin_stdc_bit_floor(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} } #else @@ -22,7 +22,6 @@ void test_unimplemented_builtin_stdc_bit(unsigned int ui, void test_unimplemented_stdc_first(unsigned int x) { volatile unsigned int r; r = stdc_bit_ceil_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_bit_ceil_ui}} - r = stdc_bit_floor_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_bit_floor_ui}} (void)stdc_first_leading_zero_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_leading_zero_ui}} (void)stdc_first_leading_one_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_leading_one_ui}} (void)stdc_first_trailing_zero_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_trailing_zero_ui}} diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index a08832ac7c168..0fdbda47b145a 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -355,6 +355,83 @@ unsigned int test_stdc_bit_width(unsigned char uc, unsigned short us, // OGCG: sub i64 64, %{{.*}} // OGCG: trunc i64 %{{.*}} to i32 +void test_stdc_bit_floor(unsigned char uc, unsigned short us, unsigned int ui, + unsigned long ul, unsigned long long ull) { + volatile unsigned char ruc; + volatile unsigned short rus; + volatile unsigned int rui; + volatile unsigned long rul; + volatile unsigned long long rull; + ruc = __builtin_stdc_bit_floor(uc); + rus = __builtin_stdc_bit_floor(us); + rui = __builtin_stdc_bit_floor(ui); + rul = __builtin_stdc_bit_floor(ul); + rull = __builtin_stdc_bit_floor(ull); +} + +// CIR-LABEL: @test_stdc_bit_floor( +// CIR: cir.clz %{{.+}} poison_zero : !u8i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u8i +// CIR: cir.shift(left, %{{.+}} : !u8i, %{{.+}} : !u8i) -> !u8i +// CIR: cir.select +// CIR: cir.clz %{{.+}} poison_zero : !u16i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u16i +// CIR: cir.shift(left, %{{.+}} : !u16i, %{{.+}} : !u16i) -> !u16i +// CIR: cir.select +// CIR: cir.clz %{{.+}} poison_zero : !u32i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u32i +// CIR: cir.shift(left, %{{.+}} : !u32i, %{{.+}} : !u32i) -> !u32i +// CIR: cir.select +// CIR: cir.clz %{{.+}} poison_zero : !u64i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// CIR: cir.shift(left, %{{.+}} : !u64i, %{{.+}} : !u64i) -> !u64i +// CIR: cir.select +// CIR: cir.clz %{{.+}} poison_zero : !u64i +// CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// CIR: cir.shift(left, %{{.+}} : !u64i, %{{.+}} : !u64i) -> !u64i +// CIR: cir.select +// LLVM-LABEL: @test_stdc_bit_floor( +// LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 true) +// LLVM: sub i8 7, %{{.*}} +// LLVM: shl i8 1, %{{.*}} +// LLVM: select i1 %{{.*}}, i8 0, i8 %{{.*}} +// LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 true) +// LLVM: sub i16 15, %{{.*}} +// LLVM: shl i16 1, %{{.*}} +// LLVM: select i1 %{{.*}}, i16 0, i16 %{{.*}} +// LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 true) +// LLVM: sub i32 31, %{{.*}} +// LLVM: shl i32 1, %{{.*}} +// LLVM: select i1 %{{.*}}, i32 0, i32 %{{.*}} +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 true) +// LLVM: sub i64 63, %{{.*}} +// LLVM: shl i64 1, %{{.*}} +// LLVM: select i1 %{{.*}}, i64 0, i64 %{{.*}} +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 true) +// LLVM: sub i64 63, %{{.*}} +// LLVM: shl i64 1, %{{.*}} +// LLVM: select i1 %{{.*}}, i64 0, i64 %{{.*}} +// OGCG-LABEL: @test_stdc_bit_floor( +// OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 true) +// OGCG: sub i8 7, %{{.*}} +// OGCG: shl i8 1, %{{.*}} +// OGCG: select i1 %{{.*}}, i8 0, i8 %{{.*}} +// OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 true) +// OGCG: sub i16 15, %{{.*}} +// OGCG: shl i16 1, %{{.*}} +// OGCG: select i1 %{{.*}}, i16 0, i16 %{{.*}} +// OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 true) +// OGCG: sub i32 31, %{{.*}} +// OGCG: shl i32 1, %{{.*}} +// OGCG: select i1 %{{.*}}, i32 0, i32 %{{.*}} +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 true) +// OGCG: sub i64 63, %{{.*}} +// OGCG: shl i64 1, %{{.*}} +// OGCG: select i1 %{{.*}}, i64 0, i64 %{{.*}} +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 true) +// OGCG: sub i64 63, %{{.*}} +// OGCG: shl i64 1, %{{.*}} +// OGCG: select i1 %{{.*}}, i64 0, i64 %{{.*}} #else unsigned int test_stdc_trailing_ones_lib(unsigned char uc, unsigned short us, @@ -482,4 +559,40 @@ unsigned int test_stdc_bit_width_lib(unsigned char uc, unsigned short us, // LIB-CIR: cir.clz %{{.+}} : !u64i // LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +void test_stdc_bit_floor_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned char ruc; + volatile unsigned short rus; + volatile unsigned int rui; + volatile unsigned long rul; + volatile unsigned long long rull; + ruc = stdc_bit_floor_uc(uc); + rus = stdc_bit_floor_us(us); + rui = stdc_bit_floor_ui(ui); + rul = stdc_bit_floor_ul(ul); + rull = stdc_bit_floor_ull(ull); +} + +// LIB-CIR-LABEL: @test_stdc_bit_floor_lib( +// LIB-CIR: cir.clz %{{.+}} poison_zero : !u8i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u8i +// LIB-CIR: cir.shift(left, %{{.+}} : !u8i, %{{.+}} : !u8i) -> !u8i +// LIB-CIR: cir.select +// LIB-CIR: cir.clz %{{.+}} poison_zero : !u16i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u16i +// LIB-CIR: cir.shift(left, %{{.+}} : !u16i, %{{.+}} : !u16i) -> !u16i +// LIB-CIR: cir.select +// LIB-CIR: cir.clz %{{.+}} poison_zero : !u32i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u32i +// LIB-CIR: cir.shift(left, %{{.+}} : !u32i, %{{.+}} : !u32i) -> !u32i +// LIB-CIR: cir.select +// LIB-CIR: cir.clz %{{.+}} poison_zero : !u64i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// LIB-CIR: cir.shift(left, %{{.+}} : !u64i, %{{.+}} : !u64i) -> !u64i +// LIB-CIR: cir.select +// LIB-CIR: cir.clz %{{.+}} poison_zero : !u64i +// LIB-CIR: cir.sub %{{.+}}, %{{.+}} : !u64i +// LIB-CIR: cir.shift(left, %{{.+}} : !u64i, %{{.+}} : !u64i) -> !u64i +// LIB-CIR: cir.select #endif >From f6ba45b0b62d7b868a214d27922ce0e31b0d4138 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Thu, 13 Aug 2026 01:06:01 +0530 Subject: [PATCH 10/11] [CIR] Added missing spellings to test Added missing leading_zeros, trailing_zeros and count_zeros to the CIR test header, also added the checks for narrow and wide argument casts to previous tests. --- .../test/CIR/CodeGenBuiltins/Inputs/stdbit.h | 18 ++++ .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 97 +++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h index 0e39daf17aeb1..6b81015c498e9 100644 --- a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h +++ b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h @@ -1,12 +1,24 @@ #ifndef LLVM_CLANG_TEST_CIR_STDBIT_H #define LLVM_CLANG_TEST_CIR_STDBIT_H +unsigned int stdc_leading_zeros_uc(unsigned char); +unsigned int stdc_leading_zeros_us(unsigned short); +unsigned int stdc_leading_zeros_ui(unsigned int); +unsigned int stdc_leading_zeros_ul(unsigned long); +unsigned int stdc_leading_zeros_ull(unsigned long long); + unsigned int stdc_leading_ones_uc(unsigned char); unsigned int stdc_leading_ones_us(unsigned short); unsigned int stdc_leading_ones_ui(unsigned int); unsigned int stdc_leading_ones_ul(unsigned long); unsigned int stdc_leading_ones_ull(unsigned long long); +unsigned int stdc_trailing_zeros_uc(unsigned char); +unsigned int stdc_trailing_zeros_us(unsigned short); +unsigned int stdc_trailing_zeros_ui(unsigned int); +unsigned int stdc_trailing_zeros_ul(unsigned long); +unsigned int stdc_trailing_zeros_ull(unsigned long long); + unsigned int stdc_trailing_ones_uc(unsigned char); unsigned int stdc_trailing_ones_us(unsigned short); unsigned int stdc_trailing_ones_ui(unsigned int); @@ -19,6 +31,12 @@ unsigned int stdc_count_zeros_ui(unsigned int); unsigned int stdc_count_zeros_ul(unsigned long); unsigned int stdc_count_zeros_ull(unsigned long long); +unsigned int stdc_count_ones_uc(unsigned char); +unsigned int stdc_count_ones_us(unsigned short); +unsigned int stdc_count_ones_ui(unsigned int); +unsigned int stdc_count_ones_ul(unsigned long); +unsigned int stdc_count_ones_ull(unsigned long long); + _Bool stdc_has_single_bit_uc(unsigned char); _Bool stdc_has_single_bit_us(unsigned short); _Bool stdc_has_single_bit_ui(unsigned int); diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index 0fdbda47b145a..47783ae474b0a 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -32,16 +32,24 @@ void test_stdc_trailing_zeros(unsigned char uc, unsigned short us, // CIR: cir.ctz %{{.+}} : !u64i // LLVM-LABEL: @test_stdc_trailing_zeros( // LLVM: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// LLVM: zext i8 %{{.*}} to i32 // LLVM: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// LLVM: zext i16 %{{.*}} to i32 // LLVM: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) // LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 // LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 // OGCG-LABEL: @test_stdc_trailing_zeros( // OGCG: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// OGCG: zext i8 %{{.*}} to i32 // OGCG: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// OGCG: zext i16 %{{.*}} to i32 // OGCG: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) // OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 // OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 void test_stdc_trailing_ones(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, @@ -68,25 +76,33 @@ void test_stdc_trailing_ones(unsigned char uc, unsigned short us, // LLVM-LABEL: @test_stdc_trailing_ones( // LLVM: xor i8 %{{.*}}, -1 // LLVM: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// LLVM: zext i8 %{{.*}} to i32 // LLVM: xor i16 %{{.*}}, -1 // LLVM: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// LLVM: zext i16 %{{.*}} to i32 // LLVM: xor i32 %{{.*}}, -1 // LLVM: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) // LLVM: xor i64 %{{.*}}, -1 // LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 // LLVM: xor i64 %{{.*}}, -1 // LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 // OGCG-LABEL: @test_stdc_trailing_ones( // OGCG: xor i8 %{{.*}}, -1 // OGCG: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// OGCG: zext i8 %{{.*}} to i32 // OGCG: xor i16 %{{.*}}, -1 // OGCG: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// OGCG: zext i16 %{{.*}} to i32 // OGCG: xor i32 %{{.*}}, -1 // OGCG: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) // OGCG: xor i64 %{{.*}}, -1 // OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 // OGCG: xor i64 %{{.*}}, -1 // OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 unsigned int test_stdc_leading_zeros(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, @@ -108,16 +124,24 @@ unsigned int test_stdc_leading_zeros(unsigned char uc, unsigned short us, // CIR: cir.clz %{{.+}} : !u64i // LLVM-LABEL: @test_stdc_leading_zeros( // LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// LLVM: zext i8 %{{.*}} to i32 // LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// LLVM: zext i16 %{{.*}} to i32 // LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) // LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 // LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 // OGCG-LABEL: @test_stdc_leading_zeros( // OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// OGCG: zext i8 %{{.*}} to i32 // OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// OGCG: zext i16 %{{.*}} to i32 // OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) // OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 // OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 unsigned int test_stdc_leading_ones(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, @@ -145,25 +169,33 @@ unsigned int test_stdc_leading_ones(unsigned char uc, unsigned short us, // LLVM-LABEL: @test_stdc_leading_ones( // LLVM: xor i8 %{{.*}}, -1 // LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// LLVM: zext i8 %{{.*}} to i32 // LLVM: xor i16 %{{.*}}, -1 // LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// LLVM: zext i16 %{{.*}} to i32 // LLVM: xor i32 %{{.*}}, -1 // LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) // LLVM: xor i64 %{{.*}}, -1 // LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 // LLVM: xor i64 %{{.*}}, -1 // LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 // OGCG-LABEL: @test_stdc_leading_ones( // OGCG: xor i8 %{{.*}}, -1 // OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// OGCG: zext i8 %{{.*}} to i32 // OGCG: xor i16 %{{.*}}, -1 // OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// OGCG: zext i16 %{{.*}} to i32 // OGCG: xor i32 %{{.*}}, -1 // OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) // OGCG: xor i64 %{{.*}}, -1 // OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 // OGCG: xor i64 %{{.*}}, -1 // OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 unsigned int test_stdc_count_ones(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, @@ -281,25 +313,33 @@ unsigned int test_stdc_count_zeros(unsigned char uc, unsigned short us, // LLVM-LABEL: @test_stdc_count_zeros( // LLVM: call i8 @llvm.ctpop.i8(i8 %{{.*}}) // LLVM: sub i8 8, %{{.*}} +// LLVM: zext i8 %{{.*}} to i32 // LLVM: call i16 @llvm.ctpop.i16(i16 %{{.*}}) // LLVM: sub i16 16, %{{.*}} +// LLVM: zext i16 %{{.*}} to i32 // LLVM: call i32 @llvm.ctpop.i32(i32 %{{.*}}) // LLVM: sub i32 32, %{{.*}} // LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) // LLVM: sub i64 64, %{{.*}} +// LLVM: trunc i64 %{{.*}} to i32 // LLVM: call i64 @llvm.ctpop.i64(i64 %{{.*}}) // LLVM: sub i64 64, %{{.*}} +// LLVM: trunc i64 %{{.*}} to i32 // OGCG-LABEL: @test_stdc_count_zeros( // OGCG: call i8 @llvm.ctpop.i8(i8 %{{.*}}) // OGCG: sub i8 8, %{{.*}} +// OGCG: zext i8 %{{.*}} to i32 // OGCG: call i16 @llvm.ctpop.i16(i16 %{{.*}}) // OGCG: sub i16 16, %{{.*}} +// OGCG: zext i16 %{{.*}} to i32 // OGCG: call i32 @llvm.ctpop.i32(i32 %{{.*}}) // OGCG: sub i32 32, %{{.*}} // OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) // OGCG: sub i64 64, %{{.*}} +// OGCG: trunc i64 %{{.*}} to i32 // OGCG: call i64 @llvm.ctpop.i64(i64 %{{.*}}) // OGCG: sub i64 64, %{{.*}} +// OGCG: trunc i64 %{{.*}} to i32 unsigned int test_stdc_bit_width(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, @@ -434,6 +474,63 @@ void test_stdc_bit_floor(unsigned char uc, unsigned short us, unsigned int ui, // OGCG: select i1 %{{.*}}, i64 0, i64 %{{.*}} #else +unsigned int test_stdc_trailing_zeros_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_trailing_zeros_uc(uc); + r = stdc_trailing_zeros_us(us); + r = stdc_trailing_zeros_ui(ui); + r = stdc_trailing_zeros_ul(ul); + r = stdc_trailing_zeros_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_trailing_zeros_lib( +// LIB-CIR: cir.ctz %{{.+}} : !u8i +// LIB-CIR: cir.ctz %{{.+}} : !u16i +// LIB-CIR: cir.ctz %{{.+}} : !u32i +// LIB-CIR: cir.ctz %{{.+}} : !u64i +// LIB-CIR: cir.ctz %{{.+}} : !u64i + +unsigned int test_stdc_leading_zeros_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_leading_zeros_uc(uc); + r = stdc_leading_zeros_us(us); + r = stdc_leading_zeros_ui(ui); + r = stdc_leading_zeros_ul(ul); + r = stdc_leading_zeros_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_leading_zeros_lib( +// LIB-CIR: cir.clz %{{.+}} : !u8i +// LIB-CIR: cir.clz %{{.+}} : !u16i +// LIB-CIR: cir.clz %{{.+}} : !u32i +// LIB-CIR: cir.clz %{{.+}} : !u64i +// LIB-CIR: cir.clz %{{.+}} : !u64i + +unsigned int test_stdc_count_ones_lib(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_count_ones_uc(uc); + r = stdc_count_ones_us(us); + r = stdc_count_ones_ui(ui); + r = stdc_count_ones_ul(ul); + r = stdc_count_ones_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_count_ones_lib( +// LIB-CIR: cir.popcount %{{.+}} : !u8i +// LIB-CIR: cir.popcount %{{.+}} : !u16i +// LIB-CIR: cir.popcount %{{.+}} : !u32i +// LIB-CIR: cir.popcount %{{.+}} : !u64i +// LIB-CIR: cir.popcount %{{.+}} : !u64i + unsigned int test_stdc_trailing_ones_lib(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, unsigned long long ull) { >From 71dfe71e5c7dba0f1891dd037aed3a10cb127458 Mon Sep 17 00:00:00 2001 From: Kunal Dubey <[email protected]> Date: Thu, 13 Aug 2026 15:46:53 +0530 Subject: [PATCH 11/11] [CIR] Lowering for __builtin_stdc_first_* Added lowering for __builtin_stdc_first_* matching classic CodeGen shape of ctz and clz operations on arg and ~arg. Added tests for the same. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 39 ++- .../test/CIR/CodeGenBuiltins/Inputs/stdbit.h | 19 ++ .../CodeGenBuiltins/builtin-stdc-bit-nyi.c | 8 +- .../CIR/CodeGenBuiltins/builtin-stdc-bit.c | 320 ++++++++++++++++++ 4 files changed, 381 insertions(+), 5 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index d62d50415aa77..94309190b6069 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -138,6 +138,33 @@ static RValue errorBuiltinCallNYI(CIRGenFunction &cgf, const CallExpr *e, return cgf.getUndefRValue(e->getType()); } +template <typename Op, typename... Args> +static RValue emitStdcFirstBit(CIRGenFunction &cgf, const CallExpr *e, + bool invertArg, Args... args) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location loc = cgf.getLoc(e->getSourceRange()); + mlir::Value arg = cgf.emitScalarExpr(e->getArg(0)); + auto argTy = mlir::cast<cir::IntType>(arg.getType()); + if (!isStdcBitOpWidthSupported(argTy)) + return errorStdcBitOpWidthNYI(cgf, e); + + mlir::Value actualArg = invertArg ? builder.createNot(loc, arg) : arg; + mlir::Value count = Op::create(builder, loc, actualArg, args...).getResult(); + + mlir::Value zero = builder.getNullValue(argTy, loc); + mlir::Value one = builder.getConstInt(loc, argTy, 1); + mlir::Value countPlusOne = builder.createAdd(loc, count, one); + mlir::Value isZero = + builder.createCompare(loc, cir::CmpOpKind::eq, actualArg, zero); + mlir::Value result = builder.createSelect(loc, isZero, zero, countPlusOne); + + mlir::Type resultTy = cgf.convertType(e->getType()); + if (result.getType() != resultTy) + result = builder.createIntCast(result, resultTy); + + return RValue::get(result); +} + // stdc_{leading,trailing}_{zeros,ones} and stdc_count_ones: counts bits using // clz, ctz, or popcount. InvertArg flips the input to count the opposite bit // value. @@ -1430,25 +1457,35 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BIstdc_first_leading_zero_ul: case Builtin::BIstdc_first_leading_zero_ull: case Builtin::BI__builtin_stdc_first_leading_zero: + return emitStdcFirstBit<cir::BitClzOp>(*this, e, /*invertArg=*/true, + /*poisonZero=*/false); + case Builtin::BIstdc_first_leading_one_uc: case Builtin::BIstdc_first_leading_one_us: case Builtin::BIstdc_first_leading_one_ui: case Builtin::BIstdc_first_leading_one_ul: case Builtin::BIstdc_first_leading_one_ull: case Builtin::BI__builtin_stdc_first_leading_one: + return emitStdcFirstBit<cir::BitClzOp>(*this, e, /*invertArg=*/false, + /*poisonZero=*/false); + case Builtin::BIstdc_first_trailing_zero_uc: case Builtin::BIstdc_first_trailing_zero_us: case Builtin::BIstdc_first_trailing_zero_ui: case Builtin::BIstdc_first_trailing_zero_ul: case Builtin::BIstdc_first_trailing_zero_ull: case Builtin::BI__builtin_stdc_first_trailing_zero: + return emitStdcFirstBit<cir::BitCtzOp>(*this, e, /*invertArg=*/true, + /*poisonZero=*/false); + case Builtin::BIstdc_first_trailing_one_uc: case Builtin::BIstdc_first_trailing_one_us: case Builtin::BIstdc_first_trailing_one_ui: case Builtin::BIstdc_first_trailing_one_ul: case Builtin::BIstdc_first_trailing_one_ull: case Builtin::BI__builtin_stdc_first_trailing_one: - return errorBuiltinCallNYI(*this, e, builtinID); + return emitStdcFirstBit<cir::BitCtzOp>(*this, e, /*invertArg=*/false, + /*poisonZero=*/false); case Builtin::BIstdc_bit_ceil_uc: case Builtin::BIstdc_bit_ceil_us: diff --git a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h index 6b81015c498e9..d73c39daad8ff 100644 --- a/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h +++ b/clang/test/CIR/CodeGenBuiltins/Inputs/stdbit.h @@ -43,10 +43,29 @@ _Bool stdc_has_single_bit_ui(unsigned int); _Bool stdc_has_single_bit_ul(unsigned long); _Bool stdc_has_single_bit_ull(unsigned long long); +unsigned int stdc_first_leading_zero_uc(unsigned char); +unsigned int stdc_first_leading_zero_us(unsigned short); unsigned int stdc_first_leading_zero_ui(unsigned int); +unsigned int stdc_first_leading_zero_ul(unsigned long); +unsigned int stdc_first_leading_zero_ull(unsigned long long); + +unsigned int stdc_first_leading_one_uc(unsigned char); +unsigned int stdc_first_leading_one_us(unsigned short); unsigned int stdc_first_leading_one_ui(unsigned int); +unsigned int stdc_first_leading_one_ul(unsigned long); +unsigned int stdc_first_leading_one_ull(unsigned long long); + +unsigned int stdc_first_trailing_zero_uc(unsigned char); +unsigned int stdc_first_trailing_zero_us(unsigned short); unsigned int stdc_first_trailing_zero_ui(unsigned int); +unsigned int stdc_first_trailing_zero_ul(unsigned long); +unsigned int stdc_first_trailing_zero_ull(unsigned long long); + +unsigned int stdc_first_trailing_one_uc(unsigned char); +unsigned int stdc_first_trailing_one_us(unsigned short); unsigned int stdc_first_trailing_one_ui(unsigned int); +unsigned int stdc_first_trailing_one_ul(unsigned long); +unsigned int stdc_first_trailing_one_ull(unsigned long long); unsigned int stdc_bit_width_uc(unsigned char); unsigned int stdc_bit_width_us(unsigned short); diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c index 34cd7ae103de7..dfb5366196244 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c @@ -15,6 +15,10 @@ void test_unimplemented_builtin_stdc_bit(unsigned int ui, (void)__builtin_stdc_count_zeros(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} (void)__builtin_stdc_has_single_bit(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} (void)__builtin_stdc_bit_floor(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} + (void)__builtin_stdc_first_leading_zero(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} + (void)__builtin_stdc_first_leading_one(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} + (void)__builtin_stdc_first_trailing_zero(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} + (void)__builtin_stdc_first_trailing_one(bi); // expected-error {{ClangIR code gen Not Yet Implemented: stdc bit builtin with unsupported argument integer width}} } #else @@ -22,10 +26,6 @@ void test_unimplemented_builtin_stdc_bit(unsigned int ui, void test_unimplemented_stdc_first(unsigned int x) { volatile unsigned int r; r = stdc_bit_ceil_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_bit_ceil_ui}} - (void)stdc_first_leading_zero_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_leading_zero_ui}} - (void)stdc_first_leading_one_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_leading_one_ui}} - (void)stdc_first_trailing_zero_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_trailing_zero_ui}} - (void)stdc_first_trailing_one_ui(x); // expected-error {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: stdc_first_trailing_one_ui}} } #endif diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c index 47783ae474b0a..22402a7290ec9 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c +++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit.c @@ -395,6 +395,212 @@ unsigned int test_stdc_bit_width(unsigned char uc, unsigned short us, // OGCG: sub i64 64, %{{.*}} // OGCG: trunc i64 %{{.*}} to i32 +unsigned int test_stdc_first_leading_zero(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_first_leading_zero(uc); + r = __builtin_stdc_first_leading_zero(us); + r = __builtin_stdc_first_leading_zero(ui); + r = __builtin_stdc_first_leading_zero(ul); + r = __builtin_stdc_first_leading_zero(ull); + return r; +} + +// CIR-LABEL: @test_stdc_first_leading_zero( +// CIR: cir.not %{{.+}} : !u8i +// CIR: cir.clz %{{.+}} : !u8i +// CIR: cir.select +// CIR: cir.not %{{.+}} : !u16i +// CIR: cir.clz %{{.+}} : !u16i +// CIR: cir.select +// CIR: cir.not %{{.+}} : !u32i +// CIR: cir.clz %{{.+}} : !u32i +// CIR: cir.select +// CIR: cir.not %{{.+}} : !u64i +// CIR: cir.clz %{{.+}} : !u64i +// CIR: cir.select +// CIR: cir.not %{{.+}} : !u64i +// CIR: cir.clz %{{.+}} : !u64i +// CIR: cir.select +// LLVM-LABEL: @test_stdc_first_leading_zero( +// LLVM: xor i8 %{{.*}}, -1 +// LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// LLVM: zext i8 %{{.*}} to i32 +// LLVM: xor i16 %{{.*}}, -1 +// LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// LLVM: zext i16 %{{.*}} to i32 +// LLVM: xor i32 %{{.*}}, -1 +// LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// LLVM: xor i64 %{{.*}}, -1 +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 +// LLVM: xor i64 %{{.*}}, -1 +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 +// OGCG-LABEL: @test_stdc_first_leading_zero( +// OGCG: xor i8 %{{.*}}, -1 +// OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// OGCG: zext i8 %{{.*}} to i32 +// OGCG: xor i16 %{{.*}}, -1 +// OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// OGCG: zext i16 %{{.*}} to i32 +// OGCG: xor i32 %{{.*}}, -1 +// OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// OGCG: xor i64 %{{.*}}, -1 +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 +// OGCG: xor i64 %{{.*}}, -1 +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 + +unsigned int test_stdc_first_leading_one(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_first_leading_one(uc); + r = __builtin_stdc_first_leading_one(us); + r = __builtin_stdc_first_leading_one(ui); + r = __builtin_stdc_first_leading_one(ul); + r = __builtin_stdc_first_leading_one(ull); + return r; +} + +// CIR-LABEL: @test_stdc_first_leading_one( +// CIR: cir.clz %{{.+}} : !u8i +// CIR: cir.select +// CIR: cir.clz %{{.+}} : !u16i +// CIR: cir.select +// CIR: cir.clz %{{.+}} : !u32i +// CIR: cir.select +// CIR: cir.clz %{{.+}} : !u64i +// CIR: cir.select +// CIR: cir.clz %{{.+}} : !u64i +// CIR: cir.select +// LLVM-LABEL: @test_stdc_first_leading_one( +// LLVM: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// LLVM: zext i8 %{{.*}} to i32 +// LLVM: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// LLVM: zext i16 %{{.*}} to i32 +// LLVM: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 +// LLVM: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 +// OGCG-LABEL: @test_stdc_first_leading_one( +// OGCG: call i8 @llvm.ctlz.i8(i8 %{{.*}}, i1 false) +// OGCG: zext i8 %{{.*}} to i32 +// OGCG: call i16 @llvm.ctlz.i16(i16 %{{.*}}, i1 false) +// OGCG: zext i16 %{{.*}} to i32 +// OGCG: call i32 @llvm.ctlz.i32(i32 %{{.*}}, i1 false) +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 +// OGCG: call i64 @llvm.ctlz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 + +unsigned int test_stdc_first_trailing_zero(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_first_trailing_zero(uc); + r = __builtin_stdc_first_trailing_zero(us); + r = __builtin_stdc_first_trailing_zero(ui); + r = __builtin_stdc_first_trailing_zero(ul); + r = __builtin_stdc_first_trailing_zero(ull); + return r; +} + +// CIR-LABEL: @test_stdc_first_trailing_zero( +// CIR: cir.not %{{.+}} : !u8i +// CIR: cir.ctz %{{.+}} : !u8i +// CIR: cir.select +// CIR: cir.not %{{.+}} : !u16i +// CIR: cir.ctz %{{.+}} : !u16i +// CIR: cir.select +// CIR: cir.not %{{.+}} : !u32i +// CIR: cir.ctz %{{.+}} : !u32i +// CIR: cir.select +// CIR: cir.not %{{.+}} : !u64i +// CIR: cir.ctz %{{.+}} : !u64i +// CIR: cir.select +// CIR: cir.not %{{.+}} : !u64i +// CIR: cir.ctz %{{.+}} : !u64i +// CIR: cir.select +// LLVM-LABEL: @test_stdc_first_trailing_zero( +// LLVM: xor i8 %{{.*}}, -1 +// LLVM: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// LLVM: zext i8 %{{.*}} to i32 +// LLVM: xor i16 %{{.*}}, -1 +// LLVM: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// LLVM: zext i16 %{{.*}} to i32 +// LLVM: xor i32 %{{.*}}, -1 +// LLVM: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +// LLVM: xor i64 %{{.*}}, -1 +// LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 +// LLVM: xor i64 %{{.*}}, -1 +// LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 +// OGCG-LABEL: @test_stdc_first_trailing_zero( +// OGCG: xor i8 %{{.*}}, -1 +// OGCG: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// OGCG: zext i8 %{{.*}} to i32 +// OGCG: xor i16 %{{.*}}, -1 +// OGCG: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// OGCG: zext i16 %{{.*}} to i32 +// OGCG: xor i32 %{{.*}}, -1 +// OGCG: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +// OGCG: xor i64 %{{.*}}, -1 +// OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 +// OGCG: xor i64 %{{.*}}, -1 +// OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 + +unsigned int test_stdc_first_trailing_one(unsigned char uc, unsigned short us, + unsigned int ui, unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = __builtin_stdc_first_trailing_one(uc); + r = __builtin_stdc_first_trailing_one(us); + r = __builtin_stdc_first_trailing_one(ui); + r = __builtin_stdc_first_trailing_one(ul); + r = __builtin_stdc_first_trailing_one(ull); + return r; +} + +// CIR-LABEL: @test_stdc_first_trailing_one( +// CIR: cir.ctz %{{.+}} : !u8i +// CIR: cir.select +// CIR: cir.ctz %{{.+}} : !u16i +// CIR: cir.select +// CIR: cir.ctz %{{.+}} : !u32i +// CIR: cir.select +// CIR: cir.ctz %{{.+}} : !u64i +// CIR: cir.select +// CIR: cir.ctz %{{.+}} : !u64i +// CIR: cir.select +// LLVM-LABEL: @test_stdc_first_trailing_one( +// LLVM: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// LLVM: zext i8 %{{.*}} to i32 +// LLVM: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// LLVM: zext i16 %{{.*}} to i32 +// LLVM: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +// LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 +// LLVM: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// LLVM: trunc i64 %{{.*}} to i32 +// OGCG-LABEL: @test_stdc_first_trailing_one( +// OGCG: call i8 @llvm.cttz.i8(i8 %{{.*}}, i1 false) +// OGCG: zext i8 %{{.*}} to i32 +// OGCG: call i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +// OGCG: zext i16 %{{.*}} to i32 +// OGCG: call i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +// OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 +// OGCG: call i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +// OGCG: trunc i64 %{{.*}} to i32 + void test_stdc_bit_floor(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, unsigned long long ull) { volatile unsigned char ruc; @@ -579,6 +785,120 @@ unsigned int test_stdc_leading_ones_lib(unsigned char uc, unsigned short us, // LIB-CIR: cir.not %{{.+}} : !u64i // LIB-CIR: cir.clz %{{.+}} : !u64i +unsigned int test_stdc_first_leading_zero_lib(unsigned char uc, + unsigned short us, + unsigned int ui, + unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_first_leading_zero_uc(uc); + r = stdc_first_leading_zero_us(us); + r = stdc_first_leading_zero_ui(ui); + r = stdc_first_leading_zero_ul(ul); + r = stdc_first_leading_zero_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_first_leading_zero_lib( +// LIB-CIR: cir.not %{{.+}} : !u8i +// LIB-CIR: cir.clz %{{.+}} : !u8i +// LIB-CIR: cir.select +// LIB-CIR: cir.not %{{.+}} : !u16i +// LIB-CIR: cir.clz %{{.+}} : !u16i +// LIB-CIR: cir.select +// LIB-CIR: cir.not %{{.+}} : !u32i +// LIB-CIR: cir.clz %{{.+}} : !u32i +// LIB-CIR: cir.select +// LIB-CIR: cir.not %{{.+}} : !u64i +// LIB-CIR: cir.clz %{{.+}} : !u64i +// LIB-CIR: cir.select +// LIB-CIR: cir.not %{{.+}} : !u64i +// LIB-CIR: cir.clz %{{.+}} : !u64i +// LIB-CIR: cir.select + +unsigned int test_stdc_first_leading_one_lib(unsigned char uc, + unsigned short us, + unsigned int ui, + unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_first_leading_one_uc(uc); + r = stdc_first_leading_one_us(us); + r = stdc_first_leading_one_ui(ui); + r = stdc_first_leading_one_ul(ul); + r = stdc_first_leading_one_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_first_leading_one_lib( +// LIB-CIR: cir.clz %{{.+}} : !u8i +// LIB-CIR: cir.select +// LIB-CIR: cir.clz %{{.+}} : !u16i +// LIB-CIR: cir.select +// LIB-CIR: cir.clz %{{.+}} : !u32i +// LIB-CIR: cir.select +// LIB-CIR: cir.clz %{{.+}} : !u64i +// LIB-CIR: cir.select +// LIB-CIR: cir.clz %{{.+}} : !u64i +// LIB-CIR: cir.select + +unsigned int test_stdc_first_trailing_zero_lib(unsigned char uc, + unsigned short us, + unsigned int ui, + unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_first_trailing_zero_uc(uc); + r = stdc_first_trailing_zero_us(us); + r = stdc_first_trailing_zero_ui(ui); + r = stdc_first_trailing_zero_ul(ul); + r = stdc_first_trailing_zero_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_first_trailing_zero_lib( +// LIB-CIR: cir.not %{{.+}} : !u8i +// LIB-CIR: cir.ctz %{{.+}} : !u8i +// LIB-CIR: cir.select +// LIB-CIR: cir.not %{{.+}} : !u16i +// LIB-CIR: cir.ctz %{{.+}} : !u16i +// LIB-CIR: cir.select +// LIB-CIR: cir.not %{{.+}} : !u32i +// LIB-CIR: cir.ctz %{{.+}} : !u32i +// LIB-CIR: cir.select +// LIB-CIR: cir.not %{{.+}} : !u64i +// LIB-CIR: cir.ctz %{{.+}} : !u64i +// LIB-CIR: cir.select +// LIB-CIR: cir.not %{{.+}} : !u64i +// LIB-CIR: cir.ctz %{{.+}} : !u64i +// LIB-CIR: cir.select + +unsigned int test_stdc_first_trailing_one_lib(unsigned char uc, + unsigned short us, + unsigned int ui, + unsigned long ul, + unsigned long long ull) { + volatile unsigned int r; + r = stdc_first_trailing_one_uc(uc); + r = stdc_first_trailing_one_us(us); + r = stdc_first_trailing_one_ui(ui); + r = stdc_first_trailing_one_ul(ul); + r = stdc_first_trailing_one_ull(ull); + return r; +} + +// LIB-CIR-LABEL: @test_stdc_first_trailing_one_lib( +// LIB-CIR: cir.ctz %{{.+}} : !u8i +// LIB-CIR: cir.select +// LIB-CIR: cir.ctz %{{.+}} : !u16i +// LIB-CIR: cir.select +// LIB-CIR: cir.ctz %{{.+}} : !u32i +// LIB-CIR: cir.select +// LIB-CIR: cir.ctz %{{.+}} : !u64i +// LIB-CIR: cir.select +// LIB-CIR: cir.ctz %{{.+}} : !u64i +// LIB-CIR: cir.select + _Bool test_stdc_has_single_bit_lib(unsigned char uc, unsigned short us, unsigned int ui, unsigned long ul, unsigned long long ull) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
