Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
isa_pseudo_gen.cxx
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 // isa_pseudo_gen.cxx
00038 //
00039 //  Generate an interface for pseudo instructions.
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]; // must be last
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 * /* name */)
00141 //  See interface description.
00143 {
00144 }
00145 
00147 static int save_expr(const char *s, EXPR_KIND kind)
00148 {
00150 //  Save a unique copy of <s> for the expression kind <kind> and
00151 //  return it's identifier, which is a integer (it's really the
00152 //  nth string of kind <kind> in the list of all expressions.
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 //  See interface description.
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 //  See interface description.
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 //  See interface description.
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 //  See interface description.
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 //  qsort comparison function for sorting pseudos.
00266 {
00267   PSEUDO_OP_INFO *ps1 = *(PSEUDO_OP_INFO **)p1;
00268   PSEUDO_OP_INFO *ps2 = *(PSEUDO_OP_INFO **)p2;
00269 
00270   /* Sort so pseudo-to-machine translations come first.
00271    */
00272   if (ps1->dir != ps2->dir) {
00273     if (ps1->dir == PSEUDO_TO_MACHINE) return -1;
00274     return 1;
00275   }
00276 
00277   /* Sort so that machine-to-pseudo translations are grouped together
00278    * by "from" opcode; if same opcode then sort according to number 
00279    * of operands required to match such that pseudos with larger number 
00280    * of matches required come first.
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 //  vec[i] is the first of a sequence of one or more machine-to-pseudo
00292 //  translations for the same "from" opcode. Verify that there aren't
00293 //  duplicate translations.
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       /*NOTREACHED*/
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         /*NOTREACHED*/
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       /*NOTREACHED*/
00371     }
00372   }
00373 }
00374 
00375 
00377 void ISA_Pseudo_End(void)
00379 //  See interface description.
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; // allow for terminator
00407   ++max_map; // allow for terminator
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines