https://github.com/adams381 updated 
https://github.com/llvm/llvm-project/pull/205880

>From 6cf785c70e5d122e9391beee8e3be4c3f2a08df1 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Thu, 25 Jun 2026 10:57:07 -0700
Subject: [PATCH 1/2] [CIR] Load enums with a boolean underlying type

emitLoadOfScalar reported NYI for any scalar whose type has a boolean
representation but isn't the builtin bool. The types that reach this point
are an enum with a fixed bool underlying type and _BitInt(1); both convert to
the same literal CIR type as bool / _BitInt(N) (!cir.bool and !cir.int<1>),
and convertTypeForMem does not widen them. CIR
keeps these in their literal type through CIRGen and defers the in-memory
integer widening to LowerToLLVM, so the loaded value is already correct and
no register/memory conversion is needed at this point. The errorNYI also left
the function's entry block without a terminator, which then failed CIR module
verification.

Drop the over-conservative errorNYI and return the loaded value, matching the
existing emitToMemory deferral. This lets enum-with-bool-underlying loads
(and _BitInt(1) loads) compile; it does not change the in-memory
representation, which LowerToLLVM still owns.
---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp |  7 ++--
 clang/test/CIR/CodeGen/enum-bool.cpp | 50 ++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/enum-bool.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index fa14b45cbb015..9b9811f7c4cb1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -769,9 +769,12 @@ mlir::Value CIRGenFunction::emitLoadOfScalar(Address addr, 
bool isVolatile,
 
   mlir::Value loadOp =
       builder.createLoad(getLoc(loc), addr, isVolatile, isNontemporal);
-  if (!ty->isBooleanType() && ty->hasBooleanRepresentation())
-    cgm.errorNYI("emitLoadOfScalar: boolean type with boolean representation");
 
+  // Types with a boolean representation that are not the builtin bool (an enum
+  // whose underlying type is bool, or a _BitInt(1)) need no register/memory
+  // conversion here: like bool and _BitInt(N), CIR keeps them in their literal
+  // type until LowerToLLVM widens them to the in-memory integer type (see
+  // emitToMemory).
   return loadOp;
 }
 
diff --git a/clang/test/CIR/CodeGen/enum-bool.cpp 
b/clang/test/CIR/CodeGen/enum-bool.cpp
new file mode 100644
index 0000000000000..3dfb4966627a6
--- /dev/null
+++ b/clang/test/CIR/CodeGen/enum-bool.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s 
-o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+enum BoolEnum : bool { False, True };
+
+BoolEnum loadEnum(BoolEnum *p) { return *p; }
+
+// CIR-LABEL: cir.func{{.*}} @_Z8loadEnumP8BoolEnum(%arg0: !cir.ptr<!cir.bool>
+// CIR-SAME:    -> (!cir.bool
+// CIR:         %[[P:.*]] = cir.alloca {{.*}} : !cir.ptr<!cir.ptr<!cir.bool>>
+// CIR:         %[[PV:.*]] = cir.load deref {{.*}}%[[P]] : 
!cir.ptr<!cir.ptr<!cir.bool>>, !cir.ptr<!cir.bool>
+// CIR:         %[[V:.*]] = cir.load {{.*}}%[[PV]] : !cir.ptr<!cir.bool>, 
!cir.bool
+// CIR:         cir.return
+
+// LLVM-LABEL: define dso_local noundef i1 @_Z8loadEnumP8BoolEnum(ptr noundef 
%0)
+// LLVM:         %[[PTR:.*]] = load ptr, ptr
+// LLVM:         %[[MEM:.*]] = load i8, ptr %[[PTR]], align 1
+// LLVM:         %[[BOOL:.*]] = trunc i8 %[[MEM]] to i1
+
+// OGCG-LABEL: define dso_local noundef zeroext i1 @_Z8loadEnumP8BoolEnum(ptr 
noundef %p)
+// OGCG:         %[[MEM:.*]] = load i8, ptr {{.*}}, align 1
+// OGCG:         %[[BOOL:.*]] = icmp ne i8 %[[MEM]], 0
+// OGCG:         ret i1 %[[BOOL]]
+
+void storeEnum(BoolEnum *p, BoolEnum v) { *p = v; }
+
+// CIR-LABEL: cir.func{{.*}} @_Z9storeEnumP8BoolEnumS_(%arg0: 
!cir.ptr<!cir.bool>
+// CIR-SAME:    %arg1: !cir.bool
+// CIR:         %[[V:.*]] = cir.load {{.*}} : !cir.ptr<!cir.bool>, !cir.bool
+// CIR:         %[[P:.*]] = cir.load deref {{.*}} : 
!cir.ptr<!cir.ptr<!cir.bool>>, !cir.ptr<!cir.bool>
+// CIR:         cir.store {{.*}}%[[V]], %[[P]] : !cir.bool, !cir.ptr<!cir.bool>
+
+// LLVM-LABEL: define dso_local void @_Z9storeEnumP8BoolEnumS_(ptr noundef %0, 
i1 noundef %1)
+// LLVM:         %[[Z:.*]] = zext i1 %1 to i8
+// LLVM:         store i8 %[[Z]], ptr
+// LLVM:         %[[LD:.*]] = load i8, ptr
+// LLVM:         %[[TR:.*]] = trunc i8 %[[LD]] to i1
+// LLVM:         %[[ZB:.*]] = zext i1 %[[TR]] to i8
+// LLVM:         store i8 %[[ZB]], ptr
+
+// OGCG-LABEL: define dso_local void @_Z9storeEnumP8BoolEnumS_(ptr noundef %p, 
i1 noundef zeroext %v)
+// OGCG:         %[[SV:.*]] = zext i1 %v to i8
+// OGCG:         store i8 %[[SV]], ptr %v.addr
+// OGCG:         %[[LV:.*]] = icmp ne i8 {{.*}}, 0
+// OGCG:         %[[SV1:.*]] = zext i1 %[[LV]] to i8
+// OGCG:         store i8 %[[SV1]], ptr

