This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

fix 17739


Debugging numerous libjava failures for Alpha showed that we were
extending the lifetime of a call-clobbered hard register variable
across a call.

My solution is to remove hard registers from is_gimple_reg, which
means that we basically won't optimize them at all.

My rationale for this is that, before expanding rtl, we don't know
which arithmetic operations will become libcalls and which won't.
In general, this is a very good thing.  However, it means that at
least hard register variables in call-clobbered regs could be
killed at any time, so we should always copy them out to temps
when we want to manipulate them.

The result should be that, after lowering to rtl, hard registers
get mentioned exactly at the spots that the user wrote, and copied
to and from pseudos immediately.  When we get to register allocation,
we *should* be coalescing (when possible) the pseudo with the hard
register via the copy that's exposed.  At which point everyone 
should be happy.

Bootstrapped and tested on alpha-linux.  Libjava testresults are
still abysmal, but at least this particular bug is gone.


r~


        PR 17739
        * tree-gimple.c (is_gimple_reg): Reject hard registers.
        (is_gimple_asm_val): New.
        * tree-gimple.h (is_gimple_asm_val): Declare.
        * gimplify.c (gimplify_asm_expr): Use it.
        * tree-pretty-print.c (print_declaration): Dump hard regs.
        * tree-outof-ssa.c (check_replaceable): Don't check for hard regs.
        * tree-ssa-copyrename.c (copy_rename_partition_coalesce): Likewise.
        * tree-ssa-pre.c (is_undefined_value): Likewise.
        * tree-ssa-copy.c (may_propagate_copy): Likewise.
        (may_propagate_copy_into_asm): Protect DECL_HARD_REGISTER.
        * tree-ssa.c (warn_uninit): Likewise.
        * tree.h (DECL_HARD_REGISTER): Check for VAR_DECL.

Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.81
diff -c -p -d -r2.81 gimplify.c
*** gimplify.c	23 Sep 2004 14:34:18 -0000	2.81
--- gimplify.c	30 Sep 2004 01:17:13 -0000
*************** gimplify_asm_expr (tree *expr_p, tree *p
*** 3215,3221 ****
        else
  	{
  	  tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
! 				is_gimple_val, fb_rvalue);
  	  if (tret == GS_ERROR)
  	    ret = tret;
  	}
--- 3215,3221 ----
        else
  	{
  	  tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
! 				is_gimple_asm_val, fb_rvalue);
  	  if (tret == GS_ERROR)
  	    ret = tret;
  	}
Index: tree-gimple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.c,v
retrieving revision 2.26
diff -c -p -d -r2.26 tree-gimple.c
*** tree-gimple.c	25 Sep 2004 22:11:00 -0000	2.26
--- tree-gimple.c	30 Sep 2004 01:17:13 -0000
*************** is_gimple_reg (tree t)
*** 283,294 ****
    if (TREE_CODE (t) == SSA_NAME)
      t = SSA_NAME_VAR (t);
  
!   return (is_gimple_variable (t)
! 	  && is_gimple_reg_type (TREE_TYPE (t))
! 	  /* A volatile decl is not acceptable because we can't reuse it as
! 	     needed.  We need to copy it into a temp first.  */
! 	  && ! TREE_THIS_VOLATILE (t)
! 	  && ! needs_to_live_in_memory (t));
  }
  
  /* Returns true if T is a GIMPLE formal temporary variable.  */
--- 283,317 ----
    if (TREE_CODE (t) == SSA_NAME)
      t = SSA_NAME_VAR (t);
  
!   if (!is_gimple_variable (t))
!     return false;
!   if (!is_gimple_reg_type (TREE_TYPE (t)))
!     return false;
! 
!   /* A volatile decl is not acceptable because we can't reuse it as
!      needed.  We need to copy it into a temp first.  */
!   if (TREE_THIS_VOLATILE (t))
!     return false;
! 
!   /* We define "registers" as things that can be renamed as needed,
!      which with our infrastructure does not apply to memory.  */
!   if (needs_to_live_in_memory (t))
!     return false;
! 
!   /* Hard register variables are an interesting case.  For those that
!      are call-clobbered, we don't know where all the calls are, since
!      we don't (want to) take into account which operations will turn
!      into libcalls at the rtl level.  For those that are call-saved,
!      we don't currently model the fact that calls may in fact change
!      global hard registers, nor do we examine ASM_CLOBBERS at the tree
!      level, and so miss variable changes that might imply.  All around,
!      it seems safest to not do too much optimization with these at the
!      tree level at all.  We'll have to rely on the rtl optimizers to
!      clean this up, as there we've got all the appropriate bits exposed.  */
!   if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
!     return false;
! 
!   return true;
  }
  
  /* Returns true if T is a GIMPLE formal temporary variable.  */
*************** is_gimple_val (tree t)
*** 350,355 ****
--- 373,388 ----
    return (is_gimple_variable (t) || is_gimple_min_invariant (t));
  }
  
+ /* Similarly, but accept hard registers as inputs to asm statements.  */
+ 
+ bool
+ is_gimple_asm_val (tree t)
+ {
+   if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+     return true;
+ 
+   return is_gimple_val (t);
+ }
  
  /* Return true if T is a GIMPLE minimal lvalue.  */
  
Index: tree-gimple.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.h,v
retrieving revision 2.17
diff -c -p -d -r2.17 tree-gimple.h
*** tree-gimple.h	18 Aug 2004 08:24:18 -0000	2.17
--- tree-gimple.h	30 Sep 2004 01:17:13 -0000
*************** extern bool is_gimple_lvalue (tree);
*** 64,69 ****
--- 64,71 ----
  extern bool is_gimple_min_invariant (tree);
  /* Returns true iff T is a GIMPLE rvalue.  */
  extern bool is_gimple_val (tree);
+ /* Returns true iff T is a GIMPLE asm statement input.  */
+ extern bool is_gimple_asm_val (tree);
  /* Returns true iff T is a valid rhs for a MODIFY_EXPR where the LHS is a
     GIMPLE temporary, a renamed user variable, or something else,
     respectively.  */
Index: tree-outof-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-outof-ssa.c,v
retrieving revision 2.24
diff -c -p -d -r2.24 tree-outof-ssa.c
*** tree-outof-ssa.c	28 Sep 2004 07:59:52 -0000	2.24
--- tree-outof-ssa.c	30 Sep 2004 01:17:13 -0000
*************** check_replaceable (temp_expr_table_p tab
*** 1476,1486 ****
    if (version_ref_count (map, def) != 1)
      return false;
  
-   /* Assignments to variables assigned to hard registers are not
-      replaceable.  */
-   if (DECL_HARD_REGISTER (SSA_NAME_VAR (def)))
-     return false;
- 
    /* There must be no V_MAY_DEFS.  */
    if (NUM_V_MAY_DEFS (V_MAY_DEF_OPS (ann)) != 0)
      return false;
--- 1476,1481 ----
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.43
diff -c -p -d -r2.43 tree-pretty-print.c
*** tree-pretty-print.c	28 Sep 2004 17:52:57 -0000	2.43
--- tree-pretty-print.c	30 Sep 2004 01:17:13 -0000
*************** print_declaration (pretty_printer *buffe
*** 1566,1571 ****
--- 1566,1579 ----
        dump_generic_node (buffer, t, spc, flags, false);
      }
  
+   if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+     {
+       pp_string (buffer, " __asm__ ");
+       pp_character (buffer, '(');
+       dump_generic_node (buffer, DECL_ASSEMBLER_NAME (t), spc, flags, false);
+       pp_character (buffer, ')');
+     }
+ 
    /* The initial value of a function serves to determine wether the function
       is declared or defined.  So the following does not apply to function
       nodes.  */
Index: tree-ssa-copy.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-copy.c,v
retrieving revision 2.17
diff -c -p -d -r2.17 tree-ssa-copy.c
*** tree-ssa-copy.c	29 Sep 2004 02:50:46 -0000	2.17
--- tree-ssa-copy.c	30 Sep 2004 01:17:13 -0000
*************** may_propagate_copy (tree dest, tree orig
*** 145,155 ****
        && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig))
      return false;
  
!   /* If DEST is an SSA_NAME that flows from an abnormal edge or if it
!      represents a hard register, then it cannot be replaced.  */
    if (TREE_CODE (dest) == SSA_NAME
!       && (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest)
! 	  || DECL_HARD_REGISTER (SSA_NAME_VAR (dest))))
      return false;
  
    /* Anything else is OK.  */
--- 145,154 ----
        && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig))
      return false;
  
!   /* If DEST is an SSA_NAME that flows from an abnormal edge, then it
!      cannot be replaced.  */
    if (TREE_CODE (dest) == SSA_NAME
!       && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest))
      return false;
  
    /* Anything else is OK.  */
*************** may_propagate_copy_into_asm (tree dest)
*** 163,168 ****
--- 162,168 ----
  {
    /* Hard register operands of asms are special.  Do not bypass.  */
    return !(TREE_CODE (dest) == SSA_NAME
+ 	   && TREE_CODE (SSA_NAME_VAR (dest)) == VAR_DECL
  	   && DECL_HARD_REGISTER (SSA_NAME_VAR (dest)));
  }
  
