summaryrefslogtreecommitdiff
path: root/gcc/cselib.c
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-31 19:14:21 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-31 19:14:21 +0000
commit0ee5bf3c39811c9469b6be259744e38e23e7b31a (patch)
tree2f0b491691c28732618def0868a08c868f96b580 /gcc/cselib.c
parent1bd906a3a94bb5d5420280fe4dd4878e34eac6b8 (diff)
downloadgcc-0ee5bf3c39811c9469b6be259744e38e23e7b31a.tar.gz
* cselib.c (promote_debug_loc): Allow l->next non-NULL for
cselib_preserve_constants. (cselib_lookup_1): If cselib_preserve_constants, a new VALUE is being created for REG and there is a VALUE for the same register in wider mode, add another loc with lowpart SUBREG of the wider VALUE. (cselib_subst_to_values): Handle ENTRY_VALUE. * var-tracking.c (replace_expr_with_values): Return NULL for ENTRY_VALUE too. * dwarf2out.c (convert_descriptor_to_signed): New function. (mem_loc_descriptor) <case ZERO_EXTEND>: Optimize using DW_OP_and instead of two shifts. (mem_loc_descriptor) <do_shift>: ZERO_EXTEND second argument to the right mode if needed. (mem_loc_descriptor) <case MOD>: For typed ops just use DW_OP_mod. (mem_loc_descriptor) <case UNSIGNED_FIX>: Use convert_descriptor_to_signed. (mem_loc_descriptor) <case UDIV, CLZ, CTZ, FFS, POPCOUNT, PARITY, BSWAP, ROTATE, ROTATERT>: Handle these rtls. * gcc.dg/guality/bswaptest.c: New test. * gcc.dg/guality/clztest.c: New test. * gcc.dg/guality/ctztest.c: New test. * gcc.dg/guality/rotatetest.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@174508 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cselib.c')
-rw-r--r--gcc/cselib.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/gcc/cselib.c b/gcc/cselib.c
index 56e6d178576..e0697ecfca8 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -257,7 +257,7 @@ promote_debug_loc (struct elt_loc_list *l)
{
n_debug_values--;
l->setting_insn = cselib_current_insn;
- gcc_assert (!l->next);
+ gcc_assert (!l->next || cselib_preserve_constants);
}
}
@@ -1719,6 +1719,12 @@ cselib_subst_to_values (rtx x, enum machine_mode memmode)
}
return e->val_rtx;
+ case ENTRY_VALUE:
+ e = cselib_lookup (x, GET_MODE (x), 0, memmode);
+ if (! e)
+ break;
+ return e->val_rtx;
+
case CONST_DOUBLE:
case CONST_VECTOR:
case CONST_INT:
@@ -1843,6 +1849,43 @@ cselib_lookup_1 (rtx x, enum machine_mode mode,
used_regs[n_used_regs++] = i;
REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
}
+ else if (cselib_preserve_constants
+ && GET_MODE_CLASS (mode) == MODE_INT)
+ {
+ /* During var-tracking, try harder to find equivalences
+ for SUBREGs. If a setter sets say a DImode register
+ and user uses that register only in SImode, add a lowpart
+ subreg location. */
+ struct elt_list *lwider = NULL;
+ l = REG_VALUES (i);
+ if (l && l->elt == NULL)
+ l = l->next;
+ for (; l; l = l->next)
+ if (GET_MODE_CLASS (GET_MODE (l->elt->val_rtx)) == MODE_INT
+ && GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
+ > GET_MODE_SIZE (mode)
+ && (lwider == NULL
+ || GET_MODE_SIZE (GET_MODE (l->elt->val_rtx))
+ < GET_MODE_SIZE (GET_MODE (lwider->elt->val_rtx))))
+ {
+ struct elt_loc_list *el;
+ if (i < FIRST_PSEUDO_REGISTER
+ && hard_regno_nregs[i][GET_MODE (l->elt->val_rtx)] != 1)
+ continue;
+ for (el = l->elt->locs; el; el = el->next)
+ if (!REG_P (el->loc))
+ break;
+ if (el)
+ lwider = l;
+ }
+ if (lwider)
+ {
+ rtx sub = lowpart_subreg (mode, lwider->elt->val_rtx,
+ GET_MODE (lwider->elt->val_rtx));
+ if (sub)
+ e->locs->next = new_elt_loc_list (e->locs->next, sub);
+ }
+ }
REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e);
slot = cselib_find_slot (x, e->hash, INSERT, memmode);
*slot = e;