Skip to content

[flang][Semantics] Ensure deterministic mod file output follow-up #129669

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

Conversation

inaki-amatria
Copy link
Member

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.

@inaki-amatria inaki-amatria requested a review from klausler March 4, 2025 08:31
@inaki-amatria inaki-amatria self-assigned this Mar 4, 2025
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Mar 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 4, 2025

@llvm/pr-subscribers-flang-semantics

Author: Iñaki Amatria Barral (inaki-amatria)

Changes

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.


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

5 Files Affected:

  • (modified) flang/lib/Semantics/mod-file.cpp (+3-3)
  • (added) flang/test/Semantics/Inputs/modfile73-a.f90 (+197)
  • (added) flang/test/Semantics/Inputs/modfile73-b.f90 (+89)
  • (added) flang/test/Semantics/Inputs/modfile73-c.f90 (+4)
  • (added) flang/test/Semantics/modfile73.f90 (+53)
diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index 82c43d96bea44..83a06e6f4677d 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -47,7 +47,7 @@ struct ModHeader {
 
 static std::optional<SourceName> 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<SourceName> &);
 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 0000000000000..45a93f6c1b097
--- /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 0000000000000..3b9c72ab507b9
--- /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 0000000000000..abf76445d4619
--- /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 0000000000000..f27b293d79d99
--- /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

@inaki-amatria inaki-amatria merged commit 6eefadd into llvm:main Mar 5, 2025
14 checks passed
@inaki-amatria inaki-amatria deleted the fix-ensure-deterministic-mod-file-output branch March 5, 2025 07:27
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
This PR is a follow-up to llvm#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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants