1 /*
2  * Copyright (c) 2017-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 /*  ilitp.cpp - for ILI generation.
19 
20     utility program which reads ili definition file, ilitp.n,
21     and writes file of macro and data definitions:
22         iliatt.h
23         ilinfodf.h
24 
25     nroff include directives of the form ".so filename" are recognized.
26     The filename is interpreted relative to the including file.
27 
28     Lines beginning with '.' and containing one or more sets of the form
29         {x,y,z}
30     are expanded into multiple lines, each with one of the choices.
31     If more than one set appears on the line, then choices are matched by
32     position.
33 
34     E.g., a line ".IL {x,y,z} foo {X,Y,Z}" expands to three lines:
35         .IL x foo X
36         .IL y foo Y
37         .IL z foo Z
38     An error will be reported if the sets on a line have differing
39     number of elements.  Furthermore, subsequent .AT, .CG, and .SI
40     lines with {...} will be matched up with the .IL lines.
41 
42     The program assumes a non-adversarial user.  Some possible buffer
43     overruns are unchecked.
44 */
45 
46 #include "universal.h"
47 #include "scutil.h"
48 #if defined(BIGOBJ)
49 #define ISZ_T BIGINT
50 #define UISZ_T BIGUINT
51 #else
52 #define ISZ_T INT
53 #define UISZ_T UINT
54 #endif
55 #include "sharedefs.h"
56 #include "ili.h"
57 #include "utils.h"
58 
59 static int opcode_num = 0;
60 static int max_ili_num;
61 static std::string buff;
62 
63 // Flags for tracking which part of an instruction description we've seen so far.
64 struct processed_flags {
65   bool il; //!< .IL line (or similar) has been seen.
66   bool cg; //!< .CG line has been seen.
67   bool at; //!< .AT line has been seen
68 };
69 
70 // Indexed by opcode.  A vector is needed because "ILI template expansion"
71 // delivers the expansion of a line as a group of consecutive lines.
72 std::vector<processed_flags> processed;
73 
74 /*static*/ ILIINFO ilis[1050]; /* declared external in ili.h  */
75 SCHINFO schinfo[1050];
76 
77 static void do_IL_line(int pass);
78 static void do_AT_line(void);
79 static void do_CG_line(void);
80 static void do_latency(const char *lat, int shift);
81 static void do_SI_line(void);
82 static int lookup_ili(const char *name);
83 static void error(const char *text, const char *additional_text=nullptr);
84 
85 #define STASH(string) strcpy((char*)malloc(strlen(string) + 1), string)
86 
87 //! Return true iff s begins with first 3 characters of nroffCmd.
88 static bool
match(const std::string & s,const char * nroffCmd)89 match(const std::string& s, const char *nroffCmd) {
90   return strncmp(s.c_str(), nroffCmd, 3) == 0;
91 }
92 
93 /* True if text in buff introduces an ILI instruction;
94    e.g. is a ".IL" line. */
95 static bool
introduces_ILI(const std::string & buff)96 introduces_ILI(const std::string& buff)
97 {
98   if (match(buff, ".IL"))
99     return true;
100 #if defined(PGFTN) || defined(PGF90)
101   if (match(buff, ".FL"))
102     return true;
103 #elif defined(PGOCL)
104   if (match(buff, ".OL"))
105     return true;
106   if (match(buff, ".CL"))
107     return true;
108 #else
109   if (match(buff, ".CL"))
110     return true;
111 #endif
112   return false;
113 }
114 
115 /* True if text in buff elborates on a previously introduced
116    n ILI instruction. */
117 static bool
elaborates_ILI(const std::string & buff)118 elaborates_ILI(const std::string& buff)
119 {
120   if (match(buff, ".AT"))
121     return true;
122   if (match(buff, ".CG"))
123     return true;
124   if (match(buff, ".SI"))
125     return true;
126   return false;
127 }
128 
129 /* Text containing {...} that needs to be expanded. */
130 static std::string template_buff;
131 
132 /* Number of choices in template that introduced an ILI instruction.
133    Related lines such as .AT inherit this value from the line
134    that introduced the instruction.  -1 if not processing a template. */
135 static int template_size;
136 
137 /* -1 if not expanding, otherwise 1-based index of current choice to expand
138    (or has been expanded) in a {...}.  A value of 0 is used transiently
139    after a template line is first scanned and before the first choice
140    is selected. */
141 static int template_index = -1;
142 
143 /* Value of opcode_num just before a "introduces ILI" line was scanned. */
144 static int template_base_opcode_num = -1;
145 
146 static int
get_template_size(std::string & buff)147 get_template_size(std::string& buff)
148 {
149   /* Caller guarantees that '{' exists in buff. */
150   const char *s = strchr(buff.c_str(), '{');
151   int size = 1;
152   while (*++s != '}') {
153     if (*s == ',')
154       ++size;
155     if (!*s)
156       error("{... without closing }");
157   }
158   return size;
159 }
160 
161 /* Get expansion of template_buff, as determined by template_index.
162    The index  is one-based.
163 
164    For example, if a line has:
165        .IL {x,y,z} foo {X,Y,Z}
166    and template_index==2, then buff will be filled with:
167        .IL y foo Y
168 */
169 static void
get_template_expansion(std::string & buff)170 get_template_expansion(std::string& buff)
171 {
172   const char *p = template_buff.c_str();
173   buff.clear();
174   for (;;) {
175     int i;
176     /* Copy regular characters */
177     for (; *p != '{'; ++p) {
178       buff.push_back(*p);
179       if (!*p)
180         return;
181     }
182     ++p; /* Skip brace */
183     /* Find choice indexed by template_index. */
184     for (i = 1; i != template_index; ++i) {
185       /* Look for comma */
186       for (; *p != ','; ++p) {
187         if (!*p)
188           error("{... without closing '}'");
189         if (*p == '}')
190           error("{...} with fewer choices than expected");
191       }
192       ++p; /* skip comma */
193     }
194     /* Copy the choice. */
195     while (*p != ',' && *p != '}')
196       buff.push_back(*p++);
197     /* Check for user error. */
198     if (template_index == template_size) {
199       /* Should be last choice. */
200       if (*p != '}')
201         error("{...} with more choices than expected");
202     }
203     /* Advance to closing brace and skip it. */
204     p = strchr(p, '}');
205     if (!p)
206       error("{... without closing brace");
207     ++p;
208   }
209 }
210 
211 static NroffInStream input_file;
212 
213 /** Open an input file and push it on the file filestack. */
214 static void
open_input_file(const char * filename)215 open_input_file(const char *filename)
216 {
217   input_file.open(filename);
218   if (!input_file)
219     error("unable to open");
220 }
221 
222 /** Get next line of input, expanding any include files (.so directives)
223     or implicit templates ({...}). */
224 static bool
get_input_line(std::string & buff)225 get_input_line(std::string& buff)
226 {
227   for(;;) {
228     if (template_index >= 0) {
229       /* Expanding a template */
230       ++template_index;
231       if (template_index > template_size) {
232         /* Done expanding the template.  Do not reset template_size
233            or template_base_opcode_num, because these values are inherited
234            by subsequent .AT lines. */
235         template_index = -1;
236       } else {
237         if (!introduces_ILI(template_buff))
238           /* Set opcode_num to correspond with earlier .IL etc. line. */
239           opcode_num = template_base_opcode_num + template_index;
240         get_template_expansion(buff);
241         return true;
242       }
243     }
244     if (!getline(input_file, buff))
245       return false;
246     if (introduces_ILI(buff)) {
247       if (buff.find('{') != std::string::npos) {
248         /* Line will expand into multiple lines.
249            Remember the value of opcode_num so we can reset it later
250            to the right value when expanding the lines that correspond
251            to these. */
252         template_buff = buff;
253         template_index = 0;
254         template_size = get_template_size(buff);
255         template_base_opcode_num = opcode_num;
256         continue;
257       } else {
258         /* Do not not expand the line or elaborations of the same ILI. */
259         template_size = -1;
260       }
261     } else if (elaborates_ILI(buff)) {
262       if (template_size >= 0) {
263         /* Need to expand line analogously to line that introduced this ILI.
264            Line inherits template_size and template_base_opcode_num from
265            earlier line. */
266         template_buff = buff;
267         template_index = 0;
268         continue;
269       }
270     }
271     /* regular line */
272     return true;
273   }
274 }
275 
276 /* ------------------------------------------------------- */
277 
278 int
main(int argc,char * argv[])279 main(int argc, char *argv[])
280 {
281   int i;
282   int inputFileIndex = 0;
283   FILE *fdiliatt, *fdilinfo, *fdschinfo;
284 
285   /*  ---- step 0: collect commandline -I<include file paths>:   */
286 
287   collectIncludePaths(argc, argv);
288 
289   /*  ---- step 1: open input and output files:   */
290 
291   for (i = 1; i < argc; i++ ) {
292     if( strncmp(argv[i], "-I", 2) == 0 ) {
293       continue;
294     }
295     if (inputFileIndex != 0) {
296       error("More than one input file specified\n");
297     } else {
298       inputFileIndex = i;
299     }
300   }
301 
302   const char *input_file_name = inputFileIndex != 0? argv[inputFileIndex] : "ilitp.n";
303   open_input_file(input_file_name);
304 
305   fdiliatt = fopen("iliatt.h", "wb");
306   if (fdiliatt == NULL)
307     error("unable to open output file iliatt.h");
308   fdilinfo = fopen("ilinfodf.h", "wb");
309   if (fdilinfo == NULL)
310     error("unable to open output file ilinfodf.h");
311   fdschinfo = fopen("schinfo.h", "wb");
312   if (fdschinfo == NULL)
313     error("unable to open output file schinfo.h");
314 
315   /*  ---- step 2: scan input file to read in ili names from IL lines: */
316 
317   while (get_input_line(buff))
318     if (introduces_ILI(buff))
319       do_IL_line(1);
320 
321   max_ili_num = opcode_num;
322   processed.resize(max_ili_num+1);
323   opcode_num = 0;
324 
325   /*  ---- step 3: rescan input file to process all relevant lines:  */
326 
327   open_input_file(input_file_name);
328   while (get_input_line(buff)) {
329     if (introduces_ILI(buff))
330       do_IL_line(2);
331     if (match(buff, ".AT"))
332       do_AT_line();
333     if (match(buff, ".CG"))
334       do_CG_line();
335     if (match(buff, ".SI"))
336       do_SI_line();
337   }
338 
339   /*  -------------- step 4:  write output file - iliatt.h:  */
340 
341   fprintf(fdiliatt,
342           "/* iliatt.h - DO NOT EDIT!\n"
343           "   This file was automatically generated by program %s. */\n\n",
344           argv[0]);
345   /* Write as an enum ILI_OP */
346   fprintf(fdiliatt, "typedef enum ILI_OP {\n");
347   fprintf(fdiliatt, "    IL_%-24.24s = %d,\n", "NONE", 0);
348   for (i = 1; i <= opcode_num; i++)
349     fprintf(fdiliatt, "    IL_%-24.24s = %d,\n", ilis[i].name, i);
350   fprintf(fdiliatt, "    %-24.24s    = %d\n", "GARB_COLLECTED", 0xffff);
351   fprintf(fdiliatt, "} ILI_OP;\n\n");
352   /* Write as reflexive define */
353   for (i = 1; i <= opcode_num; i++)
354     fprintf(fdiliatt, "#define IL_%-24.24s IL_%s\n", ilis[i].name,
355             ilis[i].name);
356   fprintf(fdiliatt, "#define N_ILI %d\n", opcode_num + 1);
357 
358   fclose(fdiliatt);
359 
360   /*  -------------- step 5:  write output file - ilinfodf.h:  */
361 
362   fprintf(fdilinfo,
363           "/* ilinfodf.h - DO NOT EDIT!\n"
364           "   This file was automatically generated by program %s. */\n",
365           argv[0]);
366   fprintf(fdilinfo, "\nILIINFO ilis[%d] = {\n", opcode_num + 1);
367 
368   /* Make sure to update the DUMMY entry if fields are added to ILIINFO.
369    */
370   fprintf(fdilinfo,
371           " { \"DUMMY\",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'X',"
372           "{0, 0, 0, 0} },\n");
373 
374   for (i = 1; i <= opcode_num; i++) {
375     int j;
376 
377     fprintf(fdilinfo, " { \"%s\", ", ilis[i].name);
378 
379     if (ilis[i].opcod != 0)
380       fprintf(fdilinfo, "%s, %d, 0x%04x, %d, %d, ", ilis[i].opcod, ilis[i].oprs,
381               ilis[i].attr, ilis[i].notCG, ilis[i].CGonly);
382     else /* no string specified for opcod: */
383       fprintf(fdilinfo, "0, %d, 0x%04x, %d, %d, ", ilis[i].oprs, ilis[i].attr,
384               ilis[i].notCG, ilis[i].CGonly);
385 
386     fprintf(
387         fdilinfo,
388         "\n\t  %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,",
389         ilis[i].notAILI, ilis[i].terminal, ilis[i].move, ilis[i].memdest,
390         ilis[i].ccarith, ilis[i].cclogical, ilis[i].ccmod, ilis[i].shiftop,
391         ilis[i].memarg, ilis[i].ssedp, ilis[i].ssest,
392         ilis[i].conditional_branch, ilis[i].sse_avx, ilis[i].avx_only,
393         ilis[i].avx_special, ilis[i].avx3_special, ilis[i].asm_special,
394         ilis[i].asm_nop, ilis[i].accel, ilis[i].replaceby);
395 
396     if (ilis[i].size == 0)
397       fprintf(fdilinfo, " '\\0', {");
398     else
399       fprintf(fdilinfo, " '%c', {", ilis[i].size);
400 
401     for (j = 0; j < MAX_OPNDS - 1; j++)
402       fprintf(fdilinfo, " %d,", ilis[i].oprflag[j]);
403 
404     fprintf(fdilinfo, " %d} }, \t/* %d */\n", ilis[i].oprflag[j], i);
405   }
406 
407   fprintf(fdilinfo, "};\n");
408   fclose(fdilinfo);
409 
410   /*  -------------- step 6:  write output file - schinfo.h:  */
411 
412   fprintf(fdschinfo,
413           "/* schinfo.h - DO NOT EDIT!\n"
414           "   This file was automatically generated by program %s. */\n",
415           argv[0]);
416   fprintf(fdschinfo, "\nSCHINFO schinfo[%d] = {\n", opcode_num + 1);
417 
418   fprintf(fdschinfo, "{0,0},\t/* DUMMY */\n");
419   for (i = 1; i <= opcode_num; i++) {
420     fprintf(fdschinfo, " {");
421     fprintf(fdschinfo, "%#10.8x, ", schinfo[i].latency);
422     fprintf(fdschinfo, "%#10.8x", schinfo[i].attrs);
423     fprintf(fdschinfo, "},\t/* %s */\n", ilis[i].name);
424   }
425 
426   fprintf(fdschinfo, "};\n");
427   fclose(fdschinfo);
428 
429   exit(0);
430 } /* end main(int argc, char *argv[]) */
431 
432 /* -------------------------------------------------------- */
433 
434 static void
do_IL_line(int pass)435 do_IL_line(int pass /* 1 or 2 */)
436 /*
437  * Process an opcode definition line (begins with ".IL" or ".FL").
438  */
439 {
440   int token_count;
441   char name[100], token[10][100];
442 
443   opcode_num++;
444   if (opcode_num >= (int)(sizeof(schinfo) / sizeof(SCHINFO))) {
445     error("Number of ILI opcodes exceeds sizeof(schinfo)");
446   }
447 
448   token_count = sscanf(buff.c_str(), ".%*cL %s %s %s %s %s %s %s %s %s %s %s", &name[0],
449                        token[0], token[1], token[2], token[3], token[4],
450                        token[5], token[6], token[7], token[8], token[9]);
451 
452   if (pass == 1) {
453     static ILIINFO zero;
454 
455     if (token_count >= 11)
456       error("too many operands on ili line");
457     if (token_count > MAX_OPNDS + 1)
458       error("maximum number of ili operands exceeded");
459     if (token_count < 1)
460       error("ili name missing from .IL line");
461     ilis[opcode_num] = zero;
462     ilis[opcode_num].name = STASH(name);
463   } else { /* pass 2 */
464     char *ofp;
465     int i, k;
466 
467     if (processed[opcode_num].il)
468       error("internal error -- duplicate opcode_num");
469     processed[opcode_num].il = true;
470 
471     ofp = ilis[opcode_num].oprflag;
472     for (i = 0; i < MAX_OPNDS; i++)
473       ofp[i] = 0;
474     for (i = 0; i < token_count - 1; i++) {
475       k = 0;
476       if (strcmp(token[i], "sym") == 0)
477         k = ILIO_SYM;
478       if (strcmp(token[i], "stc") == 0)
479         k = ILIO_STC;
480       if (strcmp(token[i], "nme") == 0)
481         k = ILIO_NME;
482       if (strcmp(token[i], "ir") == 0)
483         k = ILIO_IR;
484       if (strcmp(token[i], "kr") == 0)
485         k = ILIO_KR;
486       if (strcmp(token[i], "hp") == 0)
487         k = ILIO_HP;
488       if (strcmp(token[i], "sp") == 0)
489         k = ILIO_SP;
490       if (strcmp(token[i], "dp") == 0)
491         k = ILIO_DP;
492       if (strcmp(token[i], "cs") == 0)
493         k = ILIO_CS;
494       if (strcmp(token[i], "cd") == 0)
495         k = ILIO_CD;
496       if (strcmp(token[i], "ar") == 0)
497         k = ILIO_AR;
498       if (strcmp(token[i], "xmm") == 0)
499         k = ILIO_XMM;
500       if (strcmp(token[i], "x87") == 0)
501         k = ILIO_X87;
502       if (strcmp(token[i], "doubledouble") == 0)
503         k = ILIO_DOUBLEDOUBLE;
504       if (strcmp(token[i], "lnk") == 0)
505         k = ILIO_LNK;
506       if (strcmp(token[i], "irlnk") == 0)
507         k = ILIO_IRLNK;
508       if (strcmp(token[i], "hplnk") == 0)
509         k = ILIO_HPLNK;
510       if (strcmp(token[i], "splnk") == 0)
511         k = ILIO_SPLNK;
512       if (strcmp(token[i], "dplnk") == 0)
513         k = ILIO_DPLNK;
514       if (strcmp(token[i], "arlnk") == 0)
515         k = ILIO_ARLNK;
516       if (strcmp(token[i], "krlnk") == 0)
517         k = ILIO_KRLNK;
518       if (strcmp(token[i], "qplnk") == 0)
519         k = ILIO_QPLNK;
520       if (strcmp(token[i], "cslnk") == 0)
521         k = ILIO_CSLNK;
522       if (strcmp(token[i], "cdlnk") == 0)
523         k = ILIO_CDLNK;
524       if (strcmp(token[i], "cqlnk") == 0)
525         k = ILIO_CQLNK;
526       if (strcmp(token[i], "128lnk") == 0)
527         k = ILIO_128LNK;
528       if (strcmp(token[i], "256lnk") == 0)
529         k = ILIO_256LNK;
530       if (strcmp(token[i], "512lnk") == 0)
531         k = ILIO_512LNK;
532       if (strcmp(token[i], "x87lnk") == 0)
533         k = ILIO_X87LNK;
534       if (strcmp(token[i], "doubledoublelnk") == 0)
535         k = ILIO_DOUBLEDOUBLELNK;
536       if (strcmp(token[i], "float128lnk") == 0)
537         k = ILIO_FLOAT128LNK;
538       if (k == 0)
539         error("unrecognized ili operand type");
540       ofp[i] = k;
541     }
542     ilis[opcode_num].oprs = token_count - 1;
543   }
544 } /* end do_IL_line(pass) */
545 
546 /* -------------------------------------------------------- */
547 
548 static void
do_AT_line(void)549 do_AT_line(void)
550 /*
551  * Process an attribute definition line (begins with ".AT").
552  */
553 {
554   static char attr[4][50], attr1[50], attr2[50], attr3[50];
555   int token_count, i;
556   int attrb = 0;
557 
558   if (!processed[opcode_num].il)
559     error(".AT line should be preceded by .IL line");
560   if (processed[opcode_num].at)
561     error("multiple .AT lines for the same opcode");
562   processed[opcode_num].at = true;
563 
564   /* Parse .AT line.  First three tokens have fixed meaning, then
565    * variable number of remaining attributes.
566    */
567 
568   token_count = sscanf(buff.c_str(), ".AT %s %s %s %s %s %s %s", attr1, attr2, attr3,
569                        attr[0], attr[1], attr[2], attr[3]);
570 
571   if (token_count < 3)
572     error("at least 3 operands required on .AT line");
573 
574   if (token_count >= 7)
575     error("too many attribute specs. on .AT line");
576 
577   /*  process first attribute - ili type:  */
578 
579   if (strcmp("arth", attr1) == 0)
580     attrb = ILTY_ARTH;
581   if (strcmp("branch", attr1) == 0)
582     attrb = ILTY_BRANCH;
583   if (strcmp("cons", attr1) == 0)
584     attrb = ILTY_CONS;
585   if (strcmp("define", attr1) == 0)
586     attrb = ILTY_DEFINE;
587   if (strcmp("load", attr1) == 0)
588     attrb = ILTY_LOAD;
589   if (strcmp("pload", attr1) == 0)
590     attrb = ILTY_PLOAD;
591   if (strcmp("move", attr1) == 0)
592     attrb = ILTY_MOVE;
593   if (strcmp("other", attr1) == 0)
594     attrb = ILTY_OTHER;
595   if (strcmp("proc", attr1) == 0)
596     attrb = ILTY_PROC;
597   if (strcmp("store", attr1) == 0)
598     attrb = ILTY_STORE;
599   if (strcmp("pstore", attr1) == 0)
600     attrb = ILTY_PSTORE;
601   if (attrb == 0)
602     error("first ili attribute, ili type, not recognized");
603 
604   /*  process second attribute - "null" or "comm":   */
605 
606   if (strcmp("comm", attr2) == 0)
607     attrb |= (1 << 4);
608   else if (strcmp("null", attr2) != 0)
609     error("second attribute must be 'null' or 'comm'");
610 
611   /*  process third attribute - ili return value type:  */
612 
613   if (strcmp("lnk", attr3) == 0)
614     attrb |= (ILIA_LNK << 5);
615   else if (strcmp("ir", attr3) == 0)
616     attrb |= (ILIA_IR << 5);
617   else if (strcmp("hp", attr3) == 0)
618     attrb |= (ILIA_HP << 5);
619   else if (strcmp("sp", attr3) == 0)
620     attrb |= (ILIA_SP << 5);
621   else if (strcmp("dp", attr3) == 0)
622     attrb |= (ILIA_DP << 5);
623   else if (strcmp("trm", attr3) == 0)
624     attrb |= (ILIA_TRM << 5);
625   else if (strcmp("ar", attr3) == 0)
626     attrb |= (ILIA_AR << 5);
627   else if (strcmp("kr", attr3) == 0)
628     attrb |= (ILIA_KR << 5);
629   else if (strcmp("qp", attr3) == 0)
630     attrb |= (ILIA_QP << 5);
631   else if (strcmp("cs", attr3) == 0)
632     attrb |= (ILIA_CS << 5);
633   else if (strcmp("cd", attr3) == 0)
634     attrb |= (ILIA_CD << 5);
635   else if (strcmp("cq", attr3) == 0)
636     attrb |= (ILIA_CQ << 5);
637   else if (strcmp("128", attr3) == 0)
638     attrb |= (ILIA_128 << 5);
639   else if (strcmp("256", attr3) == 0)
640     attrb |= (ILIA_256 << 5);
641   else if (strcmp("512", attr3) == 0)
642     attrb |= (ILIA_512 << 5);
643   else if (strcmp("x87", attr3) == 0)
644     attrb |= (ILIA_X87 << 5);
645   else if (strcmp("doubledouble", attr3) == 0)
646     attrb |= (ILIA_DOUBLEDOUBLE << 5);
647   else if (strcmp("float128", attr3) == 0)
648     attrb |= (ILIA_FLOAT128 << 5);
649   else
650     error("unrecognized 3rd attribute of .AT line");
651 
652   /*  process remaining attributes:  */
653   bool fence = false;
654   bool atomicrmw = false;
655   bool cmpxchg = false;
656   for (i = 0; i < token_count - 3; i++) {
657     if (strcmp(attr[i], "cse") == 0)
658       attrb |= (ILIA_CSE << 10);
659     else if (strcmp(attr[i], "dom") == 0)
660       attrb |= (ILIA_DOM << 10);
661     else if (strcmp(attr[i], "ssenme") == 0)
662       attrb |= (1 << 12);
663     else if (strcmp(attr[i], "vect") == 0)
664       attrb |= (1 << 13);
665     else if (strcmp(attr[i], "fence") == 0)
666       fence = true;
667     else if (strcmp(attr[i], "atomicrmw") == 0)
668       atomicrmw = true;
669     else if (strcmp(attr[i], "cmpxchg") == 0)
670       cmpxchg = true;
671     else
672       error("unrecognized attribute on .AT line: ",attr[i]);
673   }
674   if (atomicrmw && cmpxchg)
675     error("can have at most one of atomicrmw or atomic_cmpxchg attributes");
676   if ((atomicrmw || cmpxchg) && !fence)
677     error("fence attribute required if atomicrmw or atomic_cmpxchg attribute is present");
678   attrb |= (cmpxchg ? 3 : atomicrmw ? 2 : fence ? 1 : 0) << 14;
679 
680   ilis[opcode_num].attr = attrb;
681 
682   /*  check that not both "cse" and "dom" specified:  */
683   if (IL_IATYPE(opcode_num) == 3)
684     error("conflicting attributes: dom and cse");
685   if (IL_SSENME(opcode_num) && IL_OPRFLAG(opcode_num, 1) != ILIO_ARLNK)
686     error("when ssenme attribute, 1st operand must be arlnk");
687   if (IL_SSENME(opcode_num) && IL_OPRFLAG(opcode_num, 3) != ILIO_NME)
688     error("when ssenme attribute, 3rd operand must be nme");
689 
690 } /* end do_AT_line(void) */
691 
692 /* -------------------------------------------------------- */
693 
694 static void
do_CG_line(void)695 do_CG_line(void)
696 /*
697  * Process a ".CG" line which defines attributes for the Code Generator.
698  */
699 {
700   static char attr[10][50];
701   int token_count, i;
702 
703   if (!processed[opcode_num].il)
704     error(".CG line should be preceded by .IL line");
705   if (processed[opcode_num].cg)
706     error("multiple .CG lines for the same opcode");
707   processed[opcode_num].cg = true;
708 
709   /* Parse the ".CG" line.  0 or more tokens are allowed.
710    */
711   token_count = sscanf(buff.c_str(), ".CG %s %s %s %s %s %s %s %s %s %s", attr[0],
712                        attr[1], attr[2], attr[3], attr[4], attr[5], attr[6],
713                        attr[7], attr[8], attr[9]);
714 
715   if (token_count >= 10)
716     error("too many attributes on .CG line");
717 
718   for (i = 0; i < token_count; i++) {
719     if (strcmp(attr[i], "notCG") == 0) {
720       ilis[opcode_num].notCG = 1;
721     } else if (strcmp(attr[i], "CGonly") == 0) {
722       ilis[opcode_num].CGonly = 1;
723     } else if (strcmp(attr[i], "notAILI") == 0) {
724       ilis[opcode_num].notAILI = 1;
725     } else if (strcmp(attr[i], "replaceby") == 0) {
726       i++;
727       ilis[opcode_num].replaceby = lookup_ili(attr[i]);
728     } else if (strcmp(attr[i], "terminal") == 0) {
729       ilis[opcode_num].terminal = 1;
730     } else if (strcmp(attr[i], "move") == 0) {
731       ilis[opcode_num].move = 1;
732     } else if (strcmp(attr[i], "memdest") == 0) {
733       ilis[opcode_num].memdest = 1;
734     } else if (strcmp(attr[i], "ccarith") == 0) {
735       ilis[opcode_num].ccarith = 1, ilis[opcode_num].ccmod = 1;
736     } else if (strcmp(attr[i], "cclogical") == 0) {
737       ilis[opcode_num].cclogical = 1, ilis[opcode_num].ccmod = 1;
738     } else if (strcmp(attr[i], "ccmod") == 0) {
739       ilis[opcode_num].ccmod = 1;
740     } else if (strcmp(attr[i], "shiftop") == 0) {
741       ilis[opcode_num].shiftop = 1;
742     } else if (strcmp(attr[i], "memarg") == 0) {
743       ilis[opcode_num].memarg = 1;
744     } else if (strcmp(attr[i], "ssedp") == 0) {
745       ilis[opcode_num].ssedp = 1;
746     } else if (strcmp(attr[i], "ssest") == 0) {
747       ilis[opcode_num].ssest = 1;
748     } else if (strcmp(attr[i], "conditional_branch") == 0) {
749       ilis[opcode_num].conditional_branch = 1;
750     } else if (strcmp(attr[i], "sse_avx") == 0) {
751       ilis[opcode_num].sse_avx = 1;
752     } else if (strcmp(attr[i], "avx_only") == 0) {
753       ilis[opcode_num].avx_only = 1;
754     } else if (strcmp(attr[i], "avx_special") == 0) {
755       ilis[opcode_num].avx_special = 1;
756     } else if (strcmp(attr[i], "avx3_special") == 0) {
757       ilis[opcode_num].avx3_special = 1;
758     } else if (strcmp(attr[i], "asm_special") == 0) {
759       ilis[opcode_num].asm_special = 1;
760     } else if (strcmp(attr[i], "asm_nop") == 0) {
761       ilis[opcode_num].asm_nop = 1;
762     } else if (strcmp(attr[i], "accel") == 0) {
763       ilis[opcode_num].accel = 1;
764     } else if (attr[i][0] == '"') {
765       ilis[opcode_num].opcod = STASH(attr[i]);
766     } else if (strcmp(attr[i], "'l'") == 0 || strcmp(attr[i], "'q'") == 0 ||
767                strcmp(attr[i], "'w'") == 0 || strcmp(attr[i], "'b'") == 0 ||
768                strcmp(attr[i], "'y'") == 0 || strcmp(attr[i], "'z'") == 0) {
769       ilis[opcode_num].size = attr[i][1];
770     } else
771       error("unrecognized attribute on .CG line");
772   }
773 
774   /* If 'replaceby' then also require 'notCG'.
775    */
776 
777   if (ilis[opcode_num].replaceby && !ilis[opcode_num].notCG)
778     printf("warning: notCG attribte required for ili %s.\n",
779            ilis[opcode_num].name);
780 
781   /* If an AILI can have this opcode then either an instruction mnemonic
782    * or 'asm_special' (or both) or 'asm_nop' must be specified.
783    */
784 
785   if (!ilis[opcode_num].notCG && !ilis[opcode_num].notAILI) {
786     if (!ilis[opcode_num].asm_special && !ilis[opcode_num].asm_nop &&
787         ilis[opcode_num].opcod == NULL)
788       printf("warning: ili %s is missing mnemonic spec.\n",
789              ilis[opcode_num].name);
790   }
791 
792   /* Set 'notAILI' if 'notCG' is true.
793    */
794 
795   if (ilis[opcode_num].notCG)
796     ilis[opcode_num].notAILI = 1;
797 
798 } /* end do_CG_line(void) */
799 
800 /* --------------------------------------------------------- */
801 
802 /* parse latency attributes
803  *     Format:
804  *
805  *         lat[R/R]
806  *         lat[R/M:R/R]
807  *
808  * R/R: Reg/reg format, 8-bit unsigned integer value
809  * R/M: Reg/Mem format, 8-bit unsigned integer value
810  *
811  * For the single value case (lat[R/R]), the same value is copied to
812  * the R/M field for latency.
813  *
814  * The instructions that have different latencies for 8/16/32/64
815  * operands (e.g. div, mul) are assumed to be encoded for their 64-bit
816  * incarnations.  They are relatively few in number and can be handled
817  * by special cases in the scheduler.  Similar assumption for
818  * instructions with a latency range (e.g. 'int'), which are rare, and
819  * not likely to be generated in any case.
820  */
821 static void
do_latency(const char * lat,int shift)822 do_latency(const char *lat, int shift)
823 {
824   /* 'ld' and 'st' are flags */
825 
826   int rr_lat, rm_lat, lat_count;
827 
828   lat_count = sscanf(lat, "lat(%d:%d)", &rm_lat, &rr_lat);
829 
830   if (lat_count == 2) {
831     if (shift)
832       error("R/R and R/M latency are meaningless for loads/stores.");
833 
834     if (rr_lat > 255 || rm_lat > 255)
835       error("Latency out of range on .SI line");
836     schinfo[opcode_num].latency |=
837         (((unsigned short)rm_lat << RM_SHIFT) | (unsigned short)rr_lat);
838   } else {
839     lat_count = sscanf(lat, "lat(%d)", &rr_lat);
840     if (lat_count == 1) {
841       if (rr_lat > 255)
842         error("Latency out of range on .SI line");
843       schinfo[opcode_num].latency |= ((unsigned short)rr_lat << shift);
844     } else {
845       error("Incorrect latency format on .SI line");
846     }
847   }
848 } /* end do_latency(char *lat, int shift) */
849 
850 /* --------------------------------------------------------- */
851 
852 static void
do_SI_line(void)853 do_SI_line(void)
854 /*
855  * Process a ".SI" line which defines latencies, etc.
856  */
857 {
858   static char attr[10][48];
859   unsigned int attrs;
860   int token_count, i;
861   /* int ld_flg = 0, st_flg = 0, rm_flg = 0; */
862   int shift;
863 
864   if (!processed[opcode_num].il)
865     error(".SI line should be preceded by .IL line");
866 
867   token_count = sscanf(buff.c_str(), ".SI %s %s %s %s %s %s %s %s %s %s", attr[0],
868                        attr[1], attr[2], attr[3], attr[4], attr[5], attr[6],
869                        attr[7], attr[8], attr[9]);
870 
871   if (token_count >= 10) {
872     error("too many attributes on .SI line");
873   }
874 
875   if (strcmp(attr[0], "ld") == 0) {
876     /* ld_flg = 1; */
877     shift = LD_SHIFT;
878   } else if (strcmp(attr[0], "st") == 0) {
879     /* st_flg = 1; */
880     shift = ST_SHIFT;
881   } else if (strcmp(attr[0], "r/m") == 0) {
882     /* rm_flg = 1; */
883     shift = RM_SHIFT;
884   } else {
885     shift = 0;
886   }
887 
888   for (i = 0; i < token_count; i++) {
889     if (strcmp(attr[i], "fadd") == 0)
890       schinfo[opcode_num].attrs |= P_FADD << shift;
891     else if (strcmp(attr[i], "fmul") == 0)
892       schinfo[opcode_num].attrs |= P_FMUL << shift;
893     else if (strcmp(attr[i], "fst") == 0)
894       schinfo[opcode_num].attrs |= P_FST << shift;
895     else if (strcmp(attr[i], "direct") == 0)
896       schinfo[opcode_num].attrs |= DEC_DIR << shift;
897     else if (strcmp(attr[i], "double") == 0)
898       schinfo[opcode_num].attrs |= DEC_DBL << shift;
899     else if (strcmp(attr[i], "vector") == 0)
900       schinfo[opcode_num].attrs |= DEC_VEC << shift;
901     else if (strncmp(attr[i], "lat", 3) == 0)
902       do_latency(attr[i], shift);
903   }
904 
905   /* if (!rm_flg && !st_flg && !ld_flg) {
906    *   schinfo[opcode_num].attrs |= (schinfo[opcode_num] & 0xff) << RM_SHIFT;
907    * }
908    */
909 
910   attrs = ((SCH_ATTR(opcode_num) >> shift) & (DEC_DIR | DEC_DBL | DEC_VEC));
911   if (!(attrs == 0 || attrs == DEC_DIR || attrs == DEC_DBL ||
912         attrs == DEC_VEC)) {
913     error("Too many decode types listed on .SI line");
914   }
915 } /* end do_SI_line(void) */
916 
917 /* --------------------------------------------------------- */
918 
919 static int
lookup_ili(const char * name)920 lookup_ili(const char *name)
921 {
922   int i;
923 
924   for (i = 1; i <= max_ili_num; i++)
925     if (strcmp(name, ilis[i].name) == 0)
926       return i;
927 
928   error("reference to non-existent ili name");
929   return 0;
930 
931 } /* end lookup_ili(char *name) */
932 
933 /* --------------------------------------------------------- */
934 
935 /**
936  * Print an error message.
937  */
938 static void
error(const char * text,const char * additional_text)939 error(const char *text, const char *additional_text)
940 {
941   input_file.printError(FATAL, text, additional_text);
942 }
943 
944 /* --------------------------------------------------------- */
945