fold.c
1 //! @file fold.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-2024 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 //! Constant folder.
25
26 #include <vif.h>
27 #include <rts-real32.h>
28
29 // A trivial calculator to compiler generated constant expressions.
30
31 // INTEGER
32 // Exponentiation is already optimised by the code generator.
33
34 static int_4 calc_int_add (char **, int_4 *);
35
36 static int_4 calc_int_fact (char **s, int_4 *val)
37 {
38 while (isspace (*s[0])) {
39 (*s)++;
40 }
41 if (isdigit ((*s)[0])) {
42 *val = strtol (*s, s, 10);
43 return TRUE;
44 } else if ((*s)[0] == '-') {
45 int_4 rc;
46 (*s)++;
47 rc = calc_int_fact (s, val);
48 *val = -*val;
49 return rc;
50 } else if ((*s)[0] == '(') {
51 int_4 rc, sub;
52 (*s)++;
53 rc = calc_int_add (s, &sub);
54 (*s)++; // Assume ')'
55 *val = sub;
56 return rc;
57 }
58 return FALSE;
59 }
60
61 static int_4 calc_int_mul (char **s, int_4 *val)
62 {
63 int_4 lval, rval;
64 if (!calc_int_fact (s, &lval)) {
65 return FALSE;
66 }
67 while (isspace (*s[0])) {
68 (*s)++;
69 }
70 while ((*s)[0] != '\0' && ((*s)[0] == '*' || (*s)[0] == '/' || (*s[0]) == '%')) {
71 char op = (*s)++[0];
72 if (!calc_int_fact (s, &rval)) {
73 return FALSE;
74 }
75 if (op == '*') {
76 lval *= rval;
77 } else if (op == '/') {
78 lval /= rval;
79 } else {
80 lval %= rval;
81 }
82 while ((*s)[0] == ' ') {
83 (*s)++;
84 }
85 }
86 *val = lval;
87 return TRUE;
88 }
89
90 static int_4 calc_int_add (char **s, int_4 *val)
91 {
92 int_4 lval, rval;
93 if (!calc_int_mul (s, &lval)) {
94 return FALSE;
95 }
96 while ((*s)[0] == ' ') {
97 (*s)++;
98 }
99 while ((*s)[0] != '\0' && ((*s)[0] == '+' || (*s)[0] == '-')) {
100 char op = (*s)++[0];
101 if (!calc_int_mul (s, &rval)) {
102 return FALSE;
103 }
104 if (op == '+') {
105 lval += rval;
106 } else {
107 lval -= rval;
108 }
109 while (isspace (*s[0])) {
110 (*s)++;
111 }
112 }
113 *val = lval;
114 return TRUE;
115 }
116
117 int_4 calc_int_4 (char *p, int_4 *val)
118 {
119 char *q = p;
120 int_4 rc = calc_int_add (&q, val) && (q[0] == '\0');
121 return rc;
122 }
123
124 void fold_int_4 (char *buf, char *p)
125 {
126 RECORD q;
127 int_4 val;
128 bufcpy (q, p, RECLN);
129 if (calc_int_4 (q, &val)) {
130 _srecordf (buf, "%d", val);
131 } else {
132 bufcpy (buf, p, RECLN);
133 }
134 }
135
136 // REAL
137 // Exponentiation is already optimised by the code generator.
138
139 static int_4 calc_real_add (char **, real_32 *);
140
141 static int_4 calc_real_fact (char **s, real_32 *val)
142 {
143 while (isspace (*s[0])) {
144 (*s)++;
145 }
146 if (isdigit ((*s)[0])) {
147 *val = strtox (*s, s);
148 if ((*s)[0] == 'q') {
149 (*s)++;
150 }
151 return TRUE;
152 } else if ((*s)[0] == '-') {
153 int_4 rc;
154 (*s)++;
155 rc = calc_real_fact (s, val);
156 *val = xneg (*val);
157 return rc;
158 } else if ((*s)[0] == '(') {
159 int_4 rc;
160 real_32 sub;
161 (*s)++;
162 rc = calc_real_add (s, &sub);
163 (*s)++; // Assume ')'
164 *val = sub;
165 return rc;
166 }
167 return FALSE;
168 }
169
170 static int_4 calc_real_mul (char **s, real_32 *val)
171 {
172 real_32 lval, rval;
173 if (!calc_real_fact (s, &lval)) {
174 return FALSE;
175 }
176 while (isspace (*s[0])) {
177 (*s)++;
178 }
179 while ((*s)[0] != '\0' && ((*s)[0] == '*' || (*s)[0] == '/')) {
180 char op = (*s)++[0];
181 if (!calc_real_fact (s, &rval)) {
182 return FALSE;
183 }
184 if (op == '*') {
185 lval = xmul (lval, rval);
186 } else if (op == '/') {
187 lval = xdiv (lval, rval);
188 }
189 while ((*s)[0] == ' ') {
190 (*s)++;
191 }
192 }
193 *val = lval;
194 return TRUE;
195 }
196
197 static int_4 calc_real_add (char **s, real_32 *val)
198 {
199 real_32 lval, rval;
200 if (!calc_real_mul (s, &lval)) {
201 return FALSE;
202 }
203 while ((*s)[0] == ' ') {
204 (*s)++;
205 }
206 while ((*s)[0] != '\0' && ((*s)[0] == '+' || (*s)[0] == '-')) {
207 char op = (*s)++[0];
208 if (!calc_real_mul (s, &rval)) {
209 return FALSE;
210 }
211 if (op == '+') {
212 lval = xadd (lval, rval, 0);
213 } else {
214 lval = xadd (lval, rval, 1);
215 }
216 while (isspace (*s[0])) {
217 (*s)++;
218 }
219 }
220 *val = lval;
221 return TRUE;
222 }
223
224 int_4 calc_real (char *p, real_32 *val)
225 {
226 char *q = p;
227 int_4 rc = calc_real_add (&q, val) && (q[0] == '\0');
228 return rc;
229 }
230
231 // COMPLEX
232
233 static int_4 calc_complex_add (char **, complex_64 *);
234
235 int skip (char **q, char *p)
236 {
237 size_t N = strlen (p);
238 if (strncmp (*q, p, N) == 0) {
239 (*q) += N;
240 return TRUE;
241 } else {
242 return FALSE;
243 }
244 }
245
246 static int_4 calc_complex_fact (char **s, complex_64 *val)
247 {
248 while (isspace (*s[0])) {
249 (*s)++;
250 }
251 (void) skip (s, "CMPLXQ");
252 (void) skip (s, "CMPLXF");
253 (void) skip (s, "CMPLX");
254 while (isspace (*s[0])) {
255 (*s)++;
256 }
257 if (isdigit ((*s)[0])) {
258 real_32 z;
259 z = strtox (*s, s);
260 if ((*s)[0] == 'q') {
261 (*s)++;
262 }
263 *val = (complex_64) {z, X_0};
264 return TRUE;
265 } else if ((*s)[0] == '-') {
266 int_4 rc;
267 (*s)++;
268 rc = calc_complex_fact (s, val);
269 *val = cxneg (*val);
270 return rc;
271 } else if ((*s)[0] == '(') {
272 int_4 rc;
273 complex_64 sub;
274 (*s)++;
275 char *t = *s;
276 if (isdigit ((*s)[0]) || (*s)[0] == '+' || (*s)[0] == '-') {
277 real_32 re, im;
278 re = strtox (*s, s);
279 if ((*s)[0] == 'q') {
280 (*s)++;
281 }
282 if ((*s)[0] == ',') {
283 (*s)++;
284 im = strtox (*s, s);
285 if ((*s)[0] == 'q') {
286 (*s)++;
287 }
288 sub = (complex_64) {re, im};
289 rc = TRUE;
290 } else {
291 *s = t;
292 rc = calc_complex_add (s, &sub);
293 }
294 } else {
295 rc = calc_complex_add (s, &sub);
296 }
297 (*s)++; // Assume ')'
298 *val = sub;
299 return rc;
300 }
301 return FALSE;
302 }
303
304 static int_4 calc_complex_mul (char **s, complex_64 *val)
305 {
306 complex_64 lval, rval;
307 if (!calc_complex_fact (s, &lval)) {
308 return FALSE;
309 }
310 while (isspace (*s[0])) {
311 (*s)++;
312 }
313 while ((*s)[0] != '\0' && ((*s)[0] == '*' || (*s)[0] == '/')) {
314 char op = (*s)++[0];
315 if (!calc_complex_fact (s, &rval)) {
316 return FALSE;
317 }
318 if (op == '*') {
319 lval = cxmul (lval, rval);
320 } else if (op == '/') {
321 lval = cxdiv (lval, rval);
322 }
323 while ((*s)[0] == ' ') {
324 (*s)++;
325 }
326 }
327 *val = lval;
328 return TRUE;
329 }
330
331 static int_4 calc_complex_add (char **s, complex_64 *val)
332 {
333 complex_64 lval, rval;
334 if (!calc_complex_mul (s, &lval)) {
335 return FALSE;
336 }
337 while ((*s)[0] == ' ') {
338 (*s)++;
339 }
340 while ((*s)[0] != '\0' && ((*s)[0] == '+' || (*s)[0] == '-')) {
341 char op = (*s)++[0];
342 if (!calc_complex_mul (s, &rval)) {
343 return FALSE;
344 }
345 if (op == '+') {
346 lval = cxsum (lval, rval);
347 } else {
348 lval = cxsub (lval, rval);
349 }
350 while (isspace (*s[0])) {
351 (*s)++;
352 }
353 }
354 *val = lval;
355 return TRUE;
356 }
357
358 int_4 calc_complex (char *p, complex_64 *val)
359 {
360 char *q = p;
361 int_4 rc = calc_complex_add (&q, val) && (q[0] == '\0');
362 return rc;
363 }
364
365 // Drivers.
366
367 char *pretty_float (char *num)
368 {
369 // Cut zero exponent and end-zeroes in floats.
370 RECORD expo;
371 RECCLR (expo);
372 char *e = strchr (num, 'e');
373 if (e != NULL) {
374 _srecordf (expo, "%s", &e[1]);
375 *e = '\0';
376 }
377 RECORD frac;
378 RECCLR (frac);
379 char *f = strchr (num, '.');
380 if (f != NULL) {
381 _srecordf (frac, "%s", &f[1]);
382 *f = '\0';
383 }
384 // Simplify exponent.
385 if (e != NULL) {
386 int expd;
387 sscanf (expo, "%d", &expd);
388 if (expd != 0) {
389 _srecordf (expo, "%d", expd);
390 }
391 }
392 // Simplify fraction.
393 while (strlen (frac) > 0 && frac[strlen (frac) - 1] == '0') {
394 frac[strlen (frac) - 1] = '\0';
395 }
396 // Compose pretty float,
397 if (strlen (frac) > 0) {
398 strcat (num, ".");
399 strcat (num, frac);
400 } else {
401 strcat (num, ".0");
402 }
403 if (strlen (expo) > 0) {
404 strcat (num, "e");
405 strcat (num, expo);
406 }
407 return num;
408 }
409
410 void pretty_number (char *num, int_4 prec, real_32 val)
411 {
412 RECORD stre, strf, fmt;
413 _srecordf (fmt, "%%.%df", prec);
414 _fprintf_real_32 (strf, fmt, val, 5, FLT256_DIG);
415 real_32 valf = strtox (strf, NULL);
416 _srecordf (fmt, "%%.%de", prec);
417 _fprintf_real_32 (stre, fmt, val, 5, FLT256_DIG);
418 real_32 vale = strtox (stre, NULL);
419 if (xeq (vale, valf)) {
420 _srecordf (num, "%s", pretty_float (strf));
421 } else {
422 _srecordf (num, "%s", pretty_float (stre));
423 }
424 }
425
426 void pretty_real (char *num, int_4 prec, real_32 val)
427 {
428 switch (prec) {
429 case 4: {
430 pretty_number (num, FLT_DIG + 1, val);
431 return;
432 }
433 case 8: {
434 pretty_number (num, DBL_DIG + 1, val);
435 return;
436 }
437 case 16: {
438 pretty_number (num, FLT128_DIG + 1, val);
439 bufcat (num, "q", RECLN);
440 return;
441 }
442 case 32: {
443 pretty_number (num, FLT256_DIG, val);
444 return;
445 }
446 }
447 }
448
449 void pretty_complex (char *num, int_4 prec, complex_64 cval)
450 {
451 RECORD RE, IM;
452 switch (prec) {
453 case 8: {
454 pretty_real (RE, 4, cxre (cval));
455 pretty_real (IM, 4, cxim (cval));
456 _srecordf (num, "CMPLXF (%s, %s)", RE, IM);
457 return;
458 }
459 case 16: {
460 pretty_real (RE, 8, cxre (cval));
461 pretty_real (IM, 8, cxim (cval));
462 _srecordf (num, "CMPLX (%s, %s)", RE, IM);
463 return;
464 }
465 case 32: {
466 pretty_real (RE, 16, cxre (cval));
467 pretty_real (IM, 16, cxim (cval));
468 _srecordf (num, "CMPLXQ (%s, %s)", RE, IM);
469 return;
470 }
471 }
472 }
473
474 int_4 fold_intrinsic (INTRINS *F, EXPR *lhs, EXPR *rhs)
475 {
476 if (lhs->variant != EXPR_CONST) {
477 return FALSE;
478 } else if (!valid_expr (lhs)) {
479 return FALSE;
480 } else if (rhs != NULL && rhs->variant != EXPR_CONST) {
481 return FALSE;
482 } else if (rhs != NULL && !valid_expr (rhs)) {
483 return FALSE;
484 } else if (F->f3 != NULL && rhs == NULL) {
485 complex_64 lval;
486 if (! (accept_mode (lhs->mode.type, lhs->mode.len, COMPLEX, 32) && calc_complex (lhs->str, &lval))) {
487 return FALSE;
488 }
489 complex_64 cval = (F->f3) (lval);
490 pretty_complex (lhs->str, F->alen, cval);
491 return TRUE;
492 } else {
493 RECORD num;
494 num[0] = '\0';
495 real_32 lval;
496 if (! (accept_mode (lhs->mode.type, lhs->mode.len, REAL, 16) && calc_real (lhs->str, &lval))) {
497 return FALSE;
498 }
499 if (F->f1 != NULL) {
500 // Single-argumenters.
501 pretty_real (num, 32, (F->f1) (lval));
502 }
503 if (rhs != NULL) {
504 real_32 rval;
505 if (! (accept_mode (rhs->mode.type, rhs->mode.len, REAL, 16) && calc_real (rhs->str, &rval))) {
506 return FALSE;
507 }
508 if (F->f2 != NULL) {
509 // Two-argumenters.
510 pretty_real (num, 32, (F->f2) (lval, rval));
511 }
512 }
513 if (strlen (num) > 0) {
514 strcpy (lhs->str, num);
515 return TRUE;
516 } else {
517 return FALSE;
518 }
519 }
520 }
521
522 int_4 fold_expr (EXPR *reg, int_4 expect)
523 {
524 if (reg->variant != EXPR_CONST) {
525 return FALSE;
526 } else if (!valid_expr (reg)) {
527 return FALSE;
528 } else {
529 if ((reg->mode.type == INTEGER || (reg->mode.type == REAL && reg->mode.len <= 16))) {
530 real_32 rval;
531 if (calc_real (reg->str, &rval)) {
532 if (reg->mode.type == INTEGER || expect == INTEGER) {
533 reg->mode.type = INTEGER;
534 reg->mode.len = 4;
535 _srecordf (reg->str, "%d", _xint4 (rval));
536 } else {
537 RECORD z;
538 RECCLR (z);
539 pretty_real (z, reg->mode.len, rval);
540 strcpy (reg->str, z);
541 }
542 return TRUE;
543 } else {
544 return FALSE;
545 }
546 } else if (reg->mode.type == COMPLEX && reg->mode.len <= 32) {
547 complex_64 cval;
548 if (calc_complex (reg->str, &cval)) {
549 pretty_complex (reg->str, reg->mode.len, cval);
550 return TRUE;
551 } else {
552 return FALSE;
553 }
554 } else {
555 return FALSE;
556 }
557 }
558 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|