1 /*
2  * Copyright (c) 1993-2019, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 /** \file
19     \brief Compiler miscellaneous utility programs.
20  */
21 
22 #include "miscutil.h"
23 #include "global.h"
24 #include "error.h"
25 #include "main.h"
26 
27 #include <stdbool.h>
28 #include "flang/ArgParser/xflag.h"
29 
30 /**
31    \brief Allocate space for and make new filename using mkperm.
32  */
33 char *
mkfname(char * oldname,char * oldsuf,char * newsuf)34 mkfname(char *oldname, char *oldsuf, char *newsuf)
35 {
36   char *p;
37 
38   /*  get enough space for oldname, newsuf, '.', '\0', and 1 extra: */
39   p = getitem(8, strlen(oldname) + strlen(newsuf) + 3);
40   strcpy(p, oldname);
41   return (mkperm(p, oldsuf, newsuf));
42 }
43 
44 /** \brief Create literal string for STATIC STRING
45  *
46  * If isStringW is TRUE(1), oldstr is passed in as a wide string
47  * literal and a letter "L" needs to be prepended to the target string.
48 */
49 char *
literal_string(char * oldstr,int userlen,bool isStringW)50 literal_string(char *oldstr, int userlen, bool isStringW)
51 {
52   static char newstr[MAX_FILENAME_LEN];
53   char *from, *end, *curr, c;
54   int len, skip, start;
55 
56   from = oldstr;
57   end = newstr + sizeof(newstr);
58   len = userlen - 1;
59 
60   if (!isStringW) {
61     newstr[0] = '\"';
62     skip = 1;
63     start = 1;
64   } else {
65     newstr[0] = 'L';
66     newstr[1] = '\"';
67     skip = 4; /* wide char size */
68     start = 2;
69   }
70 
71   for (curr = newstr + start; len-- && curr < end;) {
72     c = *from & 0xff;
73     from += skip;
74     if (c == '\"' || c == '\'' || c == '\\') {
75       *curr++ = '\\';
76       *curr++ = c;
77     } else if (c >= ' ' && c <= '~') {
78       *curr++ = c;
79     } else if (c == '\n') {
80       *curr++ = '\\';
81       *curr++ = 'n';
82     } else {
83       *curr++ = '\\';
84       snprintf(curr, newstr + MAX_FILENAME_LEN - curr, "%03o", c);
85       curr += 3;
86     }
87   }
88 
89   *curr++ = '\"';
90   *curr = '\0';
91   return newstr;
92 }
93 
94 bool
is_xflag_bit(int indx)95 is_xflag_bit(int indx)
96 {
97   return is_xflag_bitvector(indx);
98 }
99 
100 /** \brief Called only from main() */
101 void
set_xflag(int indx,INT val)102 set_xflag(int indx, INT val)
103 {
104   set_xflag_value(flg.x, indx, val);
105   /* XXX Unexpected side effect: "set x flag" should not be upping opt level */
106   if (indx == 9 && flg.opt < 2) /* max cnt for unroller */
107     flg.opt = 2;
108 }
109 
110 /** \brief Called only from main() */
111 void
set_yflag(int indx,INT val)112 set_yflag(int indx, INT val)
113 {
114   unset_xflag_value(flg.x, indx, val);
115 }
116 
117 void
fprintf_str_esc_backslash(FILE * f,char * str)118 fprintf_str_esc_backslash(FILE *f, char *str)
119 {
120   int ch;
121   fputc('"', f);
122   while ((ch = *str++)) {
123     fputc(ch, f);
124     if (ch == '\\')
125       fputc('\\', f);
126   }
127   fputc('"', f);
128 }
129 
130 /*
131  * error message
132  */
133 static void
invalid_size(const char * funcname,int dtsize,int size,const char * stgname)134 invalid_size(const char* funcname, int dtsize, int size, const char* stgname)
135 {
136   interrf(ERR_Fatal,
137           "%s: STG %s has invalid datatype size (%d) or structure size(%d)",
138           funcname, stgname, dtsize, size);
139 } /* invalid_size */
140 
141 /*
142  * memory management
143  *  allocate STG data structure, set the appropriate fields
144  *  element zero is reserved, so stg_avail is initialized to 1
145  */
146 static void
stg_alloc_base(STG * stg,int dtsize,BIGUINT64 size,const char * name)147 stg_alloc_base(STG *stg, int dtsize, BIGUINT64 size, const char *name)
148 {
149   if (DBGBIT(7,0x10))
150     fprintf(gbl.dbgfil, "stg_alloc(stg=%p, dtsize=%d, size=%d, name=%s)\n",
151       stg, dtsize, size, name);
152   if (dtsize > 0 && size > 0) {
153     memset(stg, 0, sizeof(STG));
154     stg->stg_size = size;
155     stg->stg_dtsize = dtsize;
156     stg->stg_avail = 1;
157     stg->stg_cleared = 0;
158     stg->stg_name = name;
159     stg->stg_base = (void *)sccalloc(stg->stg_dtsize * size);
160   } else {
161     invalid_size("stg_alloc", dtsize, size, name);
162   }
163 } /* stg_alloc_base */
164 
165 /*
166  * clear 'n' elements of the data structure starting at 'r'
167  * reset stg_cleared if we're initializing or extending the cleared region
168  */
169 void
stg_clear_force(STG * stg,BIGUINT64 r,BIGUINT64 n,bool force)170 stg_clear_force(STG *stg, BIGUINT64 r, BIGUINT64 n, bool force)
171 {
172   if (r >= 0 && n > 0) {
173     STG *thisstg;
174     if (r == stg->stg_cleared) {
175       stg->stg_cleared += n;
176     } else if (r == 0 && n > stg->stg_cleared) {
177       stg->stg_cleared = n;
178     }
179     for (thisstg = stg; thisstg; thisstg = (STG *)thisstg->stg_sidecar) {
180       thisstg->stg_cleared = stg->stg_cleared;
181       if (force || !STG_CHECKFLAG((*thisstg), STG_FLAG_NOCLEAR))
182         memset((char *)(thisstg->stg_base) + (r * thisstg->stg_dtsize), 0,
183          n * thisstg->stg_dtsize);
184     }
185   }
186 } /* stg_clear_force */
187 
188 void
stg_clear(STG * stg,int r,int n)189 stg_clear(STG *stg, int r, int n)
190 {
191   if (r >= 0 && n > 0)
192     stg_clear_force(stg, r, n, false);
193 } /* stg_clear */
194 
195 /*
196  * clear the data structure up to stg_avail
197  */
198 void
stg_clear_all(STG * stg)199 stg_clear_all(STG *stg)
200 {
201   stg_clear(stg, 0, stg->stg_avail);
202 } /* stg_clear_all */
203 
204 /*
205  * allocate STG data structure, clear element zero
206  */
207 void
stg_alloc(STG * stg,int dtsize,int size,const char * name)208 stg_alloc(STG *stg, int dtsize, int size, const char *name)
209 {
210   stg_alloc_base(stg, dtsize, size, name);
211   stg_clear_force(stg, 0, 1, true);
212 } /* stg_alloc */
213 
214 /*
215  * deallocate STG data structure
216  */
217 void
stg_delete(STG * stg)218 stg_delete(STG *stg)
219 {
220   if (DBGBIT(7,0x10))
221     fprintf(gbl.dbgfil, "stg_delete(stg=%p, dtsize=%d, size=%d, name=%s)\n",
222       stg, stg->stg_dtsize, stg->stg_size, stg->stg_name);
223   if (stg->stg_base)
224     sccfree((char *)stg->stg_base);
225   memset(stg, 0, sizeof(STG));
226 } /* stg_delete */
227 
228 /*
229  * reset STG data structure
230  */
231 void
stg_reset(STG * stg)232 stg_reset(STG *stg)
233 {
234   STG *thisstg;
235   if (DBGBIT(7,0x10))
236     fprintf(gbl.dbgfil, "stg_reset(stg=%p, dtsize=%d, size=%d, name=%s)\n",
237       stg, stg->stg_dtsize, stg->stg_size, stg->stg_name);
238   for (thisstg = stg; thisstg; thisstg = (STG *)thisstg->stg_sidecar) {
239     thisstg->stg_avail = 1;
240     thisstg->stg_cleared = 0;
241   }
242 } /* stg_reset */
243 
244 /*
245  * reallocate STG structure if we need the extra size (if stg_avail > stg_size)
246  *  reallocate any sidecars as well
247  *  the new size will be 2*(stg_avail-1), which must be >= 2*stg_size
248  */
249 void
stg_need(STG * stg)250 stg_need(STG *stg)
251 {
252   STG *thisstg;
253   /* if the compiler has recycled some previously allocated space,
254    * we need to reset the stg_cleared region */
255   if (stg->stg_cleared > stg->stg_avail)
256     stg->stg_cleared = stg->stg_avail;
257   if (stg->stg_avail > stg->stg_size) {
258     BIGUINT64 newsize, oldsize;
259     oldsize = stg->stg_size;
260     newsize = (stg->stg_avail - 1) * 2;
261     /* reallocate stg and all its sidecars */
262     for (thisstg = stg; thisstg; thisstg = (STG *)thisstg->stg_sidecar) {
263       if (DBGBIT(7,0x10))
264         fprintf(gbl.dbgfil, "stg_need(stg=%p, dtsize=%d, size=%d, newsize=%d, name=%s)\n",
265           thisstg, thisstg->stg_dtsize, thisstg->stg_size, newsize, thisstg->stg_name);
266       thisstg->stg_size = newsize;
267       thisstg->stg_base = (void *)sccrelal(
268           (char *)thisstg->stg_base, newsize * thisstg->stg_dtsize);
269     }
270     /* we have to clear all newly allocated elements, in case there
271      * are sidecars with the NOCLEAR flag set, so they get initially cleared */
272     stg_clear_force(stg, oldsize, newsize - oldsize, true);
273   }
274   if (stg->stg_avail > stg->stg_cleared) {
275     /* clear any new elements */
276     stg_clear_force(stg, stg->stg_cleared, stg->stg_avail - stg->stg_cleared, true);
277   }
278 } /* stg_need */
279 
280 /*
281  * Allocate a sidecar, attach to list of sidecars
282  */
283 void
stg_alloc_sidecar(STG * basestg,STG * stg,int dtsize,const char * name)284 stg_alloc_sidecar(STG *basestg, STG *stg, int dtsize, const char *name)
285 {
286   if (DBGBIT(7,0x10))
287     fprintf(gbl.dbgfil, "stg_alloc_sidecar(basestg=%p, name=%s, stg=%p, dtsize=%d, name=%s)\n",
288       basestg, basestg->stg_name, stg, dtsize, name);
289   if (stg->stg_sidecar) {
290     interrf(ERR_Fatal, "%s: %s has a sidecar, may not add as sidecar to %s",
291       "stg_alloc_sidecar", stg->stg_name, basestg->stg_name);
292   }
293   stg_alloc_base(stg, dtsize, basestg->stg_size, name);
294   stg->stg_avail = basestg->stg_avail;
295   /* clear sidecar for any already-allocated elements */
296   stg_clear_force(stg, 0, stg->stg_size, true);
297   /* link this sidecar to the list of sidecars for the basestg */
298   stg->stg_sidecar = basestg->stg_sidecar;
299   basestg->stg_sidecar = (void *)stg;
300 } /* stg_alloc_sidecar */
301 
302 /*
303  * error message
304  */
305 static void
sidecar_not_found(const char * funcname,STG * basestg,STG * stg)306 sidecar_not_found(const char *funcname, STG *basestg, STG *stg)
307 {
308   /* sidecar not found, this is an error */
309   interrf(ERR_Fatal, "%s: Sidecar %s to %s not found", funcname,
310           basestg->stg_name, stg->stg_name);
311 } /* sidecar_not_found */
312 
313 /*
314  * Deallocate a sidecar, detach from list of sidecars
315  */
316 void
stg_delete_sidecar(STG * basestg,STG * stg)317 stg_delete_sidecar(STG *basestg, STG *stg)
318 {
319   if (DBGBIT(7,0x10))
320     fprintf(gbl.dbgfil, "stg_delete_sidecar(basestg=%p, name=%s, stg=%p, "
321             "dtsize=%d, name=%s)\n", basestg, basestg->stg_name, stg,
322             stg->stg_dtsize, stg->stg_name);
323   if ((STG *)basestg->stg_sidecar == stg) {
324     basestg->stg_sidecar = stg->stg_sidecar;
325   } else {
326     STG *sidecar;
327     for (sidecar = (STG *)basestg->stg_sidecar; sidecar;
328          sidecar = (STG *)sidecar->stg_sidecar) {
329       if ((STG *)sidecar->stg_sidecar == stg) {
330         sidecar->stg_sidecar = stg->stg_sidecar;
331         break;
332       }
333     }
334     if (!sidecar) {
335       sidecar_not_found("stg_delete_sidecar", basestg, stg);
336     }
337   }
338   stg_delete(stg);
339 } /* stg_delete_sidecar */
340 
341 /*
342  * reserve next n elements at stg_avail; increment stg_avail;
343  * grow, if necessary;
344  * clear newly allocated elements; return the first such element.
345  */
346 int
stg_next(STG * stg,int n)347 stg_next(STG *stg, int n)
348 {
349   STG *thisstg;
350   unsigned int r = stg->stg_avail;
351   if (n == 0)
352     return 0;
353   if (n < 0) {
354     interrf(ERR_Fatal, "stg_next(%s,%d) called with n < 0", stg->stg_name, n);
355     return 0;
356   }
357   /* if the compiler has recycled some previously allocated space,
358    * we need to reset the stg_cleared region */
359   if (stg->stg_cleared > r)
360     stg->stg_cleared = r;
361   stg->stg_avail += n;
362   for (thisstg = (STG *)stg->stg_sidecar; thisstg;
363        thisstg = (STG *)thisstg->stg_sidecar) {
364     thisstg->stg_avail = stg->stg_avail;
365     thisstg->stg_cleared = stg->stg_cleared;
366   }
367   if (stg->stg_avail > stg->stg_size) {
368     stg_need(stg);
369   } else {
370     stg_clear(stg, stg->stg_cleared, stg->stg_avail - stg->stg_cleared);
371   }
372   return r;
373 } /* stg_next */
374 
375 /*
376  * error message
377  */
378 static void
too_small_for_freelist(const char * funcname,STG * stg)379 too_small_for_freelist(const char *funcname, STG *stg)
380 {
381   interrf(ERR_Fatal, "%s: structure %s too small for a freelist link, size=%d",
382     funcname, stg->stg_name, stg->stg_dtsize);
383 } /* too_small_for_freelist */
384 
385 static char*
freefield(STG * stg,BIGUINT64 r)386 freefield(STG* stg, BIGUINT64 r)
387 {
388   char *base;
389   /* get stg_base */
390   base = (char *)stg->stg_base;
391   /* add the offset of the r'th element (r*dtsize) */
392   base += r * stg->stg_dtsize;
393   /* add freelink offset */
394   base += stg->stg_freelink_offset;
395   return base;
396 } /* freefield */
397 
398 /*
399  * get next element from the free list, if it's not null.
400  * reset the free list from the free list link.
401  * otherwise, just get the next available element from stg_avail
402  * the link to the next free element is stored at 'word 0' of the structure
403  */
404 int
stg_next_freelist(STG * stg)405 stg_next_freelist(STG *stg)
406 {
407   int r = stg->stg_free;
408   if (!r) {
409     r = stg_next(stg, 1);
410     stg_clear(stg, r, 1);
411   } else {
412     char *base;
413     if (stg->stg_dtsize < sizeof(int))
414       too_small_for_freelist("stg_next_freelist", stg);
415     /* get freelink for entry 'r' */
416     base = freefield(stg, r);
417     /* move stg_free to the next free element */
418     stg->stg_free = *(int *)base;
419     /* clear the new element */
420     stg_clear(stg, r, 1);
421   }
422   return r;
423 } /* stg_next_freelist */
424 
425 /*
426  * return latest entry (from stg_next)
427  */
428 void
stg_return(STG * stg)429 stg_return(STG *stg)
430 {
431   STG *thisstg;
432   unsigned int r = stg->stg_avail - 1;
433   stg->stg_avail = r;
434   if (stg->stg_cleared > r)
435     stg->stg_cleared = r;
436   for (thisstg = (STG *)stg->stg_sidecar; thisstg;
437        thisstg = (STG *)thisstg->stg_sidecar) {
438     thisstg->stg_avail = stg->stg_avail;
439     thisstg->stg_cleared = stg->stg_cleared;
440   }
441 } /* stg_return */
442 
443 /*
444  * add element to the free list
445  * store the link to the next free element at 'word 0'
446  */
447 void
stg_add_freelist(STG * stg,int r)448 stg_add_freelist(STG *stg, int r)
449 {
450   char *base;
451   if (stg->stg_dtsize < sizeof(int))
452     too_small_for_freelist("stg_next_freelist", stg);
453   /* clear the recycled element */
454   stg_clear(stg, r, 1);
455   /* get stg_base */
456   base = freefield(stg, r);
457   /* link to the free list */
458   *(int *)base = stg->stg_free;
459   stg->stg_free = r;
460 } /* stg_add_freelist */
461 
462 /*
463  * set the free list link field offset
464  */
465 void
stg_set_freelink(STG * stg,int offset)466 stg_set_freelink(STG* stg, int offset)
467 {
468   stg->stg_freelink_offset = offset;
469 } /* stg_set_freelink */
470 
471