From a68730c1908d833596a6bc615ff68aaac366ddb9 Mon Sep 17 00:00:00 2001 From: rth Date: Mon, 31 Dec 2001 23:16:08 +0000 Subject: [PATCH] * regrename.c (build_def_use): Don't rename asm operands that were originally hard registers. (copyprop_hardreg_forward_1): Likewise. (find_oldest_value_reg): Copy ORIGINAL_REGNO from source. * varasm.c (make_decl_rtl): Use gen_rtx_raw_REG. Set ORIGINAL_REGNO. * gcc.dg/asm-5.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@48435 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 8 +++++ gcc/regrename.c | 75 ++++++++++++++++++++++++++++++++-------- gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gcc.dg/asm-5.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ gcc/varasm.c | 13 +++---- 5 files changed, 160 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/asm-5.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6f9b2d6cd29..5253f248391 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2001-12-31 Richard Henderson + + * regrename.c (build_def_use): Don't rename asm operands that + were originally hard registers. + (copyprop_hardreg_forward_1): Likewise. + (find_oldest_value_reg): Copy ORIGINAL_REGNO from source. + * varasm.c (make_decl_rtl): Use gen_rtx_raw_REG. Set ORIGINAL_REGNO. + 2001-12-31 Douglas B Rupp * config/alpha/vms.h (HAS_INIT_SECTION, NEED_ATEXIT): Remove. diff --git a/gcc/regrename.c b/gcc/regrename.c index fca249e99e8..720e0cf46c9 100644 --- a/gcc/regrename.c +++ b/gcc/regrename.c @@ -838,6 +838,21 @@ build_def_use (bb) scan_rtx (insn, &CALL_INSN_FUNCTION_USAGE (insn), NO_REGS, terminate_all_read, OP_IN, 0); + /* Step 2C: Can't rename asm operands that were originally + hard registers. */ + if (asm_noperands (PATTERN (insn)) > 0) + for (i = 0; i < n_ops; i++) + { + rtx *loc = recog_data.operand_loc[i]; + rtx op = *loc; + + if (GET_CODE (op) == REG + && REGNO (op) == ORIGINAL_REGNO (op) + && (recog_data.operand_type[i] == OP_IN + || recog_data.operand_type[i] == OP_INOUT)) + scan_rtx (insn, loc, NO_REGS, terminate_all_read, OP_IN, 0); + } + /* Step 3: Append to chains for reads inside operands. */ for (i = 0; i < n_ops + recog_data.n_dups; i++) { @@ -909,8 +924,27 @@ build_def_use (bb) /* Step 6: Begin new chains for writes inside operands. */ /* ??? Many targets have output constraints on the SET_DEST of a call insn, which is stupid, since these are certainly - ABI defined hard registers. Don't change calls at all. */ - if (GET_CODE (insn) != CALL_INSN) + ABI defined hard registers. Don't change calls at all. + Similarly take special care for asm statement that originally + referenced hard registers. */ + if (asm_noperands (PATTERN (insn)) > 0) + { + for (i = 0; i < n_ops; i++) + if (recog_data.operand_type[i] == OP_OUT) + { + rtx *loc = recog_data.operand_loc[i]; + rtx op = *loc; + enum reg_class class = recog_op_alt[i][alt].class; + + if (GET_CODE (op) == REG + && REGNO (op) == ORIGINAL_REGNO (op)) + continue; + + scan_rtx (insn, loc, class, mark_write, OP_OUT, + recog_op_alt[i][alt].earlyclobber); + } + } + else if (GET_CODE (insn) != CALL_INSN) for (i = 0; i < n_ops + recog_data.n_dups; i++) { int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops]; @@ -1000,9 +1034,8 @@ static int kill_autoinc_value PARAMS ((rtx *, void *)); static void copy_value PARAMS ((rtx, rtx, struct value_data *)); static bool mode_change_ok PARAMS ((enum machine_mode, enum machine_mode, unsigned int)); -static rtx find_oldest_value_reg PARAMS ((enum reg_class, unsigned int, - enum machine_mode, - struct value_data *)); +static rtx find_oldest_value_reg PARAMS ((enum reg_class, rtx, + struct value_data *)); static bool replace_oldest_value_reg PARAMS ((rtx *, enum reg_class, rtx, struct value_data *)); static bool replace_oldest_value_addr PARAMS ((rtx *, enum reg_class, @@ -1240,19 +1273,24 @@ mode_change_ok (orig_mode, new_mode, regno) of that oldest register, otherwise return NULL. */ static rtx -find_oldest_value_reg (class, regno, mode, vd) +find_oldest_value_reg (class, reg, vd) enum reg_class class; - unsigned int regno; - enum machine_mode mode; + rtx reg; struct value_data *vd; { + unsigned int regno = REGNO (reg); + enum machine_mode mode = GET_MODE (reg); unsigned int i; for (i = vd->e[regno].oldest_regno; i != regno; i = vd->e[i].next_regno) if (TEST_HARD_REG_BIT (reg_class_contents[class], i) && (vd->e[i].mode == mode || mode_change_ok (vd->e[i].mode, mode, regno))) - return gen_rtx_REG (mode, i); + { + rtx new = gen_rtx_REG (mode, i); + ORIGINAL_REGNO (new) = ORIGINAL_REGNO (reg); + return new; + } return NULL_RTX; } @@ -1267,7 +1305,7 @@ replace_oldest_value_reg (loc, class, insn, vd) rtx insn; struct value_data *vd; { - rtx new = find_oldest_value_reg (class, REGNO (*loc), GET_MODE (*loc), vd); + rtx new = find_oldest_value_reg (class, *loc, vd); if (new) { if (rtl_dump_file) @@ -1443,6 +1481,7 @@ copyprop_hardreg_forward_1 (bb, vd) for (insn = bb->head; ; insn = NEXT_INSN (insn)) { int n_ops, i, alt, predicated; + bool is_asm; rtx set; if (! INSN_P (insn)) @@ -1459,6 +1498,7 @@ copyprop_hardreg_forward_1 (bb, vd) preprocess_constraints (); alt = which_alternative; n_ops = recog_data.n_operands; + is_asm = asm_noperands (PATTERN (insn)) >= 0; /* Simplify the code below by rewriting things to reflect matching constraints. Also promote OP_OUT to OP_INOUT @@ -1498,8 +1538,9 @@ copyprop_hardreg_forward_1 (bb, vd) be able to do the move from a different register class. */ if (set && REG_P (SET_SRC (set))) { - unsigned int regno = REGNO (SET_SRC (set)); - enum machine_mode mode = GET_MODE (SET_SRC (set)); + rtx src = SET_SRC (set); + unsigned int regno = REGNO (src); + enum machine_mode mode = GET_MODE (src); unsigned int i; rtx new; @@ -1507,8 +1548,7 @@ copyprop_hardreg_forward_1 (bb, vd) register in the same class. */ if (REG_P (SET_DEST (set))) { - new = find_oldest_value_reg (REGNO_REG_CLASS (regno), - regno, mode, vd); + new = find_oldest_value_reg (REGNO_REG_CLASS (regno), src, vd); if (new && validate_change (insn, &SET_SRC (set), new, 0)) { if (rtl_dump_file) @@ -1528,6 +1568,7 @@ copyprop_hardreg_forward_1 (bb, vd) new = gen_rtx_REG (mode, i); if (validate_change (insn, &SET_SRC (set), new, 0)) { + ORIGINAL_REGNO (new) = ORIGINAL_REGNO (src); if (rtl_dump_file) fprintf (rtl_dump_file, "insn %u: replaced reg %u with %u\n", @@ -1550,6 +1591,12 @@ copyprop_hardreg_forward_1 (bb, vd) if (recog_data.constraints[i][0] == '\0') continue; + /* Don't replace in asms intentionally referencing hard regs. */ + if (is_asm && GET_CODE (recog_data.operand[i]) == REG + && (REGNO (recog_data.operand[i]) + == ORIGINAL_REGNO (recog_data.operand[i]))) + continue; + if (recog_data.operand_type[i] == OP_IN) { if (recog_op_alt[i][alt].is_address) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 01f659ff540..d97cc967a6f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2001-12-31 Richard Henderson + + * gcc.dg/asm-5.c: New. + 2001-12-31 Paolo Carlini * g++.old-deja/g++.robertl/eb130.C: hash_set is now diff --git a/gcc/testsuite/gcc.dg/asm-5.c b/gcc/testsuite/gcc.dg/asm-5.c new file mode 100644 index 00000000000..7b8d0f2f6c5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asm-5.c @@ -0,0 +1,82 @@ +/* Asm operands that are given as hard registers must keep the same + hard register all the way through compilation. Example derived + from glibc source. */ +/* { dg-do compile { target alpha*-*-* } } */ +/* { dg-options "-O2 -frename-registers -fcprop-registers" } */ +/* { dg-final { scan-assembler "callsys1 .0 .19 .0 .16 .17" } } */ +/* { dg-final { scan-assembler "callsys2 .0 .19 .0 .16 .17" } } */ + +struct stat { + int dummy; +}; + +struct kernel_stat { + int dummy; +}; + +extern int xstat_conv (int vers, struct kernel_stat *kbuf, void *ubuf); +extern int *__errno_location (void) __attribute__ ((__const__)); + +int +__fxstat (int vers, int fd, struct stat *buf) +{ + struct kernel_stat kbuf; + int result; + + if (vers == 0) + return + ({ + long _sc_ret, _sc_err; + { + register long _sc_0 __asm__("$0"); + register long _sc_16 __asm__("$16"); + register long _sc_17 __asm__("$17"); + register long _sc_19 __asm__("$19"); + _sc_0 = 91; + _sc_16 = (long) (fd); + _sc_17 = (long) (((struct kernel_stat *) buf)); + __asm__("callsys1 %0 %1 %2 %3 %4" + : "=r"(_sc_0), "=r"(_sc_19) + : "0"(_sc_0), "r"(_sc_16), "r"(_sc_17) + : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", + "$22", "$23", "$24", "$25", "$27", "$28", "memory"); + _sc_ret = _sc_0, _sc_err = _sc_19; + } + if (_sc_err) + { + (*__errno_location ()) = (_sc_ret); + _sc_ret = -1L; + } + _sc_ret; + }); + + result = + ({ + long _sc_ret, _sc_err; + { + register long _sc_0 __asm__("$0"); + register long _sc_16 __asm__("$16"); + register long _sc_17 __asm__("$17"); + register long _sc_19 __asm__("$19"); + _sc_0 = 91; + _sc_16 = (long) (fd); + _sc_17 = (long) ((&kbuf)); + __asm__("callsys2 %0 %1 %2 %3 %4" + : "=r"(_sc_0), "=r"(_sc_19) + : "0"(_sc_0), "r"(_sc_16), "r"(_sc_17) + : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", + "$22", "$23", "$24", "$25", "$27", "$28", "memory"); + _sc_ret = _sc_0, _sc_err = _sc_19; + } + if (_sc_err) + { + (*__errno_location ()) = (_sc_ret); + _sc_ret = -1L; + } + _sc_ret; + }); + if (result == 0) + result = xstat_conv (vers, &kbuf, buf); + + return result; +} diff --git a/gcc/varasm.c b/gcc/varasm.c index 419791d6363..b88615107e6 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -898,14 +898,11 @@ make_decl_rtl (decl, asmspec) /* If the user specified one of the eliminables registers here, e.g., FRAME_POINTER_REGNUM, we don't want to get this variable - confused with that register and be eliminated. Although this - usage is somewhat suspect, we nevertheless use the following - kludge to avoid setting DECL_RTL to frame_pointer_rtx. */ - - SET_DECL_RTL (decl, - gen_rtx_REG (DECL_MODE (decl), - FIRST_PSEUDO_REGISTER)); - REGNO (DECL_RTL (decl)) = reg_number; + confused with that register and be eliminated. This usage is + somewhat suspect... */ + + SET_DECL_RTL (decl, gen_rtx_raw_REG (DECL_MODE (decl), reg_number)); + ORIGINAL_REGNO (DECL_RTL (decl)) = reg_number; REG_USERVAR_P (DECL_RTL (decl)) = 1; if (TREE_STATIC (decl)) -- 2.11.4.GIT