diff mbox

[avr] Fix PR77326: CC_NONE might clobber condition code

Message ID e42013c8-c30a-25ed-95b2-30ed3213c6dd@gjlay.de
State New
Headers show

Commit Message

Georg-Johann Lay Sept. 20, 2016, 10:07 a.m. UTC
This fixes the case of CC_NONE (insn attribute for cc is "none"):

Even in cases where the instructions of an insn do not change the condition 
code of the machine, they still might change some registers by clobber, set, 
etc.  If one such register overlaps an expression stored in cc_status.value1/2 
we must reset cc_status as the value stored there no more represents the state 
of cc0.

Ok to apply and backport?


Johann

gcc/
	PR target/77326
	* config/avr/avr.c (avr_notice_update_cc) [CC_NONE]: If insn
	touches some regs mentioned in cc_status, do CC_STATUS_INIT.

gcc/testsuite/
	PR target/77326
	* gcc.target/avr/torture/pr77326.c: New test.

Comments

Denis Chertykov Sept. 20, 2016, 5:12 p.m. UTC | #1
2016-09-20 13:07 GMT+03:00 Georg-Johann Lay <avr@gjlay.de>:
> This fixes the case of CC_NONE (insn attribute for cc is "none"):
>
> Even in cases where the instructions of an insn do not change the condition
> code of the machine, they still might change some registers by clobber, set,
> etc.  If one such register overlaps an expression stored in
> cc_status.value1/2 we must reset cc_status as the value stored there no more
> represents the state of cc0.
>
> Ok to apply and backport?

Ok.
Please apply.

>
>
> Johann
>
> gcc/
>         PR target/77326
>         * config/avr/avr.c (avr_notice_update_cc) [CC_NONE]: If insn
>         touches some regs mentioned in cc_status, do CC_STATUS_INIT.
>
> gcc/testsuite/
>         PR target/77326
>         * gcc.target/avr/torture/pr77326.c: New test.
diff mbox

Patch

Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(revision 240135)
+++ config/avr/avr.c	(working copy)
@@ -2511,8 +2511,44 @@  avr_notice_update_cc (rtx body ATTRIBUTE
       break;
 
     case CC_NONE:
-      /* Insn does not affect CC at all.  */
-      break;
+      /* Insn does not affect CC at all, but it might set some registers
+         that are stored in cc_status.  If such a register is affected by
+         the current insn, for example by means of a SET or a CLOBBER,
+         then we must reset cc_status; cf. PR77326.
+
+         Unfortunately, set_of cannot be used as reg_overlap_mentioned_p
+         will abort on COMPARE (which might be found in cc_status.value1/2).
+         Thus work out the registers set by the insn and regs mentioned
+         in cc_status.value1/2.  */
+
+      if (cc_status.value1
+          || cc_status.value2)
+        {
+          HARD_REG_SET regs_used;
+          HARD_REG_SET regs_set;
+          CLEAR_HARD_REG_SET (regs_used);
+
+          if (cc_status.value1
+              && !CONSTANT_P (cc_status.value1))
+            {
+              find_all_hard_regs (cc_status.value1, &regs_used);
+            }
+
+          if (cc_status.value2
+              && !CONSTANT_P (cc_status.value2))
+            {
+              find_all_hard_regs (cc_status.value1, &regs_used);
+            }
+
+          find_all_hard_reg_sets (insn, &regs_set, false);
+
+          if (hard_reg_set_intersect_p (regs_used, regs_set))
+            {
+              CC_STATUS_INIT;
+            }
+        }
+
+      break; // CC_NONE
 
     case CC_SET_N:
       CC_STATUS_INIT;
Index: testsuite/gcc.target/avr/torture/pr77326.c
===================================================================
--- testsuite/gcc.target/avr/torture/pr77326.c	(nonexistent)
+++ testsuite/gcc.target/avr/torture/pr77326.c	(working copy)
@@ -0,0 +1,26 @@ 
+/* { dg-do run } */
+/* { dg-options "-Wl,--defsym,test1=0" } */
+
+extern void test1 (void) __attribute__((weak));
+
+__attribute__((noinline,noclone))
+static void va_pseudo (int flag, ...)
+{
+  __asm ("nop":);
+}
+
+__attribute__((noinline,noclone))
+static void func (void)
+{
+  va_pseudo (0, 0, 0, 0);
+
+  if (test1)
+    __builtin_abort ();
+}
+
+int main (void)
+{
+  func();
+  __builtin_exit (0);
+  return 0;
+}