Index: tree-ssa-copyrename.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-copyrename.c,v
retrieving revision 2.17
diff -c -p -d -r2.17 tree-ssa-copyrename.c
*** tree-ssa-copyrename.c	24 Sep 2004 17:38:36 -0000	2.17
--- tree-ssa-copyrename.c	30 Sep 2004 01:17:13 -0000
*************** copy_rename_partition_coalesce (var_map 
*** 146,164 ****
    root1 = SSA_NAME_VAR (rep1);
    root2 = SSA_NAME_VAR (rep2);
  
-   if (DECL_HARD_REGISTER (root1) || DECL_HARD_REGISTER (root2))
-     {
-       if (debug)
-         {
- 	  if (DECL_HARD_REGISTER (root1))
- 	    print_generic_expr (debug, var1, TDF_SLIM);
- 	  else
- 	    print_generic_expr (debug, var2, TDF_SLIM);
- 	  fprintf (debug, " is a hardware register.  No Coalescing.\n");
- 	}
-       return;
-     }
- 
    ann1 = var_ann (root1);
    ann2 = var_ann (root2);
  
--- 146,151 ----
Index: tree-ssa-pre.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-pre.c,v
retrieving revision 2.43
diff -c -p -d -r2.43 tree-ssa-pre.c
*** tree-ssa-pre.c	28 Sep 2004 07:59:52 -0000	2.43
--- tree-ssa-pre.c	30 Sep 2004 01:17:13 -0000
*************** is_undefined_value (tree expr)
*** 1624,1631 ****
    return (TREE_CODE (expr) == SSA_NAME
            && IS_EMPTY_STMT (SSA_NAME_DEF_STMT (expr))
  	  /* PARM_DECLs and hard registers are always defined.  */
! 	  && TREE_CODE (SSA_NAME_VAR (expr)) != PARM_DECL
! 	  && !DECL_HARD_REGISTER (SSA_NAME_VAR (expr)));
  }
  
  
--- 1624,1630 ----
    return (TREE_CODE (expr) == SSA_NAME
            && IS_EMPTY_STMT (SSA_NAME_DEF_STMT (expr))
  	  /* PARM_DECLs and hard registers are always defined.  */
! 	  && TREE_CODE (SSA_NAME_VAR (expr)) != PARM_DECL);
  }
  
  
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa.c,v
retrieving revision 2.43
diff -c -p -d -r2.43 tree-ssa.c
*** tree-ssa.c	28 Sep 2004 07:59:52 -0000	2.43
--- tree-ssa.c	30 Sep 2004 01:17:13 -0000
*************** warn_uninit (tree t, const char *msgid, 
*** 1273,1279 ****
      return;
  
    /* Hard register variables get their initial value from the ether.  */
!   if (DECL_HARD_REGISTER (var))
      return;
  
    /* TREE_NO_WARNING either means we already warned, or the front end
--- 1273,1279 ----
      return;
  
    /* Hard register variables get their initial value from the ether.  */
!   if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
      return;
  
    /* TREE_NO_WARNING either means we already warned, or the front end
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.632
diff -c -p -d -r1.632 tree.h
*** tree.h	29 Sep 2004 09:47:36 -0000	1.632
--- tree.h	30 Sep 2004 01:17:13 -0000
*************** struct tree_binfo GTY (())
*** 2117,2123 ****
  
  /* In a VAR_DECL, nonzero if the decl is a register variable with
     an explicit asm specification.  */
! #define DECL_HARD_REGISTER(NODE)  (DECL_CHECK (NODE)->decl.inline_flag)
  
  /* Value of the decls's visibility attribute */
  #define DECL_VISIBILITY(NODE) (DECL_CHECK (NODE)->decl.visibility)
--- 2117,2123 ----
  
  /* In a VAR_DECL, nonzero if the decl is a register variable with
     an explicit asm specification.  */
! #define DECL_HARD_REGISTER(NODE)  (VAR_DECL_CHECK (NODE)->decl.inline_flag)
  
  /* Value of the decls's visibility attribute */
  #define DECL_VISIBILITY(NODE) (DECL_CHECK (NODE)->decl.visibility)
Index: testsuite/gcc.dg/tree-ssa/asm-3.c
===================================================================
RCS file: testsuite/gcc.dg/tree-ssa/asm-3.c
diff -N testsuite/gcc.dg/tree-ssa/asm-3.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/tree-ssa/asm-3.c	30 Sep 2004 01:17:14 -0000
***************
*** 0 ****
--- 1,26 ----
+ /* PR 17739 */
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-optimized" } */
+ 
+ #define REGISTER "0"
+                                                                                 
+ static inline int source(void)
+ {
+   register int hardreg __asm__(REGISTER);
+   asm("" : "=r"(hardreg));
+   return hardreg;
+ }
+                                                                                 
+ void test(void)
+ {
+   int t = source();
+   foo(t);
+   bar(t);
+ }
+ 
+ /* Hardreg should appear exactly 3 times -- declaration, asm stmt,
+    and copy out.  */
+ /* { dg-final { scan-tree-dump-times "hardreg" 3 "optimized" } } */
+ 
+ /* In particular, hardreg should *not* appear in the call to bar.  */
+ /* { dg-final { scan-tree-dump-times "bar \[(\]t\[)\]" 1 "optimized" } } */


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