[llvm-branch-commits] [clang] [CIR] Propagate initializer type adjustment failures (PR #224238)
Akimasa Watanuki via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Sep 17 02:13:17 PDT 2026
https://github.com/Men-cotton created https://github.com/llvm/llvm-project/pull/224238
Reject initializers whose active members have no LLVM representation, including when an enclosing union's storage type is convertible. Propagate recursive adjustment failures before querying data layout or constructing LLVM operations.
Assisted-by: Codex / GPT-6
>From b436b44227033e405b8e4c63080f0c18adcefbb1 Mon Sep 17 00:00:00 2001
From: mencotton <mencotton0410 at gmail.com>
Date: Tue, 15 Sep 2026 20:49:43 +0900
Subject: [PATCH] [CIR] Propagate initializer type adjustment failures
Reject initializers whose active members have no LLVM representation, including when an enclosing union's storage type is convertible. Propagate recursive adjustment failures before querying data layout or constructing LLVM operations.
Assisted-by: Codex / GPT-6
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +-
clang/include/clang/CIR/LoweringHelpers.h | 3 +-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 15 ++++-
clang/lib/CIR/Lowering/LoweringHelpers.cpp | 12 ++++
.../unsupported-initializer-types.cir | 66 +++++++++++++++++++
5 files changed, 94 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CIR/Lowering/unsupported-initializer-types.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index c5a836a0c2f03..0d28480152c54 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3476,7 +3476,7 @@ def CIR_GlobalOp : CIR_RegionBranchOpBase<"global", [
cir::GlobalOp op, mlir::Attribute init,
mlir::ConversionPatternRewriter &rewriter) const;
- void setupRegionInitializedLLVMGlobalOp(
+ mlir::LogicalResult setupRegionInitializedLLVMGlobalOp(
cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const;
llvm::SmallVector<mlir::NamedAttribute> lowerGlobalAttributes(
diff --git a/clang/include/clang/CIR/LoweringHelpers.h b/clang/include/clang/CIR/LoweringHelpers.h
index fe61db3fc5d25..a779eb2814166 100644
--- a/clang/include/clang/CIR/LoweringHelpers.h
+++ b/clang/include/clang/CIR/LoweringHelpers.h
@@ -49,7 +49,8 @@ std::optional<mlir::Attribute> lowerConstRecordAttr(
/// \p llvmType unchanged when no adjustment is needed. This is the single
/// source of truth for the shape of a lowered record constant; the
/// value-producing paths (the insertvalue visitor and lowerConstRecordAttr)
-/// conform to it.
+/// conform to it. Returns null if the input type or an initializer type cannot
+/// be lowered.
mlir::Type adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
const mlir::TypeConverter &converter,
const mlir::DataLayout &dataLayout);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6280b853d6e79..8b1053ae86503 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -762,6 +762,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) {
mlir::Type llvmTy = converter->convertType(attr.getType());
mlir::DataLayout dataLayout(parentOp->getParentOfType<mlir::ModuleOp>());
llvmTy = adjustGlobalTypeForInit(llvmTy, attr, *converter, dataLayout);
+ if (!llvmTy)
+ return {};
mlir::Location loc = parentOp->getLoc();
mlir::Value result;
@@ -811,6 +813,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstRecordAttr constRecord) {
llvm::SmallVector<unsigned> paddingAddedIndexes;
llvmTy = adjustGlobalTypeForInit(llvmTy, constRecord, *converter, dataLayout,
paddingAddedIndexes);
+ if (!llvmTy)
+ return {};
const mlir::Location loc = parentOp->getLoc();
mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy);
@@ -2962,7 +2966,8 @@ convertTlsModelAttrToLLVM(TLSModelAttr attr) {
/// Replace CIR global with a region initialized LLVM global and update
/// insertion point to the end of the initializer block.
-void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
+mlir::LogicalResult
+CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {
mlir::Type llvmType =
convertTypeForMemory(*getTypeConverter(), dataLayout, op.getSymType());
@@ -2972,6 +2977,8 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
if (std::optional<mlir::Attribute> init = op.getInitialValue())
llvmType = adjustGlobalTypeForInit(llvmType, *init, *getTypeConverter(),
dataLayout);
+ if (!llvmType)
+ return mlir::failure();
// FIXME: These default values are placeholders until the the equivalent
// attributes are available on cir.global ops. This duplicates code
@@ -2999,6 +3006,7 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
isDsoLocal, threadLocalMode, comdatAttr, attributes);
newGlobalOp.getRegion().emplaceBlock();
rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());
+ return mlir::success();
}
mlir::LogicalResult
@@ -3016,7 +3024,8 @@ CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(
// should be updated. For now, we use a custom op to initialize globals
// to the appropriate value.
const mlir::Location loc = op.getLoc();
- setupRegionInitializedLLVMGlobalOp(op, rewriter);
+ if (failed(setupRegionInitializedLLVMGlobalOp(op, rewriter)))
+ return mlir::failure();
// Pass blockInfoAddr so that block address initializers (either as the whole
// initializer or nested inside an aggregate) can be resolved by the
@@ -3061,6 +3070,8 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
if (init.has_value())
llvmType = adjustGlobalTypeForInit(llvmType, *init, *getTypeConverter(),
dataLayout);
+ if (!llvmType)
+ return mlir::failure();
// FIXME: These default values are placeholders until the the equivalent
// attributes are available on cir.global ops.
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index 1dad8beaa4bce..d7c74d80d032a 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -498,6 +498,8 @@ static mlir::Type adjustGlobalStructTypeForInit(
break;
mlir::Type adjusted =
adjustGlobalTypeForInit(origBody[idx], member, converter, dataLayout);
+ if (!adjusted)
+ return {};
unsigned adjustedAlign = dataLayout.getTypeABIAlignment(adjusted);
if (adjusted != origBody[idx]) {
@@ -550,6 +552,8 @@ static mlir::Type adjustGlobalStructTypeForInit(
newBody.back() =
adjustGlobalTypeForInit(converter.convertType(lastInitType),
initMembers.back(), converter, dataLayout);
+ if (!newBody.back())
+ return {};
packed = packed || shouldPackFAMStruct(dataLayout, newBody);
widenedFAM = true;
changed = true;
@@ -599,6 +603,8 @@ static mlir::Type adjustGlobalUnionTypeForInit(
// The active member may itself need adjusting (e.g. it is a nested union, or
// a struct containing one), so recurse before using its type below.
memberTy = adjustGlobalTypeForInit(memberTy, member, converter, dataLayout);
+ if (!memberTy)
+ return {};
// The converted union type is { storage, [padding] }, where storage is the
// union's most-aligned member. When the active member IS that storage type,
@@ -643,6 +649,8 @@ static mlir::Type adjustGlobalArrayTypeForInit(
for (auto [idx, elt] : llvm::enumerate(elts)) {
mlir::Type adjusted =
adjustGlobalTypeForInit(origEltTy, elt, converter, dataLayout);
+ if (!adjusted)
+ return {};
if (idx >= arrayTy.getNumElements()) {
adjustedElts.push_back(adjusted);
@@ -671,6 +679,8 @@ adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
const mlir::TypeConverter &converter,
const mlir::DataLayout &dataLayout,
llvm::SmallVectorImpl<unsigned> &paddingAddedIndexes) {
+ if (!llvmType)
+ return {};
if (auto arrayInit = mlir::dyn_cast_if_present<cir::ConstArrayAttr>(init)) {
auto arrayTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(llvmType);
if (!arrayTy)
@@ -744,6 +754,8 @@ std::optional<mlir::Attribute> lowerConstRecordAttr(
mlir::Type adjustedTy = adjustGlobalTypeForInit(
converter->convertType(constRecord.getType()), constRecord, *converter,
mlir::DataLayout(moduleOp), paddingAddedIndexes);
+ if (!adjustedTy)
+ return std::nullopt;
// This handles #3 from above. adjustGlobalTypeForInit ensures the
// indexes are in increasing order, so we can insert 'backwards' without
diff --git a/clang/test/CIR/Lowering/unsupported-initializer-types.cir b/clang/test/CIR/Lowering/unsupported-initializer-types.cir
new file mode 100644
index 0000000000000..43b34f3994b93
--- /dev/null
+++ b/clang/test/CIR/Lowering/unsupported-initializer-types.cir
@@ -0,0 +1,66 @@
+// RUN: cir-opt %s --split-input-file --cir-to-llvm -verify-diagnostics | FileCheck %s
+
+// Vector-of-_BitInt conversion is unsupported; propagate its failure to the
+// enclosing operation instead of constructing invalid LLVM operations.
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ // The union's integer storage converts, but its active initializer does not.
+ // expected-error @below {{failed to legalize operation 'cir.global'}}
+ cir.global external @global_union = #cir.const_record<{#cir.zero : !vec}> : !union
+}
+
+// -----
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ cir.func @constant_union() {
+ // expected-error @below {{failed to legalize operation 'cir.const'}}
+ %0 = cir.const #cir.const_record<{#cir.zero : !vec}> : !union
+ cir.return
+ }
+}
+
+// -----
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+!outer = !cir.union<"Outer" {data !cir.int<s, 128>, data !union}>
+!record = !cir.struct<"Record" {data !outer}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ // Propagate adjustment failure through both the enclosing union and struct.
+ cir.func @nested_union() {
+ // expected-error @below {{failed to legalize operation 'cir.const'}}
+ %0 = cir.const #cir.const_record<{#cir.const_record<{#cir.const_record<{#cir.zero : !vec}> : !union}> : !outer}> : !record
+ cir.return
+ }
+}
+
+// -----
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ cir.func @array_union() {
+ // expected-error @below {{failed to legalize operation 'cir.const'}}
+ %0 = cir.const #cir.const_array<[#cir.const_record<{#cir.zero : !vec}> : !union]> : !cir.array<!union x 1>
+ cir.return
+ }
+}
+
+// -----
+
+!vec = !cir.vector<4 x !cir.int<s, 7, bitint>>
+!union = !cir.union<"U" {data !cir.int<s, 128>, data !vec}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+ // An inactive unsupported member does not prevent lowering integer storage.
+ // CHECK: llvm.mlir.global external @integer_initializer
+ cir.global external @integer_initializer = #cir.const_record<{#cir.int<0> : !cir.int<s, 128>}> : !union
+}
More information about the llvm-branch-commits
mailing list