Skip to content

[flang] Zero initialize uninitialized components in saved default init #67777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 2, 2023

Conversation

jeanPerier
Copy link
Contributor

Follow up up of #67693

  • Zero initialize uninitialized components of saved derived type entity with a default initial value.
  • Zero initialize uninitialized storage of common blocks with a member with an initial value.
  • Zero initialized uninitialized saved equivalence

This removes all the cases where fir.global are created with an initial value that results in an undef in LLVM for part of the global, leading in surprising LLVM optimizations at -O2 for Fortran folks that expects there saved variables to be zero initialized if there is no explicit or default initial value.

Follow up up of llvm#67693

- Zero initialize uninitialized components of saved derived type entity
  with a default initial value.
- Zero initialize uninitialized storage of common blocks with a member
  with an initial value.
- Zero initialized uninitialized saved equivalence

This removes all the cases where fir.global are created with an
initial value that results in an undef in LLVM for part of the global,
leading in surprising LLVM optimizations at -O2 for Fortran folks that
expects there saved variables to be zero initialized if there is no
explicit or default initial value.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Sep 29, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 29, 2023

@llvm/pr-subscribers-flang-fir-hlfir

Changes

Follow up up of #67693

  • Zero initialize uninitialized components of saved derived type entity with a default initial value.
  • Zero initialize uninitialized storage of common blocks with a member with an initial value.
  • Zero initialized uninitialized saved equivalence

This removes all the cases where fir.global are created with an initial value that results in an undef in LLVM for part of the global, leading in surprising LLVM optimizations at -O2 for Fortran folks that expects there saved variables to be zero initialized if there is no explicit or default initial value.


Full diff: https://github.com/llvm/llvm-project/pull/67777.diff

9 Files Affected:

  • (modified) flang/docs/Extensions.md (+2)
  • (modified) flang/lib/Lower/ConvertVariable.cpp (+6-5)
  • (modified) flang/test/Lower/array.f90 (+1-1)
  • (modified) flang/test/Lower/common-block-2.f90 (+2-2)
  • (modified) flang/test/Lower/common-block.f90 (+1-1)
  • (modified) flang/test/Lower/default-initialization-globals.f90 (+4-4)
  • (modified) flang/test/Lower/equivalence-static-init.f90 (+1-1)
  • (modified) flang/test/Lower/pointer-default-init.f90 (+2-2)
  • (modified) flang/test/Lower/pointer-initial-target-2.f90 (+2-2)
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index c1591eb49732b7f..480039911719c6d 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -101,6 +101,8 @@ end
 * `$` and `@` as legal characters in names
 * Initialization in type declaration statements using `/values/`
 * Saved variables without explicit or default initializers are zero initialized.
+* In a saved entity of a type with a default initializer, components without default
+  values are zero initialized.
 * Kind specification with `*`, e.g. `REAL*4`
 * `DOUBLE COMPLEX` as a synonym for `COMPLEX(KIND(0.D0))` --
   but not when spelled `TYPE(DOUBLECOMPLEX)`.
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 87b570d1ac4b7e2..74e07ec77c0cb55 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -352,8 +352,9 @@ static mlir::Value genDefaultInitializerValue(
         componentValue = genDefaultInitializerValue(converter, loc, component,
                                                     componentTy, stmtCtx);
       } else {
-        // Component has no initial value.
-        componentValue = builder.create<fir::UndefOp>(loc, componentTy);
+        // Component has no initial value. Set its bits to zero by extension
+        // to match what is expected because other compilers are doing it.
+        componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
       }
     } else if (const auto *proc{
                    component
@@ -361,7 +362,7 @@ static mlir::Value genDefaultInitializerValue(
       if (proc->init().has_value())
         TODO(loc, "procedure pointer component default initialization");
       else
-        componentValue = builder.create<fir::UndefOp>(loc, componentTy);
+        componentValue = builder.create<fir::ZeroOp>(loc, componentTy);
     }
     assert(componentValue && "must have been computed");
     componentValue = builder.createConvert(loc, componentTy, componentValue);
@@ -890,7 +891,7 @@ static fir::GlobalOp defineGlobalAggregateStore(
   Fortran::lower::createGlobalInitialization(
       builder, global, [&](fir::FirOpBuilder &builder) {
         Fortran::lower::StatementContext stmtCtx;
-        mlir::Value initVal = builder.create<fir::UndefOp>(loc, aggTy);
+        mlir::Value initVal = builder.create<fir::ZeroOp>(loc, aggTy);
         builder.create<fir::HasValueOp>(loc, initVal);
       });
   return global;
@@ -1171,7 +1172,7 @@ static void finalizeCommonBlockDefinition(
   mlir::TupleType commonTy = global.getType().cast<mlir::TupleType>();
   auto initFunc = [&](fir::FirOpBuilder &builder) {
     mlir::IndexType idxTy = builder.getIndexType();
-    mlir::Value cb = builder.create<fir::UndefOp>(loc, commonTy);
+    mlir::Value cb = builder.create<fir::ZeroOp>(loc, commonTy);
     unsigned tupIdx = 0;
     std::size_t offset = 0;
     LLVM_DEBUG(llvm::dbgs() << "block {\n");
diff --git a/flang/test/Lower/array.f90 b/flang/test/Lower/array.f90
index e6e12862858385d..3371887d041279a 100644
--- a/flang/test/Lower/array.f90
+++ b/flang/test/Lower/array.f90
@@ -4,7 +4,7 @@
 ! CHECK-DAG: %[[VAL_1:.*]] = arith.constant 1.000000e+00 : f32
 ! CHECK-DAG: %[[VAL_2:.*]] = arith.constant 2.400000e+00 : f32
 ! CHECK-DAG: %[[VAL_3:.*]] = arith.constant 0.000000e+00 : f32
-! CHECK: %[[VAL_4:.*]] = fir.undefined tuple<!fir.array<5x5xf32>>
+! CHECK: %[[VAL_4:.*]] = fir.zero_bits tuple<!fir.array<5x5xf32>>
 ! CHECK: %[[VAL_5:.*]] = fir.undefined !fir.array<5x5xf32>
 ! CHECK: %[[VAL_6:.*]] = fir.insert_on_range %[[VAL_5]], %[[VAL_1]] from (0, 0) to (1, 0) : (!fir.array<5x5xf32>, f32) -> !fir.array<5x5xf32>
 ! CHECK: %[[VAL_7:.*]] = fir.insert_on_range %[[VAL_6]], %[[VAL_3]] from (2, 0) to (4, 0) : (!fir.array<5x5xf32>, f32) -> !fir.array<5x5xf32>
diff --git a/flang/test/Lower/common-block-2.f90 b/flang/test/Lower/common-block-2.f90
index 31916f4be9fcb2e..4b12860a48ffaed 100644
--- a/flang/test/Lower/common-block-2.f90
+++ b/flang/test/Lower/common-block-2.f90
@@ -6,12 +6,12 @@
 ! - A common block that is initialized outside of a BLOCK DATA.
 
 ! CHECK-LABEL: fir.global @__BLNK__ : tuple<i32, !fir.array<8xi8>> {
-! CHECK:  %[[undef:.*]] = fir.undefined tuple<i32, !fir.array<8xi8>>
+! CHECK:  %[[undef:.*]] = fir.zero_bits tuple<i32, !fir.array<8xi8>>
 ! CHECK:  %[[init:.*]] = fir.insert_value %[[undef]], %c42{{.*}}, [0 : index] : (tuple<i32, !fir.array<8xi8>>, i32) -> tuple<i32, !fir.array<8xi8>>
 ! CHECK:  fir.has_value %[[init]] : tuple<i32, !fir.array<8xi8>>
 
 ! CHECK-LABEL: fir.global @a_ : tuple<i32, !fir.array<8xi8>> {
-! CHECK:  %[[undef:.*]] = fir.undefined tuple<i32, !fir.array<8xi8>>
+! CHECK:  %[[undef:.*]] = fir.zero_bits tuple<i32, !fir.array<8xi8>>
 ! CHECK:  %[[init:.*]] = fir.insert_value %[[undef]], %c42{{.*}}, [0 : index] : (tuple<i32, !fir.array<8xi8>>, i32) -> tuple<i32, !fir.array<8xi8>>
 ! CHECK:  fir.has_value %[[init]] : tuple<i32, !fir.array<8xi8>>
 
diff --git a/flang/test/Lower/common-block.f90 b/flang/test/Lower/common-block.f90
index bd3fab507c0ef41..3934b71b75694ed 100644
--- a/flang/test/Lower/common-block.f90
+++ b/flang/test/Lower/common-block.f90
@@ -6,7 +6,7 @@
 ! CHECK: @with_empty_equiv_ = common global [8 x i8] zeroinitializer
 ! CHECK: @x_ = global { float, float } { float 1.0{{.*}}, float 2.0{{.*}} }
 ! CHECK: @y_ = common global [12 x i8] zeroinitializer
-! CHECK: @z_ = global { i32, [4 x i8], float } { i32 42, [4 x i8] undef, float 3.000000e+00 }
+! CHECK: @z_ = global { i32, [4 x i8], float } { i32 42, [4 x i8] zeroinitializer, float 3.000000e+00 }
 
 ! CHECK-LABEL: _QPs0
 subroutine s0
diff --git a/flang/test/Lower/default-initialization-globals.f90 b/flang/test/Lower/default-initialization-globals.f90
index bbcea75a5b1f979..2b5e3c36367e2e5 100644
--- a/flang/test/Lower/default-initialization-globals.f90
+++ b/flang/test/Lower/default-initialization-globals.f90
@@ -97,7 +97,7 @@ module tinit
   ! CHECK-DAG: %[[VAL_15:.*]] = arith.constant 66 : i32
   ! CHECK: %[[VAL_16:.*]] = fir.undefined !fir.type<_QMtinitTt1{{.*}}>
   ! CHECK: %[[VAL_17:.*]] = fir.insert_value %[[VAL_16]], %[[VAL_11]], ["i", !fir.type<_QMtinitTt1{{.*}}>] : (!fir.type<_QMtinitTt1{{.*}}>, i32) -> !fir.type<_QMtinitTt1{{.*}}>
-  ! CHECK: %[[VAL_18:.*]] = fir.undefined i32
+  ! CHECK: %[[VAL_18:.*]] = fir.zero_bits i32
   ! CHECK: %[[VAL_19:.*]] = fir.insert_value %[[VAL_17]], %[[VAL_18]], ["j", !fir.type<_QMtinitTt1{{.*}}>] : (!fir.type<_QMtinitTt1{{.*}}>, i32) -> !fir.type<_QMtinitTt1{{.*}}>
   ! CHECK: %[[VAL_20:.*]] = fir.address_of(@_QMtinitEziel) : !fir.ref<!fir.array<100xf32>>
   ! CHECK: %[[VAL_21:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1>
@@ -111,12 +111,12 @@ module tinit
   ! CHECK: %[[VAL_28:.*]] = fir.insert_value %[[VAL_27]], %[[VAL_26]], ["z", !fir.type<_QMtinitTt1{{.*}}>] : (!fir.type<_QMtinitTt1{{.*}}>, !fir.box<!fir.ptr<!fir.array<?xf32>>>) -> !fir.type<_QMtinitTt1{{.*}}>
   ! CHECK: %[[VAL_29:.*]] = fir.string_lit "hello     "(10) : !fir.char<1,10>
   ! CHECK: %[[VAL_30:.*]] = fir.insert_value %[[VAL_28]], %[[VAL_29]], ["c1", !fir.type<_QMtinitTt1{{.*}}>] : (!fir.type<_QMtinitTt1{{.*}}>, !fir.char<1,10>) -> !fir.type<_QMtinitTt1{{.*}}>
-  ! CHECK: %[[VAL_31:.*]] = fir.undefined !fir.char<1,10>
+  ! CHECK: %[[VAL_31:.*]] = fir.zero_bits !fir.char<1,10>
   ! CHECK: %[[VAL_32:.*]] = fir.insert_value %[[VAL_30]], %[[VAL_31]], ["c2", !fir.type<_QMtinitTt1{{.*}}>] : (!fir.type<_QMtinitTt1{{.*}}>, !fir.char<1,10>) -> !fir.type<_QMtinitTt1{{.*}}>
   ! CHECK: %[[VAL_33:.*]] = fir.undefined !fir.type<_QMtinitTt0{k:i32}>
   ! CHECK: %[[VAL_34:.*]] = fir.insert_value %[[VAL_33]], %[[VAL_15]], ["k", !fir.type<_QMtinitTt0{k:i32}>] : (!fir.type<_QMtinitTt0{k:i32}>, i32) -> !fir.type<_QMtinitTt0{k:i32}>
   ! CHECK: %[[VAL_35:.*]] = fir.insert_value %[[VAL_32]], %[[VAL_34]], ["somet0", !fir.type<_QMtinitTt1{{.*}}>] : (!fir.type<_QMtinitTt1{{.*}}>, !fir.type<_QMtinitTt0{k:i32}>) -> !fir.type<_QMtinitTt1{{.*}}>
-  ! CHECK: %[[VAL_36:.*]] = fir.undefined !fir.type<_QMtinitTtno_init{k:i32}>
+  ! CHECK: %[[VAL_36:.*]] = fir.zero_bits !fir.type<_QMtinitTtno_init{k:i32}>
   ! CHECK: %[[VAL_37:.*]] = fir.insert_value %[[VAL_35]], %[[VAL_36]], ["sometno_init", !fir.type<_QMtinitTt1{{.*}}>] : (!fir.type<_QMtinitTt1{{.*}}>, !fir.type<_QMtinitTtno_init{k:i32}>) -> !fir.type<_QMtinitTt1{{.*}}>
   ! CHECK: %[[VAL_38:.*]] = fir.insert_value %[[VAL_33]], %[[VAL_14]], ["k", !fir.type<_QMtinitTt0{k:i32}>] : (!fir.type<_QMtinitTt0{k:i32}>, i32) -> !fir.type<_QMtinitTt0{k:i32}>
   ! CHECK: %[[VAL_39:.*]] = fir.insert_value %[[VAL_37]], %[[VAL_38]], ["somet0_2", !fir.type<_QMtinitTt1{{.*}}>] : (!fir.type<_QMtinitTt1{{.*}}>, !fir.type<_QMtinitTt0{k:i32}>) -> !fir.type<_QMtinitTt1{{.*}}>
@@ -129,7 +129,7 @@ module tinit
   ! CHECK: %[[VAL_42:.*]] = arith.constant 66 : i32
   ! CHECK: %[[VAL_43:.*]] = fir.undefined !fir.type<_QMtinitTtextendst0{k:i32,l:i32}>
   ! CHECK: %[[VAL_44:.*]] = fir.insert_value %[[VAL_43]], %[[VAL_42]], ["k", !fir.type<_QMtinitTtextendst0{k:i32,l:i32}>] : (!fir.type<_QMtinitTtextendst0{k:i32,l:i32}>, i32) -> !fir.type<_QMtinitTtextendst0{k:i32,l:i32}>
-  ! CHECK: %[[VAL_45:.*]] = fir.undefined i32
+  ! CHECK: %[[VAL_45:.*]] = fir.zero_bits i32
   ! CHECK: %[[VAL_46:.*]] = fir.insert_value %[[VAL_44]], %[[VAL_45]], ["l", !fir.type<_QMtinitTtextendst0{k:i32,l:i32}>] : (!fir.type<_QMtinitTtextendst0{k:i32,l:i32}>, i32) -> !fir.type<_QMtinitTtextendst0{k:i32,l:i32}>
   ! CHECK: fir.has_value %[[VAL_46]] : !fir.type<_QMtinitTtextendst0{k:i32,l:i32}>
 
diff --git a/flang/test/Lower/equivalence-static-init.f90 b/flang/test/Lower/equivalence-static-init.f90
index 6b4b0ccff4c5e66..4c52a4a7d8448ae 100644
--- a/flang/test/Lower/equivalence-static-init.f90
+++ b/flang/test/Lower/equivalence-static-init.f90
@@ -8,7 +8,7 @@ module module_without_init
   equivalence(i(1), x)
 end module
 ! CHECK-LABEL: fir.global @_QMmodule_without_initEi : !fir.array<8xi8> {
-  ! CHECK: %0 = fir.undefined !fir.array<8xi8>
+  ! CHECK: %0 = fir.zero_bits !fir.array<8xi8>
   ! CHECK: fir.has_value %0 : !fir.array<8xi8>
 ! CHECK}
 
diff --git a/flang/test/Lower/pointer-default-init.f90 b/flang/test/Lower/pointer-default-init.f90
index 4697d601347e749..6dde5d56aaa8222 100644
--- a/flang/test/Lower/pointer-default-init.f90
+++ b/flang/test/Lower/pointer-default-init.f90
@@ -21,7 +21,7 @@ module test
   type(t) :: test_module_var
 ! CHECK-LABEL:   fir.global @_QMtestEtest_module_var : !fir.type<_QMtestTt{i:i32,x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}> {
 ! CHECK:  %[[VAL_0:.*]] = fir.undefined !fir.type<_QMtestTt{i:i32,x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>
-! CHECK:  %[[VAL_1:.*]] = fir.undefined i32
+! CHECK:  %[[VAL_1:.*]] = fir.zero_bits i32
 ! CHECK:  %[[VAL_2:.*]] = fir.field_index i
 ! CHECK:  %[[VAL_3:.*]] = fir.insert_value %[[VAL_0]], %[[VAL_1]]
 ! CHECK:  %[[VAL_4:.*]] = fir.zero_bits !fir.ptr<!fir.array<?xf32>>
@@ -97,7 +97,7 @@ subroutine test_saved_pointer()
 
 ! CHECK-LABEL:   fir.global internal @_QFtest_savedEx : !fir.type<_QMtestTt{i:i32,x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}> {
 ! CHECK:  %[[VAL_0:.*]] = fir.undefined !fir.type<_QMtestTt{i:i32,x:!fir.box<!fir.ptr<!fir.array<?xf32>>>}>
-! CHECK:  %[[VAL_1:.*]] = fir.undefined i32
+! CHECK:  %[[VAL_1:.*]] = fir.zero_bits i32
 ! CHECK:  %[[VAL_2:.*]] = fir.field_index i
 ! CHECK:  %[[VAL_3:.*]] = fir.insert_value %[[VAL_0]], %[[VAL_1]]
 ! CHECK:  %[[VAL_4:.*]] = fir.zero_bits !fir.ptr<!fir.array<?xf32>>
diff --git a/flang/test/Lower/pointer-initial-target-2.f90 b/flang/test/Lower/pointer-initial-target-2.f90
index 69e9f23126708fb..a3f2292e7fb7676 100644
--- a/flang/test/Lower/pointer-initial-target-2.f90
+++ b/flang/test/Lower/pointer-initial-target-2.f90
@@ -12,7 +12,7 @@
   common /a/ p
   data p /b/
 ! CHECK-LABEL: fir.global @a_ : tuple<!fir.box<!fir.ptr<f32>>>
-  ! CHECK: %[[undef:.*]] = fir.undefined tuple<!fir.box<!fir.ptr<f32>>>
+  ! CHECK: %[[undef:.*]] = fir.zero_bits tuple<!fir.box<!fir.ptr<f32>>>
   ! CHECK: %[[b:.*]] = fir.address_of(@_QEb) : !fir.ref<f32>
   ! CHECK: %[[box:.*]] = fir.embox %[[b]] : (!fir.ref<f32>) -> !fir.box<f32>
   ! CHECK: %[[rebox:.*]] = fir.rebox %[[box]] : (!fir.box<f32>) -> !fir.box<!fir.ptr<f32>>
@@ -41,7 +41,7 @@ block data bdsnake
   integer, pointer :: p => b
   common /snake/ p, b
 ! CHECK-LABEL: fir.global @snake_ : tuple<!fir.box<!fir.ptr<i32>>, i32>
-  ! CHECK: %[[tuple0:.*]] = fir.undefined tuple<!fir.box<!fir.ptr<i32>>, i32>
+  ! CHECK: %[[tuple0:.*]] = fir.zero_bits tuple<!fir.box<!fir.ptr<i32>>, i32>
   ! CHECK: %[[snakeAddr:.*]] = fir.address_of(@snake_) : !fir.ref<tuple<!fir.box<!fir.ptr<i32>>, i32>>
   ! CHECK: %[[byteView:.*]] = fir.convert %[[snakeAddr:.*]] : (!fir.ref<tuple<!fir.box<!fir.ptr<i32>>, i32>>) -> !fir.ref<!fir.array<?xi8>>
   ! CHECK: %[[coor:.*]] = fir.coordinate_of %[[byteView]], %c24{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>

Copy link
Contributor

@psteinfeld psteinfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All builds and tests correctly and looks good.

@jeanPerier jeanPerier merged commit 87e2521 into llvm:main Oct 2, 2023
@jeanPerier jeanPerier deleted the jp-zero-op-2 branch October 2, 2023 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants