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