equivalence.c
1 //! @file equivalence.c
2 //! @author J. Marcel van der Veer
3 //
4 //! @section Copyright
5 //
6 // This file is part of VIF - vintage FORTRAN compiler.
7 // Copyright 2020-2025 J. Marcel van der Veer <algol68g@xs4all.nl>.
8 //
9 //! @section License
10 //
11 // This program is free software; you can redistribute it and/or modify it
12 // under the terms of the GNU General Public License as published by the
13 // Free Software Foundation; either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 // more details. You should have received a copy of the GNU General Public
20 // License along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 //! @section Synopsis
23 //!
24 //! Compile EQUIVALENCE statements.
25
26 // This code compiles pairwise equivalence statements of the form
27 //
28 // EQUIVALENCE (A, B), ...
29 //
30 // Multiple equivalence was allowed by vintage Fortran,
31 // but hardly used (if at all) in practice.
32 // Anyway, VIF compiles
33 //
34 // EQUIVALENCE (A, B, C, D)
35 //
36 // as (Aho, Sethi, Ullman)
37 //
38 // EQUIVALENCE (B, A), (C, A), (D, A)
39 //
40 // Not all EQUIVALENCE statements may work in VIF as VIF neither emulates the
41 // FORTRAN memory model, nor combines equivalence statements. This hardly has
42 // consequences for compiling existing vintage code. Programmers apparently
43 // only need(ed) basic equivalence facilities.
44
45 #include <vif.h>
46
47 static void eq_compute_row_size (IDENT *idf, int_4 *val)
48 {
49 // Compute size of row in bytes.
50 RECORD buf;
51 RECCLR (buf);
52 compute_row_size (buf, idf);
53 if (EQUAL (buf, "VARY")) {
54 ERROR (1201, "varying row in equivalence", NO_TEXT);
55 }
56 if (!isint_4 (buf, val)) {
57 (*val) = 0;
58 }
59 }
60
61 static void eq_var_any (EXPR lhs, EXPR rhs, int_4 *N)
62 {
63 // Link a variable to either variable or row.
64 IDENT *lid = lhs.idf, *rid = rhs.idf; RECORD str;
65 // Redirect if possible.
66 if (lid->equiv != NO_IDENT) {
67 if (rid->equiv == NO_IDENT) {
68 eq_var_any (rhs, lhs, N);
69 } else {
70 _srecordf (str, "(%s, %s)", FTN_NAME (lid), FTN_NAME (rid));
71 ERROR (1202, "cannot alias", str);
72 }
73 return;
74 }
75 // Peephole optimization.
76 RECORD target, buf;
77 RECCLR (target);
78 if (IS_SCALAR (rid->mode)) {
79 _srecordf (target, "&(%s)", rhs.str);
80 } else {
81 if (!isint_4 (rhs.elem, &rhs.value)) {
82 SYNTAX (1203, "rhs must have a constant index");
83 return;
84 }
85 if (rhs.value == 0) {
86 _srecordf (target, "%s", idf_full_c_name (buf, rid));
87 } else {
88 _srecordf (target, "&(%s)", rhs.str);
89 }
90 }
91 // Make alias.
92 if (rid->common != LOCAL) {
93 cpp_direct (nprocs, prelin, REFDECL);
94 _srecordf (str, "static %s %s = %s %s;\n", wtype (&lhs.mode, NOARG, NOFUN), ptr_to_array (lhs.idf, CONST, NOCAST, ACTUAL), ptr_to_array (lhs.idf, NOCONST, CAST, ACTUAL), target);
95 code (nprocs, REFDECL, str);
96 lid->const_ref = TRUE;
97 } else if (lhs.mode.save == STATIC) {
98 if (rhs.mode.save == STATIC) {
99 cpp_direct (nprocs, prelin, REFDECL);
100 _srecordf (str, "static %s %s = %s %s;\n", wtype (&lhs.mode, NOARG, NOFUN), ptr_to_array (lhs.idf, CONST, NOCAST, ACTUAL), ptr_to_array (lhs.idf, NOCONST, CAST, ACTUAL), target);
101 code (nprocs, REFDECL, str);
102 lid->const_ref = TRUE;
103 } else {
104 cpp_direct (nprocs, prelin, EQUIV);
105 _srecordf (str, "%s = %s %s;\n", lhs.str, ptr_to_array (lhs.idf, NOCONST, CAST, ACTUAL), target);
106 code (nprocs, EQUIV, str);
107 N++;
108 }
109 } else {
110 cpp_direct (nprocs, prelin, BODY);
111 _srecordf (str, "%s = %s %s;\n", lhs.str, ptr_to_array (lhs.idf, NOCONST, CAST, ACTUAL), target);
112 code (nprocs, BODY, str);
113 }
114 }
115
116 static void eq_row_row (EXPR lhs, EXPR rhs, int_4 *N)
117 {
118 // Link a row to a row.
119 IDENT *lid = lhs.idf, *rid = rhs.idf; RECORD str;
120 RECORD index, buf;
121 // Peephole optimization.
122 if (lhs.value == rhs.value) {
123 _srecordf (index, "%s", idf_full_c_name (buf, rid));
124 } else {
125 _srecordf (index, "&(%s[%d])", idf_full_c_name (buf, rid), rhs.value - lhs.value);
126 }
127 // Make alias.
128 if (rid->common != LOCAL) {
129 cpp_direct (nprocs, prelin, DECL);
130 _srecordf (str, "static %s %s = %s %s;\n", wtype (&lhs.mode, NOARG, NOFUN), ptr_to_array (lid, CONST, NOCAST, ACTUAL), ptr_to_array (lid, NOCONST, CAST, ACTUAL), index);
131 code (nprocs, DECL, str);
132 lid->const_ref = TRUE;
133 } else {
134 _srecordf (str, "%s = %s %s;\n", C_NAME (lid), ptr_to_array (lid, NOCONST, CAST, ACTUAL), index);
135 if (lhs.mode.save == STATIC) {
136 cpp_direct (nprocs, prelin, EQUIV);
137 code (nprocs, EQUIV, str);
138 N++;
139 } else {
140 cpp_direct (nprocs, prelin, BODY);
141 code (nprocs, BODY, str);
142 }
143 }
144 }
145
146 static void eq_link (EXPR lhs, EXPR rhs, int_4 *N)
147 {
148 IDENT *lid = lhs.idf, *rid = rhs.idf;
149 // Oops!
150 if (lid == NO_IDENT || rid == NO_IDENT) {
151 SYNTAX (1204, "equivalence statement");
152 return;
153 }
154 // ROW -> ROW is mostly OK.
155 if (IS_ROW (lid->mode) && IS_ROW (rid->mode)) {
156 if (!isint_4 (lhs.elem, &lhs.value)) {
157 SYNTAX (1205, "lhs must have a constant index");
158 return;
159 }
160 if (!isint_4 (rhs.elem, &rhs.value)) {
161 SYNTAX (1206, "rhs must have a constant index");
162 return;
163 }
164 int_4 lsz, rsz;
165 eq_compute_row_size (lid, &lsz);
166 eq_compute_row_size (rid, &rsz);
167 // We want the alias to fit in the target.
168 if (rhs.idf->common == LOCAL && (rhs.value <= lhs.value) && (rsz <= lsz - lhs.value)) {
169 rid->alias = lid;
170 lid->equiv = rid;
171 eq_row_row (rhs, lhs, N);
172 } else if (lhs.idf->common == LOCAL && (rhs.value >= lhs.value) && (lsz <= rsz - rhs.value)) {
173 lid->alias = rid;
174 rid->equiv = lid;
175 eq_row_row (lhs, rhs, N);
176 } else {
177 // Alias sticks out to the right.
178 ERROR (1207, "equivalence", "cannot equivalence");
179 }
180 return;
181 }
182 // ROW -> VAR is VAR -> ROW.
183 if (IS_ROW (lid->mode) && IS_SCALAR (rid->mode)) {
184 eq_link (rhs, lhs, N);
185 return;
186 }
187 // Shuffle to avoid multiple equivalencing if possible.
188 if (lid->equiv != NO_IDENT) {
189 if (rid->equiv == NO_IDENT) {
190 eq_link (rhs, lhs, N);
191 return;
192 } else {
193 RECORD str;
194 _srecordf (str, "(%s, %s)", FTN_NAME (lid), FTN_NAME (rid));
195 ERROR (1208, "cannot alias", str);
196 }
197 }
198 // VAR -> VAR is OK.
199 if (IS_SCALAR (lid->mode) && IS_SCALAR (rid->mode)) {
200 lid->alias = rid;
201 rid->equiv = lid;
202 eq_var_any (lhs, rhs, N);
203 }
204 // VAR -> ROW is OK.
205 if (IS_SCALAR (lid->mode) && IS_ROW (rid->mode)) {
206 lid->alias = rid;
207 rid->equiv = lid;
208 eq_var_any (lhs, rhs, N);
209 }
210 }
211
212 void equivalence (void)
213 {
214 // EQUIVALENCE by aliasing already allocated variables or arrays.
215 // We already know that parentheses are balanced.
216 int_4 rc, N = 0;
217 int_4 epatch = code (nprocs, EQUIV, NO_TEXT);
218 while ((rc = scan (EXPECT_NONE)) != END_OF_LINE) {
219 if (TOKEN (",")) {
220 continue;
221 } else if (TOKEN ("(")) {
222 continue;
223 } else if (rc != WORD) {
224 EXPECT (1209, "identifier");
225 } else {
226 IDENT *lid, *rid;
227 EXPR lhs, rhs;
228 MODE lmode, rmode;
229 rid = impl_decl (curlex, &lmode);
230 if (rid->alias != NO_IDENT) {
231 ERROR (1210, "cannot alias", curlex);
232 }
233 factor (&rhs);
234 rc = scan (EXPECT_NONE);
235 if (!TOKEN (",")) {
236 EXPECT (1211, ",");
237 }
238 // Loop resolving multiple equivalence.
239 while (TOKEN (",")) {
240 rc = scan (EXPECT_NONE);
241 if (rc != WORD) {
242 EXPECT (1212, "variable");
243 }
244 lid = impl_decl (curlex, &rmode);
245 factor (&lhs);
246 rc = scan (EXPECT_NONE);
247 // Mistakes.
248 if (lid == NO_IDENT || rid == NO_IDENT) {
249 break;
250 }
251 if (lid->mode.save != rid->mode.save) {
252 ERROR (1213, "aliasing static and automatic", NO_TEXT);
253 break;
254 }
255 if (lid->common != LOCAL && rid->common != LOCAL) {
256 ERROR (1214, "lhs and rhs are in common block", NO_TEXT);
257 break;
258 }
259 // If a row is denoted as variable, address of first element is implied.
260 // Padding "[0]" simplifies code generation.
261 if (lhs.variant == EXPR_VAR && IS_ROW (lid->mode)) {
262 bufcat (lhs.str, "[0]", RECLN);
263 _srecordf (lhs.elem, "0");
264 lhs.value = 0;
265 }
266 if (rhs.variant == EXPR_VAR && IS_ROW (rid->mode)) {
267 bufcat (rhs.str, "[0]", RECLN);
268 _srecordf (rhs.elem, "0");
269 rhs.value = 0;
270 }
271 // Warning!
272 if (lid->mode.type != rid->mode.type || lid->mode.len != rid->mode.len) {
273 RECORD str;
274 _srecordf (str, "equivalence (%s, %s)", qtype (&(rhs.mode)), qtype (&(lhs.mode)));
275 WARNING (1215, "mixed types", str);
276 }
277 // Equivalence in correct order.
278 if (lid->common == LOCAL) {
279 eq_link (lhs, rhs, &N);
280 } else if (rid->common == LOCAL) {
281 eq_link (rhs, lhs, &N);
282 } else {
283 eq_link (lhs, rhs, &N);
284 }
285 }
286 }
287 }
288 if (N > 0) {
289 RECORD str;
290 cpp_direct (nprocs, prelin, EQUIV);
291 _srecordf (str, "if (__calls[%d].calls == 0) {\n", nprocs - 1);
292 patch (epatch, str);
293 code (nprocs, EQUIV, "}\n");
294 }
295 }
296
297 void decl_equiv (void)
298 {
299 int_4 go_on = TRUE;
300 while (go_on) {
301 SAVE_POS;
302 int_4 rc = scan (EXPECT_NONE);
303 if (rc == DECLAR) {
304 skip_card (FALSE);
305 } else if (TOKEN ("implicit")) {
306 skip_card (FALSE);
307 } else if (TOKEN ("save")) {
308 skip_card (FALSE);
309 } else if (TOKEN ("automatic")) {
310 skip_card (FALSE);
311 } else if (TOKEN ("parameter")) {
312 skip_card (FALSE);
313 } else if (TOKEN ("common")) {
314 skip_card (FALSE);
315 } else if (TOKEN ("dimension")) {
316 skip_card (FALSE);
317 } else if (TOKEN ("equivalence")) {
318 equivalence ();
319 skip_card (FALSE);
320 } else if (TOKEN ("external")) {
321 skip_card (FALSE);
322 } else if (TOKEN ("intrinsic")) {
323 skip_card (FALSE);
324 } else if (TOKEN ("data")) {
325 skip_card (FALSE);
326 } else if (strlen (curlex) > 0) {
327 // Backspace and done.
328 RESTORE_POS;
329 go_on = FALSE;
330 }
331 }
332 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|