From 6eefadd8efc0584211cb5283e0acc00a45588242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20Amatria=20Barral?= <140811900+inaki-amatria@users.noreply.github.com> Date: Wed, 5 Mar 2025 08:27:17 +0100 Subject: [PATCH] [flang][Semantics] Ensure deterministic mod file output (#129669) This PR is a follow-up to #128655. It adds another test to ensure deterministic ordering in `.mod` files and includes related changes to prevent non-deterministic ordering caused by iterating over a set ordered by heap pointers. This issue is particularly noticeable when using Flang as a library and compiling the same files multiple times. The reduced test case is as minimal as possible. We were unable to reproduce the issue with a smaller set of files. --- flang/lib/Semantics/mod-file.cpp | 6 +- flang/test/Semantics/Inputs/modfile73-a.f90 | 197 ++++++++++++++++++++ flang/test/Semantics/Inputs/modfile73-b.f90 | 89 +++++++++ flang/test/Semantics/Inputs/modfile73-c.f90 | 4 + flang/test/Semantics/modfile73.f90 | 53 ++++++ 5 files changed, 346 insertions(+), 3 deletions(-) create mode 100644 flang/test/Semantics/Inputs/modfile73-a.f90 create mode 100644 flang/test/Semantics/Inputs/modfile73-b.f90 create mode 100644 flang/test/Semantics/Inputs/modfile73-c.f90 create mode 100644 flang/test/Semantics/modfile73.f90 diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp index 1dfd9c35b3f4..ac176978a45a 100644 --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -47,7 +47,7 @@ struct ModHeader { static std::optional GetSubmoduleParent(const parser::Program &); static void CollectSymbols( - const Scope &, SymbolVector &, SymbolVector &, UnorderedSymbolSet &); + const Scope &, SymbolVector &, SymbolVector &, SourceOrderedSymbolSet &); static void PutPassName(llvm::raw_ostream &, const std::optional &); static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &, const parser::Expr *); @@ -363,7 +363,7 @@ void ModFileWriter::PutSymbols( auto &renamings{context_.moduleFileOutputRenamings()}; auto previousRenamings{std::move(renamings)}; PrepareRenamings(scope); - UnorderedSymbolSet modules; + SourceOrderedSymbolSet modules; CollectSymbols(scope, sorted, uses, modules); // Write module files for dependencies first so that their // hashes are known. @@ -839,7 +839,7 @@ void ModFileWriter::PutUseExtraAttr( // Collect the symbols of this scope sorted by their original order, not name. // Generics and namelists are exceptions: they are sorted after other symbols. void CollectSymbols(const Scope &scope, SymbolVector &sorted, - SymbolVector &uses, UnorderedSymbolSet &modules) { + SymbolVector &uses, SourceOrderedSymbolSet &modules) { SymbolVector namelist, generics; auto symbols{scope.GetSymbols()}; std::size_t commonSize{scope.commonBlocks().size()}; diff --git a/flang/test/Semantics/Inputs/modfile73-a.f90 b/flang/test/Semantics/Inputs/modfile73-a.f90 new file mode 100644 index 000000000000..45a93f6c1b09 --- /dev/null +++ b/flang/test/Semantics/Inputs/modfile73-a.f90 @@ -0,0 +1,197 @@ +MODULE modfile73a +PUBLIC re_alloc, defaults +integersp +integerselected_real_kind0 +integer:: i8b = selected_int_kind(8) +interface + subroutine alloc_error_report_interf(str,code) + end + subroutine alloc_memory_event_interf(bytes,name) + end +end interface +procedure()alloc_error_report +procedure()alloc_memory_event + interface de_alloc + end interface + charactercharacter, DEFAULT_ROUTINE + type allocDefaults + logical copy + logical shrink + integer imin + characterroutine + end type + type(allocDefaults)DEFAULT + integer IERR + logical ASSOCIATED_ARRAY, NEEDS_ALLOC, NEEDS_COPY, NEEDS_DEALLOC +CONTAINS + subroutine set_alloc_event_handler(func) + end + subroutine set_alloc_error_handler(func) + end + subroutine dummy_alloc_memory_event(bytes,name) + end + subroutine dummy_alloc_error_report(name,code) + end +SUBROUTINE alloc_default( old, new, restore, routine, copy, shrink, imin ) +END +SUBROUTINE realloc_i1( array, i1min, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_i2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_i3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_i4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_i5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_E1( array, i1min, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r1( array, i1min, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_d1( array, i1min, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_d2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_d3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_d4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_d5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, i5min,i5max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_c1( array, i1min, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_c2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_c3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_c4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_c5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_z1( array, i1min, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_z2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_z3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_z4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_z5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_l1( array, i1min,i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_l2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_l3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_l4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_l5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_i1s( array, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_i2s( array, i1max, i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_i3s( array, i1max, i2max, i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r1s( array, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r2s( array, i1max, i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r3s( array, i1max, i2max, i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_r4s( array, i1max, i2max, i3max, i4max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_d1s( array, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_d3s( array, i1max, i2max, i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_d4s( array, i1max, i2max, i3max, i4max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_l1s( array, i1max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_l2s( array, i1max, i2max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_l3s( array, i1max, i2max, i3max, name, routine, copy, shrink ) +END +SUBROUTINE realloc_s1( array, i1min, i1max, name, routine, copy, shrink ) +END +SUBROUTINE dealloc_i1( array, name, routine ) +END +SUBROUTINE dealloc_i2( array, name, routine ) +END +SUBROUTINE dealloc_i3( array, name, routine ) +END +SUBROUTINE dealloc_i4( array, name, routine ) + END +SUBROUTINE dealloc_i5( array, name, routine ) + END +SUBROUTINE dealloc_E1( array, name, routine ) +END +SUBROUTINE dealloc_r1( array, name, routine ) +END +SUBROUTINE dealloc_r2( array, name, routine ) +END +SUBROUTINE dealloc_r3( array, name, routine ) +END +SUBROUTINE dealloc_r4( array, name, routine ) +END +SUBROUTINE dealloc_r5( array, name, routine ) +END +SUBROUTINE dealloc_d1( array, name, routine ) +END +SUBROUTINE dealloc_d2( array, name, routine ) +END +SUBROUTINE dealloc_d3( array, name, routine ) +END +SUBROUTINE dealloc_d4( array, name, routine ) +END +SUBROUTINE dealloc_d5( array, name, routine ) +END +SUBROUTINE dealloc_c1( array, name, routine ) +END +SUBROUTINE dealloc_c2( array, name, routine ) +END +SUBROUTINE dealloc_c3( array, name, routine ) +END +SUBROUTINE dealloc_c4( array, name, routine ) +END +SUBROUTINE dealloc_c5( array, name, routine ) + END +SUBROUTINE dealloc_z1( array, name, routine ) +END +SUBROUTINE dealloc_z2( array, name, routine ) +END +SUBROUTINE dealloc_z3( array, name, routine ) +END +SUBROUTINE dealloc_z4( array, name, routine ) +END +SUBROUTINE dealloc_z5( array, name, routine ) + END +SUBROUTINE dealloc_l1( array, name, routine ) +END +SUBROUTINE dealloc_l2( array, name, routine ) +END +SUBROUTINE dealloc_l3( array, name, routine ) +END +SUBROUTINE dealloc_l4( array, name, routine ) + END +SUBROUTINE dealloc_l5( array, name, routine ) + END +SUBROUTINE dealloc_s1( array, name, routine ) +END +SUBROUTINE options( final_bounds, common_bounds, old_bounds, new_bounds, copy, shrink ) +END +SUBROUTINE alloc_err( ierr, name, routine, bounds ) +END +SUBROUTINE alloc_count( delta_size, type, name, routine ) +END +END diff --git a/flang/test/Semantics/Inputs/modfile73-b.f90 b/flang/test/Semantics/Inputs/modfile73-b.f90 new file mode 100644 index 000000000000..3b9c72ab507b --- /dev/null +++ b/flang/test/Semantics/Inputs/modfile73-b.f90 @@ -0,0 +1,89 @@ +module modfile73ba + use modfile73a, only: re_alloc, de_alloc + charactermod_name + type lData1D + integer refCount + character id + character name + end type + type TYPE_NAME + type(lData1D), pointer :: data => null() + end type + interface refcount + end interface + interface initialized + end interface + interface same + end interface +CONTAINS + subroutine init_(this) + end + subroutine delete_(this) + end + subroutine assign_(this, other) + end + function initialized_(thisinit) + end + function same_(this1,this2same) + end + function refcount_(thiscount) + end + function id_(thisstr) + end + function name_(this) result(str) + type(TYPE_NAME) this + character(len_trim(this%data%name)) str + end + subroutine tag_new_object(this) + end + subroutine delete_Data(a1d_data) + end +end + +module modfile73bb + use modfile73a, only: re_alloc, de_alloc + charactermod_name + type lData1D + integer refCount + character id + character name +logical, pointer :: val => null() + end type + TYPE_NAME + type(lData1D), pointer :: data => null() + end type + PRIVATE + public TYPE_NAME + public initdelete, assignment, refcount, id + public name + public allocated + interface init + end interface + interface delete + end interface + interface initialized + subroutine die(str) + end + end interface +CONTAINS + subroutine init_(this) + end + subroutine delete_(this) + end + subroutine assign_(this, other) + end + function initialized_(thisinit) + end + function same_(this1,this2same) + end + function refcount_(thiscount) + end + function id_(thisstr) + end + function name_(thisstr) + end + subroutine tag_new_object(this) + end + subroutine delete_Data(a1d_data) + end +end diff --git a/flang/test/Semantics/Inputs/modfile73-c.f90 b/flang/test/Semantics/Inputs/modfile73-c.f90 new file mode 100644 index 000000000000..abf76445d461 --- /dev/null +++ b/flang/test/Semantics/Inputs/modfile73-c.f90 @@ -0,0 +1,4 @@ +module modfile73c + type OrbitalDistribution_ + end type + end diff --git a/flang/test/Semantics/modfile73.f90 b/flang/test/Semantics/modfile73.f90 new file mode 100644 index 000000000000..f27b293d79d9 --- /dev/null +++ b/flang/test/Semantics/modfile73.f90 @@ -0,0 +1,53 @@ +! This test verifies that both invocations produce a consistent order in the +! generated `.mod` file. Previous versions of Flang exhibited non-deterministic +! behavior due to iterating over a set ordered by heap pointers. This issue was +! particularly noticeable when using Flang as a library. + +! RUN: rm -rf %t && mkdir -p %t +! RUN: %flang_fc1 \ +! RUN: -fsyntax-only \ +! RUN: -J%t \ +! RUN: %S/Inputs/modfile73-a.f90 \ +! RUN: %S/Inputs/modfile73-b.f90 \ +! RUN: %S/Inputs/modfile73-c.f90 +! RUN: %flang_fc1 -fsyntax-only -J%t %s +! RUN: cat %t/modfile73.mod | FileCheck %s + +! RUN: rm -rf %t && mkdir -p %t +! RUN: %flang_fc1 \ +! RUN: -fsyntax-only \ +! RUN: -J%t \ +! RUN: %S/Inputs/modfile73-a.f90 \ +! RUN: %S/Inputs/modfile73-b.f90 \ +! RUN: %S/Inputs/modfile73-c.f90 \ +! RUN: %s +! RUN: cat %t/modfile73.mod | FileCheck %s + + use modfile73ba +end +module modfile73 + use modfile73bb + use modfile73c + CONTAINS + subroutine init_ + end + subroutine delete_ + end + subroutine assign_ + end + function initialized_ + end + function same_ + end + function refcount_ + end + function id_ + end + function name_ + end + subroutine tag_new_object + end +end + +! CHECK: !need$ {{.*}} n modfile73bb +! CHECK-NEXT: !need$ {{.*}} n modfile73c