[patch,commited] PR 34355

Zdenek Dvorak rakdver@kam.mff.cuni.cz
Wed Dec 19 15:59:00 GMT 2007


Hi,

in order to avoid referencing local variables inside the parallelized
loop, parallelizer rewrites say &a[0] to &(*addr_of_a)[0], where
addr_of_a is set to &a outside of the loop.  There are several problems
with this:

1) &a[0] is invariant, &(*addr_of_a)[0] is not, but the TREE_INVARIANT
   flag is not cleared
2) &a[0] is gimple operand, but &(*addr_of_a)[0] is not, so the created
   code is not a valid gimple
3) the trees in &a[0] may be shared, so we end up rewriting trees
   elsewhere in the program as well

Thus, a bit more care is needed in this case -- we need to move the
expression &a[0] to an ssa name, not just &a, and we need to unshare the
expression when doing this.

Bootstrapped & regtested on amd64-linux, commited,

Zdenek

	PR tree-optimization/34355
	* tree-parloops.c (take_address_of): Handle expresions
	instead of just variables.
	(eliminate_local_variables_1): Force whole invariant
	address to ssa name.

	* g++.dg/tree-ssa/pr34355.C: New test.

Index: testsuite/g++.dg/tree-ssa/pr34355.C
===================================================================
*** testsuite/g++.dg/tree-ssa/pr34355.C	(revision 0)
--- testsuite/g++.dg/tree-ssa/pr34355.C	(revision 0)
***************
*** 0 ****
--- 1,26 ----
+ // { dg-do compile }
+ // { dg-options "-O3 -ftree-parallelize-loops=4" }
+ 
+ typedef double EXPRESS[5];
+ 
+ extern int Terms;
+ 
+ void Parse_Rel_Factor (EXPRESS Express, int *Terms)
+ {
+   EXPRESS Local_Express = {5.0, 4.0, 3.0, 2.0, 1.0};
+   int Local_Terms = 5;
+ 
+   int i;
+ 
+   for (i = (*Terms); i < Local_Terms; i++)
+     Express[i] = 0.0;
+ 
+   Express[i] += Local_Express[i];
+ }
+ 
+ double Parse_Float ()
+ {
+   EXPRESS Express = {1.0, 2.0, 3.0, 4.0, 5.0};
+ 
+   Parse_Rel_Factor (Express, &Terms);
+ }
Index: tree-parloops.c
===================================================================
*** tree-parloops.c	(revision 131038)
--- tree-parloops.c	(working copy)
*************** loop_parallel_p (struct loop *loop, htab
*** 431,459 ****
    return ret;
  }
  
! /* Assigns the address of VAR in TYPE to an ssa name, and returns this name.
     The assignment statement is placed before LOOP.  DECL_ADDRESS maps decls
!    to their addresses that can be reused.  */
  
  static tree
