The below patch fixes a miscompilation of function calls with__memx address 
space
arguments.

For code like

extern const  __memx float a;
extern const float b;

int diff () { return a > b; }

when compiled with -Os, a is never loaded and passed in as an argument
to the __gtsf2 libgcc function.

Turns out that mov<mode> for the variable a expands into

(insn 8 7 9 2 (parallel [
            (set (reg:SF 22 r22)
                (mem/u/c:SF (reg/f:PSI 47) [1 a+0 S4 A8 AS7]))
            (clobber (reg:SF 22 r22))
            (clobber (reg:QI 21 r21))
            (clobber (reg:HI 30 r30))
        ]) "test.c":4 36 {xloadsf_A}
     (expr_list:REG_DEAD (reg/f:PSI 47)
        (expr_list:REG_UNUSED (reg:HI 30 r30)
            (expr_list:REG_EQUAL (mem/u/c:SF (symbol_ref:PSI ("a") [flags 
0xe40]  <var_decl 0x7fabf444c900 a>) [1 a+0 S4 A8 AS7])
                (nil)))))

The ud_dce pass sees this insn and deletes it as reg:SF r22 is both set
and clobbered.

Georg-Johann pointed out a similar issue (PR63633), and that was fixed
by introducing a pseudo as the target of set. This patch does the same -
adds an avr_emit2_fix_outputs for gen functions with 2 operands, that
detects hard reg conflicts with clobbered regs and substitutes pseudos
in their place.

The patch also adds a testcase to verify a is actually read. Reg testing
passed. Ok to commit to trunk?

Regards
Senthil

gcc/ChangeLog:

2018-07-25  Senthil Kumar Selvaraj  <senthilkumar.selva...@microchip.com>

        * config/avr/avr-protos.h (avr_emit2_fix_outputs): New prototype.
        * config/avr/avr.c (avr_emit2_fix_outputs): New function.
        * config/avr/avr.md (mov<mode>): Wrap gen_xload<mode>_A call
  with avr_emit2_fix_outputs.

gcc/testsuite/ChangeLog:

2018-07-25  Senthil Kumar Selvaraj  <senthilkumar.selva...@microchip.com>

        * gcc.target/avr/torture/pr86635.c: New test.


diff --git gcc/config/avr/avr-protos.h gcc/config/avr/avr-protos.h
index 5622e9035a0..f8db418582e 100644
--- gcc/config/avr/avr-protos.h
+++ gcc/config/avr/avr-protos.h
@@ -135,6 +135,7 @@ regmask (machine_mode mode, unsigned regno)
 }
 
 extern void avr_fix_inputs (rtx*, unsigned, unsigned);
+extern bool avr_emit2_fix_outputs (rtx (*)(rtx,rtx), rtx*, unsigned, unsigned);
 extern bool avr_emit3_fix_outputs (rtx (*)(rtx,rtx,rtx), rtx*, unsigned, 
unsigned);
 
 extern rtx lpm_reg_rtx;
diff --git gcc/config/avr/avr.c gcc/config/avr/avr.c
index 81c35e7fbc2..996d5187c52 100644
--- gcc/config/avr/avr.c
+++ gcc/config/avr/avr.c
@@ -13335,6 +13335,34 @@ avr_emit3_fix_outputs (rtx (*gen)(rtx,rtx,rtx), rtx 
*op,
   return avr_move_fixed_operands (op, hreg, opmask);
 }
 
+/* Same as avr_emit3_fix_outputs, but for 2 operands */
+bool
+avr_emit2_fix_outputs (rtx (*gen)(rtx,rtx), rtx *op,
+                       unsigned opmask, unsigned rmask)
+{
+  const int n = 2;
+  rtx hreg[n];
+
+  /* It is letigimate for GEN to call this function, and in order not to
+     get self-recursive we use the following static kludge.  This is the
+     only way not to duplicate all expanders and to avoid ugly and
+     hard-to-maintain C-code instead of the much more appreciated RTL
+     representation as supplied by define_expand.  */
+  static bool lock = false;
+
+  gcc_assert (opmask < (1u << n));
+
+  if (lock)
+    return false;
+
+  avr_fix_operands (op, hreg, opmask, rmask);
+
+  lock = true;
+  emit_insn (gen (op[0], op[1]));
+  lock = false;
+
+  return avr_move_fixed_operands (op, hreg, opmask);
+}
 
 /* Worker function for movmemhi expander.
    XOP[0]  Destination as MEM:BLK
diff --git gcc/config/avr/avr.md gcc/config/avr/avr.md
index e619e695418..5ff4e490a21 100644
--- gcc/config/avr/avr.md
+++ gcc/config/avr/avr.md
@@ -672,7 +672,11 @@
              ; insn-emit does not depend on the mode, it's all about operands. 
 */
           emit_insn (gen_xload8qi_A (dest, src));
         else
-          emit_insn (gen_xload<mode>_A (dest, src));
+          if (!avr_emit2_fix_outputs (gen_xload<mode>_A, operands, 1 << 0,
+                                      regmask (<MODE>mode, 22)
+                                               | regmask (QImode, 21)
+                                               | regmask (HImode, REG_Z)))
+            FAIL;
 
         DONE;
       }
diff --git gcc/testsuite/gcc.target/avr/torture/pr86635.c 
gcc/testsuite/gcc.target/avr/torture/pr86635.c
new file mode 100644
index 00000000000..f91367f7e7a
--- /dev/null
+++ gcc/testsuite/gcc.target/avr/torture/pr86635.c
@@ -0,0 +1,9 @@
+/* { dg-do compile { target { ! avr_tiny } } } */
+/* { dg-options "-std=gnu99" } */
+
+extern const __memx float a;
+extern const float b;
+
+unsigned long diff () { return a > b; }
+
+/* { dg-final { scan-assembler "call __xload_4" } } */

Reply via email to