>From f35bc039da1800d11e523137d72fbbf07f6f06dd Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Fri, 26 Jun 2026 13:02:46 -0700
Subject: [PATCH 2/2] [CIR] Combine LLVM/OGCG checks in enum-bool.cpp

Combine the separate LLVM and OGCG FileCheck prefixes in enum-bool.cpp
into a single LLVM prefix over the lines that match in both emits (the
i8 memory loads/stores and the i1 signature/return), and replace the
hard-coded value names with wildcards.

The CIR-lowered and classic emits still differ in ways unrelated to this
test: CIR drops the zeroext on the i1 return/parameter and narrows i8 to
i1 with trunc where classic uses icmp ne.  Those are pre-existing
bool-lowering differences, not specific to an enum with a bool underlying
type, so the incidental lines are left unchecked here rather than pinned
as a split.
---
 clang/test/CIR/CodeGen/enum-bool.cpp | 33 ++++++++--------------------
 1 file changed, 9 insertions(+), 24 deletions(-)

diff --git a/clang/test/CIR/CodeGen/enum-bool.cpp 
b/clang/test/CIR/CodeGen/enum-bool.cpp
index 3dfb4966627a6..c8a7a0c1ebb79 100644
--- a/clang/test/CIR/CodeGen/enum-bool.cpp
+++ b/clang/test/CIR/CodeGen/enum-bool.cpp
@@ -3,7 +3,7 @@
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-llvm %s -o %t-cir.ll
 // RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s 
-o %t.ll
-// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
 
 enum BoolEnum : bool { False, True };
 
@@ -16,15 +16,9 @@ BoolEnum loadEnum(BoolEnum *p) { return *p; }
 // CIR:         %[[V:.*]] = cir.load {{.*}}%[[PV]] : !cir.ptr<!cir.bool>, 
!cir.bool
 // CIR:         cir.return
 
-// LLVM-LABEL: define dso_local noundef i1 @_Z8loadEnumP8BoolEnum(ptr noundef 
%0)
-// LLVM:         %[[PTR:.*]] = load ptr, ptr
-// LLVM:         %[[MEM:.*]] = load i8, ptr %[[PTR]], align 1
-// LLVM:         %[[BOOL:.*]] = trunc i8 %[[MEM]] to i1
-
-// OGCG-LABEL: define dso_local noundef zeroext i1 @_Z8loadEnumP8BoolEnum(ptr 
noundef %p)
-// OGCG:         %[[MEM:.*]] = load i8, ptr {{.*}}, align 1
-// OGCG:         %[[BOOL:.*]] = icmp ne i8 %[[MEM]], 0
-// OGCG:         ret i1 %[[BOOL]]
+// LLVM-LABEL: define dso_local noundef {{(zeroext )?}}i1 
@_Z8loadEnumP8BoolEnum(ptr noundef %{{.*}})
+// LLVM:         load i8, ptr %{{.*}}, align 1
+// LLVM:         ret i1 %{{.*}}
 
 void storeEnum(BoolEnum *p, BoolEnum v) { *p = v; }
 
@@ -34,17 +28,8 @@ void storeEnum(BoolEnum *p, BoolEnum v) { *p = v; }
 // CIR:         %[[P:.*]] = cir.load deref {{.*}} : 
!cir.ptr<!cir.ptr<!cir.bool>>, !cir.ptr<!cir.bool>
 // CIR:         cir.store {{.*}}%[[V]], %[[P]] : !cir.bool, !cir.ptr<!cir.bool>
 
-// LLVM-LABEL: define dso_local void @_Z9storeEnumP8BoolEnumS_(ptr noundef %0, 
i1 noundef %1)
-// LLVM:         %[[Z:.*]] = zext i1 %1 to i8
-// LLVM:         store i8 %[[Z]], ptr
-// LLVM:         %[[LD:.*]] = load i8, ptr
-// LLVM:         %[[TR:.*]] = trunc i8 %[[LD]] to i1
-// LLVM:         %[[ZB:.*]] = zext i1 %[[TR]] to i8
-// LLVM:         store i8 %[[ZB]], ptr
-
-// OGCG-LABEL: define dso_local void @_Z9storeEnumP8BoolEnumS_(ptr noundef %p, 
i1 noundef zeroext %v)
-// OGCG:         %[[SV:.*]] = zext i1 %v to i8
-// OGCG:         store i8 %[[SV]], ptr %v.addr
-// OGCG:         %[[LV:.*]] = icmp ne i8 {{.*}}, 0
-// OGCG:         %[[SV1:.*]] = zext i1 %[[LV]] to i8
-// OGCG:         store i8 %[[SV1]], ptr
+// LLVM-LABEL: define dso_local void @_Z9storeEnumP8BoolEnumS_(ptr noundef 
%{{.*}}, i1 noundef {{(zeroext )?}}%{{.*}})
+// LLVM:         zext i1 %{{.*}} to i8
+// LLVM:         store i8 %{{.*}}, ptr %{{.*}}, align 1
+// LLVM:         load i8, ptr %{{.*}}, align 1
+// LLVM:         store i8 %{{.*}}, ptr %{{.*}}, align 1

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to