From 472f2cfae7bd6ea5996fd8c386e553f44ac0c20b Mon Sep 17 00:00:00 2001
From: Charles Baylis <charles.baylis@linaro.org>
Date: Wed, 2 Apr 2014 12:03:53 +0100
Subject: [PATCH] initial attempt at fixing push_minipool_fix ICE

---
 gcc/config/arm/arm-protos.h |  2 ++
 gcc/config/arm/arm.c        |  9 +++++++
 gcc/config/arm/arm.md       | 64 +++++++++++++++++++++++++++++++++++----------
 3 files changed, 61 insertions(+), 14 deletions(-)

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 13874ee..b03db15 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -294,4 +294,6 @@ extern void arm_emit_eabi_attribute (const char *, int, int);
 /* Defined in gcc/common/config/arm-common.c.  */
 extern const char *arm_rewrite_selected_cpu (const char *name);
 
+extern bool arm_is_constant_pool_ref (rtx);
+
 #endif /* ! GCC_ARM_PROTOS_H */
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 0240cc7..2eecda5 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -31116,4 +31116,13 @@ arm_asan_shadow_offset (void)
   return (unsigned HOST_WIDE_INT) 1 << 29;
 }
 
+/* return TRUE if x is a reference to a value in a constant pool */
+extern bool
+arm_is_constant_pool_ref (rtx x)
+{
+  return (MEM_P (x)
+	  && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+	  && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
+}
+
 #include "gt-arm.h"
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 4df24a2..72d4b16 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -5289,7 +5289,7 @@
   "TARGET_ARM && arm_arch6"
   "@
    uxth%?\\t%0, %1
-   ldr%(h%)\\t%0, %1"
+   * return arm_is_constant_pool_ref(operands[1]) ? \"#\" : \"ldr%(h%)\\t%0, %1\";"
   [(set_attr "predicable" "yes")
    (set_attr "type" "extend,load_byte")]
 )
@@ -5377,13 +5377,55 @@
    (set_attr "predicable" "yes")]
 )
 
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+	(zero_extend:SI (match_operand 1 "nonimmediate_operand" "")))]
+  "arm_is_constant_pool_ref (operands[1])
+     && (GET_MODE (operands[1]) == QImode || GET_MODE (operands[1]) == HImode)"
+  [(set (match_dup 0) (match_dup 1))]
+{
+    rtx cop = avoid_constant_pool_reference (operands[1]);
+    /* Casting the address of something to a mode narrower
+       than a word can cause avoid_constant_pool_reference()
+       to return the pool reference itself.  That's no good to
+       us here.  Lets just hope that we can use the
+       constant pool value directly.  */
+    if (operands[1] == cop)
+      cop = get_pool_constant (XEXP (operands[1], 0));
+    operands[1] = cop;
+})
+
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+	(sign_extend:SI (match_operand 1 "nonimmediate_operand" "")))]
+  "arm_is_constant_pool_ref (operands[1])
+     && (GET_MODE (operands[1]) == QImode || GET_MODE (operands[1]) == HImode)"
+  [(set (match_dup 0) (match_dup 1))]
+{
+    unsigned HOST_WIDE_INT val;
+    rtx cop = avoid_constant_pool_reference (operands[1]);
+    /* Casting the address of something to a mode narrower
+       than a word can cause avoid_constant_pool_reference()
+       to return the pool reference itself.  That's no good to
+       us here.  Lets just hope that we can use the
+       constant pool value directly.  */
+    if (operands[1] == cop)
+      cop = get_pool_constant (XEXP (operands[1], 0));
+    val = INTVAL(cop);
+    if (GET_MODE (operands[1]) == QImode && (val & 0x80))
+      val |= 0xffffff00u;
+    if (GET_MODE (operands[1]) == HImode && (val & 0x8000))
+      val |= 0xffff0000u;
+    operands[1] = GEN_INT (val);
+})
+
 (define_insn "*arm_zero_extendqisi2_v6"
   [(set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
   "TARGET_ARM && arm_arch6"
   "@
    uxtb%(%)\\t%0, %1
-   ldr%(b%)\\t%0, %1\\t%@ zero_extendqisi2"
+   * return arm_is_constant_pool_ref(operands[1]) ? \"#\" : \"ldr%(b%)\\t%0, %1\\t%@ zero_extendqisi2\";"
   [(set_attr "type" "extend,load_byte")
    (set_attr "predicable" "yes")]
 )
@@ -5617,12 +5659,10 @@
   "TARGET_ARM && arm_arch4 && !arm_arch6"
   "@
    #
-   ldr%(sh%)\\t%0, %1"
+   * return arm_is_constant_pool_ref(operands[1]) ? \"#\" : \"ldr%(sh%)\\t%0, %1\";"
   [(set_attr "length" "8,4")
    (set_attr "type" "alu_shift_reg,load_byte")
-   (set_attr "predicable" "yes")
-   (set_attr "pool_range" "*,256")
-   (set_attr "neg_pool_range" "*,244")]
+   (set_attr "predicable" "yes")]
 )
 
 ;; ??? Check Thumb-2 pool range
@@ -5632,12 +5672,10 @@
   "TARGET_32BIT && arm_arch6"
   "@
    sxth%?\\t%0, %1
-   ldr%(sh%)\\t%0, %1"
+   * return arm_is_constant_pool_ref(operands[1]) ? \"#\" : \"ldr%(sh%)\\t%0, %1\";"
   [(set_attr "type" "extend,load_byte")
    (set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")
-   (set_attr "pool_range" "*,256")
-   (set_attr "neg_pool_range" "*,244")]
+   (set_attr "predicable_short_it" "no")]
 )
 
 (define_insn "*arm_extendhisi2addsi"
@@ -5734,11 +5772,9 @@
   "TARGET_ARM && arm_arch6"
   "@
    sxtb%?\\t%0, %1
-   ldr%(sb%)\\t%0, %1"
+   * return arm_is_constant_pool_ref(operands[1]) ? \"#\" : \"ldr%(sb%)\\t%0, %1\";"
   [(set_attr "type" "extend,load_byte")
-   (set_attr "predicable" "yes")
-   (set_attr "pool_range" "*,256")
-   (set_attr "neg_pool_range" "*,244")]
+   (set_attr "predicable" "yes")]
 )
 
 (define_insn "*arm_extendqisi2addsi"
-- 
1.8.3.2

