Skip to content

Commit 6eefadd

Browse files
[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.
1 parent 107fe0e commit 6eefadd

File tree

5 files changed

+346
-3
lines changed

5 files changed

+346
-3
lines changed

flang/lib/Semantics/mod-file.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ struct ModHeader {
4747

4848
static std::optional<SourceName> GetSubmoduleParent(const parser::Program &);
4949
static void CollectSymbols(
50-
const Scope &, SymbolVector &, SymbolVector &, UnorderedSymbolSet &);
50+
const Scope &, SymbolVector &, SymbolVector &, SourceOrderedSymbolSet &);
5151
static void PutPassName(llvm::raw_ostream &, const std::optional<SourceName> &);
5252
static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &,
5353
const parser::Expr *);
@@ -363,7 +363,7 @@ void ModFileWriter::PutSymbols(
363363
auto &renamings{context_.moduleFileOutputRenamings()};
364364
auto previousRenamings{std::move(renamings)};
365365
PrepareRenamings(scope);
366-
UnorderedSymbolSet modules;
366+
SourceOrderedSymbolSet modules;
367367
CollectSymbols(scope, sorted, uses, modules);
368368
// Write module files for dependencies first so that their
369369
// hashes are known.
@@ -839,7 +839,7 @@ void ModFileWriter::PutUseExtraAttr(
839839
// Collect the symbols of this scope sorted by their original order, not name.
840840
// Generics and namelists are exceptions: they are sorted after other symbols.
841841
void CollectSymbols(const Scope &scope, SymbolVector &sorted,
842-
SymbolVector &uses, UnorderedSymbolSet &modules) {
842+
SymbolVector &uses, SourceOrderedSymbolSet &modules) {
843843
SymbolVector namelist, generics;
844844
auto symbols{scope.GetSymbols()};
845845
std::size_t commonSize{scope.commonBlocks().size()};
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
MODULE modfile73a
2+
PUBLIC re_alloc, defaults
3+
integersp
4+
integerselected_real_kind0
5+
integer:: i8b = selected_int_kind(8)
6+
interface
7+
subroutine alloc_error_report_interf(str,code)
8+
end
9+
subroutine alloc_memory_event_interf(bytes,name)
10+
end
11+
end interface
12+
procedure()alloc_error_report
13+
procedure()alloc_memory_event
14+
interface de_alloc
15+
end interface
16+
charactercharacter, DEFAULT_ROUTINE
17+
type allocDefaults
18+
logical copy
19+
logical shrink
20+
integer imin
21+
characterroutine
22+
end type
23+
type(allocDefaults)DEFAULT
24+
integer IERR
25+
logical ASSOCIATED_ARRAY, NEEDS_ALLOC, NEEDS_COPY, NEEDS_DEALLOC
26+
CONTAINS
27+
subroutine set_alloc_event_handler(func)
28+
end
29+
subroutine set_alloc_error_handler(func)
30+
end
31+
subroutine dummy_alloc_memory_event(bytes,name)
32+
end
33+
subroutine dummy_alloc_error_report(name,code)
34+
end
35+
SUBROUTINE alloc_default( old, new, restore, routine, copy, shrink, imin )
36+
END
37+
SUBROUTINE realloc_i1( array, i1min, i1max, name, routine, copy, shrink )
38+
END
39+
SUBROUTINE realloc_i2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink )
40+
END
41+
SUBROUTINE realloc_i3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink )
42+
END
43+
SUBROUTINE realloc_i4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink )
44+
END
45+
SUBROUTINE realloc_i5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink )
46+
END
47+
SUBROUTINE realloc_E1( array, i1min, i1max, name, routine, copy, shrink )
48+
END
49+
SUBROUTINE realloc_r1( array, i1min, i1max, name, routine, copy, shrink )
50+
END
51+
SUBROUTINE realloc_r2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink )
52+
END
53+
SUBROUTINE realloc_r3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink )
54+
END
55+
SUBROUTINE realloc_r4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink )
56+
END
57+
SUBROUTINE realloc_r5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink )
58+
END
59+
SUBROUTINE realloc_d1( array, i1min, i1max, name, routine, copy, shrink )
60+
END
61+
SUBROUTINE realloc_d2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink )
62+
END
63+
SUBROUTINE realloc_d3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink )
64+
END
65+
SUBROUTINE realloc_d4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink )
66+
END
67+
SUBROUTINE realloc_d5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, i5min,i5max, name, routine, copy, shrink )
68+
END
69+
SUBROUTINE realloc_c1( array, i1min, i1max, name, routine, copy, shrink )
70+
END
71+
SUBROUTINE realloc_c2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink )
72+
END
73+
SUBROUTINE realloc_c3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink )
74+
END
75+
SUBROUTINE realloc_c4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink )
76+
END
77+
SUBROUTINE realloc_c5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink )
78+
END
79+
SUBROUTINE realloc_z1( array, i1min, i1max, name, routine, copy, shrink )
80+
END
81+
SUBROUTINE realloc_z2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink )
82+
END
83+
SUBROUTINE realloc_z3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink )
84+
END
85+
SUBROUTINE realloc_z4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink )
86+
END
87+
SUBROUTINE realloc_z5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink )
88+
END
89+
SUBROUTINE realloc_l1( array, i1min,i1max, name, routine, copy, shrink )
90+
END
91+
SUBROUTINE realloc_l2( array, i1min,i1max, i2min,i2max, name, routine, copy, shrink )
92+
END
93+
SUBROUTINE realloc_l3( array, i1min,i1max, i2min,i2max, i3min,i3max, name, routine, copy, shrink )
94+
END
95+
SUBROUTINE realloc_l4( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min,i4max, name, routine, copy, shrink )
96+
END
97+
SUBROUTINE realloc_l5( array, i1min,i1max, i2min,i2max, i3min,i3max, i4min, i4max, i5min, i5max, name, routine, copy, shrink )
98+
END
99+
SUBROUTINE realloc_i1s( array, i1max, name, routine, copy, shrink )
100+
END
101+
SUBROUTINE realloc_i2s( array, i1max, i2max, name, routine, copy, shrink )
102+
END
103+
SUBROUTINE realloc_i3s( array, i1max, i2max, i3max, name, routine, copy, shrink )
104+
END
105+
SUBROUTINE realloc_r1s( array, i1max, name, routine, copy, shrink )
106+
END
107+
SUBROUTINE realloc_r2s( array, i1max, i2max, name, routine, copy, shrink )
108+
END
109+
SUBROUTINE realloc_r3s( array, i1max, i2max, i3max, name, routine, copy, shrink )
110+
END
111+
SUBROUTINE realloc_r4s( array, i1max, i2max, i3max, i4max, name, routine, copy, shrink )
112+
END
113+
SUBROUTINE realloc_d1s( array, i1max, name, routine, copy, shrink )
114+
END
115+
SUBROUTINE realloc_d3s( array, i1max, i2max, i3max, name, routine, copy, shrink )
116+
END
117+
SUBROUTINE realloc_d4s( array, i1max, i2max, i3max, i4max, name, routine, copy, shrink )
118+
END
119+
SUBROUTINE realloc_l1s( array, i1max, name, routine, copy, shrink )
120+
END
121+
SUBROUTINE realloc_l2s( array, i1max, i2max, name, routine, copy, shrink )
122+
END
123+
SUBROUTINE realloc_l3s( array, i1max, i2max, i3max, name, routine, copy, shrink )
124+
END
125+
SUBROUTINE realloc_s1( array, i1min, i1max, name, routine, copy, shrink )
126+
END
127+
SUBROUTINE dealloc_i1( array, name, routine )
128+
END
129+
SUBROUTINE dealloc_i2( array, name, routine )
130+
END
131+
SUBROUTINE dealloc_i3( array, name, routine )
132+
END
133+
SUBROUTINE dealloc_i4( array, name, routine )
134+
END
135+
SUBROUTINE dealloc_i5( array, name, routine )
136+
END
137+
SUBROUTINE dealloc_E1( array, name, routine )
138+
END
139+
SUBROUTINE dealloc_r1( array, name, routine )
140+
END
141+
SUBROUTINE dealloc_r2( array, name, routine )
142+
END
143+
SUBROUTINE dealloc_r3( array, name, routine )
144+
END
145+
SUBROUTINE dealloc_r4( array, name, routine )
146+
END
147+
SUBROUTINE dealloc_r5( array, name, routine )
148+
END
149+
SUBROUTINE dealloc_d1( array, name, routine )
150+
END
151+
SUBROUTINE dealloc_d2( array, name, routine )
152+
END
153+
SUBROUTINE dealloc_d3( array, name, routine )
154+
END
155+
SUBROUTINE dealloc_d4( array, name, routine )
156+
END
157+
SUBROUTINE dealloc_d5( array, name, routine )
158+
END
159+
SUBROUTINE dealloc_c1( array, name, routine )
160+
END
161+
SUBROUTINE dealloc_c2( array, name, routine )
162+
END
163+
SUBROUTINE dealloc_c3( array, name, routine )
164+
END
165+
SUBROUTINE dealloc_c4( array, name, routine )
166+
END
167+
SUBROUTINE dealloc_c5( array, name, routine )
168+
END
169+
SUBROUTINE dealloc_z1( array, name, routine )
170+
END
171+
SUBROUTINE dealloc_z2( array, name, routine )
172+
END
173+
SUBROUTINE dealloc_z3( array, name, routine )
174+
END
175+
SUBROUTINE dealloc_z4( array, name, routine )
176+
END
177+
SUBROUTINE dealloc_z5( array, name, routine )
178+
END
179+
SUBROUTINE dealloc_l1( array, name, routine )
180+
END
181+
SUBROUTINE dealloc_l2( array, name, routine )
182+
END
183+
SUBROUTINE dealloc_l3( array, name, routine )
184+
END
185+
SUBROUTINE dealloc_l4( array, name, routine )
186+
END
187+
SUBROUTINE dealloc_l5( array, name, routine )
188+
END
189+
SUBROUTINE dealloc_s1( array, name, routine )
190+
END
191+
SUBROUTINE options( final_bounds, common_bounds, old_bounds, new_bounds, copy, shrink )
192+
END
193+
SUBROUTINE alloc_err( ierr, name, routine, bounds )
194+
END
195+
SUBROUTINE alloc_count( delta_size, type, name, routine )
196+
END
197+
END
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
module modfile73ba
2+
use modfile73a, only: re_alloc, de_alloc
3+
charactermod_name
4+
type lData1D
5+
integer refCount
6+
character id
7+
character name
8+
end type
9+
type TYPE_NAME
10+
type(lData1D), pointer :: data => null()
11+
end type
12+
interface refcount
13+
end interface
14+
interface initialized
15+
end interface
16+
interface same
17+
end interface
18+
CONTAINS
19+
subroutine init_(this)
20+
end
21+
subroutine delete_(this)
22+
end
23+
subroutine assign_(this, other)
24+
end
25+
function initialized_(thisinit)
26+
end
27+
function same_(this1,this2same)
28+
end
29+
function refcount_(thiscount)
30+
end
31+
function id_(thisstr)
32+
end
33+
function name_(this) result(str)
34+
type(TYPE_NAME) this
35+
character(len_trim(this%data%name)) str
36+
end
37+
subroutine tag_new_object(this)
38+
end
39+
subroutine delete_Data(a1d_data)
40+
end
41+
end
42+
43+
module modfile73bb
44+
use modfile73a, only: re_alloc, de_alloc
45+
charactermod_name
46+
type lData1D
47+
integer refCount
48+
character id
49+
character name
50+
logical, pointer :: val => null()
51+
end type
52+
TYPE_NAME
53+
type(lData1D), pointer :: data => null()
54+
end type
55+
PRIVATE
56+
public TYPE_NAME
57+
public initdelete, assignment, refcount, id
58+
public name
59+
public allocated
60+
interface init
61+
end interface
62+
interface delete
63+
end interface
64+
interface initialized
65+
subroutine die(str)
66+
end
67+
end interface
68+
CONTAINS
69+
subroutine init_(this)
70+
end
71+
subroutine delete_(this)
72+
end
73+
subroutine assign_(this, other)
74+
end
75+
function initialized_(thisinit)
76+
end
77+
function same_(this1,this2same)
78+
end
79+
function refcount_(thiscount)
80+
end
81+
function id_(thisstr)
82+
end
83+
function name_(thisstr)
84+
end
85+
subroutine tag_new_object(this)
86+
end
87+
subroutine delete_Data(a1d_data)
88+
end
89+
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module modfile73c
2+
type OrbitalDistribution_
3+
end type
4+
end

flang/test/Semantics/modfile73.f90

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
! This test verifies that both invocations produce a consistent order in the
2+
! generated `.mod` file. Previous versions of Flang exhibited non-deterministic
3+
! behavior due to iterating over a set ordered by heap pointers. This issue was
4+
! particularly noticeable when using Flang as a library.
5+
6+
! RUN: rm -rf %t && mkdir -p %t
7+
! RUN: %flang_fc1 \
8+
! RUN: -fsyntax-only \
9+
! RUN: -J%t \
10+
! RUN: %S/Inputs/modfile73-a.f90 \
11+
! RUN: %S/Inputs/modfile73-b.f90 \
12+
! RUN: %S/Inputs/modfile73-c.f90
13+
! RUN: %flang_fc1 -fsyntax-only -J%t %s
14+
! RUN: cat %t/modfile73.mod | FileCheck %s
15+
16+
! RUN: rm -rf %t && mkdir -p %t
17+
! RUN: %flang_fc1 \
18+
! RUN: -fsyntax-only \
19+
! RUN: -J%t \
20+
! RUN: %S/Inputs/modfile73-a.f90 \
21+
! RUN: %S/Inputs/modfile73-b.f90 \
22+
! RUN: %S/Inputs/modfile73-c.f90 \
23+
! RUN: %s
24+
! RUN: cat %t/modfile73.mod | FileCheck %s
25+
26+
use modfile73ba
27+
end
28+
module modfile73
29+
use modfile73bb
30+
use modfile73c
31+
CONTAINS
32+
subroutine init_
33+
end
34+
subroutine delete_
35+
end
36+
subroutine assign_
37+
end
38+
function initialized_
39+
end
40+
function same_
41+
end
42+
function refcount_
43+
end
44+
function id_
45+
end
46+
function name_
47+
end
48+
subroutine tag_new_object
49+
end
50+
end
51+
52+
! CHECK: !need$ {{.*}} n modfile73bb
53+
! CHECK-NEXT: !need$ {{.*}} n modfile73c

0 commit comments

Comments
 (0)