! take_address_of (tree var, tree type, struct loop *loop, htab_t decl_address)
  {
!   int uid = DECL_UID (var);
    void **dslot;
    struct int_tree_map ielt, *nielt;
!   tree name, bvar, stmt;
    edge entry = loop_preheader_edge (loop);
  
    ielt.uid = uid;
    dslot = htab_find_slot_with_hash (decl_address, &ielt, uid, INSERT);
    if (!*dslot)
      {
!       bvar = create_tmp_var (type, get_name (var));
        add_referenced_var (bvar);
!       stmt = build_gimple_modify_stmt (bvar,
! 				       fold_convert (type,
! 						     build_addr (var,
! 								 current_function_decl)));
        name = make_ssa_name (bvar, stmt);
        GIMPLE_STMT_OPERAND (stmt, 0) = name;
        bsi_insert_on_edge_immediate (entry, stmt);
--- 431,467 ----
    return ret;
  }
  
! /* Assigns the address of OBJ in TYPE to an ssa name, and returns this name.
     The assignment statement is placed before LOOP.  DECL_ADDRESS maps decls
!    to their addresses that can be reused.  The address of OBJ is known to
!    be invariant in the whole function.  */
  
  static tree
! take_address_of (tree obj, tree type, struct loop *loop, htab_t decl_address)
  {
!   int uid;
    void **dslot;
    struct int_tree_map ielt, *nielt;
!   tree *var_p, name, bvar, stmt, addr;
    edge entry = loop_preheader_edge (loop);
  
+   /* Since the address of OBJ is invariant, the trees may be shared.
+      Avoid rewriting unrelated parts of the code.  */
+   obj = unshare_expr (obj);
+   for (var_p = &obj;
+        handled_component_p (*var_p);
+        var_p = &TREE_OPERAND (*var_p, 0))
+     continue;
+   uid = DECL_UID (*var_p);
+ 
    ielt.uid = uid;
    dslot = htab_find_slot_with_hash (decl_address, &ielt, uid, INSERT);
    if (!*dslot)
      {
!       addr = build_addr (*var_p, current_function_decl);
!       bvar = create_tmp_var (TREE_TYPE (addr), get_name (*var_p));
        add_referenced_var (bvar);
!       stmt = build_gimple_modify_stmt (bvar, addr);
        name = make_ssa_name (bvar, stmt);
        GIMPLE_STMT_OPERAND (stmt, 0) = name;
        bsi_insert_on_edge_immediate (entry, stmt);
*************** take_address_of (tree var, tree type, st
*** 462,480 ****
        nielt->uid = uid;
        nielt->to = name;
        *dslot = nielt;
- 
-       return name;
      }
  
!   name = ((struct int_tree_map *) *dslot)->to;
!   if (TREE_TYPE (name) == type)
!     return name;
  
!   bvar = SSA_NAME_VAR (name);
!   stmt = build_gimple_modify_stmt (bvar, fold_convert (type, name));
!   name = make_ssa_name (bvar, stmt);
!   GIMPLE_STMT_OPERAND (stmt, 0) = name;
!   bsi_insert_on_edge_immediate (entry, stmt);
  
    return name;
  }
--- 470,495 ----
        nielt->uid = uid;
        nielt->to = name;
        *dslot = nielt;
      }
+   else
+     name = ((struct int_tree_map *) *dslot)->to;
  
!   if (var_p != &obj)
!     {
!       *var_p = build1 (INDIRECT_REF, TREE_TYPE (*var_p), name);
!       name = force_gimple_operand (build_addr (obj, current_function_decl),
! 				   &stmt, true, NULL_TREE);
!       if (stmt)
! 	bsi_insert_on_edge_immediate (entry, stmt);
!     }
  
!   if (TREE_TYPE (name) != type)
!     {
!       name = force_gimple_operand (fold_convert (type, name), &stmt, true,
! 				   NULL_TREE);
!       if (stmt)
! 	bsi_insert_on_edge_immediate (entry, stmt);
!     }
  
    return name;
  }
*************** struct elv_data
*** 543,552 ****
     walk_tree.  */
  
  static tree
! eliminate_local_variables_1 (tree * tp, int *walk_subtrees, void *data)
  {
    struct elv_data *dta = data;
!   tree t = *tp, var, addr, addr_type, type;
  
    if (DECL_P (t))
      {
--- 558,567 ----
     walk_tree.  */
  
  static tree
! eliminate_local_variables_1 (tree *tp, int *walk_subtrees, void *data)
  {
    struct elv_data *dta = data;
!   tree t = *tp, var, addr, addr_type, type, obj;
  
    if (DECL_P (t))
      {
*************** eliminate_local_variables_1 (tree * tp, 
*** 566,581 ****
  
    if (TREE_CODE (t) == ADDR_EXPR)
      {
!       var = TREE_OPERAND (t, 0);
!       if (!DECL_P (var))
  	return NULL_TREE;
  
        *walk_subtrees = 0;
!       if (!SSA_VAR_P (var) || DECL_EXTERNAL (var))
  	return NULL_TREE;
  
        addr_type = TREE_TYPE (t);
!       addr = take_address_of (var, addr_type, dta->loop, dta->decl_address);
        *tp = addr;
  
        dta->changed = true;
--- 581,608 ----
  
    if (TREE_CODE (t) == ADDR_EXPR)
      {
!       /* ADDR_EXPR may appear in two contexts:
! 	 -- as a gimple operand, when the address taken is a function invariant
! 	 -- as gimple rhs, when the resulting address in not a function
! 	    invariant
! 	 We do not need to do anything special in the latter case (the base of
! 	 the memory reference whose address is taken may be replaced in the
! 	 DECL_P case).  The former case is more complicated, as we need to
! 	 ensure that the new address is still a gimple operand.  Thus, it
! 	 is not sufficient to replace just the base of the memory reference --
! 	 we need to move the whole computation of the address out of the
! 	 loop.  */
!       if (!is_gimple_val (t))
  	return NULL_TREE;
  
        *walk_subtrees = 0;
!       obj = TREE_OPERAND (t, 0);
!       var = get_base_address (obj);
!       if (!var || !SSA_VAR_P (var) || DECL_EXTERNAL (var))
  	return NULL_TREE;
  
        addr_type = TREE_TYPE (t);
!       addr = take_address_of (obj, addr_type, dta->loop, dta->decl_address);
        *tp = addr;
  
        dta->changed = true;



More information about the Gcc-patches mailing list