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
