Skip to content

Commit bb38f26

Browse files
authored
[flang] zero initialized all saved values without initial values (#67693)
This is not standard but is vastly expected by existing code. This was implemented by https://reviews.llvm.org/D149877 for simple scalars, but MLIR lacked a generic way to deal with aggregate types (arrays and derived type). Support was recently added in #65508. Leverage it to zero initialize all types.
1 parent 3f8d4a8 commit bb38f26

File tree

5 files changed

+35
-50
lines changed

5 files changed

+35
-50
lines changed

flang/docs/Extensions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ end
100100
* `<>` as synonym for `.NE.` and `/=`
101101
* `$` and `@` as legal characters in names
102102
* Initialization in type declaration statements using `/values/`
103-
* Saved integer, logical and real scalars are zero initialized.
103+
* Saved variables without explicit or default initializers are zero initialized.
104104
* Kind specification with `*`, e.g. `REAL*4`
105105
* `DOUBLE COMPLEX` as a synonym for `COMPLEX(KIND(0.D0))` --
106106
but not when spelled `TYPE(DOUBLECOMPLEX)`.

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -504,25 +504,20 @@ static fir::GlobalOp defineGlobal(Fortran::lower::AbstractConverter &converter,
504504
} else {
505505
TODO(loc, "global"); // Procedure pointer or something else
506506
}
507-
// Creates zero or undefined initializer for globals without initializers
508-
// Zero initializer is used for "simple types" (integer, real and logical),
509-
// undefined is used for types aside from those types.
507+
// Creates zero initializer for globals without initializers, this is a common
508+
// and expected behavior (although not required by the standard)
510509
if (!globalIsInitialized(global)) {
511-
// TODO: Is it really required to add the undef init if the Public
512-
// visibility is set ? We need to make sure the global is not optimized out
513-
// by LLVM if unused in the current compilation unit, but at least for
514-
// BIND(C) variables, an initial value may be given in another compilation
515-
// unit (on the C side), and setting an undef init here creates linkage
516-
// conflicts.
510+
// TODO: For BIND(C) variables, an initial value may be given in another
511+
// compilation unit (on the C side), and setting an zero init here creates
512+
// linkage conflicts. See if there is a way to get it zero initialized if
513+
// not initialized elsewhere. MLIR also used to drop globals without
514+
// initializers that are not used in the file, but this may not be true
515+
// anymore.
517516
if (sym.attrs().test(Fortran::semantics::Attr::BIND_C))
518517
TODO(loc, "BIND(C) module variable linkage");
519518
Fortran::lower::createGlobalInitialization(
520519
builder, global, [&](fir::FirOpBuilder &builder) {
521-
mlir::Value initValue;
522-
if (symTy.isa<mlir::IntegerType, mlir::FloatType, fir::LogicalType>())
523-
initValue = builder.create<fir::ZeroOp>(loc, symTy);
524-
else
525-
initValue = builder.create<fir::UndefOp>(loc, symTy);
520+
mlir::Value initValue = builder.create<fir::ZeroOp>(loc, symTy);
526521
builder.create<fir::HasValueOp>(loc, initValue);
527522
});
528523
}

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3406,20 +3406,7 @@ struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
34063406
matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
34073407
mlir::ConversionPatternRewriter &rewriter) const override {
34083408
mlir::Type ty = convertType(zero.getType());
3409-
if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
3410-
rewriter.replaceOpWithNewOp<mlir::LLVM::ZeroOp>(zero, ty);
3411-
} else if (ty.isa<mlir::IntegerType>()) {
3412-
rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
3413-
zero, ty, mlir::IntegerAttr::get(ty, 0));
3414-
} else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
3415-
rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
3416-
zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
3417-
} else {
3418-
// TODO: create ConstantAggregateZero for FIR aggregate/array types.
3419-
return rewriter.notifyMatchFailure(
3420-
zero,
3421-
"conversion of fir.zero with aggregate type not implemented yet");
3422-
}
3409+
rewriter.replaceOpWithNewOp<mlir::LLVM::ZeroOp>(zero, ty);
34233410
return mlir::success();
34243411
}
34253412
};

