Open64 (mfef90, whirl2f, and IR tools)
TAG: version-openad; SVN changeset: 916
|
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 /* -*-Mode: c++;-*- (Tell emacs to use c++ mode) */ 00037 00038 #include "anl_common.h" 00039 #include "anl_diagnostics.h" // For warnings and errors 00040 #include "anl_file_mngr.h" // For writing to output file 00041 #include "w2cf_translator.h" // For translating WHIRL into high-level-language 00042 #include "anl_func_entry.h" // For func entry related utilities 00043 #include "anl_varlist.h" 00044 00045 extern ANL_DIAGNOSTICS *Anl_Diag; // Defined in anl_driver.cxx 00046 00047 // ================== Internal utilities ================== 00048 // ======================================================== 00049 00050 // This is necessary until we consistently use SCLASS_FORMAL_REF ro 00051 // represent reference parameters. 00052 // 00053 #define ANL_IS_REF_PARM_ADDR(st) \ 00054 (ST_sclass(st) == SCLASS_FORMAL && \ 00055 TY_IS_POINTER(ST_type(st)) && \ 00056 !ST_is_value_parm(st)) 00057 00058 static BOOL 00059 St_Belongs_In_Varlist(ST *st) 00060 { 00061 return ((ST_sym_class(st) == CLASS_VAR) && 00062 (!ST_is_temp_var(st)) && 00063 (!Has_Base_Block(st) || St_Belongs_In_Varlist(ST_base(st)))); 00064 } // St_Belongs_In_Varlist 00065 00066 00067 static void 00068 Write_Sclass(ANL_CBUF *cbuf, ST *st) 00069 { 00070 00071 if (Has_Base_Block(st)) 00072 st = ST_base(st); 00073 00074 switch (ST_sclass(st)) 00075 { 00076 case SCLASS_AUTO: 00077 cbuf->Write_Char('A'); 00078 break; 00079 00080 case SCLASS_FORMAL: 00081 if (ANL_IS_REF_PARM_ADDR(st)) 00082 cbuf->Write_Char('R'); // Reference parameter 00083 else 00084 cbuf->Write_Char('V'); // Value parameter 00085 break; 00086 00087 case SCLASS_PSTATIC: 00088 case SCLASS_FSTATIC: 00089 cbuf->Write_Char('S'); 00090 break; 00091 00092 case SCLASS_COMMON: 00093 case SCLASS_EXTERN: 00094 case SCLASS_UGLOBAL: 00095 case SCLASS_DGLOBAL: 00096 cbuf->Write_Char('G'); 00097 break; 00098 00099 00100 case SCLASS_FORMAL_REF: 00101 cbuf->Write_Char('R'); // Reference parameter 00102 break; 00103 00104 default: 00105 cbuf->Write_Char('U'); // We do not expect this in a varlist! 00106 break; 00107 } 00108 } // Write_Sclass 00109 00110 00111 // =============== Private Member Functions =============== 00112 // ======================================================== 00113 00114 mUINT32 00115 ANL_VARLIST::_Binary_Search(INT32 id, mUINT32 from, mUINT32 till) 00116 { 00117 // Return the approximate insertion point, if the desired item 00118 // is not found. Note that the actual insertion point will be 00119 // either immediately before or after the returned index. 00120 // 00121 mUINT32 found_idx; 00122 00123 if (from >= till) 00124 found_idx = from; 00125 else 00126 { 00127 const mUINT32 halfway = (till + from) / 2; 00128 const INT32 id2 = _vlist.Indexed_Get(halfway)->Id(); 00129 00130 if (id == id2) 00131 found_idx = halfway; 00132 else if (id < id2) 00133 { 00134 if (halfway == 0) 00135 found_idx = 0; 00136 else 00137 found_idx = _Binary_Search(id, from, halfway-1); 00138 } 00139 else 00140 found_idx = _Binary_Search(id, halfway+1, till); 00141 } 00142 return found_idx; 00143 } // ANL_VARLIST::_Binary_Search 00144 00145 00146 UINT32 00147 ANL_VARLIST::_Get_Io_Item_Lda_Access_Status(WN *io_item) 00148 { 00149 UINT32 status; 00150 00151 // Assume all LDAs under io items that are not in an IO list are 00152 // read but not written. 00153 // 00154 switch (WN_io_item(io_item)) 00155 { 00156 case IOL_ARRAY: 00157 case IOL_CHAR: 00158 case IOL_CHAR_ARRAY: 00159 case IOL_EXPR: 00160 case IOL_IMPLIED_DO: 00161 case IOL_IMPLIED_DO_1TRIP: 00162 case IOL_LOGICAL: 00163 case IOL_RECORD: 00164 case IOL_VAR: 00165 case IOL_DOPE: 00166 status = 0; 00167 break; 00168 default: 00169 status = ANL_VAR_READ; 00170 break; 00171 } 00172 00173 if (status == 0) 00174 { 00175 // First determine whether this is an input or output IO statement 00176 // for the given IO list item. 00177 // 00178 WN *io_stmt = io_item; 00179 while (WN_operator(io_stmt) != OPR_IO) 00180 io_stmt = LWN_Get_Parent(io_stmt); 00181 00182 switch (WN_io_statement(io_stmt)) 00183 { 00184 case IOS_PRINT: 00185 case IOS_TYPE: 00186 case IOS_REWRITE: 00187 case IOS_WRITE: 00188 status = ANL_VAR_READ; 00189 break; 00190 00191 case IOS_READ: 00192 case IOS_ACCEPT: 00193 status = ANL_VAR_WRITTEN; 00194 break; 00195 00196 case IOS_ENCODE: 00197 status = ANL_VAR_READ; // Reads from the IOL item 00198 break; 00199 00200 case IOS_DECODE: 00201 status = ANL_VAR_WRITTEN; // Writes to the IOL item 00202 break; 00203 00204 default: 00205 status = ANL_VAR_READ | ANL_VAR_WRITTEN; 00206 break; 00207 } 00208 } 00209 return status; 00210 } // ANL_VARLIST::_Get_Io_Item_Lda_Access_Status 00211 00212 00213 UINT32 00214 ANL_VARLIST::_Get_Lda_Access_Status(WN *lda) 00215 { 00216 UINT32 status; 00217 WN *parent = LWN_Get_Parent(lda); 00218 00219 switch (WN_operator(parent)) 00220 { 00221 case OPR_ARRAY: 00222 if (lda == WN_kid0(parent)) 00223 status = _Get_Lda_Access_Status(parent); 00224 else 00225 status = ANL_VAR_READ | ANL_VAR_WRITTEN; // Whatever this means! 00226 break; 00227 00228 case OPR_ILOAD: 00229 status = ANL_VAR_READ; 00230 break; 00231 00232 case OPR_MLOAD: 00233 if (lda == WN_kid0(parent)) 00234 status = ANL_VAR_READ; 00235 else 00236 status = ANL_VAR_READ | ANL_VAR_WRITTEN; // Whatever this means! 00237 break; 00238 00239 case OPR_ISTORE: 00240 if (lda == WN_kid1(parent)) 00241 status = ANL_VAR_WRITTEN; 00242 else 00243 status = ANL_VAR_READ | ANL_VAR_WRITTEN; // Whatever this means! 00244 break; 00245 00246 case OPR_MSTORE: 00247 if (lda == WN_kid1(parent)) 00248 status = ANL_VAR_READ; 00249 else 00250 status = ANL_VAR_READ | ANL_VAR_WRITTEN; // Whatever this means! 00251 break; 00252 00253 case OPR_SUB: 00254 case OPR_ADD: 00255 status = _Get_Lda_Access_Status(parent); // Pointer arithmetics?? 00256 break; 00257 00258 case OPR_PARM: 00259 // Base this on flag values associated with the PARM node, instead 00260 // of specially recognizing intrinsics while feeling hopeless about 00261 // non-instrinsic calls. 00262 // 00263 if (WN_Parm_In(parent) || WN_Parm_Out(parent)) 00264 { 00265 if (WN_Parm_In(parent)) 00266 status = ANL_VAR_READ; 00267 if (WN_Parm_Out(parent)) 00268 status = ANL_VAR_WRITTEN; 00269 } 00270 else 00271 { 00272 status = ANL_VAR_READ | ANL_VAR_WRITTEN; // We have no idea 00273 } 00274 break; 00275 00276 case OPR_IO_ITEM: 00277 // Base this on the kind of IO item. 00278 // 00279 status = _Get_Io_Item_Lda_Access_Status(parent); 00280 break; 00281 00282 case OPR_XPRAGMA: 00283 if (WN_pragma(parent) == WN_PRAGMA_CRITICAL_SECTION_BEGIN) 00284 status = ANL_VAR_READ; 00285 else 00286 status = ANL_VAR_READ | ANL_VAR_WRITTEN; 00287 break; 00288 00289 default: 00290 // We have no idea, so just assume it is both read and written. 00291 // 00292 status = ANL_VAR_READ | ANL_VAR_WRITTEN; 00293 break; 00294 } 00295 return status; 00296 } // ANL_VARLIST::_Get_Lda_Access_Status 00297 00298 00299 // =============== Public Member Functions ================ 00300 // ======================================================== 00301 00302 00303 void 00304 ANL_VAR::Set_Name_Alias(ANL_VAR *var) 00305 { 00306 if (this != var) 00307 { 00308 ANL_VAR *alias; 00309 00310 // See if var is already in the alias list for this 00311 // 00312 for (alias = _alias; 00313 alias != var && alias != this; 00314 alias = alias->_alias); 00315 00316 if (alias == this) 00317 { 00318 // Combine the two disjoint alias cycles into one cycle. 00319 // 00320 ANL_VAR *next = _alias; 00321 00322 _alias = var; // Open and connect this cycle to var cycle 00323 for (alias = var->_alias; 00324 alias->_alias != var; 00325 alias = alias->_alias); // Gets to the end of the var cycle 00326 alias->_alias = next; // Connect the var cycle with this cycle. 00327 } 00328 } 00329 } // ANL_VAR::Set_Name_Alias 00330 00331 00332 void 00333 ANL_VAR::Reset_References() 00334 { 00335 _status = 0; 00336 for (ANL_VAR *var = _alias; var != this; var = var->_alias) 00337 var->_status = 0; 00338 } // ANL_VAR::Reset_References 00339 00340 00341 void 00342 ANL_VAR::Write(ANL_CBUF *cbuf, ANL_FUNC_ENTRY *func_entry) 00343 { 00344 BOOL read = Is_Read(); 00345 BOOL written = Is_Written(); 00346 ANL_VAR *var; 00347 00348 for (var = _alias; var != this; var = var->_alias) 00349 { 00350 read = read || var->Is_Read(); 00351 written = written || var->Is_Written(); 00352 } 00353 00354 cbuf->Write_String(" \""); 00355 func_entry->Pu_Translator()->Original_Symname_To_String(cbuf, _st); 00356 cbuf->Write_String("\"("); 00357 Write_Sclass(cbuf, _st); 00358 cbuf->Write_String("):"); 00359 if (read) 00360 cbuf->Write_Char('r'); 00361 if (written) 00362 cbuf->Write_Char('w'); 00363 } // ANL_VAR::Write 00364 00365 00366 ANL_VAR * 00367 ANL_VARLIST::Find(ST *st) 00368 { 00369 // Return NULL if not found. 00370 // 00371 ANL_VAR *found; 00372 const INT32 id = ST_st_idx(st); 00373 mUINT32 idx = _Binary_Search(id, 0, _vlist.Size()); 00374 if (idx < _vlist.Size() && id == _vlist.Indexed_Get(idx)->Id()) 00375 found = _vlist.Indexed_Get(idx); 00376 else 00377 found = NULL; 00378 00379 return found; 00380 } // ANL_VARLIST::Find 00381 00382 00383 ANL_VAR * 00384 ANL_VARLIST::Find_or_Insert(ST *st) 00385 { 00386 // Insert new ANL_VAR if not found. 00387 // 00388 ANL_VAR *found; 00389 const INT32 id = ST_st_idx(st); 00390 00391 mUINT32 idx = _Binary_Search(id, 0, _vlist.Size()); 00392 if (idx < _vlist.Size() && id == _vlist.Indexed_Get(idx)->Id()) 00393 found = _vlist.Indexed_Get(idx); 00394 else 00395 { 00396 ANL_VAR *var = CXX_NEW(ANL_VAR(st), _pool); 00397 BOOL added; 00398 00399 // Insert the new item 00400 // 00401 if (idx >= _vlist.Size()) 00402 { 00403 _vlist.Insert_Last(var, &added); 00404 found = _vlist.Indexed_Get(_vlist.Size()-1); 00405 } 00406 else if (id < _vlist.Indexed_Get(idx)->Id()) 00407 { 00408 _vlist.Insert_Before(var, idx, &added); 00409 found = _vlist.Indexed_Get(idx); 00410 } 00411 else 00412 { 00413 _vlist.Insert_After(var, idx, &added); 00414 found = _vlist.Indexed_Get(idx+1); 00415 } 00416 if (!added) 00417 Anl_Diag->Error("Cannot insert element in variable list!!"); 00418 } 00419 return found; 00420 } // ANL_VARLIST::Find_or_Insert 00421 00422 00423 void 00424 ANL_VARLIST::Insert_Var_Refs(WN *subtree) 00425 { 00426 // Traverse every expression subtree in the PU to determine what 00427 // variables are referenced and how they are referenced. 00428 // 00429 for (WN_ITER *tree_iter = WN_WALK_TreeIter(subtree); 00430 tree_iter != NULL; 00431 tree_iter = WN_WALK_TreeNext(tree_iter)) 00432 { 00433 UINT32 status; 00434 ANL_VAR *var; 00435 WN *wn = WN_ITER_wn(tree_iter); 00436 00437 switch (WN_operator(wn)) 00438 { 00439 case OPR_LDID: 00440 if (St_Belongs_In_Varlist(WN_st(wn))) 00441 { 00442 var = Find_or_Insert(WN_st(wn)); 00443 00444 if (ANL_IS_REF_PARM_ADDR(WN_st(wn)) || 00445 ST_pt_to_unique_mem(WN_st(wn))) 00446 { 00447 // Either a reference parameter or an adjustable array, 00448 // where references are indirect. 00449 // 00450 status = _Get_Lda_Access_Status(wn); 00451 if ((status & ANL_VAR_READ) != 0) 00452 var->Set_Read(); 00453 if ((status & ANL_VAR_WRITTEN) != 0) 00454 var->Set_Written(); 00455 } 00456 else 00457 { 00458 var->Set_Read(); 00459 } 00460 } 00461 break; 00462 00463 case OPR_STID: 00464 if (St_Belongs_In_Varlist(WN_st(wn)) && 00465 !ST_pt_to_unique_mem(WN_st(wn))) 00466 { 00467 // Typically a unique memory pointer is due to an adjustable 00468 // automatic variable. We do not record the initial assignment 00469 // to such a variable. 00470 // 00471 BOOL record_write = TRUE; 00472 00473 var = Find_or_Insert(WN_st(wn)); 00474 00475 if (WN_operator(WN_kid0(wn)) == OPR_LDID) 00476 { 00477 // Detect compiler temporaries used as aliases for user-declared 00478 // scalar variables (e.g. for parameters used in adjustable 00479 // array bounds). 00480 // 00481 ANL_CBUF lhs(_pool); 00482 ANL_CBUF rhs(_pool); 00483 _func_entry->Pu_Translator()-> 00484 Original_Symname_To_String(&lhs, WN_st(wn)); 00485 _func_entry->Pu_Translator()-> 00486 Original_Symname_To_String(&rhs, WN_st(WN_kid0(wn))); 00487 00488 if (strcmp(lhs.Chars(), rhs.Chars()) == 0) 00489 { 00490 record_write = FALSE; // Copy-in of params into temporary 00491 var->Set_Name_Alias(Find_or_Insert(WN_st(WN_kid0(wn)))); 00492 } 00493 } 00494 if (record_write) 00495 var->Set_Written(); 00496 } 00497 break; 00498 00499 case OPR_LDA: 00500 if (St_Belongs_In_Varlist(WN_st(wn))) 00501 { 00502 status = _Get_Lda_Access_Status(wn); 00503 var = Find_or_Insert(WN_st(wn)); 00504 if ((status & ANL_VAR_READ) != 0) 00505 var->Set_Read(); 00506 if ((status & ANL_VAR_WRITTEN) != 0) 00507 var->Set_Written(); 00508 } 00509 break; 00510 00511 case OPR_PRAGMA: 00512 if (WN_operator(wn) == OPR_PRAGMA) 00513 { 00514 switch (WN_pragma(wn)) 00515 { 00516 case WN_PRAGMA_LOCAL: 00517 case WN_PRAGMA_LASTLOCAL: 00518 case WN_PRAGMA_SHARED: 00519 case WN_PRAGMA_FIRSTPRIVATE: 00520 break; // No need to register a reference for these? 00521 00522 case WN_PRAGMA_COPYIN: 00523 if (St_Belongs_In_Varlist(WN_st(wn))) 00524 { 00525 var = Find_or_Insert(WN_st(wn)); 00526 var->Set_Read(); 00527 } 00528 break; 00529 default: 00530 break; 00531 } 00532 } 00533 break; 00534 00535 default: 00536 break; // Nothing to do 00537 } 00538 } 00539 } // ANL_VARLIST::Insert_Var_Refs 00540 00541 00542 void 00543 ANL_VARLIST::Write(ANL_CBUF *cbuf, INT64 construct_id) 00544 { 00545 const INT32 NUM_CHARS_PER_LINE = 72; 00546 BOOL first_var_list_item = TRUE; 00547 INT max_idx; 00548 ANL_CBUF tmpbuf(_pool); 00549 00550 tmpbuf.Write_String("varlist "); 00551 tmpbuf.Write_Int(construct_id); 00552 for (INT var_idx = 0; var_idx < _vlist.Size(); var_idx++) 00553 { 00554 ANL_VAR *var = _vlist.Indexed_Get(var_idx); 00555 00556 if (tmpbuf.Size() >= NUM_CHARS_PER_LINE) 00557 { 00558 // Start a new "varlist" 00559 // 00560 tmpbuf.Write_Char('\n'); 00561 cbuf->Write_String(tmpbuf.Chars()); 00562 tmpbuf.Reset(); 00563 tmpbuf.Write_String("varlist "); 00564 tmpbuf.Write_Int(construct_id); 00565 first_var_list_item = TRUE; 00566 } 00567 00568 // Write the next varlist item 00569 // 00570 if (var->Is_Read() || var->Is_Written()) 00571 { 00572 if (first_var_list_item) 00573 { 00574 first_var_list_item = FALSE; 00575 } 00576 else 00577 { 00578 tmpbuf.Write_String(","); 00579 } 00580 var->Write(&tmpbuf, _func_entry); 00581 var->Reset_References(); 00582 } 00583 } 00584 if (tmpbuf.Size() > 0) 00585 cbuf->Write_String(tmpbuf.Chars()); 00586 } // ANL_VARLIST::Write 00587