Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
anl_loop_construct.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 /* -*-Mode: c++;-*- (Tell emacs to use c++ mode) */
00037 
00038 #include "wn_tree_util.h"
00039 #include "anl_common.h"
00040 #include "anl_diagnostics.h"  // For warnings and errors
00041 #include "anl_file_mngr.h"    // For managing files
00042 #include "w2cf_translator.h"  // For translating WHIRL into high-level-language
00043 #include "anl_varlist.h"      // For emitting attributes of symbol references
00044 #include "anl_pragma_attribute.h" // For <dir> entries
00045 #include "anl_func_entry.h"
00046 #include "anl_loop_construct.h"
00047 
00048 extern ANL_DIAGNOSTICS *Anl_Diag; // Defined in anl_driver.cxx
00049 
00050 
00051 // =============== Static Helper Functions ===============
00052 // =======================================================
00053 
00054 #define WN_current_loop_nest(wn) WN_pragma_arg1(wn)
00055 #define WN_max_loop_nest(wn) WN_pragma_arg2(wn)
00056 
00057 
00058 // ================ Static Member Functions ===============
00059 // ========================================================
00060 
00061 BOOL 
00062 ANL_LOOP_CONSTRUCT::Is_Valid_Dir(ANL_PRAGMA_ATTRIBUTE *dir,
00063                                  INT32                 construct_level)
00064 {
00065    return dir->Is_Loop_Construct_Attribute(construct_level);
00066 }
00067 
00068 BOOL 
00069 ANL_LOOP_CONSTRUCT::Is_End_Of_Loop_Comment(WN *end_stmt)
00070 {
00071    return (WN_operator(end_stmt) == OPR_COMMENT &&
00072            strcmp(Index_To_Str(WN_GetComment(end_stmt)), "ENDLOOP") == 0);
00073 }
00074 
00075 void
00076 ANL_LOOP_CONSTRUCT::Remove_Stmt_In_Block(WN *stmt)
00077 {
00078    WN *block = LWN_Get_Parent(stmt);
00079 
00080    while (block != NULL && WN_operator(block) != OPR_BLOCK)
00081       block = LWN_Get_Parent(block);
00082    
00083    if (WN_operator(block) == OPR_BLOCK)
00084    {
00085       WN_DELETE_FromBlock(block, stmt);
00086    }
00087 }
00088 
00089 
00090 // =============== Private Member Functions ===============
00091 // ========================================================
00092 
00093 WN *
00094 ANL_LOOP_CONSTRUCT::_First_Loop_Stmt()
00095 {
00096    WN        *base = (_Is_Parallel_Loop()? _loop_region : _loop);
00097    ANL_SRCPOS basepos(base);
00098 
00099    while (WN_prev(base) != NULL && ANL_SRCPOS(WN_prev(base)) >= basepos)
00100       base = WN_prev(base);
00101    return base;
00102 } // ANL_LOOP_CONSTRUCT::_First_Loop_Stmt
00103 
00104 
00105 WN *
00106 ANL_LOOP_CONSTRUCT::_Last_Loop_Stmt()
00107 {
00108    WN        *base = (_Is_Parallel_Loop()? _loop_region : _loop);
00109    ANL_SRCPOS basepos(base);
00110 
00111    while (WN_next(base) != NULL && ANL_SRCPOS(WN_next(base)) <= basepos)
00112       base = WN_next(base);
00113    return base;
00114 } //ANL_LOOP_CONSTRUCT::_Last_Loop_Stmt
00115 
00116 
00117 void 
00118 ANL_LOOP_CONSTRUCT::_Loop_Srcpos_Range(ANL_SRCPOS *min, ANL_SRCPOS *max)
00119 {
00120    // Get the source-position range for the loop, including associated
00121    // pragmas and loop initialization statements (which may have been moved
00122    // in front of the loop by the compiler front-end).
00123    //
00124    WN        *end_stmt = NULL;
00125    WN        *end_comment = NULL;
00126    WN        *base = (_Is_Parallel_Loop()? _loop_region : _loop);
00127    WN        *first_stmt = _First_Loop_Stmt();
00128    WN        *last_stmt = _Last_Loop_Stmt();
00129    ANL_SRCPOS minpos(first_stmt);
00130    ANL_SRCPOS maxpos(last_stmt);
00131 
00132    // Start out with the top-level stmts (at same nesting level as the
00133    // region or loop) as a first approximation, looking only at the stmts
00134    // within the loopor region.
00135    //
00136    for (WN *stmt = first_stmt; 
00137         stmt != NULL && WN_prev(stmt) != last_stmt;
00138         stmt = WN_next(stmt))
00139    {
00140       Adjust_Srcpos_Range(stmt, &minpos, &maxpos);
00141    }
00142 
00143    // See if the maxpos we got from the above analysis is accurate,
00144    // or whether we should adjust it to extend up to the statement 
00145    // following this construct.
00146    //
00147    if (_Is_Parallel_Loop())
00148    {
00149       // Look for special pragma to end the loop.
00150       //
00151       for (end_stmt = WN_first(WN_region_pragmas(_loop_region));
00152            (end_stmt != NULL && 
00153             WN_pragma(end_stmt) != WN_PRAGMA_PDO_END    &&
00154             WN_pragma(end_stmt) != WN_PRAGMA_END_MARKER &&
00155             (WN_pragma(end_stmt) != WN_PRAGMA_NOWAIT ||
00156              _func_entry->Pu_Translator()->Language_is_C()));
00157            end_stmt = WN_next(end_stmt));
00158    }
00159 
00160    // Look for special comment to end the loop.  We always need to do this
00161    // such that we can remove it from WHIRL.
00162    //
00163    if (_Is_Parallel_Loop())
00164    {
00165       // Get to the do-loop
00166       //
00167       for (end_comment = WN_first(WN_region_body(_loop_region));
00168            (end_comment != NULL && WN_operator(end_comment) != OPR_DO_LOOP);
00169            end_comment = WN_next(end_comment));
00170 
00171       // Look for the special loop terminating comment within the body of
00172       // the loop.
00173       //
00174       if (end_comment != NULL)
00175          for (end_comment = WN_first(WN_do_body(end_comment));
00176               (end_comment != NULL && !Is_End_Of_Loop_Comment(end_comment));
00177               end_comment = WN_next(end_comment));
00178    }
00179    else
00180    {
00181       WN *const body = (_loop_kind == ANL_DO_LOOP? 
00182                         WN_do_body(_loop) : WN_while_body(_loop));
00183          
00184       // Look for a special loop terminating comment in the body of
00185       // the loop.
00186       //
00187       for (end_comment = WN_first(body);
00188            (end_comment != NULL && !Is_End_Of_Loop_Comment(end_comment));
00189            end_comment = WN_next(end_comment));
00190    }
00191    if (end_comment != NULL)
00192    {
00193       if (end_stmt == NULL)
00194          end_stmt = end_comment;
00195       Remove_Stmt_In_Block(end_comment);
00196    }
00197 
00198    // Adjust the max position, when there is no true indication of
00199    // the end of the construct.
00200    //
00201    if (end_stmt == NULL && WN_next(last_stmt) != NULL)
00202    {
00203       // Assume the end is just before the next statement.
00204       //
00205       ANL_SRCPOS next_min(WN_next(last_stmt));
00206       ANL_SRCPOS next_max(WN_next(last_stmt));
00207 
00208       Adjust_Srcpos_Range(WN_next(last_stmt), &next_min, &next_max);
00209       if (next_min > maxpos) // FALSE when the file-numbers are different!
00210       {
00211          next_min -= 1;
00212          maxpos = next_min;
00213       }
00214    }
00215 
00216    Is_True(end_stmt == NULL || maxpos == ANL_SRCPOS(end_stmt), 
00217            ("Unexpected maxpos (maxpos=[%d,%d,%d],end_stmt_pos=[%d,%d,%d]) in "
00218             "ANL_LOOP_CONSTRUCT::_Loop_Srcpos_Range",
00219             maxpos.Filenum(), maxpos.Linenum(), maxpos.Column(),
00220             ANL_SRCPOS(end_stmt).Filenum(),
00221             ANL_SRCPOS(end_stmt).Linenum(),
00222             ANL_SRCPOS(end_stmt).Column()));
00223 
00224    *min = minpos;
00225    *max = maxpos;
00226 } // ANL_LOOP_CONSTRUCT::_Loop_Srcpos_Range
00227 
00228 
00229 void
00230 ANL_LOOP_CONSTRUCT::_Write_Loop_Header(ANL_CBUF *cbuf)
00231 {
00232    ANL_SRCPOS min_srcpos;
00233    ANL_SRCPOS max_srcpos;
00234 
00235    _Loop_Srcpos_Range(&min_srcpos, &max_srcpos);
00236    switch (_loop_kind)
00237    {
00238    case ANL_WHILE_LOOP:
00239       cbuf->Write_String("owhile ");
00240       cbuf->Write_Int(_id);
00241       if (_func_entry->Pu_Translator()->Language_is_C())
00242          cbuf->Write_String(" \"while ");
00243       else
00244          cbuf->Write_String(" \"do while ");
00245       _func_entry->Pu_Translator()->Expr_To_String(cbuf, WN_while_test(_loop));
00246       break;
00247 
00248    case ANL_WHILE_AS_DO_LOOP:
00249       cbuf->Write_String("oloop ");
00250       cbuf->Write_Int(_id);
00251       if (_func_entry->Pu_Translator()->Language_is_C())
00252          cbuf->Write_String(" \"for ");
00253       else
00254          cbuf->Write_String(" \"do ");
00255       _func_entry->Pu_Translator()->
00256          Original_Symname_To_String(cbuf, WN_st(WN_prev(_loop)));
00257       break;
00258 
00259    case ANL_DO_LOOP:
00260    case ANL_DOACROSS_LOOP:
00261    case ANL_PARALLELDO_LOOP:
00262    case ANL_PDO_LOOP:
00263       cbuf->Write_String("oloop ");
00264       cbuf->Write_Int(_id);
00265       if (_func_entry->Pu_Translator()->Language_is_C())
00266          cbuf->Write_String(" \"for ");
00267       else
00268          cbuf->Write_String(" \"do ");
00269       _func_entry->Pu_Translator()->
00270          Original_Symname_To_String(cbuf, WN_st(WN_index(_loop)));
00271       break;
00272       
00273    default:
00274       break;
00275    }
00276    cbuf->Write_String("\" range ");
00277    min_srcpos.Write(cbuf);
00278    cbuf->Write_Char('-');
00279    max_srcpos.Write(cbuf);
00280    cbuf->Write_Char('\n');
00281 } // ANL_LOOP_CONSTRUCT::_Write_Loop_Header
00282 
00283 
00284 void
00285 ANL_LOOP_CONSTRUCT::_Write_Loop_Directive(ANL_CBUF *cbuf)
00286 {
00287    BOOL       omp_pragma;
00288    WN        *nowait = NULL;
00289    WN        *end_pdo = NULL;
00290    WN        *region_pragma = WN_first(WN_region_pragmas(_loop_region));
00291    WN        *next_clause = WN_next(region_pragma);
00292    ANL_SRCPOS startpos;
00293    ANL_SRCPOS endpos;
00294    
00295    // Some preliminiaries.
00296    //
00297    _func_entry->Get_Pragma_Srcpos_Range(region_pragma, &startpos, &endpos);
00298 
00299    // The idir clause.
00300    //
00301    cbuf->Write_String("idir ");
00302    cbuf->Write_Int(_id);
00303    cbuf->Write_Char(' ');
00304    startpos.Write(cbuf);
00305    cbuf->Write_Char('-');
00306    endpos.Write(cbuf);
00307 
00308    omp_pragma = WN_pragma_omp(region_pragma);
00309    cbuf->Append_Pragma_Preamble(omp_pragma,FALSE);
00310 
00311    switch (_loop_kind)
00312    {
00313    case ANL_DOACROSS_LOOP:   
00314       cbuf->Write_String("DOACROSS ");
00315       break;
00316    case ANL_PARALLELDO_LOOP:   
00317       cbuf->Write_String("PARALLEL DO ");
00318       break;
00319    case ANL_PDO_LOOP:
00320       if (omp_pragma)
00321          cbuf->Write_String("DO ");
00322       else if (_func_entry->Pu_Translator()->Language_is_C())
00323          cbuf->Write_String("PFOR ");
00324       else
00325          cbuf->Write_String("PDO ");
00326       break;
00327    default:
00328       cbuf->Write_String("<WHATLOOP??> ");
00329       break;
00330    }
00331 
00332    // Emit the "nest" clause if relevant
00333    //
00334    if (WN_max_loop_nest(region_pragma) > 1)
00335    {
00336       _func_entry->Pu_Translator()->
00337          Nest_Clauses_To_String(cbuf, 
00338                                 _loop_region, 
00339                                 WN_max_loop_nest(region_pragma));
00340       if ( _func_entry->Pu_Translator()->Is_A_Pragma_Clause(next_clause))
00341         cbuf->Write_String(", ");
00342    }
00343 
00344    // The list of clauses on an idir.
00345    //
00346    _func_entry->Pu_Translator()->ClauseList_To_String(cbuf, &next_clause);
00347    cbuf->Write_String("\n");
00348 
00349    // The edir clause.
00350    //
00351    if (next_clause != NULL &&
00352        !_func_entry->Pu_Translator()->Language_is_C())
00353    {
00354       // We never emit an edir for language C (sections of code are delimited
00355       // by a nested scope, not by BEGIN/END pragmas).
00356       //
00357       if (WN_pragma(next_clause) == WN_PRAGMA_PDO_END &&
00358           !WN_pragma_compiler_generated(next_clause))
00359          end_pdo = next_clause;
00360       else if (WN_pragma(next_clause) == WN_PRAGMA_NOWAIT &&
00361                !WN_pragma_compiler_generated(next_clause))
00362          nowait = next_clause;
00363    }
00364    if (nowait != NULL || end_pdo != NULL)
00365    {
00366       if (end_pdo != NULL)
00367          startpos = ANL_SRCPOS(end_pdo);
00368       else
00369          startpos = ANL_SRCPOS(nowait);
00370       cbuf->Write_String("edir ");
00371       cbuf->Write_Int(_id);
00372       cbuf->Write_String(" ");
00373       startpos.Write(cbuf);
00374 
00375       cbuf->Append_Pragma_Preamble(omp_pragma,FALSE);
00376       if (WN_pragma_omp(next_clause))
00377         cbuf->Write_String("END DO");
00378       else
00379         cbuf->Write_String("END PDO");
00380       if (nowait)
00381          cbuf->Write_String(" nowait\n");
00382       else
00383          cbuf->Write_Char('\n');
00384    }
00385 } // ANL_LOOP_CONSTRUCT::_Write_Loop_Directive
00386 
00387 
00388 // =============== Public Member Functions ================
00389 // ========================================================
00390 
00391 
00392 ANL_LOOP_CONSTRUCT::ANL_LOOP_CONSTRUCT(WN             *loop,
00393                                        INT32           construct_level,
00394                                        ANL_FUNC_ENTRY *func_entry,
00395                                        MEM_POOL       *pool):
00396    _loop_region(NULL),
00397    _loop(loop),
00398    _construct_level(construct_level),
00399    _func_entry(func_entry),
00400    _pool(pool)
00401 {
00402    WN  *parent_region = NULL;
00403    BOOL in_region = FALSE;
00404    
00405    // Set tentative loop kind (we may later change an ANL_DO_LOOP if its
00406    // context shows it to be a parallel loop).
00407    //
00408    if (WN_operator(loop) == OPR_WHILE_DO ||
00409        WN_operator(loop) == OPR_DO_WHILE)
00410    {
00411       if (_func_entry->Pu_Translator()->Whileloop_Looks_Like_Forloop(loop))
00412          _loop_kind = ANL_WHILE_AS_DO_LOOP;
00413       else
00414          _loop_kind = ANL_WHILE_LOOP;
00415    }
00416    else // An OPR_DO_LOOP
00417    {
00418       _loop_kind = ANL_DO_LOOP;
00419       parent_region = LWN_Get_Parent(LWN_Get_Parent(loop));
00420       in_region = (WN_operator(parent_region) == OPR_REGION);
00421    }
00422 
00423    // Set the ID for this loop.
00424    //
00425    _id = _func_entry->Next_Construct_Id()->Post_Incr();
00426    func_entry->Set_Construct_Id(loop, _id);
00427 
00428    // See if it is a special parallel loop
00429    //
00430    if (in_region)
00431    {
00432       WN *pragma = WN_first(WN_region_pragmas(parent_region));
00433 
00434       if (pragma != NULL)
00435       {
00436          if (WN_pragma(pragma) == WN_PRAGMA_DOACROSS &&
00437              WN_current_loop_nest(pragma) == 0)
00438          {
00439             _loop_kind = ANL_DOACROSS_LOOP;
00440             _loop_region = parent_region;
00441             func_entry->Set_Construct_Id(parent_region, _id);
00442          }
00443          else if (WN_pragma(pragma) == WN_PRAGMA_PARALLEL_DO &&
00444                   WN_current_loop_nest(pragma) == 0)
00445          {
00446             _loop_kind = ANL_PARALLELDO_LOOP;
00447             _loop_region = parent_region;
00448             func_entry->Set_Construct_Id(parent_region, _id);
00449          }
00450          else if (WN_pragma(pragma) == WN_PRAGMA_PDO_BEGIN &&
00451                   WN_current_loop_nest(pragma) == 0)
00452          {
00453             _loop_kind = ANL_PDO_LOOP;
00454             _loop_region = parent_region;
00455             func_entry->Set_Construct_Id(parent_region, _id);
00456          }
00457       } // if region pragma
00458    } // if in region
00459 } // ANL_LOOP_CONSTRUCT::ANL_LOOP_CONSTRUCT
00460 
00461    
00462 WN *
00463 ANL_LOOP_CONSTRUCT::Next_Stmt()
00464 {
00465    // The next statement must be in the same scope as the _loop, since
00466    // that is expected from ANL_FUNC_ENTRY::Emit_Nested_Original_Constructs().
00467    //
00468    return WN_next(_loop);
00469 } // ANL_LOOP_CONSTRUCT::Next_Stmt
00470 
00471 
00472 void
00473 ANL_LOOP_CONSTRUCT::Write(ANL_CBUF *cbuf)
00474 {
00475    ANL_CBUF    varlist_cbuf(_pool);
00476    ANL_CBUF    nested_cbuf(_pool);
00477    ANL_SRCPOS  min_srcpos;
00478    ANL_SRCPOS  max_srcpos;
00479    ANL_VARLIST varlist(_pool, _func_entry);
00480    WN         *first_stmt = _First_Loop_Stmt();
00481    WN         *last_stmt = _Last_Loop_Stmt();
00482    WN         *body = ((_loop_kind == ANL_WHILE_AS_DO_LOOP ||
00483                         _loop_kind == ANL_WHILE_LOOP)?  
00484                        WN_while_body(_loop) :
00485                        WN_do_body(_loop));
00486 
00487    // Write out the loop header
00488    //
00489    _Write_Loop_Header(cbuf);
00490 
00491    // Write out the index variable.
00492    //
00493    if (_loop_kind != ANL_WHILE_LOOP)
00494    {
00495       ST *const st = (_loop_kind == ANL_WHILE_AS_DO_LOOP?
00496                       WN_st(WN_prev(_loop)) : WN_st(WN_index(_loop)));
00497       
00498       cbuf->Write_String("index \"");
00499       _func_entry->Pu_Translator()-> Original_Symname_To_String(cbuf, st);
00500       cbuf->Write_String("\"\n");
00501    }
00502 
00503    // Write out the loop related directives
00504    //
00505    if (_loop_kind == ANL_DOACROSS_LOOP   ||
00506        _loop_kind == ANL_PARALLELDO_LOOP ||
00507        _loop_kind == ANL_PDO_LOOP)
00508    {
00509       _Write_Loop_Directive(cbuf);
00510    }
00511 
00512    // Determine variable references within the statements belonging to the
00513    // loop, and write them to a temporary buffer.
00514    //
00515    for (WN *stmt = first_stmt;
00516         stmt != NULL && WN_prev(stmt) != last_stmt;
00517         stmt = WN_next(stmt))
00518    {
00519       varlist.Insert_Var_Refs(stmt);
00520    }
00521    varlist.Write(&varlist_cbuf, _id);
00522    varlist_cbuf.Write_Char('\n');
00523 
00524    // Write nested constructs to a temporary buffer
00525    //
00526    _func_entry->Emit_Nested_Original_Constructs(&nested_cbuf, 
00527                                                 WN_first(body), WN_last(body));
00528 
00529    // Write out any applicable <dir> entries (i.e. those that were
00530    // not attributed to nested constructs).
00531    //
00532    _func_entry->
00533       Emit_Dir_Entries(cbuf, _id, _construct_level,
00534                        &ANL_LOOP_CONSTRUCT::Is_Valid_Dir);
00535 
00536    // Write the varlist and nested constructs.
00537    //
00538    if (varlist_cbuf.Size() > 0)
00539       cbuf->Write_String(varlist_cbuf.Chars());
00540    if (nested_cbuf.Size() > 0)
00541       cbuf->Write_String(nested_cbuf.Chars());
00542 
00543    // Finish writing the function descriptor.
00544    //
00545    if (_loop_kind == ANL_WHILE_LOOP)
00546       cbuf->Write_String("end_owhile ");
00547    else
00548       cbuf->Write_String("end_oloop ");
00549    cbuf->Write_Int(_id);
00550    cbuf->Write_String("\n"); // Start next construct on a new line
00551 } // ANL_LOOP_CONSTRUCT::Write
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines