00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00038
00039
00040
00042
00043
00044 #include <cstddef>
00045 #include <cstdlib>
00046 #include <cstdarg>
00047 #include <cstdio>
00048 #include <cassert>
00049 #include <cstring>
00050 #include <alloca.h>
00051
00052 #include <vector>
00053 #include <list>
00054
00055 using namespace std;
00056
00057 #include "topcode.h"
00058 #include "gen_util.h"
00059 #include "targ_isa_operands.h"
00060 #include "isa_pseudo_gen.h"
00061
00062 #define MAX_REQUIRE 10
00063 #define MAX_MAP (ISA_OPERAND_max_results + ISA_OPERAND_max_operands)
00064
00065 typedef enum {
00066 UNKNOWN_DIRECTION,
00067 MACHINE_TO_PSEUDO,
00068 PSEUDO_TO_MACHINE
00069 } DIRECTION;
00070
00071 typedef struct pseudo_op {
00072 DIRECTION dir;
00073 TOP to_opc;
00074 TOP from_opc;
00075 int index;
00076 int nrequire;
00077 int require[MAX_REQUIRE+1];
00078 int nmap;
00079 int map[2][MAX_MAP+1];
00080 } PSEUDO_OP_INFO;
00081
00082 static int num_pseudos;
00083 static list <PSEUDO_OP_INFO *> pseudos;
00084 static PSEUDO_OP_INFO *cur_pseudo;
00085 static int max_require;
00086 static int max_map;
00087
00088 typedef enum expr_kind {
00089 EXPR_BOOL,
00090 EXPR_ARG_LVALUE,
00091 EXPR_ARG_RVALUE
00092 } EXPR_KIND;
00093
00094 typedef struct expr {
00095 struct expr *next;
00096 EXPR_KIND kind;
00097 char s[1];
00098 } EXPR;
00099
00100 static EXPR exprs;
00101 static EXPR *last_expr = &exprs;
00102
00103 static const char * const interface[] = {
00104 "/* ====================================================================",
00105 " * ====================================================================",
00106 " *",
00107 " * Description:",
00108 " *",
00109 " * Utilities for pseudo instructions. The following are exported:",
00110 " *",
00111 " * typedef (enum) ISA_PSEUDO_DIRECTION",
00112 " * Specifies the direction of a machine/pseudo instruction",
00113 " * translation:",
00114 " *",
00115 " * ISA_PSEUDO_to_pseudo -- translate from machine to pseudo instruction",
00116 " * ISA_PSEUDO_to_machine -- translate from pseudo to machine instruction",
00117 " *",
00118 " * TOP ISA_PSEUDO_Translate(TOP opc,",
00119 " * INT64 *r,",
00120 " * INT64 *o,",
00121 " * ISA_PSEUDO_DIRECTION dir)",
00122 " * Translate the instruction with opcode <opc>, results",
00123 " * array <r> and operands array <o>. The direction of the",
00124 " * translation is controlled by <dir>. If there is a translation",
00125 " * return the translated topcode by function return value, and",
00126 " * the possibly modified operands and results by the <o> and <r>",
00127 " * arrays. If there is no translation, return <opc> by function",
00128 " * value, with unmodified operands and results. If an internal",
00129 " * error is detected, TOP_UNDEFINED is returned rather than",
00130 " * asserting.",
00131 " *",
00132 " * ====================================================================",
00133 " * ====================================================================",
00134 " */",
00135 NULL
00136 };
00137
00139 void ISA_Pseudo_Begin(const char * )
00141
00143 {
00144 }
00145
00147 static int save_expr(const char *s, EXPR_KIND kind)
00148 {
00150
00151
00152
00154 EXPR *e;
00155 int i = 1;
00156 for (e = exprs.next; e; e = e->next) {
00157 if (kind == e->kind) {
00158 if (strcmp(s, e->s) == 0) return i;
00159 ++i;
00160 }
00161 }
00162 e = (EXPR *)malloc(sizeof(EXPR) + strlen(s));
00163 e->next = NULL;
00164 e->kind = kind;
00165 strcpy(e->s, s);
00166 last_expr->next = e;
00167 last_expr = e;
00168 return i;
00169 }
00170
00171
00173 void Machine_To_Pseudo(TOP pseudo, TOP machine)
00175
00177 {
00178 cur_pseudo = new PSEUDO_OP_INFO;
00179 pseudos.push_back(cur_pseudo);
00180 bzero(cur_pseudo, sizeof(PSEUDO_OP_INFO));
00181 cur_pseudo->from_opc = machine;
00182 cur_pseudo->to_opc = pseudo;
00183 cur_pseudo->dir = MACHINE_TO_PSEUDO;
00184 num_pseudos++;
00185 }
00186
00187
00189 void Pseudo_To_Machine(TOP machine, TOP pseudo)
00191
00193 {
00194 cur_pseudo = new PSEUDO_OP_INFO;
00195 pseudos.push_back(cur_pseudo);
00196 bzero(cur_pseudo, sizeof(PSEUDO_OP_INFO));
00197 cur_pseudo->from_opc = pseudo;
00198 cur_pseudo->to_opc = machine;
00199 cur_pseudo->dir = PSEUDO_TO_MACHINE;
00200 num_pseudos++;
00201 }
00202
00203
00205 void Require(const char *bool_expr)
00207
00209 {
00210 if (cur_pseudo == NULL) {
00211 fprintf(stderr, "### Error: must specify a translation prior to "
00212 "Require(\"%s\")\n",
00213 bool_expr);
00214 exit(EXIT_FAILURE);
00215 }
00216 if (cur_pseudo->dir != MACHINE_TO_PSEUDO) {
00217 fprintf(stderr, "### Error: Require() only valid for machine-to-pseudo "
00218 "op translations\n");
00219 exit(EXIT_FAILURE);
00220 }
00221
00222 int idx = cur_pseudo->nrequire;
00223 if (idx == MAX_REQUIRE) {
00224 fprintf(stderr, "too many requirements for pseudo %s\n",
00225 TOP_Name(cur_pseudo->to_opc));
00226 exit(EXIT_FAILURE);
00227 }
00228 cur_pseudo->require[idx] = save_expr(bool_expr, EXPR_BOOL);
00229 cur_pseudo->nrequire = ++idx;
00230 if (idx > max_require) max_require = idx;
00231 }
00232
00233
00235 void Map_Arg(const char *lvalue, const char *expr)
00237
00239 {
00240 if (cur_pseudo == NULL) {
00241 fprintf(stderr, "### Error: must specify a translation prior to "
00242 "Map_Arg(\"%s\", \"%s\")\n",
00243 lvalue, expr);
00244 exit(EXIT_FAILURE);
00245 }
00246 if (strcmp(lvalue, expr) != 0) {
00247 int idx = cur_pseudo->nmap;
00248 if (idx == MAX_MAP) {
00249 fprintf(stderr, "too many arg mappings for pseudo %s\n",
00250 TOP_Name(cur_pseudo->to_opc));
00251 exit(EXIT_FAILURE);
00252 }
00253 cur_pseudo->map[0][idx] = save_expr(lvalue, EXPR_ARG_LVALUE);
00254 cur_pseudo->map[1][idx] = save_expr(expr, EXPR_ARG_RVALUE);
00255 cur_pseudo->nmap = ++idx;
00256 if (idx > max_map) max_map = idx;
00257 }
00258 }
00259
00260
00262 static int compare_pseudos(const void *p1, const void *p2)
00264
00266 {
00267 PSEUDO_OP_INFO *ps1 = *(PSEUDO_OP_INFO **)p1;
00268 PSEUDO_OP_INFO *ps2 = *(PSEUDO_OP_INFO **)p2;
00269
00270
00271
00272 if (ps1->dir != ps2->dir) {
00273 if (ps1->dir == PSEUDO_TO_MACHINE) return -1;
00274 return 1;
00275 }
00276
00277
00278
00279
00280
00281
00282 int cmp = ps1->from_opc - ps2->from_opc;
00283 if (cmp == 0) cmp = ps2->nrequire - ps1->nrequire;
00284 return cmp;
00285 }
00286
00287
00289 static void verify_machine_to_pseudo(PSEUDO_OP_INFO **vec, int i)
00291
00292
00293
00295 {
00296 int j;
00297 int k;
00298 int n;
00299 TOP from_opc = vec[i]->from_opc;
00300 for (j = i; j < num_pseudos && vec[j]->from_opc == from_opc; ++j) {
00301 for (k = j + 1; k < num_pseudos && vec[k]->from_opc == from_opc; ++k) {
00302 if (vec[j]->nrequire != vec[k]->nrequire) break;
00303
00304 for (n = 0; n < vec[j]->nrequire; ++n) {
00305 if (vec[j]->require[n] != vec[k]->require[n]) goto next_k;
00306 }
00307
00308 fprintf(stderr, "### Error: duplicate machine-to-pseudo translations "
00309 "for %s (to %s and %s)\n",
00310 TOP_Name(vec[j]->from_opc),
00311 TOP_Name(vec[j]->to_opc),
00312 TOP_Name(vec[k]->to_opc));
00313 exit(EXIT_FAILURE);
00314
00315
00316 next_k:
00317 ;
00318 }
00319 }
00320 }
00321
00322
00324 void order_pseudos(int *machine_to_pseudo_index, int *pseudo_to_machine_index)
00326
00328 {
00329 int i;
00330 list <PSEUDO_OP_INFO *>::iterator ps_iter;
00331 PSEUDO_OP_INFO **vec = (PSEUDO_OP_INFO **)alloca(sizeof(PSEUDO_OP_INFO *) * num_pseudos);
00332
00333 for (i = 0; i < TOP_count; ++i) {
00334 machine_to_pseudo_index[i] = num_pseudos;
00335 pseudo_to_machine_index[i] = num_pseudos;
00336 }
00337
00338 for (i = 0, ps_iter = pseudos.begin();
00339 ps_iter != pseudos.end();
00340 ++i, ++ps_iter)
00341 {
00342 vec[i] = *ps_iter;
00343 }
00344 qsort(vec, num_pseudos, sizeof(PSEUDO_OP_INFO *), compare_pseudos);
00345 pseudos.clear();
00346 for (i = 0; i < num_pseudos; ++i) {
00347 PSEUDO_OP_INFO *ps = vec[i];
00348 ps->index = i;
00349 pseudos.push_back(ps);
00350
00351 switch (ps->dir) {
00352 case MACHINE_TO_PSEUDO:
00353 if (machine_to_pseudo_index[(int)ps->from_opc] == num_pseudos) {
00354 machine_to_pseudo_index[(int)ps->from_opc] = i;
00355 verify_machine_to_pseudo(vec, i);
00356 }
00357 break;
00358 case PSEUDO_TO_MACHINE:
00359 if (pseudo_to_machine_index[(int)ps->from_opc] != num_pseudos) {
00360 fprintf(stderr, "### Error: multiple pseudo-to-machine translations for %s\n",
00361 TOP_Name(ps->from_opc));
00362 exit(EXIT_FAILURE);
00363
00364 }
00365 pseudo_to_machine_index[(int)ps->from_opc] = i;
00366 break;
00367 default:
00368 fprintf(stderr, "### Error: unexpected DIRECTION (%d)\n", ps->dir);
00369 exit(EXIT_FAILURE);
00370
00371 }
00372 }
00373 }
00374
00375
00377 void ISA_Pseudo_End(void)
00379
00381 {
00382 DIRECTION last_dir = UNKNOWN_DIRECTION;
00383 int machine_to_pseudo_index[TOP_count];
00384 int pseudo_to_machine_index[TOP_count];
00385 list <PSEUDO_OP_INFO *>::iterator ps_iter;
00386 int i;
00387 EXPR *e;
00388 char buf[1000];
00389 #define FNAME "targ_isa_pseudo"
00390 sprintf (buf, "%s.h", FNAME);
00391 FILE* hfile = fopen(buf, "w");
00392 sprintf (buf, "%s.c", FNAME);
00393 FILE* cfile = fopen(buf, "w");
00394 sprintf (buf, "%s.Exported", FNAME);
00395 FILE* efile = fopen(buf, "w");
00396
00397 fprintf(cfile, "#include \"topcode.h\"\n"
00398 "#include \"%s.h\"\n\n", FNAME);
00399
00400 sprintf (buf, "%s", FNAME);
00401 Emit_Header (hfile, buf, interface);
00402 fprintf(hfile, "#include \"topcode.h\"\n");
00403
00404 order_pseudos(machine_to_pseudo_index, pseudo_to_machine_index);
00405
00406 ++max_require;
00407 ++max_map;
00408
00409 fprintf(cfile, "typedef struct {\n"
00410 " mTOP to_opc;\n"
00411 " mTOP from_opc;\n"
00412 " mUINT8 require[%d];\n"
00413 " mUINT8 map[%d][2];\n"
00414 "} PSEUDO;\n",
00415 max_require,
00416 max_map);
00417
00418 fprintf(cfile, "\nstatic const PSEUDO pseudos[%d] = {\n", num_pseudos + 1);
00419 for (ps_iter = pseudos.begin();
00420 ps_iter != pseudos.end();
00421 ++ps_iter)
00422 {
00423 PSEUDO_OP_INFO *info = *ps_iter;
00424 if (last_dir != info->dir) {
00425 fprintf(cfile, "\n /* %s */\n\n",
00426 info->dir == MACHINE_TO_PSEUDO
00427 ? "machine => pseudo" : "pseudo => machine");
00428 last_dir = info->dir;
00429 }
00430 fprintf(cfile, " /* %2d: %s => %s */\n",
00431 info->index,
00432 TOP_Name((TOP)info->from_opc),
00433 TOP_Name((TOP)info->to_opc));
00434 fprintf(cfile, " { %3d, %3d, {",
00435 info->to_opc,
00436 info->from_opc);
00437 for (i = 0; i < max_require; ++i) {
00438 fprintf(cfile, " %d,", (i < info->nrequire) ? info->require[i] : 0);
00439 }
00440 fprintf(cfile, " }, {");
00441 for (i = 0; i < max_map; ++i) {
00442 fprintf(cfile, " {%d, %d},",
00443 (i < info->nmap) ? info->map[0][i] : 0,
00444 (i < info->nmap) ? info->map[1][i] : 0);
00445 }
00446 fprintf(cfile, " } },\n");
00447 }
00448 fprintf(cfile, " /* %2d: TOP_UNDEFINED => TOP_UNDEFINED */\n",
00449 num_pseudos);
00450 fprintf(cfile, " { %3d, %3d, { 0 }, { {0, 0} }}\n",
00451 TOP_UNDEFINED,
00452 TOP_UNDEFINED);
00453 fprintf(cfile, "};\n");
00454
00455 fprintf(cfile, "\nstatic const mUINT8 pseudo_index[%d][2] = {\n", TOP_count);
00456 for (i = 0; i < TOP_count; ++i) {
00457 fprintf(cfile, " { %2d, %2d }, /* %-9s */\n",
00458 machine_to_pseudo_index[i],
00459 pseudo_to_machine_index[i],
00460 TOP_Name((TOP)i));
00461 }
00462 fprintf(cfile, "};\n");
00463
00464 fprintf(hfile, "\ntypedef enum {\n"
00465 " ISA_PSEUDO_to_pseudo = 0,\n"
00466 " ISA_PSEUDO_to_machine = 1\n"
00467 "} ISA_PSEUDO_DIRECTION;\n");
00468
00469 fprintf(hfile, "\nextern TOP ISA_PSEUDO_Translate(TOP opc,\n"
00470 " INT64 *r,\n"
00471 " INT64 *o,\n"
00472 " ISA_PSEUDO_DIRECTION dir);\n");
00473
00474 fprintf(efile, "ISA_PSEUDO_Translate\n");
00475
00476 fprintf(cfile, "\n"
00477 "#define OPND(n) (o[(n)])\n"
00478 "#define RESULT(n) (r[(n)])\n");
00479
00480 fprintf(cfile, "\nTOP ISA_PSEUDO_Translate(TOP opc, INT64 *r, INT64 *o, ISA_PSEUDO_DIRECTION dir)\n"
00481 "{\n"
00482 " int i;\n"
00483 " int j;\n"
00484 " int n;\n"
00485 " int arg[%d];\n"
00486 " const INT idx = pseudo_index[(INT)opc][dir];\n"
00487 " const PSEUDO *pop = pseudos + idx;\n"
00488 "\n"
00489 " if (pop->from_opc != opc) return opc;\n"
00490 "\n"
00491 " if (dir == ISA_PSEUDO_to_pseudo) {\n"
00492 " do {\n"
00493 " for (i = 0;; ++i) {\n"
00494 " BOOL val;\n"
00495 " n = pop->require[i];\n"
00496 " switch (n) {\n"
00497 " case 0:\n"
00498 " goto xlate_pseudo;\n",
00499 max_map - 1);
00500 for (e = exprs.next, i = 1; e; e = e->next) {
00501 if (e->kind == EXPR_BOOL) {
00502 fprintf(cfile, " case %d:\n", i);
00503 fprintf(cfile, " val = (%s);\n", e->s);
00504 fprintf(cfile, " break;\n");
00505 ++i;
00506 }
00507 }
00508 fprintf(cfile, " default:\n"
00509 " return TOP_UNDEFINED;\n"
00510 " }\n"
00511 " if (!val) break;\n"
00512 " }\n"
00513 " } while ((++pop)->from_opc == opc);\n"
00514 " return opc;\n"
00515 " }\n"
00516 "\n"
00517 "xlate_pseudo:\n");
00518 if (max_map > 1) {
00519 fprintf(cfile, " for (j = 0, i = 0; (n = pop->map[i][1]); ++j, ++i) {\n"
00520 " switch (n) {\n");
00521 for (e = exprs.next, i = 1; e; e = e->next) {
00522 if (e->kind == EXPR_ARG_RVALUE) {
00523 fprintf(cfile, " case %d:\n", i);
00524 fprintf(cfile, " arg[j] = (%s);\n", e->s);
00525 fprintf(cfile, " break;\n");
00526 ++i;
00527 }
00528 }
00529 fprintf(cfile, " default:\n"
00530 " return TOP_UNDEFINED;\n"
00531 " }\n"
00532 " }\n"
00533 " for (j = 0, i = 0; (n = pop->map[i][0]); ++j, ++i) {\n"
00534 " switch (n) {\n");
00535 for (e = exprs.next, i = 1; e; e = e->next) {
00536 if (e->kind == EXPR_ARG_LVALUE) {
00537 fprintf(cfile, " case %d:\n", i);
00538 fprintf(cfile, " (%s) = arg[j];\n", e->s);
00539 fprintf(cfile, " break;\n");
00540 ++i;
00541 }
00542 }
00543 fprintf(cfile, " default:\n"
00544 " return TOP_UNDEFINED;\n"
00545 " }\n"
00546 " }\n");
00547 } else {
00548 fprintf(cfile, " ;\n");
00549 }
00550 fprintf(cfile, " return (TOP)pop->to_opc;\n"
00551 "}\n");
00552
00553 Emit_Footer (hfile);
00554 }