Open64 (mfef90, whirl2f, and IR tools)
TAG: version-openad; SVN changeset: 916
|
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 */