Skip to content

Commit cea27ae

Browse files
committed
[MLIR][LLVMIR] Fix import of ConstantAggregateZero to use zero instead of undef
1 parent fbaa28e commit cea27ae

File tree

3 files changed

+118
-12
lines changed

3 files changed

+118
-12
lines changed

mlir/lib/Target/LLVMIR/ModuleImport.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,17 +1681,25 @@ FailureOr<Value> ModuleImport::convertConstant(llvm::Constant *constant) {
16811681
return lookupValue(inst);
16821682
}
16831683

1684+
// Convert zero-initialized aggregates to ZeroOp.
1685+
if (auto *aggregateZero = dyn_cast<llvm::ConstantAggregateZero>(constant)) {
1686+
Type type = convertType(aggregateZero->getType());
1687+
return builder.create<ZeroOp>(loc, type).getResult();
1688+
}
1689+
16841690
// Convert aggregate constants.
16851691
if (isa<llvm::ConstantAggregate>(constant) ||
16861692
isa<llvm::ConstantAggregateZero>(constant)) {
16871693
// Lookup the aggregate elements that have been converted before.
16881694
SmallVector<Value> elementValues;
1695+
bool isAggregateZero = false;
16891696
if (auto *constAgg = dyn_cast<llvm::ConstantAggregate>(constant)) {
16901697
elementValues.reserve(constAgg->getNumOperands());
16911698
for (llvm::Value *operand : constAgg->operands())
16921699
elementValues.push_back(lookupValue(operand));
16931700
}
16941701
if (auto *constAgg = dyn_cast<llvm::ConstantAggregateZero>(constant)) {
1702+
isAggregateZero = true;
16951703
unsigned numElements = constAgg->getElementCount().getFixedValue();
16961704
elementValues.reserve(numElements);
16971705
for (unsigned i = 0, e = numElements; i != e; ++i)
@@ -1700,12 +1708,18 @@ FailureOr<Value> ModuleImport::convertConstant(llvm::Constant *constant) {
17001708
assert(llvm::count(elementValues, nullptr) == 0 &&
17011709
"expected all elements have been converted before");
17021710

1703-
// Generate an UndefOp as root value and insert the aggregate elements.
1711+
// Generate a root value and insert the aggregate elements.
1712+
// For ConstantAggregateZero, use ZeroOp to preserve zero-initialization
1713+
// semantics. Otherwise use UndefOp as the root.
17041714
Type rootType = convertType(constant->getType());
17051715
bool isArrayOrStruct = isa<LLVMArrayType, LLVMStructType>(rootType);
17061716
assert((isArrayOrStruct || LLVM::isCompatibleVectorType(rootType)) &&
17071717
"unrecognized aggregate type");
1708-
Value root = builder.create<UndefOp>(loc, rootType);
1718+
Value root;
1719+
if (isAggregateZero)
1720+
root = builder.create<ZeroOp>(loc, rootType);
1721+
else
1722+
root = builder.create<UndefOp>(loc, rootType);
17091723
for (const auto &it : llvm::enumerate(elementValues)) {
17101724
if (isArrayOrStruct) {
17111725
root = builder.create<InsertValueOp>(loc, root, it.value(), it.index());

mlir/test/Target/LLVMIR/Import/constant.ll

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,8 @@ define i32 @function_address_after_def() {
198198
%nested_agg_type = type {%simple_agg_type, ptr}
199199
@nested_agg = global %nested_agg_type { %simple_agg_type{i32 1, i8 2, i16 3, i32 4}, ptr null }
200200

201-
; CHECK-DAG: %[[NULL:.+]] = llvm.mlir.zero : !llvm.ptr
202-
; CHECK-DAG: %[[ROOT:.+]] = llvm.mlir.undef : vector<2x!llvm.ptr>
203-
; CHECK-DAG: %[[P0:.+]] = llvm.mlir.constant(0 : i32) : i32
204-
; CHECK-DAG: %[[CHAIN0:.+]] = llvm.insertelement %[[NULL]], %[[ROOT]][%[[P0]] : i32] : vector<2x!llvm.ptr>
205-
; CHECK-DAG: %[[P1:.+]] = llvm.mlir.constant(1 : i32) : i32
206-
; CHECK-DAG: %[[CHAIN1:.+]] = llvm.insertelement %[[NULL]], %[[CHAIN0]][%[[P1]] : i32] : vector<2x!llvm.ptr>
207-
; CHECK-DAG: llvm.return %[[CHAIN1]] : vector<2x!llvm.ptr>
201+
; CHECK-DAG: %[[VEC:.+]] = llvm.mlir.zero : vector<2x!llvm.ptr>
202+
; CHECK-DAG: llvm.return %[[VEC]] : vector<2x!llvm.ptr>
208203
@vector_agg = global <2 x ptr> <ptr null, ptr null>
209204

210205
; // -----
@@ -274,3 +269,46 @@ define void @call_alias_func() {
274269

275270
; CHECK-LABEL: @call_alias_func()
276271
; CHECK: llvm.dso_local_equivalent @alias_func : !llvm.ptr
272+
273+
; // -----
274+
275+
; Test that zeroinitializer for zero-element arrays is correctly translated
276+
; to llvm.mlir.zero instead of llvm.mlir.undef. This is a regression test for
277+
; a bug where empty aggregate constants were incorrectly converted to undef.
278+
279+
@global_zero_array = global [0 x ptr] zeroinitializer
280+
281+
; CHECK: llvm.mlir.global external @global_zero_array() {addr_space = 0 : i32} : !llvm.array<0 x ptr> {
282+
; CHECK: %[[ZERO:.+]] = llvm.mlir.zero : !llvm.array<0 x ptr>
283+
; CHECK: llvm.return %[[ZERO]] : !llvm.array<0 x ptr>
284+
; CHECK: }
285+
286+
; CHECK-LABEL: @load_zero_array
287+
define [0 x ptr] @load_zero_array() {
288+
; CHECK: %[[ADDR:.+]] = llvm.mlir.addressof @global_zero_array : !llvm.ptr
289+
; CHECK: %[[VAL:.+]] = llvm.load %[[ADDR]] {{.*}}: !llvm.ptr -> !llvm.array<0 x ptr>
290+
; CHECK: llvm.return %[[VAL]] : !llvm.array<0 x ptr>
291+
%val = load [0 x ptr], ptr @global_zero_array
292+
ret [0 x ptr] %val
293+
}
294+
295+
; // -----
296+
297+
; Test that zeroinitializer for zero-element structs is correctly handled
298+
299+
@global_zero_struct = global {} zeroinitializer
300+
301+
; CHECK: llvm.mlir.global external @global_zero_struct() {addr_space = 0 : i32} : !llvm.struct<()> {
302+
; CHECK: %[[ZERO:.+]] = llvm.mlir.zero : !llvm.struct<()>
303+
; CHECK: llvm.return %[[ZERO]] : !llvm.struct<()>
304+
; CHECK: }
305+
306+
; // -----
307+
308+
; Test that zeroinitializer for arrays with elements still works correctly.
309+
; Note that arrays with primitive types that can be represented as dense
310+
; attributes may use the attribute form directly.
311+
312+
@global_array_with_elements = global [3 x i32] zeroinitializer
313+
314+
; CHECK: llvm.mlir.global external @global_array_with_elements({{.*}}) {addr_space = 0 : i32} : !llvm.array<3 x i32>

mlir/test/Target/LLVMIR/Import/exception.ll

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,7 @@ define void @landingpad_dominance() personality ptr @__gxx_personality_v0 {
123123
entry:
124124
; CHECK: %[[null:.*]] = llvm.mlir.zero : !llvm.ptr
125125
; CHECK: %[[c1:.*]] = llvm.mlir.constant(0 : i32) : i32
126-
; CHECK: %[[undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i32)>
127-
; CHECK: %[[tmpstruct:.*]] = llvm.insertvalue %[[null]], %[[undef]][0] : !llvm.struct<(ptr, i32)>
128-
; CHECK: %[[struct:.*]] = llvm.insertvalue %[[c1]], %[[tmpstruct]][1] : !llvm.struct<(ptr, i32)>
126+
; CHECK: %[[struct:.*]] = llvm.mlir.zero : !llvm.struct<(ptr, i32)>
129127
; CHECK: llvm.call @f0(%[[null]]) : (!llvm.ptr) -> ()
130128
call void @f0(ptr null)
131129
; CHECK: llvm.call @f1(%[[c1]]) : (i32) -> ()
@@ -190,3 +188,59 @@ bb3:
190188
!6 = !DILocation(line: 2, column: 2, scope: !3)
191189
!7 = !DILocation(line: 7, column: 4, scope: !4, inlinedAt: !6)
192190
!8 = !DILocalVariable(scope: !4, name: "size")
191+
192+
; // -----
193+
194+
declare i32 @__gxx_personality_v0(...)
195+
declare void @foo(ptr)
196+
197+
; Test that landingpad filter clauses with zeroinitializer are correctly
198+
; translated to llvm.mlir.zero instead of llvm.mlir.undef.
199+
; This is a regression test for a bug where zero-element arrays used in
200+
; filter clauses were incorrectly converted to undef.
201+
202+
; CHECK-LABEL: @landingpad_zero_filter
203+
define void @landingpad_zero_filter() personality ptr @__gxx_personality_v0 {
204+
entry:
205+
; CHECK: %[[ZERO:.+]] = llvm.mlir.zero : !llvm.array<0 x ptr>
206+
invoke void @foo(ptr null) to label %normal unwind label %lpad
207+
208+
normal:
209+
ret void
210+
211+
lpad:
212+
; CHECK: %{{[0-9]+}} = llvm.landingpad cleanup (filter %[[ZERO]] : !llvm.array<0 x ptr>) : !llvm.struct<(ptr, i32)>
213+
%0 = landingpad { ptr, i32 }
214+
cleanup
215+
filter [0 x ptr] zeroinitializer
216+
ret void
217+
}
218+
219+
; // -----
220+
221+
declare i32 @__gxx_personality_v0(...)
222+
declare void @foo(ptr)
223+
224+
; Test that landingpad with multiple filter clauses of different zero-element
225+
; array types are correctly handled. Note that zero-element arrays of primitive
226+
; types like i32 may be converted to dense attributes, while ptr arrays use
227+
; llvm.mlir.zero.
228+
229+
; CHECK-LABEL: @landingpad_mixed_filters
230+
define void @landingpad_mixed_filters() personality ptr @__gxx_personality_v0 {
231+
entry:
232+
; CHECK: %[[ZERO1:.+]] = llvm.mlir.zero : !llvm.array<0 x ptr>
233+
; CHECK: %[[ZERO2:.+]] = llvm.mlir.{{(zero|constant)}}{{.*}}: !llvm.array<0 x i32>
234+
invoke void @foo(ptr null) to label %normal unwind label %lpad
235+
236+
normal:
237+
ret void
238+
239+
lpad:
240+
; CHECK: %{{[0-9]+}} = llvm.landingpad cleanup (filter %[[ZERO1]] : !llvm.array<0 x ptr>) (filter %[[ZERO2]] : !llvm.array<0 x i32>) : !llvm.struct<(ptr, i32)>
241+
%0 = landingpad { ptr, i32 }
242+
cleanup
243+
filter [0 x ptr] zeroinitializer
244+
filter [0 x i32] zeroinitializer
245+
ret void
246+
}

0 commit comments

Comments
 (0)