From b55922d45fd16f5e8fc7c3885da42b2b9b37754d Mon Sep 17 00:00:00 2001
From: Claudiu Zissulescu <claziss@synopsys.com>
Date: Mon, 18 Jan 2016 16:43:18 +0100
Subject: [PATCH] UPDATE: Fix handling complex PIC moves.

fwprop is putting in the REG_EQUIV notes which are involving the
constant pic unspecs.  Then, loop may use those notes for
optimizations rezulting in complex patterns that are not supported by
the current implementation. The following piece of code tries to
convert the complex instruction in simpler ones.

The fix is done in development tree: [arc-4.8-dev b55922d] 
and will be a part of the next release of ARC GNU tools.
Once that new release happens this patch must be removed.


gcc/
2016-01-18  Claudiu Zissulescu  <claziss@synopsys.com>

	* config/arc/arc.c (arc_legitimize_pic_address): Handle MINUS
	operations when doing PIC moves. Make this function static.
	(arc_legitimate_pc_offset_p): Use
	arc_raw_symbolic_reference_mentioned_p.
	* config/arc/arc-protos.h (arc_legitimize_pic_address): Remove.

 gcc/config/arc/arc-protos.h |  1 -
 gcc/config/arc/arc.c        | 33 +++++++++++++++++++--------------
 2 files changed, 19 insertions(+), 15 deletions(-)

 	* config/arc/arc.c (arc_legitimize_pic_address): Handle complex
diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h
index 464e0ab..5986e06 100644
--- a/gcc/config/arc/arc-protos.h
+++ b/gcc/config/arc/arc-protos.h
@@ -53,7 +53,6 @@ extern unsigned int arc_compute_frame_size ();
 extern bool arc_ccfsm_branch_deleted_p (void);
 extern void arc_ccfsm_record_branch_deleted (void);
 
-extern rtx arc_legitimize_pic_address (rtx, rtx);
 void arc_asm_output_aligned_decl_local (FILE *, tree, const char *,
 					unsigned HOST_WIDE_INT,
 					unsigned HOST_WIDE_INT,
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index a89c8ee..f7cae9f 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -5243,19 +5243,7 @@ arc_legitimate_pc_offset_p (rtx addr)
   if (GET_CODE (addr) != CONST)
     return false;
   addr = XEXP (addr, 0);
-  if (GET_CODE (addr) == PLUS)
-    {
-      if (GET_CODE (XEXP (addr, 1)) != CONST_INT)
-	return false;
-      addr = XEXP (addr, 0);
-    }
-  return (GET_CODE (addr) == UNSPEC
-	  && XVECLEN (addr, 0) == 1
-	  && (XINT (addr, 1) == ARC_UNSPEC_GOT
-	      || XINT (addr, 1) == ARC_UNSPEC_GOTOFFPC
-	      || XINT (addr, 1) == UNSPEC_TLS_GD
-	      || XINT (addr, 1) == UNSPEC_TLS_IE)
-	  && GET_CODE (XVECEXP (addr, 0, 0)) == SYMBOL_REF);
+  return flag_pic && !arc_raw_symbolic_reference_mentioned_p (addr, false);
 }
 
 /* Return true if ADDR is a valid pic address.
@@ -5522,7 +5510,7 @@ arc_legitimize_tls_address (rtx addr, enum tls_model model)
    The return value is the legitimated address.
    If OLDX is non-zero, it is the target to assign the address to first.  */
 
-rtx
+static rtx
 arc_legitimize_pic_address (rtx orig, rtx oldx)
 {
   rtx addr = orig;
@@ -5569,6 +5557,23 @@ arc_legitimize_pic_address (rtx orig, rtx oldx)
 	      /* Check that the unspec is one of the ones we generate?  */
 	      return orig;
 	    }
+	  else if (GET_CODE (addr) == MINUS)
+	    {
+	      /* The same story with fwprop.  */
+	      rtx op0 = XEXP (addr, 0);
+	      rtx op1 = XEXP (addr, 1);
+	      gcc_assert (oldx);
+	      gcc_assert (GET_CODE (op1) == UNSPEC);
+
+	      emit_move_insn (oldx,
+			      gen_rtx_CONST (SImode,
+					     arc_legitimize_pic_address (op1,
+									 NULL_RTX)));
+	      emit_insn (gen_rtx_SET (VOIDmode, oldx,
+				      gen_rtx_MINUS (SImode, op0, oldx)));
+	      return oldx;
+
+	    }
 	  else if (GET_CODE (addr) != PLUS)
 	    {
 	      /* fwprop is putting in the REG_EQUIV notes which are
-- 
2.5.0