flang/test/Fir/convert-to-llvm-invalid.fir

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,6 @@
22

33
// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" --verify-diagnostics %s
44

5-
// Test `fir.zero` conversion failure with aggregate type.
6-
// Not implemented yet.
7-
8-
func.func @zero_aggregate() {
9-
// expected-error@+1{{failed to legalize operation 'fir.zero_bits'}}
10-
%a = fir.zero_bits !fir.array<10xf32>
11-
return
12-
}
13-
14-
// -----
15-
165
// Verify that `fir.dt_entry` requires a parent op
176

187
// expected-error@+1{{'fir.dt_entry' op expects parent op 'fir.dispatch_table'}}

flang/test/Fir/convert-to-llvm.fir

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ func.func @zero_test_integer() {
160160
return
161161
}
162162

163-
// CHECK: %{{.*}} = llvm.mlir.constant(0 : i8) : i8
164-
// CHECK: %{{.*}} = llvm.mlir.constant(0 : i16) : i16
165-
// CHECK: %{{.*}} = llvm.mlir.constant(0 : i32) : i32
166-
// CHECK: %{{.*}} = llvm.mlir.constant(0 : i64) : i64
163+
// CHECK: %{{.*}} = llvm.mlir.zero : i8
164+
// CHECK: %{{.*}} = llvm.mlir.zero : i16
165+
// CHECK: %{{.*}} = llvm.mlir.zero : i32
166+
// CHECK: %{{.*}} = llvm.mlir.zero : i64
167167
// CHECK-NOT: fir.zero_bits
168168

169169
// -----
@@ -180,16 +180,30 @@ func.func @zero_test_float() {
180180
return
181181
}
182182

183-
// CHECK: %{{.*}} = llvm.mlir.constant(0.000000e+00 : f16) : f16
184-
// CHECK: %{{.*}} = llvm.mlir.constant(0.000000e+00 : bf16) : bf16
185-
// CHECK: %{{.*}} = llvm.mlir.constant(0.000000e+00 : f32) : f32
186-
// CHECK: %{{.*}} = llvm.mlir.constant(0.000000e+00 : f64) : f64
187-
// CHECK: %{{.*}} = llvm.mlir.constant(0.000000e+00 : f80) : f80
188-
// CHECK: %{{.*}} = llvm.mlir.constant(0.000000e+00 : f128) : f128
183+
// CHECK: %{{.*}} = llvm.mlir.zero : f16
184+
// CHECK: %{{.*}} = llvm.mlir.zero : bf16
185+
// CHECK: %{{.*}} = llvm.mlir.zero : f32
186+
// CHECK: %{{.*}} = llvm.mlir.zero : f64
187+
// CHECK: %{{.*}} = llvm.mlir.zero : f80
188+
// CHECK: %{{.*}} = llvm.mlir.zero : f128
189189
// CHECK-NOT: fir.zero_bits
190190

191191
// -----
192192

193+
// Test fir.zero_bits with aggregate types.
194+
195+
func.func @zero_aggregate() {
196+
%a = fir.zero_bits !fir.array<10xf32>
197+
%b = fir.zero_bits !fir.type<a{i:i32,j:f32}>
198+
return
199+
}
200+
// CHECK: %{{.*}} = llvm.mlir.zero : !llvm.array<10 x f32>
201+
// CHECK: %{{.*}} = llvm.mlir.zero : !llvm.struct<"a", (i32, f32)>
202+
// CHECK-NOT: fir.zero_bits
203+
204+
// -----
205+
206+
193207
// Verify that fir.allocmem is transformed to a call to malloc
194208
// and that fir.freemem is transformed to a call to free
195209
// Single item case

0 commit comments

Comments
 (0)