[clang] [CIR] Avoid folding non-integer constants as integer casts (PR #214551)
Kunal Dubey via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 6 18:09:44 PDT 2026
https://github.com/xakep8 updated https://github.com/llvm/llvm-project/pull/214551
>From 154c3e1c5ddba2b65bfa247a0996c329d4ddad2f Mon Sep 17 00:00:00 2001
From: Kunal Dubey <xakep8 at protonmail.com>
Date: Fri, 7 Aug 2026 00:30:05 +0530
Subject: [PATCH 1/2] [CIR] Avoid folding non-integer constants as integer
casts
CIRGen may produce undef constants while recovering from NYI builtin lowering. When such a value feeds an implicit integral cast, CastOp::fold currently treats the source as an integer constant solely because it is a cir.constant, then calls getIntValue() and crashes.
Added a check for the constant to see if the payload is actually an IntAttr before folding the cast. If it is not, return the cast unfolded.
Added a regression test covering an unimplemented __builtin_stdc_* call whose undef result was implicitly being cast to integer by CastOp::fold.
---
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 9 +++++++--
clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c | 7 +++++++
2 files changed, 14 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index cd94219655e02..ca4d14f61cacd 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1013,10 +1013,15 @@ OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {
auto srcIntTy = mlir::cast<cir::IntType>(srcTy);
auto dstIntTy = mlir::cast<cir::IntType>(getType());
+ auto constIntAttr = srcConst.getValueAttr<cir::IntAttr>();
+ if (!constIntAttr)
+ return {};
+
+ APInt srcValue = constIntAttr.getValue();
APInt newVal =
srcIntTy.isSigned()
- ? srcConst.getIntValue().sextOrTrunc(dstIntTy.getWidth())
- : srcConst.getIntValue().zextOrTrunc(dstIntTy.getWidth());
+ ? srcValue.sextOrTrunc(dstIntTy.getWidth())
+ : srcValue.zextOrTrunc(dstIntTy.getWidth());
return cir::IntAttr::get(dstIntTy, newVal);
}
default:
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..e74f295aa6931
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -verify %s -o -
+
+void test_stdc_trailing_zeros_undef_cast(unsigned long long x) {
+ // expected-error at +1 {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: __builtin_stdc_trailing_zeros}}
+ int cnt = __builtin_stdc_trailing_zeros(x);
+ (void)cnt;
+}
>From 8fd1fd2ee5b51a6efc00f8d9898eeb2078061d17 Mon Sep 17 00:00:00 2001
From: Kunal Dubey <xakep8 at protonmail.com>
Date: Fri, 7 Aug 2026 06:35:10 +0530
Subject: [PATCH 2/2] [CIR] Propogate UndefAttr through CastOp::fold
Propogates UndefAtrr similar to Poison propogation, keeping the IntAttr
guard in place.
---
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 11 +++++++----
clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c | 5 ++++-
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index ca4d14f61cacd..2e812ba61876b 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -975,6 +975,10 @@ OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {
return cir::PoisonAttr::get(getContext(), getType());
}
+ // Propogate Undef value
+ if (mlir::isa_and_present<cir::UndefAttr>(adaptor.getSrc()))
+ return cir::UndefAttr::get(getType());
+
if (getSrc().getType() == getType()) {
switch (getKind()) {
case cir::CastKind::integral: {
@@ -1018,10 +1022,9 @@ OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {
return {};
APInt srcValue = constIntAttr.getValue();
- APInt newVal =
- srcIntTy.isSigned()
- ? srcValue.sextOrTrunc(dstIntTy.getWidth())
- : srcValue.zextOrTrunc(dstIntTy.getWidth());
+ APInt newVal = srcIntTy.isSigned()
+ ? srcValue.sextOrTrunc(dstIntTy.getWidth())
+ : srcValue.zextOrTrunc(dstIntTy.getWidth());
return cir::IntAttr::get(dstIntTy, newVal);
}
default:
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c
index e74f295aa6931..2d0894da0bdbf 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-stdc-bit-nyi.c
@@ -1,7 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -verify %s -o -
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -verify %s -o - | FileCheck %s
void test_stdc_trailing_zeros_undef_cast(unsigned long long x) {
// expected-error at +1 {{ClangIR code gen Not Yet Implemented: unimplemented builtin call: __builtin_stdc_trailing_zeros}}
int cnt = __builtin_stdc_trailing_zeros(x);
(void)cnt;
}
+
+// CHECK-LABEL: test_stdc_trailing_zeros_undef_cast
+// CHECK: cir.const #cir.undef : !s32i
More information about the cfe-commits
mailing list