[PATCH] PR63404, gcc 5 miscompiles linux block layer
Richard Henderson
rth@redhat.com
Fri Oct 10 16:02:00 GMT 2014
On 10/08/2014 08:31 AM, Jiong Wang wrote:
>
> On 30/09/14 19:36, Jiong Wang wrote:
>> 2014-09-30 17:30 GMT+01:00 Jeff Law <law@redhat.com>:
>>> On 09/30/14 08:37, Jiong Wang wrote:
>>>>
>>>> On 30/09/14 05:21, Jeff Law wrote:
>>>>
>>>>> I do agree with Richard that it would be useful to see the insns that
>>>>> are incorrectly sunk and the surrounding context.
>>> So I must be missing something. I thought the shrink-wrapping code wouldn't
>>> sink arithmetic/logical insns like we see with insn 14 and insn 182. I
>>> thought it was limited to reg-reg copies and constant initializations.
>> yes, it was limited to reg-reg copies, and my previous sink improvement aimed to
>> sink any rtx
>>
>> A: be single_set
>> B: the src operand be any combination of no more than one register
>> and no non-constant objects.
>>
>> while some operator like shift may have side effect. IMHO, all side
>> effects are reflected on RTX,
>> together with this fail_on_clobber_use modification, the rtx returned
>> by single_set_no_clobber_use is
>> safe to sink if it meets the above limit B and pass later register
>> use/def check in move_insn_for_shrink_wrap ?
>
> Ping ~
>
> And as there is NONDEBUG_INSN_P check before move_insn_for_shrink_wrap invoked,
> we could avoid creating new wrapper function by invoke single_set_2 directly.
I'm committing the following to fix this.
(1) Don't bother modifying single_set; just look for a bare SET.
(2) Tighten the set of expressions we're willing to move.
(3) Use direct "return false" in the failure case, rather than
counting a non-zero number of non-constants, etc.
Tested on x86_64, and against Andi's test case (unfortunately unreduced).
r~
-------------- next part --------------
2014-10-10 Richard Henderson <rth@redhat.com>
PR target/63404
* shrink-wrap.c (move_insn_for_shrink_wrap): Don't use single_set.
Restrict the set of expressions we're willing to move.
diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
index b1ff8a2..257812c 100644
--- a/gcc/shrink-wrap.c
+++ b/gcc/shrink-wrap.c
@@ -176,17 +176,40 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
basic_block next_block;
edge live_edge;
- /* Look for a simple register copy. */
- set = single_set (insn);
- if (!set)
+ /* Look for a simple register assignment. We don't use single_set here
+ because we can't deal with any CLOBBERs, USEs, or REG_UNUSED secondary
+ destinations. */
+ if (!INSN_P (insn))
+ return false;
+ set = PATTERN (insn);
+ if (GET_CODE (set) != SET)
return false;
src = SET_SRC (set);
dest = SET_DEST (set);
- if (!REG_P (src))
+ /* For the destination, we want only a register. Also disallow STACK
+ or FRAME related adjustments. They are likely part of the prologue,
+ so keep them in the entry block. */
+ if (!REG_P (dest)
+ || dest == stack_pointer_rtx
+ || dest == frame_pointer_rtx
+ || dest == hard_frame_pointer_rtx)
+ return false;
+
+ /* For the source, we want one of:
+ (1) A (non-overlapping) register
+ (2) A constant,
+ (3) An expression involving no more than one register.
+
+ That last point comes from the code following, which was originally
+ written to handle only register move operations, and still only handles
+ a single source register when checking for overlaps. Happily, the
+ same checks can be applied to expressions like (plus reg const). */
+
+ if (CONSTANT_P (src))
+ ;
+ else if (!REG_P (src))
{
- unsigned int reg_num = 0;
- unsigned int nonconstobj_num = 0;
rtx src_inner = NULL_RTX;
if (can_throw_internal (insn))
@@ -196,30 +219,50 @@ move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
FOR_EACH_SUBRTX_VAR (iter, array, src, ALL)
{
rtx x = *iter;
- if (REG_P (x))
+ switch (GET_RTX_CLASS (GET_CODE (x)))
{
- reg_num++;
- src_inner = x;
+ case RTX_CONST_OBJ:
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
+ case RTX_BIN_ARITH:
+ case RTX_COMM_ARITH:
+ case RTX_UNARY:
+ case RTX_TERNARY:
+ /* Constant or expression. Continue. */
+ break;
+
+ case RTX_OBJ:
+ case RTX_EXTRA:
+ switch (GET_CODE (x))
+ {
+ case UNSPEC:
+ case SUBREG:
+ case STRICT_LOW_PART:
+ case PC:
+ /* Ok. Continue. */
+ break;
+
+ case REG:
+ /* Fail if we see a second inner register. */
+ if (src_inner != NULL)
+ return false;
+ src_inner = x;
+ break;
+
+ default:
+ return false;
+ }
+ break;
+
+ default:
+ return false;
}
- else if (!CONSTANT_P (x) && OBJECT_P (x))
- nonconstobj_num++;
}
- if (nonconstobj_num > 0
- || reg_num > 1)
- src = NULL_RTX;
- else if (reg_num == 1)
+ if (src_inner != NULL)
src = src_inner;
}
- if (!REG_P (dest) || src == NULL_RTX
- /* STACK or FRAME related adjustment might be part of prologue.
- So keep them in the entry block. */
- || dest == stack_pointer_rtx
- || dest == frame_pointer_rtx
- || dest == hard_frame_pointer_rtx)
- return false;
-
/* Make sure that the source register isn't defined later in BB. */
if (REG_P (src))
{
More information about the Gcc-patches
mailing list