diff mbox

[ree] PR rtl-optimization/78038: Handle global register dataflow definitions in ree

Message ID 5808DB6A.6070105@foss.arm.com
State New
Headers show

Commit Message

Kyrill Tkachov Oct. 20, 2016, 2:57 p.m. UTC
Hi all,

In this PR we've got code like this:
register struct test2_s *g __asm__("x28");

void
do_something ()
{
   test_fptr ();
   struct test2_s *p1 = 0;
   *p1 = *g;
}

And we get an ICE in gcc/ree.c:655 in get_sub_rtx.
The problem is when we try to process the defining insn of register x28 from the insn:
(set (reg/f:DI 1 x1 [orig:74 g.1_2 ] [74])
     (zero_extend:DI (reg/v:SI 28 x28 [ g ])))

The dataflow reports the insn setting x28 to be:
(call_insn 8 7 10 2 (parallel [
             (call (mem:DI (reg/f:DI 0 x0 [orig:77 test_fptr ] [77]) [0 *test_fptr.0_1 S8 A8])
                 (const_int 0 [0]))
             (use (const_int 0 [0]))
             (clobber (reg:DI 30 x30))
         ]) "ree.c":14 41 {*call_reg}
      (expr_list:REG_CALL_DECL (nil)
         (nil))
     (expr_list (clobber (reg:DI 17 x17))
         (expr_list (clobber (reg:DI 16 x16))
             (nil))))

which, as you can see, doesn't actually set x28.
AFAICS the reason dataflow reports call_insn 8 as defining x28 is because x28 is a global register variable
and that means that every function call is considered to define it.
But the ree pass can't really use any of that. It only wants some SET RTL patterns to play with.
One solution is to bail out at the ICE location, in get_sub_rtx, when no SETs are found inside the parallel.
But I think we shouldn't be getting this far along anyway.
So this patch prevents the call_insn from being recognised as a defining insn for x28 for the purposes of ree.
It makes sure that if the register we're extending is a global register that all the insns in the def chain
actually set it directly as determined by set_of from rtlanal.c.
This should hopefully still allow ree to optimise extensions of global registers as long as they are combined
with legitimate defining insns.

Bootstrapped and tested on aarch64, arm, x86_64.

Ok for trunk?

Thanks,
Kyrill

2016-10-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

     PR rtl-optimization/78038
     * ree.c (get_defs): Return NULL if a defining insn for REG cannot
     be deduced to set REG through the RTL structure.
     (make_defs_and_copies_lists): Return false on a failing get_defs call.

2016-10-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

     PR rtl-optimization/78038
     * gcc.target/aarch64/pr78038.c: New test.

Comments

Jeff Law Oct. 20, 2016, 6:52 p.m. UTC | #1
On 10/20/2016 08:57 AM, Kyrill Tkachov wrote:
> Hi all,
>
> In this PR we've got code like this:
> register struct test2_s *g __asm__("x28");
>
> void
> do_something ()
> {
>   test_fptr ();
>   struct test2_s *p1 = 0;
>   *p1 = *g;
> }
>
> And we get an ICE in gcc/ree.c:655 in get_sub_rtx.
> The problem is when we try to process the defining insn of register x28
> from the insn:
> (set (reg/f:DI 1 x1 [orig:74 g.1_2 ] [74])
>     (zero_extend:DI (reg/v:SI 28 x28 [ g ])))
>
> The dataflow reports the insn setting x28 to be:
> (call_insn 8 7 10 2 (parallel [
>             (call (mem:DI (reg/f:DI 0 x0 [orig:77 test_fptr ] [77]) [0
> *test_fptr.0_1 S8 A8])
>                 (const_int 0 [0]))
>             (use (const_int 0 [0]))
>             (clobber (reg:DI 30 x30))
>         ]) "ree.c":14 41 {*call_reg}
>      (expr_list:REG_CALL_DECL (nil)
>         (nil))
>     (expr_list (clobber (reg:DI 17 x17))
>         (expr_list (clobber (reg:DI 16 x16))
>             (nil))))
>
> which, as you can see, doesn't actually set x28.
> AFAICS the reason dataflow reports call_insn 8 as defining x28 is
> because x28 is a global register variable
> and that means that every function call is considered to define it.
> But the ree pass can't really use any of that. It only wants some SET
> RTL patterns to play with.
> One solution is to bail out at the ICE location, in get_sub_rtx, when no
> SETs are found inside the parallel.
> But I think we shouldn't be getting this far along anyway.
> So this patch prevents the call_insn from being recognised as a defining
> insn for x28 for the purposes of ree.
> It makes sure that if the register we're extending is a global register
> that all the insns in the def chain
> actually set it directly as determined by set_of from rtlanal.c.
> This should hopefully still allow ree to optimise extensions of global
> registers as long as they are combined
> with legitimate defining insns.
>
> Bootstrapped and tested on aarch64, arm, x86_64.
>
> Ok for trunk?
>
> Thanks,
> Kyrill
>
> 2016-10-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
>
>     PR rtl-optimization/78038
>     * ree.c (get_defs): Return NULL if a defining insn for REG cannot
>     be deduced to set REG through the RTL structure.
>     (make_defs_and_copies_lists): Return false on a failing get_defs call.
>
> 2016-10-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
>
>     PR rtl-optimization/78038
>     * gcc.target/aarch64/pr78038.c: New test.
OK.

Jeff
Kyrill Tkachov Nov. 1, 2016, 10:16 a.m. UTC | #2
On 20/10/16 19:52, Jeff Law wrote:
> On 10/20/2016 08:57 AM, Kyrill Tkachov wrote:
>> Hi all,
>>
>> In this PR we've got code like this:
>> register struct test2_s *g __asm__("x28");
>>
>> void
>> do_something ()
>> {
>>   test_fptr ();
>>   struct test2_s *p1 = 0;
>>   *p1 = *g;
>> }
>>
>> And we get an ICE in gcc/ree.c:655 in get_sub_rtx.
>> The problem is when we try to process the defining insn of register x28
>> from the insn:
>> (set (reg/f:DI 1 x1 [orig:74 g.1_2 ] [74])
>>     (zero_extend:DI (reg/v:SI 28 x28 [ g ])))
>>
>> The dataflow reports the insn setting x28 to be:
>> (call_insn 8 7 10 2 (parallel [
>>             (call (mem:DI (reg/f:DI 0 x0 [orig:77 test_fptr ] [77]) [0
>> *test_fptr.0_1 S8 A8])
>>                 (const_int 0 [0]))
>>             (use (const_int 0 [0]))
>>             (clobber (reg:DI 30 x30))
>>         ]) "ree.c":14 41 {*call_reg}
>>      (expr_list:REG_CALL_DECL (nil)
>>         (nil))
>>     (expr_list (clobber (reg:DI 17 x17))
>>         (expr_list (clobber (reg:DI 16 x16))
>>             (nil))))
>>
>> which, as you can see, doesn't actually set x28.
>> AFAICS the reason dataflow reports call_insn 8 as defining x28 is
>> because x28 is a global register variable
>> and that means that every function call is considered to define it.
>> But the ree pass can't really use any of that. It only wants some SET
>> RTL patterns to play with.
>> One solution is to bail out at the ICE location, in get_sub_rtx, when no
>> SETs are found inside the parallel.
>> But I think we shouldn't be getting this far along anyway.
>> So this patch prevents the call_insn from being recognised as a defining
>> insn for x28 for the purposes of ree.
>> It makes sure that if the register we're extending is a global register
>> that all the insns in the def chain
>> actually set it directly as determined by set_of from rtlanal.c.
>> This should hopefully still allow ree to optimise extensions of global
>> registers as long as they are combined
>> with legitimate defining insns.
>>
>> Bootstrapped and tested on aarch64, arm, x86_64.
>>
>> Ok for trunk?
>>
>> Thanks,
>> Kyrill
>>
>> 2016-10-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
>>
>>     PR rtl-optimization/78038
>>     * ree.c (get_defs): Return NULL if a defining insn for REG cannot
>>     be deduced to set REG through the RTL structure.
>>     (make_defs_and_copies_lists): Return false on a failing get_defs call.
>>
>> 2016-10-20  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
>>
>>     PR rtl-optimization/78038
>>     * gcc.target/aarch64/pr78038.c: New test.
> OK.

Thanks.
As this patch has been in trunk for more than a week with no issues I'd like to apply it to the release branches.
I've so far bootstrapped and tested it on the GCC 6 branch on aarch64-none-linux-gnu and I'll be applying it there.

Kyrill

>
> Jeff
>
diff mbox

Patch

diff --git a/gcc/ree.c b/gcc/ree.c
index 4ab2ad088c363caaaae8abaad375ec5a78bf13ea..374988e792e27fc342518e8e98af618bc595dbce 100644
--- a/gcc/ree.c
+++ b/gcc/ree.c
@@ -482,6 +482,14 @@  get_defs (rtx_insn *insn, rtx reg, vec<rtx_insn *> *dest)
         return NULL;
       if (DF_REF_INSN_INFO (ref_link->ref) == NULL)
         return NULL;
+      /* As global regs are assumed to be defined at each function call
+	 dataflow can report a call_insn as being a definition of REG.
+	 But we can't do anything with that in this pass so proceed only
+	 if the instruction really sets REG in a way that can be deduced
+	 from the RTL structure.  */
+      if (global_regs[REGNO (reg)]
+	  && !set_of (reg, DF_REF_INSN (ref_link->ref)))
+	return NULL;
     }
 
   if (dest)
@@ -580,7 +588,7 @@  make_defs_and_copies_lists (rtx_insn *extend_insn, const_rtx set_pat,
 
   /* Initialize the work list.  */
   if (!get_defs (extend_insn, src_reg, &state->work_list))
-    gcc_unreachable ();
+    return false;
 
   is_insn_visited = XCNEWVEC (bool, max_insn_uid);
 
diff --git a/gcc/testsuite/gcc.target/aarch64/pr78038.c b/gcc/testsuite/gcc.target/aarch64/pr78038.c
new file mode 100644
index 0000000000000000000000000000000000000000..76d97d3b0ad44cd75afa1e1e45434413421c5afa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr78038.c
@@ -0,0 +1,28 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/* PR rtl-optimization/78038.
+   Make sure ree can gracefully handle extensions of the global
+   variable register after a call.  */
+
+typedef void (*test_fptr_t) (void);
+void
+test_f (void)
+{
+}
+test_fptr_t test_fptr = test_f;
+
+struct test2_s
+{
+  int f;
+};
+
+register struct test2_s *g __asm__("x28");
+
+void
+do_something ()
+{
+  test_fptr ();
+  struct test2_s *p1 = 0;
+  *p1 = *g;
+}