diff options
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/config/s390/s390.c | 46 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/pr25311.c | 47 |
4 files changed, 93 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 22a9fbc..e189251 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2005-12-09 Ulrich Weigand <uweigand@de.ibm.com> + + PR target/25311 + * config/s390/s390.c (struct s390_address): New field literal_pool. + (s390_decompose_address): Compute literal_pool field. Do not + assume register %r13 is always (and solely) used as pool base. + (s390_extra_constraint_str): Use literal_pool field. + 2005-12-09 Thiemo Seufer <ths@networkno.de> * config/mips/mips.c (override_options): Don't allow too small diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 6766af7..02174ff 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -209,6 +209,7 @@ struct s390_address rtx indx; rtx disp; bool pointer; + bool literal_pool; }; /* Which cpu are we tuning for. */ @@ -1473,6 +1474,14 @@ s390_decompose_address (rtx addr, struct s390_address *out) bool pointer = false; bool base_ptr = false; bool indx_ptr = false; + bool literal_pool = false; + + /* We may need to substitute the literal pool base register into the address + below. However, at this point we do not know which register is going to + be used as base, so we substitute the arg pointer register. This is going + to be treated as holding a pointer below -- it shouldn't be used for any + other purpose. */ + rtx fake_pool_base = gen_rtx_REG (Pmode, ARG_POINTER_REGNUM); /* Decompose address into base + index + displacement. */ @@ -1545,9 +1554,9 @@ s390_decompose_address (rtx addr, struct s390_address *out) { /* Either base or index must be free to hold the base register. */ if (!base) - base = gen_rtx_REG (Pmode, BASE_REGNUM); + base = fake_pool_base, literal_pool = true; else if (!indx) - indx = gen_rtx_REG (Pmode, BASE_REGNUM); + indx = fake_pool_base, literal_pool = true; else return false; @@ -1570,11 +1579,14 @@ s390_decompose_address (rtx addr, struct s390_address *out) else return false; - base = gen_rtx_REG (Pmode, BASE_REGNUM); + base = XVECEXP (base, 0, 1); break; case UNSPEC_LTREL_BASE: - base = gen_rtx_REG (Pmode, BASE_REGNUM); + if (XVECLEN (base, 0) == 1) + base = fake_pool_base, literal_pool = true; + else + base = XVECEXP (base, 0, 1); break; default: @@ -1584,8 +1596,7 @@ s390_decompose_address (rtx addr, struct s390_address *out) if (GET_CODE (base) != REG || GET_MODE (base) != Pmode) return false; - if (REGNO (base) == BASE_REGNUM - || REGNO (base) == STACK_POINTER_REGNUM + if (REGNO (base) == STACK_POINTER_REGNUM || REGNO (base) == FRAME_POINTER_REGNUM || ((reload_completed || reload_in_progress) && frame_pointer_needed @@ -1594,6 +1605,10 @@ s390_decompose_address (rtx addr, struct s390_address *out) || (flag_pic && REGNO (base) == PIC_OFFSET_TABLE_REGNUM)) pointer = base_ptr = true; + + if ((reload_completed || reload_in_progress) + && base == cfun->machine->base_reg) + pointer = base_ptr = literal_pool = true; } /* Validate index register. */ @@ -1610,11 +1625,14 @@ s390_decompose_address (rtx addr, struct s390_address *out) else return false; - indx = gen_rtx_REG (Pmode, BASE_REGNUM); + indx = XVECEXP (indx, 0, 1); break; case UNSPEC_LTREL_BASE: - indx = gen_rtx_REG (Pmode, BASE_REGNUM); + if (XVECLEN (indx, 0) == 1) + indx = fake_pool_base, literal_pool = true; + else + indx = XVECEXP (indx, 0, 1); break; default: @@ -1624,8 +1642,7 @@ s390_decompose_address (rtx addr, struct s390_address *out) if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode) return false; - if (REGNO (indx) == BASE_REGNUM - || REGNO (indx) == STACK_POINTER_REGNUM + if (REGNO (indx) == STACK_POINTER_REGNUM || REGNO (indx) == FRAME_POINTER_REGNUM || ((reload_completed || reload_in_progress) && frame_pointer_needed @@ -1634,6 +1651,10 @@ s390_decompose_address (rtx addr, struct s390_address *out) || (flag_pic && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM)) pointer = indx_ptr = true; + + if ((reload_completed || reload_in_progress) + && indx == cfun->machine->base_reg) + pointer = indx_ptr = literal_pool = true; } /* Prefer to use pointer as base, not index. */ @@ -1721,6 +1742,7 @@ s390_decompose_address (rtx addr, struct s390_address *out) out->indx = indx; out->disp = orig_disp; out->pointer = pointer; + out->literal_pool = literal_pool; } return true; @@ -1809,9 +1831,7 @@ s390_extra_constraint_str (rtx op, int c, const char * str) return 0; if (!s390_decompose_address (XEXP (op, 0), &addr)) return 0; - if (addr.base && REG_P (addr.base) && REGNO (addr.base) == BASE_REGNUM) - return 0; - if (addr.indx && REG_P (addr.indx) && REGNO (addr.indx) == BASE_REGNUM) + if (addr.literal_pool) return 0; c = str[1]; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fdb2cb4..15da2cf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-12-09 Ulrich Weigand <uweigand@de.ibm.com> + + PR target/25311 + * gcc.c-torture/compile/pr25311.c: New test. + 2005-12-08 Jerry DeLisle <jvdelisle@gcc.gnu.org> PR libgfortran/25039 diff --git a/gcc/testsuite/gcc.c-torture/compile/pr25311.c b/gcc/testsuite/gcc.c-torture/compile/pr25311.c new file mode 100644 index 0000000..26c5bc3 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr25311.c @@ -0,0 +1,47 @@ + +struct w +{ + int top; + int left; + int height; + int width; + struct w *next; + struct w *parent; + struct w *child; +}; + +extern struct w *Qnil; + +void +set_size (struct w *w, int new_size, int nodelete, int set_height) +{ + int old_size = set_height? w->height : w->width; + + if (nodelete || w->parent == Qnil) + { + int last_pos, last_old_pos, pos, old_pos, first; + int div_val = old_size << 1; + struct w *c; + + last_pos = first = set_height? w->top : w->left; + last_old_pos = 0; + + for (c = w->child; c != Qnil; c = c->next) + { + if (set_height) + old_pos = last_old_pos + c->height; + else + old_pos = last_old_pos + c->width; + + pos = (((old_pos * new_size) << 1) + old_size) / div_val; + set_size (c, pos + first - last_pos, 1, set_height); + last_pos = pos + first; + last_old_pos = old_pos; + } + + if (!nodelete) + for (c = w->child; c != Qnil; c = c->next) + use (c); + } +} + |