Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
ir_a2b_util.h
Go to the documentation of this file.
00001 /* -*-Mode: C++;-*- */
00002 /* $Id: ir_a2b_util.h,v 1.3 2005-01-24 20:59:43 eraxxon Exp $ */
00003 /* * BeginRiceCopyright *****************************************************
00004  * 
00005  * ******************************************************* EndRiceCopyright */
00006 
00007 /* ====================================================================
00008  * ====================================================================
00009  *
00010  *
00011  * Nathan Tallent.
00012  *
00013  * Description:
00014  *
00015  * Utilities for converting between ascii and whirl.
00016  *
00017  * ====================================================================
00018  * ====================================================================
00019  */
00020 
00021 #ifndef ir_a2b_util_INCLUDED
00022 #define ir_a2b_util_INCLUDED
00023 
00024 #include "defs.h"
00025 #include "cxx_memory.h"                 // for CXX_NEW
00026 #include "errors.h"                     // for Fail_FmtAssertion
00027 #include "x_string.h"                   // for strcasecmp()
00028 
00029 /* ====================================================================
00030  *
00031  * Templated schemes for translating between integral values and
00032  * symbolic names and vice-versa.  Should be quite adequate for
00033  * Open64.
00034  *
00035  * Note 1: For each mapping routine designated by a (*), a O(n) table
00036  * check is performed, where n is the size of the table, the first
00037  * time the routine is called.
00038  *
00039  * Note 2: n will be a relatively small compile-time constant.
00040  * 
00041  * 1. Translate between an enumerated value (INT values between 0 and
00042  *    n) and a unique string (case insensitive).
00043  *
00044  *    enum to string: O(1); no additional memory allocation. (*)
00045  *
00046  *    string to enum: O(log n). The first time the routine is called,
00047  *      an auxilliary table of size n pointers is allocated and sorted
00048  *      (O(n*log n)) to be later used with binary-search. (*)
00049  *
00050  * 2. Translate between a set of flags (a set is a UINT64) to a
00051  *    comma-separated list of strings (case insensitive) and vice-versa.
00052  *
00053  *    flag to string: O(log n); no additional table memory allocation. (*)
00054  *
00055  *    string to flag: O(log n). The first time the routine is called,
00056  *      an auxilliary table of size n pointers is allocated and sorted
00057  *      (O(n*log n)) to be later used with binary-search. (*)
00058  *
00059  * ====================================================================
00060  */
00061 
00062 // Example for an enumerated type (flags are very similar)
00063 //
00064 // Given an enumerated type, 
00065 //   enum TY_KIND {
00066 //     KIND_APPLES,
00067 //     KIND_ORANGES,
00068 //     KIND_PEARS,
00069 //     KIND_COUNT 
00070 //   };     
00071 //
00072 // the user defines a table mapping the enumerated type to unique
00073 // strings.  The table should have an entry for every value between 0
00074 // and n and should use ir_a2b::enum2str_tbl_entry_t as the base class of
00075 // the entry type:
00076 //
00077 //   struct myentry_t : public ir_a2b::enum2str_tbl_entry_t
00078 //    ... 
00079 //   };
00080 //
00081 //   myentry_t TYKindToNameTbl[KIND_COUNT] = 
00082 //     myentry_t(KIND_APPLES,  "APPLES"),
00083 //     myentry_t(KIND_ORANGES, "ORANGES"),
00084 //     myentry_t(KIND_PEARS,   "PEARS")
00085 //   };
00086 //
00087 // Given this table, the mappings can be performed using the routines
00088 //   ir_a2b::MapEnumToStr(...)
00089 //   ir_a2b::MapStrToEnum(...)
00090 //
00091 // See symtab.cxx for one set of examples.
00092 
00093 namespace ir_a2b {
00094 
00095 //----------------------------------------------------------------------
00096 // enum2str_tbl_entry_t, flag2str_tbl_entry_t
00097 //----------------------------------------------------------------------
00098 
00099 // enum2str_tbl_entry_t: The virtual base class for an enumeration->string
00100 // table entry.
00101 struct enum2str_tbl_entry_t {
00102   enum2str_tbl_entry_t() { }
00103   enum2str_tbl_entry_t(const enum2str_tbl_entry_t& x) { }
00104   virtual ~enum2str_tbl_entry_t() { }
00105 
00106   // get the integer representation for the entry
00107   virtual INT getEnumVal() const = 0;
00108   
00109   // get the string for the entry
00110   virtual const char* getStr() const = 0;
00111   
00112   // cmp: for use with qsort(), bsearch()
00113   static int 
00114   cmp(const void * entry1, const void * entry2) {
00115     enum2str_tbl_entry_t* e1 = (enum2str_tbl_entry_t*)entry1;
00116     enum2str_tbl_entry_t* e2 = (enum2str_tbl_entry_t*)entry2;
00117     return ux_strcasecmp(e1->getStr(), e2->getStr());
00118   }
00119   
00120 };
00121 
00122 
00123 // flag2str_tbl_entry_t: The virtual base class for an enumeration->string
00124 // table entry.
00125 struct flag2str_tbl_entry_t {
00126   flag2str_tbl_entry_t() { }
00127   flag2str_tbl_entry_t(const flag2str_tbl_entry_t& x) { }
00128   virtual ~flag2str_tbl_entry_t() { }
00129 
00130   // get the integer representation for the entry
00131   virtual UINT64 getFlagVal() const = 0;
00132   
00133   // get the string for the entry
00134   virtual const char* getStr() const = 0;
00135   
00136   // flagcmp: for use with qsort(), bsearch()
00137   static int 
00138   flagcmp(const void * entry1, const void * entry2) {
00139     flag2str_tbl_entry_t* e1 = (flag2str_tbl_entry_t*)entry1;
00140     flag2str_tbl_entry_t* e2 = (flag2str_tbl_entry_t*)entry2;
00141     UINT64 v1 = e1->getFlagVal();
00142     UINT64 v2 = e2->getFlagVal();
00143     // to prevent type overflow we do not do: (INT64)(e1 - e2)
00144     if (v1 == v2) { 
00145       return 0; 
00146     }
00147     else if (v1 < v2) {
00148       return -1;
00149     }
00150     else {
00151       return 1;
00152     }
00153   }
00154   
00155   // strcmp: for use with qsort(), bsearch()
00156   static int 
00157   strcmp(const void * entry1, const void * entry2) {
00158     flag2str_tbl_entry_t* e1 = (flag2str_tbl_entry_t*)entry1;
00159     flag2str_tbl_entry_t* e2 = (flag2str_tbl_entry_t*)entry2;
00160     return ux_strcasecmp(e1->getStr(), e2->getStr());
00161   }
00162   
00163 };
00164 
00165 
00166 // CheckEnumTable: Ensures that the enum-to-string table meets the
00167 // basic constraints for the mapping to work correctly.
00168 //
00169 // N.B.: 'table' is not part of the template-parameter-list since we
00170 // only need a separate instantiation for each ENUM_TBL_ENTRY_T.
00171 template <typename ENUM_TBL_ENTRY_T>
00172 void
00173 CheckEnumTable(const char* tablenm, const ENUM_TBL_ENTRY_T* table, INT tablesz)
00174 {
00175   // Ensure that the table is sorted and contains all entries between
00176   // 0 and n
00177   for (INT val = 0; val < tablesz; ++val) {
00178     if (table[val].getEnumVal() != val) {
00179       const char* str = table[val].getStr() ? table[val].getStr() : "";
00180       Fail_FmtAssertion("ir_a2b::CheckEnumTable: Error in table '%s': invalid entry: %d -> { %d %s }", tablenm, val, table[val].getEnumVal(), str);
00181     }
00182   }
00183 }
00184 
00185 
00186 // CheckFlagTable: Ensures that the flag-to-string table meets the
00187 // basic constraints for the mapping to work correctly.
00188 //
00189 // N.B.: 'table' is not part of the template-parameter-list since we
00190 // only need a separate instantiation for each FLG_TBL_ENTRY_T.
00191 template <typename FLG_TBL_ENTRY_T>
00192 void
00193 CheckFlagTable(const char* tablenm, const FLG_TBL_ENTRY_T* table, INT tablesz)
00194 {
00195   // Ensure table is sorted
00196   UINT64 val, prevval = 0;
00197   for (INT i = 0; i < tablesz; ++i) {
00198     val = table[i].getFlagVal();
00199     if (i != 0 && !(prevval < val)) {
00200       Fail_FmtAssertion("ir_a2b::CheckFlagTable: Error in table '%s': %llx preceeds %llx (out of order)", tablenm, prevval, val);
00201     }
00202     prevval = table[i].getFlagVal();
00203   }
00204 }
00205 
00206 
00207 //----------------------------------------------------------------------
00208 // MapEnumToStr, MapStrToEnum
00209 //----------------------------------------------------------------------
00210 
00211 // MapEnumToStr: Given 1) a enum2str_tbl_entry_t table (sorted by
00212 // enumeration value), its name and the number of entries therein and
00213 // 2) an enumeration value, return a string representation.
00214 //
00215 // N.B.: 'table' is part of the template-parameter-list to ensure
00216 // there is a separate instantiation for each distinct source table.
00217 template <typename ENUM_TBL_ENTRY_T, 
00218           const ENUM_TBL_ENTRY_T* table, INT tablesz>
00219 const char*
00220 MapEnumToStr(const char* tablenm, INT val)
00221 {
00222   // Check Table
00223   static bool isTableChecked = false;
00224   if (!isTableChecked) {
00225     CheckEnumTable(tablenm, table, tablesz);
00226     isTableChecked = true;
00227   }
00228   
00229   // Perform mapping
00230   if (0 <= val && val < tablesz) {
00231     return table[val].getStr();
00232   }
00233   else {
00234     Fail_FmtAssertion("ir_a2b::MapEnumToStr: Error accessing table '%s': no entry for '%d'.", tablenm, val);
00235   }
00236 }
00237 
00238 
00239 // MapStrToEnum: Given 1) a enum2str_tbl_entry_t table (sorted by
00240 // enumeration value), its name and the number of entries therein and
00241 // 2) a string, return an enumeration value.
00242 //
00243 // N.B.: 'table' is part of the template-parameter-list to ensure
00244 // there is a separate instantiation for each distinct source table.
00245 template <typename ENUM_TBL_ENTRY_T, 
00246           const ENUM_TBL_ENTRY_T* table, INT tablesz>
00247 INT
00248 MapStrToEnum(const char* tablenm, const char* str)
00249 {
00250   struct key_t : public enum2str_tbl_entry_t {
00251     key_t(const char* s_) : s(s_) { }
00252     virtual ~key_t() { }
00253     
00254     virtual INT getEnumVal() const { return 0; }
00255     virtual const char* getStr() const { return s; }
00256     
00257     const char* s;
00258   };
00259 
00260   // Check table
00261   static bool isTableChecked = false;
00262   if (!isTableChecked) {
00263     CheckEnumTable(tablenm, table, tablesz);
00264     isTableChecked = true;
00265   }
00266 
00267   // Compute translation table on demand (shallow copy of source table
00268   // is fine).  This table is sorted by string (instead of
00269   // enumeration) value.
00270   static ENUM_TBL_ENTRY_T* Str2EnumTbl = NULL; 
00271   if (!Str2EnumTbl) {
00272     Str2EnumTbl = CXX_NEW_ARRAY(ENUM_TBL_ENTRY_T, tablesz, Malloc_Mem_Pool);
00273     memcpy(Str2EnumTbl, table, sizeof(ENUM_TBL_ENTRY_T) * tablesz);
00274     qsort(Str2EnumTbl, tablesz, sizeof(ENUM_TBL_ENTRY_T), 
00275           enum2str_tbl_entry_t::cmp);
00276   }
00277   
00278   // Use binary search to find the enumeration value
00279   key_t key(str);
00280   ENUM_TBL_ENTRY_T* found = 
00281     (ENUM_TBL_ENTRY_T*)bsearch(&key, Str2EnumTbl, tablesz, 
00282                                sizeof(ENUM_TBL_ENTRY_T), 
00283                                enum2str_tbl_entry_t::cmp);
00284   FmtAssert(found, ("ir_a2b::MapStrToEnum: Error accessing table '%s': no entry for '%s'.", tablenm, str));
00285   return found->getEnumVal();
00286 }
00287 
00288 
00289 //----------------------------------------------------------------------
00290 // MapFlagsToStr, MapStrToFlags
00291 //----------------------------------------------------------------------
00292 
00293 struct flag_key_t : public flag2str_tbl_entry_t {
00294   flag_key_t(UINT64 flg_, const char* str_) : flg(flg_), str(str_) { }
00295   virtual ~flag_key_t() { }
00296   
00297   virtual UINT64 getFlagVal() const { return flg; }
00298   virtual const char* getStr() const { return str; }
00299 
00300   UINT64      flg;
00301   const char* str;
00302 };
00303 
00304 
00305 // MapFlagsToStr: Given 1) a flag2str_tbl_entry_t table (sorted by flag
00306 // value), its name and the number of entries therein and 2) a set of
00307 // flags, return a string representation (comma-separated flag list)
00308 //
00309 // N.B.: 'table' is part of the template-parameter-list to ensure
00310 // there is a separate instantiation for each distinct source table.
00311 template <typename FLAG_TBL_ENTRY_T, 
00312           const FLAG_TBL_ENTRY_T* table, INT tablesz>
00313 const char*
00314 MapFlagsToStr(const char* tablenm, UINT64 flags)
00315 {
00316   // Check table
00317   static bool isTableChecked = false;
00318   if (!isTableChecked) {
00319     CheckFlagTable(tablenm, table, tablesz);
00320     isTableChecked = true;
00321   }
00322 
00323   // Maintain this buffer to simplify usage; it should never be very large.
00324   static char* buf = NULL;
00325   static UINT bufSz = 256;
00326   if (!buf) {
00327     buf = TYPE_MEM_POOL_ALLOC_N(char, Malloc_Mem_Pool, bufSz);
00328   }
00329 
00330   // For each flag, find the string representation
00331   buf[0] = '\0';
00332   UINT curBufLen = 0;
00333   bool isBufEmpty = true;
00334   for (UINT64 curflg = 0x1000000000000000LL; curflg != 0; 
00335        curflg = curflg >> 1) {
00336     if ( !(flags & curflg) ) {
00337       continue;
00338     }
00339 
00340     // Use binary search to find the flag value
00341     flag_key_t key(curflg, NULL);
00342     FLAG_TBL_ENTRY_T* found = 
00343       (FLAG_TBL_ENTRY_T*)bsearch(&key, table, tablesz, 
00344                                  sizeof(FLAG_TBL_ENTRY_T), 
00345                                  flag2str_tbl_entry_t::flagcmp);
00346     FmtAssert(found, ("ir_a2b::MapFlagsToStr: Error accessing table '%s': no entry for '%llx'.", tablenm, curflg));
00347 
00348     // Add string to list
00349     const char* flgstr = found->getStr();
00350     curBufLen += strlen(flgstr);
00351     if (curBufLen+2 > bufSz) { // comma + terminator
00352       UINT oldSz = bufSz;
00353       bufSz *= 2;
00354       buf = TYPE_MEM_POOL_REALLOC_N(char, Malloc_Mem_Pool, buf, 
00355                                     oldSz, bufSz);
00356     }
00357     if (!isBufEmpty) {
00358       strcat(buf, ",");
00359     }
00360     strcat(buf, flgstr);
00361     isBufEmpty = false;
00362   }
00363   
00364   return buf;
00365 }
00366 
00367 
00368 // MapStrToFlags: Given 1) a flag2str_tbl_entry_t table (sorted by
00369 // flag value), its name and the number of entries therein and
00370 // 2) a comma-separated flag string, return a set of flags.
00371 //
00372 // N.B.: 'table' is part of the template-parameter-list to ensure
00373 // there is a separate instantiation for each distinct source table.
00374 template <typename FLAG_TBL_ENTRY_T, 
00375           const FLAG_TBL_ENTRY_T* table, INT tablesz>
00376 UINT64
00377 MapStrToFlags(const char* tablenm, const char* str)
00378 {
00379   // Check table
00380   static bool isTableChecked = false;
00381   if (!isTableChecked) {
00382     CheckFlagTable(tablenm, table, tablesz);
00383     isTableChecked = true;
00384   }
00385   
00386   // Compute translation table on demand (shallow copy of source table
00387   // is fine).  This table is sorted by string (instead of
00388   // enumeration) value.
00389   static FLAG_TBL_ENTRY_T* Str2FlagTbl = NULL; 
00390   if (!Str2FlagTbl) {
00391     Str2FlagTbl = CXX_NEW_ARRAY(FLAG_TBL_ENTRY_T, tablesz, Malloc_Mem_Pool);
00392     memcpy(Str2FlagTbl, table, sizeof(FLAG_TBL_ENTRY_T) * tablesz);
00393     qsort(Str2FlagTbl, tablesz, sizeof(FLAG_TBL_ENTRY_T), 
00394           flag2str_tbl_entry_t::strcmp);
00395   }
00396   
00397   UINT64 flags = 0;
00398   
00399   // For each flag-string in the list, find the numerical flag
00400   // note: strtok() will destroy the string so we use strdup
00401   char* flgstr = ux_strdup(str);
00402   for (char* tok = strtok(flgstr, ","); (tok != NULL);
00403        tok = strtok((char*)NULL, ",")) {
00404     // Use binary search to find the flag value
00405     flag_key_t key(0, tok);
00406     FLAG_TBL_ENTRY_T* found = 
00407       (FLAG_TBL_ENTRY_T*)bsearch(&key, Str2FlagTbl, tablesz, 
00408                                  sizeof(FLAG_TBL_ENTRY_T), 
00409                                  flag2str_tbl_entry_t::strcmp);
00410     if (tok[0] != '\0') {
00411       FmtAssert(found, ("ir_a2b::MapStrToFlags: Error accessing table '%s': no entry for '%s'.", tablenm, tok));
00412     }
00413     flags |= found->getFlagVal();
00414   }
00415   free(flgstr);
00416   
00417   return flags;
00418 }
00419 
00420 
00421 }; // namespace ir_a2b
00422 
00423 #endif /* ir_a2b_util_INCLUDED */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines