From e670d9e4cec6b4d18e98bf8e0fddc0373d781c9f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 29 Sep 2004 18:22:07 -0700 Subject: [PATCH] re PR tree-optimization/17739 (tree-optimizers extend the lifetime of a hard register variable) 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. From-SVN: r88321 --- gcc/ChangeLog | 16 ++++++++++ gcc/gimplify.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/asm-3.c | 26 ++++++++++++++++ gcc/tree-gimple.c | 45 +++++++++++++++++++++++---- gcc/tree-gimple.h | 2 ++ gcc/tree-outof-ssa.c | 5 --- gcc/tree-pretty-print.c | 8 +++++ gcc/tree-ssa-copy.c | 8 ++--- gcc/tree-ssa-copyrename.c | 13 -------- gcc/tree-ssa-pre.c | 3 +- gcc/tree-ssa.c | 2 +- gcc/tree.h | 2 +- 12 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/asm-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a99fd42a0030..c58b388c96a2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2004-09-29 Richard Henderson + + 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. + 2004-09-29 Fariborz Jahanian * c-decl.c (merge_decls): Use comptype when comparing diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 27744bcb6893..ca233617b897 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -3215,7 +3215,7 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p) else { tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, - is_gimple_val, fb_rvalue); + is_gimple_asm_val, fb_rvalue); if (tret == GS_ERROR) ret = tret; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/asm-3.c b/gcc/testsuite/gcc.dg/tree-ssa/asm-3.c new file mode 100644 index 000000000000..ddb0ddcbc6a1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/asm-3.c @@ -0,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" } } */ diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c index 82b82a43fed3..b2a2ad9a2bda 100644 --- a/gcc/tree-gimple.c +++ b/gcc/tree-gimple.c @@ -282,12 +282,35 @@ is_gimple_reg (tree t) 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)); + 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. */ @@ -349,6 +372,16 @@ is_gimple_val (tree t) 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. */ diff --git a/gcc/tree-gimple.h b/gcc/tree-gimple.h index d0f8ff5ed909..b3fb9c69c912 100644 --- a/gcc/tree-gimple.h +++ b/gcc/tree-gimple.h @@ -64,6 +64,8 @@ extern bool is_gimple_lvalue (tree); 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. */ diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c index 4d9986d1953c..827f91d15110 100644 --- a/gcc/tree-outof-ssa.c +++ b/gcc/tree-outof-ssa.c @@ -1476,11 +1476,6 @@ check_replaceable (temp_expr_table_p tab, tree stmt) 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; diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index b59e6dd4ed2d..9337c3856fd3 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1566,6 +1566,14 @@ print_declaration (pretty_printer *buffer, tree t, int spc, int flags) 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. */ diff --git a/gcc/tree-ssa-copy.c b/gcc/tree-ssa-copy.c index 63a3c20417d7..dc41e8e058ec 100644 --- a/gcc/tree-ssa-copy.c +++ b/gcc/tree-ssa-copy.c @@ -145,11 +145,10 @@ may_propagate_copy (tree dest, tree orig) && 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 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) - || DECL_HARD_REGISTER (SSA_NAME_VAR (dest)))) + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest)) return false; /* Anything else is OK. */ @@ -163,6 +162,7 @@ may_propagate_copy_into_asm (tree dest) { /* 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))); } diff --git a/gcc/tree-ssa-copyrename.c b/gcc/tree-ssa-copyrename.c index 4ef5b3dbd1c6..7495c6b8753e 100644 --- a/gcc/tree-ssa-copyrename.c +++ b/gcc/tree-ssa-copyrename.c @@ -146,19 +146,6 @@ copy_rename_partition_coalesce (var_map map, tree var1, tree var2, FILE *debug) 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); diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index b0809d14b73a..3d505b5579be 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -1624,8 +1624,7 @@ is_undefined_value (tree expr) 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))); + && TREE_CODE (SSA_NAME_VAR (expr)) != PARM_DECL); } diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 5b9b3ccd1852..1ddaf7d3e660 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -1273,7 +1273,7 @@ warn_uninit (tree t, const char *msgid, location_t *locus) return; /* Hard register variables get their initial value from the ether. */ - if (DECL_HARD_REGISTER (var)) + if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var)) return; /* TREE_NO_WARNING either means we already warned, or the front end diff --git a/gcc/tree.h b/gcc/tree.h index 3814fda2eb18..b40253ccfaf6 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2123,7 +2123,7 @@ struct tree_binfo GTY (()) /* 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) +#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) -- 2.43.5