Hi all,

We're hitting an ICE when expanding a DImode xor with an immediate on 
TARGET_IWMMXT:
(insn 6 5 7 2 (set (reg:DI 111 [ t1.1_3 ])
        (xor:DI (reg:DI 110 [ t1.0_2 ])
            (const_int 85 [0x55]))) ./z32.c:13 -1
     (nil))

The problem is that the general xordi3 expander accepts some immediates in 
operand 2 but the iwmmxt_xordi3
define_insn only accepts register operands, and nothing forces the operand into 
a register in between.
This doesn't affect the iordi3 or anddi3 expanders because their predicates are 
designed to accept immediates
valid for the VORR and VBIC NEON instructions and thus check for TARGET_NEON as 
well, so they don't accept any
immediates during expand time for TARGET_IWMMXT.

A fix could be to modify arm_xordi_operand to allow only register operands for 
TARGET_IWMMXT.
Another approach, used in this patch, is to force the constants into registers 
in the expander itself.

Bootstrapped and tested on arm-none-linux-gnueabihf (I don't have access to 
iWMMXt hardware).

Ok for trunk and the branches after some time?
This patch should only affect TARGET_IWMMXT and therefore is pretty safe at any 
stage.

Thanks,
Kyrill

2016-01-25  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

    PR target/79145
    * config/arm/arm.md (xordi3): Force constant operand into a register
    for TARGET_IWMMXT.

2016-01-25  Kyrylo Tkachov  <kyrylo.tkac...@arm.com>

    PR target/79145
    * gcc.target/arm/pr79145.c: New test.
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 2eee8bc5701297f52e5ed991f074f1069bde1b6e..48bf07e5b6c121944b38ab8d0d14b029d2b34560 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -3328,7 +3328,14 @@ (define_expand "xordi3"
 	(xor:DI (match_operand:DI 1 "s_register_operand" "")
 		(match_operand:DI 2 "arm_xordi_operand" "")))]
   "TARGET_32BIT"
-  ""
+  {
+    /* The iWMMXt pattern for xordi3 accepts only register operands but we want
+       to reuse this expander for all TARGET_32BIT targets so just force the
+       constants into a register.  Unlike for the anddi3 and iordi3 there are
+       no NEON instructions that take an immediate.  */
+    if (TARGET_IWMMXT && !REG_P (operands[2]))
+      operands[2] = force_reg (DImode, operands[2]);
+  }
 )
 
 (define_insn_and_split "*xordi3_insn"
diff --git a/gcc/testsuite/gcc.target/arm/pr79145.c b/gcc/testsuite/gcc.target/arm/pr79145.c
new file mode 100644
index 0000000000000000000000000000000000000000..667824400390d6fe72d05a85769d210791b8c378
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr79145.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Test is specific to the iWMMXt" { arm*-*-* } { "-mcpu=*" } { "-mcpu=iwmmxt" } } */
+/* { dg-skip-if "Test is specific to the iWMMXt" { arm*-*-* } { "-mabi=*" } { "-mabi=iwmmxt" } } */
+/* { dg-skip-if "Test is specific to the iWMMXt" { arm*-*-* } { "-march=*" } { "-march=iwmmxt" } } */
+/* { dg-skip-if "Test is specific to ARM mode" { arm*-*-* } { "-mthumb" } { "" } } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-require-effective-target arm_iwmmxt_ok } */
+/* { dg-options "-mcpu=iwmmxt" } */
+
+int
+main (void)
+{
+  volatile long long t1;
+  t1 ^= 0x55;
+  return 0;
+}

Reply via email to