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