This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Fortran] Optimize WHEREs with empty statement lists


This patch optimizes some corner cases in the code generation of
WHERE statements.  Rule R739 of section 7.5.3.1 of the F95 standard
allows all "where-body-constructs" to be empty.  These empty bodies
result in us currently populating/allocating temporary masks when
they're not needed.

The simplest change is in the call to gfc_evaluate_where_mask, where
if the current WHERE/conditional ELSEWHERE clause has any empty body,
there's no need to update "cmask".  Subsequent clauses only require
the pending execution mask.

Then related to this change is that we can now tweak the conditions
under which we allocate the temporary "cmask" and "pmask".  It doesn't
matter how many clauses there are in WHERE construct, if all of the
bodies are empty we won't need either of pmask or cmask.  However,
these corner cases are rare, and there's little benefit of looking at
more than the first two or three clauses.  This is sufficient for us
to completely optimize F90's WHERE construct (which didn't allow
conditional ELSEWHERE clauses).

The logic is that if the construct contains three or more clauses
(i.e. must be an F95 construct), just allocate both temporary masks
as always, (tested via cblock->block && cblock->block->block).
Otherwise if we only need a "cmask", if there are executable statements
in either of the first two clauses, and we only need a "pmask" if
there are executabe statements in the second clause (if one exists).

Finally, there's one further refinement to the above logic that we
can omit the "cmask" in where_15.f90 [which has an empty initial WHERE
followed by a non-empty unconditional ELSEWHERE], where the "unconditional
ELSEWHERE simply uses pmask" optimization obviates the need for cmask.

The testsuite testcases for these exceptional corner cases are the
recently added where_1[2-5].f90.  The following patch has been tested
on x86_64-unknown-linux-gnu with a bootstrap incuding fortran with
no new "make -k check" failures.

Ok for mainline?



2006-02-19  Roger Sayle  <roger@eyesopen.com>

	* trans-stmt.c (gfc_trans_where_2): Avoid updating unused current
	execution mask for empty WHERE/ELSEWHERE clauses.  Don't allocate
	temporary mask arrays if they won't be used.


Index: trans-stmt.c
===================================================================
*** trans-stmt.c	(revision 111245)
--- trans-stmt.c	(working copy)
*************** gfc_trans_where_2 (gfc_code * code, tree
*** 2983,2994 ****
    /* As the mask array can be very big, prefer compact boolean types.  */
    mask_type = gfc_get_logical_type (gfc_logical_kinds[0].kind);

!   /* Allocate temporary for where mask.  */
!   cmask = allocate_temp_for_forall_nest_1 (mask_type, size, block, &pcmask);

!   if (cblock->block)
      {
-       /* Allocate temporary for !mask.  */
        pmask = allocate_temp_for_forall_nest_1 (mask_type, size, block,
  					       &ppmask);
      }
--- 2983,3010 ----
    /* As the mask array can be very big, prefer compact boolean types.  */
    mask_type = gfc_get_logical_type (gfc_logical_kinds[0].kind);

!   /* Allocate temporary for WHERE mask.  We only need a "cmask" if
!      there are statements to be executed.  The following test only
!      checks the first ELSEWHERE to catch the F90 cases.  */
!   if (cblock->next
!       || (cblock->block && cblock->block->next && cblock->block->expr)
!       || (cblock->block && cblock->block->block))
!     {
!       cmask = allocate_temp_for_forall_nest_1 (mask_type, size, block,
! 					       &pcmask);
!     }
!   else
!     {
!       pcmask = NULL_TREE;
!       cmask = NULL_TREE;
!     }

!   /* Allocate temporary for !mask.  We only need a "pmask" if there
!      is an ELSEWHERE clause containing executable statements.  Again
!      we only lookahead a single ELSEWHERE to catch the F90 cases.  */
!   if ((cblock->block && cblock->block->next)
!       || (cblock->block && cblock->block->block))
      {
        pmask = allocate_temp_for_forall_nest_1 (mask_type, size, block,
  					       &ppmask);
      }
*************** gfc_trans_where_2 (gfc_code * code, tree
*** 3003,3019 ****
        /* Has mask-expr.  */
        if (cblock->expr)
          {
! 	  /* If this is the last clause of the WHERE construct, then
  	     we don't need to update the pending control mask (pmask).  */
! 	  if (! cblock->block)
! 	    pmask = NULL_TREE;
!
!           /* Ensure that the WHERE mask be evaluated only once.  */
!           gfc_evaluate_where_mask (cblock->expr, nested_forall_info,
! 				   mask, cmask, pmask, mask_type, block);

          }
!       /* It's a elsewhere-stmt. No mask-expr is present.  */
        else
          cmask = mask;

--- 3019,3036 ----
        /* Has mask-expr.  */
        if (cblock->expr)
          {
!           /* Ensure that the WHERE mask will be evaluated exactly once.
! 	     If there are no statements in this WHERE/ELSEWHERE clause,
! 	     then we don't need to update the control mask (cmask).
! 	     If this is the last clause of the WHERE construct, then
  	     we don't need to update the pending control mask (pmask).  */
!           gfc_evaluate_where_mask (cblock->expr, nested_forall_info, mask,
! 				   cblock->next ? cmask : NULL_TREE,
! 				   cblock->block ? pmask : NULL_TREE,
! 				   mask_type, block);

          }
!       /* It's a final elsewhere-stmt. No mask-expr is present.  */
        else
          cmask = mask;


Roger
--


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]