public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* m32c support for named addr spaces branch
@ 2009-10-15  4:17 DJ Delorie
  2009-10-15 18:07 ` Ulrich Weigand
  0 siblings, 1 reply; 34+ messages in thread
From: DJ Delorie @ 2009-10-15  4:17 UTC (permalink / raw)
  To: gcc-patches


In case anyone's interested, here's preliminary support for named
address spaces for the m32c-elf target.  It's relative to the branch,
but with the (hopefully) looming approval of the merge to mainline,
I'm holding off on committing it.

The only thing I haven't gotten it to do is this addressing mode,
which I think would help m16c a lot:

  (mem (plus:SI (zero_extendhisi:SI (reg:HI)) (symbol_ref)))

GCC instead uses sign extension, which isn't what the chip does:

(plus:SI (sign_extend:SI (reg:HI 28))
    (symbol_ref:SI ("far_int_array") [flags 0x40] <var_decl 0xb7f830b8 far_int_array>))


Index: m32c.c
===================================================================
--- m32c.c	(revision 152757)
+++ m32c.c	(working copy)
@@ -70,12 +70,13 @@ static int interrupt_p (tree node);
 static bool m32c_asm_integer (rtx, unsigned int, int);
 static int m32c_comp_type_attributes (const_tree, const_tree);
 static bool m32c_fixed_condition_code_regs (unsigned int *, unsigned int *);
 static struct machine_function *m32c_init_machine_status (void);
 static void m32c_insert_attributes (tree, tree *);
 static bool m32c_legitimate_address_p (enum machine_mode, rtx, bool);
+static bool m32c_addr_space_legitimate_address_p (enum machine_mode, rtx, bool, addr_space_t);
 static bool m32c_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
 				    const_tree, bool);
 static bool m32c_promote_prototypes (const_tree);
 static int m32c_pushm_popm (Push_Pop_Type);
 static bool m32c_strict_argument_naming (CUMULATIVE_ARGS *);
 static rtx m32c_struct_value_rtx (tree, int);
@@ -111,12 +112,20 @@ static GTY(()) rtx patternr[30];
 #define IS_MEM_REGNO(regno) ((regno) >= MEM0_REGNO && (regno) <= MEM7_REGNO)
 #define IS_MEM_REG(rtx) (GET_CODE (rtx) == REG && IS_MEM_REGNO (REGNO (rtx)))
 
 #define IS_CR_REGNO(regno) ((regno) >= SB_REGNO && (regno) <= PC_REGNO)
 #define IS_CR_REG(rtx) (GET_CODE (rtx) == REG && IS_CR_REGNO (REGNO (rtx)))
 
+static int
+far_addr_space_p (rtx x)
+{
+  if (GET_CODE (x) != MEM)
+    return 0;
+  return MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR;
+}
+
 /* We do most RTX matching by converting the RTX into a string, and
    using string compares.  This vastly simplifies the logic in many of
    the functions in this file.
 
    On exit, pattern[] has the encoded string (use RTX_IS("...") to
    compare it) and patternr[] has pointers to the nodes in the RTX
@@ -504,12 +513,18 @@ m32c_conditional_register_usage (void)
 	{
 	  fixed_regs[MEM0_REGNO + i] = 1;
 	  CLEAR_HARD_REG_BIT (reg_class_contents[MEM_REGS], MEM0_REGNO + i);
 	}
     }
 
+  if (TARGET_A16)
+    {
+      SET_HARD_REG_BIT (reg_class_contents[SI_REGS], A0_REGNO);
+      SET_HARD_REG_BIT (reg_class_contents[SI_REGS], A1_REGNO);
+    }
+
   /* M32CM and M32C preserve more registers across function calls.  */
   if (TARGET_A24)
     {
       call_used_regs[R1_REGNO] = 0;
       call_used_regs[R2_REGNO] = 0;
       call_used_regs[R3_REGNO] = 0;
@@ -535,13 +550,13 @@ m32c_hard_regno_nregs_1 (int regno, enum
     return (GET_MODE_SIZE (mode) + 1) / 2;
 
   if (GET_MODE_SIZE (mode) <= 1)
     return nregs_table[regno].qi_regs;
   if (GET_MODE_SIZE (mode) <= 2)
     return nregs_table[regno].hi_regs;
-  if (regno == A0_REGNO && mode == PSImode && TARGET_A16)
+  if (regno == A0_REGNO && mode == SImode && TARGET_A16)
     return 2;
   if ((GET_MODE_SIZE (mode) <= 3 || mode == PSImode) && TARGET_A24)
     return nregs_table[regno].pi_regs;
   if (GET_MODE_SIZE (mode) <= 4)
     return nregs_table[regno].si_regs;
   if (GET_MODE_SIZE (mode) <= 8)
@@ -1044,12 +1059,25 @@ m32c_extra_constraint_p2 (rtx value, cha
 	      && !(INTVAL (patternr[1]) & ~0x1fff));
     }
   else if (memcmp (str, "S1", 2) == 0)
     {
       return r1h_operand (value, QImode);
     }
+  else if (memcmp (str, "SF", 2) == 0)
+    {
+      if (! far_addr_space_p (value))
+	return 0;
+      return ((RTX_IS ("mr")
+	       && IS_REG (patternr[1], A0_REGNO)
+	       && GET_MODE (patternr[1]) == SImode)
+	      || (RTX_IS ("m+ri")
+		  && (IS_REG (patternr[2], A0_REGNO))
+		  && GET_MODE (patternr[2]) == HImode)
+	      || RTX_IS ("ms")
+	      );
+    }
 
   gcc_assert (str[0] != 'S');
 
   if (memcmp (str, "Rpa", 2) == 0)
     return GET_CODE (value) == PARALLEL;
 
@@ -1788,12 +1816,15 @@ bool
 m32c_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
 {
   int mode_adjust;
   if (CONSTANT_P (x))
     return 1;
 
+  if (GET_MODE (x) != HImode)
+    return 0;
+
   /* Wide references to memory will be split after reload, so we must
      ensure that all parts of such splits remain legitimate
      addresses.  */
   mode_adjust = GET_MODE_SIZE (mode) - 1;
 
   /* allowing PLUS yields mem:HI(plus:SI(mem:SI(plus:SI in m32c_split_move */
@@ -2048,12 +2079,191 @@ int
 m32c_legitimate_constant_p (rtx x ATTRIBUTE_UNUSED)
 {
   return 1;
 }
 
 
+/* Return the appropriate mode for a named address pointer.  */
+#undef TARGET_ADDR_SPACE_POINTER_MODE
+#define TARGET_ADDR_SPACE_POINTER_MODE m32c_addr_space_pointer_mode
+static enum machine_mode
+m32c_addr_space_pointer_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+      return TARGET_A24 ? PSImode : HImode;
+    case ADDR_SPACE_FAR:
+      return SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Return the appropriate mode for a named address address.  */
+#undef TARGET_ADDR_SPACE_ADDRESS_MODE
+#define TARGET_ADDR_SPACE_ADDRESS_MODE m32c_addr_space_address_mode
+static enum machine_mode
+m32c_addr_space_address_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+      return TARGET_A24 ? PSImode : HImode;
+    case ADDR_SPACE_FAR:
+      return SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Like m32c_legitimate_address_p, except with named addresses.  */
+#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
+#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \
+  m32c_addr_space_legitimate_address_p
+static bool
+m32c_addr_space_legitimate_address_p (enum machine_mode mode, rtx x,
+				      bool strict, addr_space_t as)
+{
+  if (as == ADDR_SPACE_FAR)
+    {
+      if (TARGET_A24)
+	return 0;
+      debug_rtx(x);
+      encode_pattern (x);
+      if (RTX_IS ("r"))
+	{
+	  if (GET_MODE (x) != SImode)
+	    return 0;
+	  switch (REGNO (patternr[0]))
+	    {
+	    case A0_REGNO:
+	      return 1;
+
+	    default:
+	      if (IS_PSEUDO (patternr[0], strict))
+		return 1;
+	      return 0;
+	    }
+	}
+#if 1
+      if (RTX_IS ("+ri"))
+	{
+	  int rn = REGNO (patternr[1]);
+	  HOST_WIDE_INT offs = INTVAL (patternr[2]);
+	  if (GET_MODE (patternr[1]) != HImode)
+	    return 0;
+	  switch (rn)
+	    {
+	    case A0_REGNO:
+	      return (offs >= 0 && offs <= 0xfffff);
+
+	    default:
+	      if (IS_PSEUDO (patternr[1], strict))
+		return 1;
+	      return 0;
+	    }
+	}
+      if (RTX_IS ("+rs"))
+	{
+	  int rn = REGNO (patternr[1]);
+	  if (GET_MODE (patternr[1]) != HImode)
+	    return 0;
+	  switch (rn)
+	    {
+	    case A0_REGNO:
+	      return 1;
+
+	    default:
+	      if (IS_PSEUDO (patternr[1], strict))
+		return 1;
+	      return 0;
+	    }
+	}
+#endif
+      if (RTX_IS ("s"))
+	{
+	  return 1;
+	}
+      return 0;
+    }
+
+  else if (as != ADDR_SPACE_GENERIC)
+    gcc_unreachable ();
+
+  return m32c_legitimate_address_p (mode, x, strict);
+}
+
+/* Like m32c_legitimate_address, except with named address support.  */
+#undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS
+#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS m32c_addr_space_legitimize_address
+static rtx
+m32c_addr_space_legitimize_address (rtx x, rtx oldx, enum machine_mode mode,
+				    addr_space_t as)
+{
+  if (as != ADDR_SPACE_GENERIC)
+    {
+      if (GET_CODE (x) != REG)
+	{
+	  x = force_reg (SImode, x);
+	}
+      return x;
+    }
+
+  return m32c_legitimize_address (x, oldx, mode);
+}
+
+/* Determine if one named address space is a subset of another.  */
+#undef TARGET_ADDR_SPACE_SUBSET_P
+#define TARGET_ADDR_SPACE_SUBSET_P m32c_addr_space_subset_p
+static bool
+m32c_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
+{
+  gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_FAR);
+  gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_FAR);
+
+  if (subset == superset)
+    return true;
+
+  else
+    return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_FAR);
+}
+
+#undef TARGET_ADDR_SPACE_CONVERT
+#define TARGET_ADDR_SPACE_CONVERT m32c_addr_space_convert
+/* Convert from one address space to another.  */
+static rtx
+m32c_addr_space_convert (rtx op, tree from_type, tree to_type)
+{
+  addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
+  addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
+  rtx result;
+
+  gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_FAR);
+  gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_FAR);
+
+  if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_FAR)
+    {
+      /* This is unpredictable, as we're truncating off usable address
+	 bits.  */
+
+      result = gen_reg_rtx (HImode);
+      emit_move_insn (result, simplify_subreg (HImode, op, SImode, 0));
+      return result;
+    }
+  else if (to_as == ADDR_SPACE_FAR && from_as == ADDR_SPACE_GENERIC)
+    {
+      /* This always works.  */
+      result = gen_reg_rtx (SImode);
+      emit_insn (gen_zero_extendhisi2 (result, op));
+      return result;
+    }
+  else
+    gcc_unreachable ();
+}
+
 /* Condition Code Status */
 
 #undef TARGET_FIXED_CONDITION_CODE_REGS
 #define TARGET_FIXED_CONDITION_CODE_REGS m32c_fixed_condition_code_regs
 static bool
 m32c_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
@@ -3315,12 +3525,17 @@ m32c_split_move (rtx * operands, enum ma
      point, so it's safe to set it to 3 even with define_insn.  */
   /* None of the chips can move SI operands to sp-relative addresses,
      so we always split those.  */
   if (m32c_extra_constraint_p (operands[0], 'S', "Ss"))
     split_all = 3;
 
+  if (TARGET_A16
+      && (far_addr_space_p (operands[0])
+	  || far_addr_space_p (operands[1])))
+    split_all |= 1;
+
   /* We don't need to split these.  */
   if (TARGET_A24
       && split_all != 3
       && (mode == SImode || mode == PSImode)
       && !(GET_CODE (operands[1]) == MEM
 	   && GET_CODE (XEXP (operands[1], 0)) == POST_INC))
Index: m32c.h
===================================================================
--- m32c.h	(revision 152757)
+++ m32c.h	(working copy)
@@ -582,12 +582,19 @@ typedef struct m32c_cumulative_args
 #define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \
 	if (m32c_legitimize_reload_address(&(X),MODE,OPNUM,TYPE,IND_LEVELS)) \
 	  goto WIN;
 
 #define LEGITIMATE_CONSTANT_P(X) m32c_legitimate_constant_p (X)
 
+/* Address spaces.  */
+#define ADDR_SPACE_FAR	1
+
+/* Named address space keywords.  */
+#define TARGET_ADDR_SPACE_KEYWORDS ADDR_SPACE_KEYWORD ("__far", ADDR_SPACE_FAR)
+
+
 /* Condition Code Status */
 
 #define REVERSIBLE_CC_MODE(MODE) 1
 
 /* Describing Relative Costs of Operations */
 
Index: mov.md
===================================================================
--- mov.md	(revision 152757)
+++ mov.md	(working copy)
@@ -29,51 +29,54 @@
 ;; the stack.
 
 ;; Match push/pop before mov.b for passing char as arg,
 ;; e.g. stdlib/efgcvt.c.
 (define_insn "movqi_op"
   [(set (match_operand:QI 0 "m32c_nonimmediate_operand"
-			  "=Rqi*Rmm, <,          RqiSd*Rmm, SdSs,    Rqi*Rmm, Sd")
+			  "=SF,Rhi*RmmSd, Rqi*Rmm, <,          RqiSd*Rmm, SdSs,    Rqi*Rmm, Sd")
 	(match_operand:QI 1 "m32c_any_operand"
-			  "iRqi*Rmm, iRqiSd*Rmm, >,         Rqi*Rmm, SdSs,    i"))]
+			  "Rhi*RmmSd,SF, iRqi*Rmm, iRqiSd*Rmm, >,         Rqi*Rmm, SdSs,    i"))]
   "m32c_mov_ok (operands, QImode)"
   "@
+    lde.b\t%1,%0
+    ste.b\t%1,%0
     mov.b\t%1,%0
     push.b\t%1
     pop.b\t%0
     mov.b\t%1,%0
     mov.b\t%1,%0
     mov.b\t%1,%0"
-  [(set_attr "flags" "sz,*,*,sz,sz,sz")]
+  [(set_attr "flags" "sz,sz,sz,*,*,sz,sz,sz")]
   )
 
 (define_expand "movqi"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=RqiSd*Rmm")
 	(match_operand:QI 1 "general_operand" "iRqiSd*Rmm"))]
   ""
   "if (m32c_prepare_move (operands, QImode)) DONE;"
   )
 
-
 (define_insn "movhi_op"
   [(set (match_operand:HI 0 "m32c_nonimmediate_operand"
-			  "=Rhi*Rmm,     Sd, SdSs,   *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr")
+			  "=SF,Rhi*RmmSd, Rhi*Rmm,     Sd, SdSs,   *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr")
 	(match_operand:HI 1 "m32c_any_operand"
-			  "iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))]
+			  " Rhi*RmmSd,SF, iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))]
   "m32c_mov_ok (operands, HImode)"
   "@
+   lde.w\t%1,%0
+   ste.w\t%1,%0
    mov.w\t%1,%0
    mov.w\t%1,%0
    mov.w\t%1,%0
    ldc\t%1,%0
    stc\t%1,%0
    push.w\t%1
    pop.w\t%0
    pushc\t%1
    popc\t%0"
-  [(set_attr "flags" "sz,sz,sz,n,n,n,n,n,n")]
+  [(set_attr "flags" "sz,sz,sz,sz,sz,n,n,n,n,n,n")]
   )
 
 (define_expand "movhi"
   [(set (match_operand:HI 0 "m32c_nonimmediate_operand" "=RhiSd*Rmm")
 	(match_operand:HI 1 "m32c_any_operand" "iRhiSd*Rmm"))]
   ""
Index: addsub.md
===================================================================
--- addsub.md	(revision 152757)
+++ addsub.md	(working copy)
@@ -90,15 +90,23 @@
     { 
     case 0:
       return \"add.w %X2,%h0\;adcf.w %H0\";
     case 1:
       return \"add.w %X2,%h0\;adcf.w %H0\";
     case 2:
-      output_asm_insn (\"add.w %X2,%h0\",operands);
-      operands[2]= GEN_INT (INTVAL (operands[2]) >> 16);
-      return \"adc.w %X2,%H0\";
+      if (GET_CODE (operands[2]) == SYMBOL_REF)
+        {
+          output_asm_insn (\"add.w #%%lo(%d2),%h0\",operands);
+          return \"adc.w #%%hi(%d2),%H0\";
+        }
+      else
+        {
+          output_asm_insn (\"add.w %X2,%h0\",operands);
+          operands[2]= GEN_INT (INTVAL (operands[2]) >> 16);
+          return \"adc.w %X2,%H0\";
+        }
     case 3:
       return \"add.w %h2,%h0\;adc.w %H2,%H0\";
     case 4:
       output_asm_insn (\"add.w %X2,%h0\",operands);
       operands[2]= GEN_INT (INTVAL (operands[2]) >> 16);
       return \"adc.w %X2,%H0\";

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-15  4:17 m32c support for named addr spaces branch DJ Delorie
@ 2009-10-15 18:07 ` Ulrich Weigand
  2009-10-15 18:11   ` DJ Delorie
  0 siblings, 1 reply; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-15 18:07 UTC (permalink / raw)
  To: DJ Delorie; +Cc: gcc-patches

DJ Delorie wrote:

> In case anyone's interested, here's preliminary support for named
> address spaces for the m32c-elf target.  It's relative to the branch,
> but with the (hopefully) looming approval of the merge to mainline,
> I'm holding off on committing it.

Thanks!

> The only thing I haven't gotten it to do is this addressing mode,
> which I think would help m16c a lot:
> 
>   (mem (plus:SI (zero_extendhisi:SI (reg:HI)) (symbol_ref)))
> 
> GCC instead uses sign extension, which isn't what the chip does:
> 
> (plus:SI (sign_extend:SI (reg:HI 28))
>     (symbol_ref:SI ("far_int_array") [flags 0x40] <var_decl 0xb7f830b8 far_int_array>))

Hmm, I'm assuming the HI originates from a signed variable at
source code level?  In this case, it actually might really be
negative ...

I guess one could make the assumption that negative offsets
relative to the start of a global variable (symbol_ref) are
undefined.  In that case, you might maybe try to replace the
sign_extend with a zero_extend in legitimize_address?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-15 18:07 ` Ulrich Weigand
@ 2009-10-15 18:11   ` DJ Delorie
  2009-10-16 14:19     ` Ulrich Weigand
  0 siblings, 1 reply; 34+ messages in thread
From: DJ Delorie @ 2009-10-15 18:11 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gcc-patches


> Hmm, I'm assuming the HI originates from a signed variable at
> source code level?  In this case, it actually might really be
> negative ...

I tried changing that variable to unsigned, didn't help.

> I guess one could make the assumption that negative offsets
> relative to the start of a global variable (symbol_ref) are
> undefined.  In that case, you might maybe try to replace the
> sign_extend with a zero_extend in legitimize_address?

Yes, I thought of that too ;-)

That would limit far objects to 32k, vs 64k.  Not sure if that's
acceptable or not, but I suppose I could enable that addressing mode
with a command line switch.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-15 18:11   ` DJ Delorie
@ 2009-10-16 14:19     ` Ulrich Weigand
  2009-10-16 18:22       ` DJ Delorie
                         ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-16 14:19 UTC (permalink / raw)
  To: DJ Delorie; +Cc: gcc-patches

DJ Delorie wrote:

> > Hmm, I'm assuming the HI originates from a signed variable at
> > source code level?  In this case, it actually might really be
> > negative ...
> 
> I tried changing that variable to unsigned, didn't help.

That's odd.  I tried building an analogous test:

unsigned short x;
char buf[1024];

char test (void)
{
  return buf[x];
}

on a system with 32-bit pointers, and I get:

(insn 5 4 6 test.c:6 (set (reg/f:SI 48)
        (symbol_ref:SI ("buf") [flags 0x400] <var_decl 0x20000279320 buf>)) -1 (nil))

(insn 6 5 7 test.c:6 (set (reg/f:SI 50)
        (symbol_ref:SI ("x") <var_decl 0x20000279280 x>)) -1 (nil))

(insn 7 6 8 test.c:6 (set (reg:SI 52)
        (zero_extend:SI (mem/c/i:HI (reg/f:SI 50) [5 x+0 S2 A16]))) -1 (nil))

(insn 8 7 9 test.c:6 (set (reg:SI 54)
        (zero_extend:SI (mem/s/j:QI (plus:SI (reg/f:SI 48)
                    (reg:SI 52)) [0 buf S1 A8]))) -1 (nil))

so the offset does get zero-extended.  (If "x" is signed, I get
a sign_extend in insn 7 instead ...)

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-16 14:19     ` Ulrich Weigand
@ 2009-10-16 18:22       ` DJ Delorie
  2009-10-16 22:05       ` DJ Delorie
  2009-10-16 23:57       ` DJ Delorie
  2 siblings, 0 replies; 34+ messages in thread
From: DJ Delorie @ 2009-10-16 18:22 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gcc-patches


In m32c, Pmode and "int" are HImode.  So it's not a "C unsigned math"
bug, it's a pointer signedness issue.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-16 14:19     ` Ulrich Weigand
  2009-10-16 18:22       ` DJ Delorie
@ 2009-10-16 22:05       ` DJ Delorie
  2009-10-19 14:28         ` Ulrich Weigand
  2009-10-16 23:57       ` DJ Delorie
  2 siblings, 1 reply; 34+ messages in thread
From: DJ Delorie @ 2009-10-16 22:05 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gcc-patches


Found it, bug in expr.c:

Index: expr.c
===================================================================
--- expr.c	(revision 152895)
+++ expr.c	(working copy)
@@ -4248,13 +4248,13 @@ expand_assignment (tree to, tree from, b
 	    }
 
 	  offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 	  address_mode
 	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx));
 	  if (GET_MODE (offset_rtx) != address_mode)
-	    offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+	    offset_rtx = convert_to_mode (address_mode, offset_rtx, POINTERS_EXTEND_UNSIGNED);
 
 	  /* A constant address in TO_RTX can have VOIDmode, we must not try
 	     to call force_reg for that case.  Avoid that case.  */
 	  if (MEM_P (to_rtx)
 	      && GET_MODE (to_rtx) == BLKmode
 	      && GET_MODE (XEXP (to_rtx, 0)) != VOIDmode


M32c generates happy code now:

_lde_qi_array:                           
        mov.w   r1,a0                    ; 2                            movhi_op/3
        mov.b   _near_char_array[a0],r0l ; 11                           movqi_op/7
        lde.b   r0l,_far_char_array[a0]  ; 12                           movqi_op/1
        rts                              ; 18                           epilogue_rts

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-16 14:19     ` Ulrich Weigand
  2009-10-16 18:22       ` DJ Delorie
  2009-10-16 22:05       ` DJ Delorie
@ 2009-10-16 23:57       ` DJ Delorie
  2009-10-19 14:50         ` Ulrich Weigand
  2 siblings, 1 reply; 34+ messages in thread
From: DJ Delorie @ 2009-10-16 23:57 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gcc-patches


Trying to compile this:

extern char __far far_char_array[50];
void
far_array_set (int i)
{
  far_char_array[i+10] = 0;
}


How do I tell gcc which registers are legal base registers for the
__far addressing mode?  It tries $a1 and $r0, but only $a0 is allowed.

It works just fine without the "__far", and in fact chooses $a0
although $a1 *would* work then.


dj.c:76:1: error: unrecognizable insn:
(insn 19 18 13 2 dj.c:75 (set (mem/s/j:QI (plus:SI (reg:SI 0 r0)
                (symbol_ref:SI ("far_char_array") [flags 0x40] <var_decl 0xb8050170 far_char_array>)) [0 far_char_array S1 A8 AS1])
        (reg:QI 2 r1)) -1 (nil))


This is the pattern I want, aside from the use of $a1:

(mem/s/j:QI (plus:SI (zero_extend:SI (plus:HI (reg/v:HI 5 a1 [orig:26 i ] [26])
                (const_int 10 [0xa])))
        (symbol_ref:SI ("far_char_array") [flags 0x40] <var_decl 0xb8050170 far_char_array>)) [0 far_char_array S1 A8 AS1])

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-16 22:05       ` DJ Delorie
@ 2009-10-19 14:28         ` Ulrich Weigand
  2009-10-19 14:36           ` Richard Guenther
  0 siblings, 1 reply; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-19 14:28 UTC (permalink / raw)
  To: DJ Delorie; +Cc: gcc-patches

DJ Delorie wrote:

> Found it, bug in expr.c:
> 
> Index: expr.c
> ===================================================================
> --- expr.c	(revision 152895)
> +++ expr.c	(working copy)
> @@ -4248,13 +4248,13 @@ expand_assignment (tree to, tree from, b
>  	    }
>  
>  	  offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
>  	  address_mode
>  	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx));
>  	  if (GET_MODE (offset_rtx) != address_mode)
> -	    offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
> +	    offset_rtx = convert_to_mode (address_mode, offset_rtx, POINTERS_EXTEND_UNSIGNED);

I'm not sure POINTERS_EXTEND_UNSIGNED is the correct test here; the offset
is not itself a pointer type.  What if the offset actually *is* a negative
value of a smaller, signed type?

Maybe this should take the signed-ness of the type of "offset" into
account instead.

(B.t.w. there are more instances of computing address offsets that should
probably be handled analogously.  Look for other instances of offset_address
in expr.c ...)

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-19 14:28         ` Ulrich Weigand
@ 2009-10-19 14:36           ` Richard Guenther
  2009-10-19 17:45             ` Ulrich Weigand
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Guenther @ 2009-10-19 14:36 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: DJ Delorie, gcc-patches

On Mon, Oct 19, 2009 at 4:24 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> DJ Delorie wrote:
>
>> Found it, bug in expr.c:
>>
>> Index: expr.c
>> ===================================================================
>> --- expr.c    (revision 152895)
>> +++ expr.c    (working copy)
>> @@ -4248,13 +4248,13 @@ expand_assignment (tree to, tree from, b
>>           }
>>
>>         offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
>>         address_mode
>>           = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx));
>>         if (GET_MODE (offset_rtx) != address_mode)
>> -         offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
>> +         offset_rtx = convert_to_mode (address_mode, offset_rtx, POINTERS_EXTEND_UNSIGNED);
>
> I'm not sure POINTERS_EXTEND_UNSIGNED is the correct test here; the offset
> is not itself a pointer type.  What if the offset actually *is* a negative
> value of a smaller, signed type?

If the above is expanding a POINTER_PLUS_EXPR then the offset
needs to be extended as _signed_ always, independent of the
sign of sizetype which is the type of the offset (as sizetypes
are always sign-extended).

Richard.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-16 23:57       ` DJ Delorie
@ 2009-10-19 14:50         ` Ulrich Weigand
  2009-10-29 18:37           ` [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch) Ulrich Weigand
  0 siblings, 1 reply; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-19 14:50 UTC (permalink / raw)
  To: DJ Delorie; +Cc: gcc-patches

DJ Delorie wrote:

> How do I tell gcc which registers are legal base registers for the
> __far addressing mode?  It tries $a1 and $r0, but only $a0 is allowed.
> 
> It works just fine without the "__far", and in fact chooses $a0
> although $a1 *would* work then.

As far as I can see, there's two things to consider:

- The legitimate_address target macro, when called in "strict" mode,
  must refuse addresses that use invalid base registers for the
  given address space.

- The base_reg_class and ok_for_base_p_1 routines in addresses.h should
  take the target address space into account.

The first should be easily doable with the current address-space-aware
variant of legitimate_address.

The second, however, seems to require additional changes:  the callers
of the base_reg_class / ok_for_base_p_1 routines need to be adapted to
pass the address space, and we need to define new target macros as
variants of MODE_CODE_BASE_REG_CLASS / REGNO_MODE_CODE_OK_FOR_BASE_P
that take an address space.

I probably missed this as on the spu, non-generic space addresses
never survive past "expand" in any case ...

Can you try implementing a change along those lines?  Or, if you prefer,
I can come up with a patch.

(As a work-around for now, you could just restrict the implementation of
the OK_FOR_BASE / BASE_REG_CLASS macros for your target to the set of
registers allowed for any address space.)

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-19 14:36           ` Richard Guenther
@ 2009-10-19 17:45             ` Ulrich Weigand
  2009-10-19 20:57               ` DJ Delorie
  0 siblings, 1 reply; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-19 17:45 UTC (permalink / raw)
  To: Richard Guenther; +Cc: DJ Delorie, gcc-patches

Richard Guenther wrote:

> On Mon, Oct 19, 2009 at 4:24 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> > I'm not sure POINTERS_EXTEND_UNSIGNED is the correct test here; the offset
> > is not itself a pointer type.  What if the offset actually *is* a negative
> > value of a smaller, signed type?
> 
> If the above is expanding a POINTER_PLUS_EXPR then the offset
> needs to be extended as _signed_ always, independent of the
> sign of sizetype which is the type of the offset (as sizetypes
> are always sign-extended).

It's not a POINTER_PLUS_EXPR as such; we're expanding a component
access as handled by get_inner_reference here.  But it seems this
still results in an offset of type "sizetype".

It may be the problem is indeed that in DJ's situation, sizetype is
a 16-bit integer type, while (__far) pointers are of a wider type.
Is this supposed to be supported?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-19 17:45             ` Ulrich Weigand
@ 2009-10-19 20:57               ` DJ Delorie
  2009-10-20  9:27                 ` Richard Guenther
  0 siblings, 1 reply; 34+ messages in thread
From: DJ Delorie @ 2009-10-19 20:57 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: richard.guenther, gcc-patches


> It may be the problem is indeed that in DJ's situation, sizetype is
> a 16-bit integer type, while (__far) pointers are of a wider type.

Indeed, m32c has a lot of problems with the "size types size extend"
rule, because it's not always right.  Size types should extend to
pointer size according to their native signedness, *then* extend
signed if needed.  In m32c, size types are smaller than pointer types
(it's a hardware limitation) but the chip only supports unsigned
offsets.

The "size types sign extend" rule is why I had to disable one of the
loop optimizers - the sign-extend rule meant that pointer math to
replace the IVs was almost always wrong.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-19 20:57               ` DJ Delorie
@ 2009-10-20  9:27                 ` Richard Guenther
  2009-10-20 18:10                   ` DJ Delorie
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Guenther @ 2009-10-20  9:27 UTC (permalink / raw)
  To: DJ Delorie; +Cc: Ulrich Weigand, gcc-patches

On Mon, Oct 19, 2009 at 10:18 PM, DJ Delorie <dj@redhat.com> wrote:
>
>> It may be the problem is indeed that in DJ's situation, sizetype is
>> a 16-bit integer type, while (__far) pointers are of a wider type.
>
> Indeed, m32c has a lot of problems with the "size types size extend"
> rule, because it's not always right.  Size types should extend to
> pointer size according to their native signedness, *then* extend
> signed if needed.

I don't think this observation is correct.  sizetypes are _always_
sign-extended.  At least this is how it is implemented for constants
since forever and of course deviating for non-constants would
be bogus here.

Richard.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-20  9:27                 ` Richard Guenther
@ 2009-10-20 18:10                   ` DJ Delorie
  2009-10-21 10:20                     ` Richard Guenther
  0 siblings, 1 reply; 34+ messages in thread
From: DJ Delorie @ 2009-10-20 18:10 UTC (permalink / raw)
  To: Richard Guenther; +Cc: uweigand, gcc-patches


> I don't think this observation is correct.  sizetypes are _always_
> sign-extended.

The problem on m32c is like this: size_t is HImode, pointers are
PSImode (24 bits).  Loop optimization sees this:

	char *p = x;
	for (i=0; i<j; i++)
	  *p++ = n;

It replaces the 'i' loop with a 'p'-based loop.  It pre-calculates the
end value of 'p'.  However, it sign extends 'j' before adding it to
'p', or worse, casts 'p' to size_t, does the math, the re-casts it
back to a pointer.

Thus, you end up with the termination value of 'p' being truncated or
mis-computed, and the loop overruns.

My preference is this: pointers and integers are NOT interchangable.
Pointer offsets must be sign or zero extended according to their
underlying types before being added to pointers.  If I add -1 to a
pointer, it had better result in a pointer that's one less than the
previous value, not 65536 more.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-20 18:10                   ` DJ Delorie
@ 2009-10-21 10:20                     ` Richard Guenther
  2009-10-27 18:32                       ` Ulrich Weigand
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Guenther @ 2009-10-21 10:20 UTC (permalink / raw)
  To: DJ Delorie; +Cc: uweigand, gcc-patches

On Tue, Oct 20, 2009 at 8:09 PM, DJ Delorie <dj@redhat.com> wrote:
>
>> I don't think this observation is correct.  sizetypes are _always_
>> sign-extended.
>
> The problem on m32c is like this: size_t is HImode, pointers are
> PSImode (24 bits).  Loop optimization sees this:
>
>        char *p = x;
>        for (i=0; i<j; i++)
>          *p++ = n;
>
> It replaces the 'i' loop with a 'p'-based loop.  It pre-calculates the
> end value of 'p'.  However, it sign extends 'j' before adding it to
> 'p', or worse, casts 'p' to size_t, does the math, the re-casts it
> back to a pointer.
>
> Thus, you end up with the termination value of 'p' being truncated or
> mis-computed, and the loop overruns.
>
> My preference is this: pointers and integers are NOT interchangable.
> Pointer offsets must be sign or zero extended according to their
> underlying types before being added to pointers.  If I add -1 to a
> pointer, it had better result in a pointer that's one less than the
> previous value, not 65536 more.

Well, you are right.  sizetype originally only was present in sizetype-only
operations where the above would not have been an issue.  Now
with POINTER_PLUS_EXPR we introduced a mixed-type operation
between pointer types and sizetype - which was obviously a mistake.
Thus, the correct thing to do is to transition POINTER_PLUS_EXPR
away from using sizetype but instead use regular integer types for
the offset (I'm not sure if constraining the offset type to a single type
was a good idea - it probably was good to catch transition errors).

But I don't see anyone doing the required work.

Richard.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-21 10:20                     ` Richard Guenther
@ 2009-10-27 18:32                       ` Ulrich Weigand
  2009-10-28 11:29                         ` Richard Guenther
  0 siblings, 1 reply; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-27 18:32 UTC (permalink / raw)
  To: Richard Guenther; +Cc: DJ Delorie, gcc-patches

Richard Guenther wrote:

> On Tue, Oct 20, 2009 at 8:09 PM, DJ Delorie <dj@redhat.com> wrote:
> > My preference is this: pointers and integers are NOT interchangable.
> > Pointer offsets must be sign or zero extended according to their
> > underlying types before being added to pointers.  If I add -1 to a
> > pointer, it had better result in a pointer that's one less than the
> > previous value, not 65536 more.
> 
> Well, you are right.  sizetype originally only was present in sizetype-only
> operations where the above would not have been an issue.  Now
> with POINTER_PLUS_EXPR we introduced a mixed-type operation
> between pointer types and sizetype - which was obviously a mistake.
> Thus, the correct thing to do is to transition POINTER_PLUS_EXPR
> away from using sizetype but instead use regular integer types for
> the offset (I'm not sure if constraining the offset type to a single type
> was a good idea - it probably was good to catch transition errors).

I now seem to be running into a related problem with __ea on SPU, in a 
loop where the loop optimizer decides to use a DImode IV to implement
a 64-bit __ea pointer.

This causes create_mem_ref to be called with an affine combination
that contains only a single value, of 64-bit integral type.

Because this is not a pointer type, addr_to_parts interprets this
value as "index", not "base".  (I'm not quite sure I understand
how this is intended to work anyway: it seems to me that loop IVs
use (nearly?) always integral types.  Why does move_pointer_to_base
check for pointer type then?)

But add_to_parts will always convert "index" to sizetype.  In the
case where the incoming type is larger than sizetype, this leads
to the value being silently truncated.  This behaviour seems to
be mandated by the definition of TARGET_MEM_REF, which currently
requires all elements (except base) to be of type sizetype ...
 
> But I don't see anyone doing the required work.

I guess I can try to look into this.  Do you have any further
suggestions what needs to be done?

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-27 18:32                       ` Ulrich Weigand
@ 2009-10-28 11:29                         ` Richard Guenther
  2009-10-29 18:32                           ` Fix PR tree-optimization/41857 (Re: m32c support for named addr spaces branch) Ulrich Weigand
  2009-10-30 15:55                           ` m32c support for named addr spaces branch Ulrich Weigand
  0 siblings, 2 replies; 34+ messages in thread
From: Richard Guenther @ 2009-10-28 11:29 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: DJ Delorie, gcc-patches

On Tue, Oct 27, 2009 at 7:22 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> Richard Guenther wrote:
>
>> On Tue, Oct 20, 2009 at 8:09 PM, DJ Delorie <dj@redhat.com> wrote:
>> > My preference is this: pointers and integers are NOT interchangable.
>> > Pointer offsets must be sign or zero extended according to their
>> > underlying types before being added to pointers.  If I add -1 to a
>> > pointer, it had better result in a pointer that's one less than the
>> > previous value, not 65536 more.
>>
>> Well, you are right.  sizetype originally only was present in sizetype-only
>> operations where the above would not have been an issue.  Now
>> with POINTER_PLUS_EXPR we introduced a mixed-type operation
>> between pointer types and sizetype - which was obviously a mistake.
>> Thus, the correct thing to do is to transition POINTER_PLUS_EXPR
>> away from using sizetype but instead use regular integer types for
>> the offset (I'm not sure if constraining the offset type to a single type
>> was a good idea - it probably was good to catch transition errors).
>
> I now seem to be running into a related problem with __ea on SPU, in a
> loop where the loop optimizer decides to use a DImode IV to implement
> a 64-bit __ea pointer.
>
> This causes create_mem_ref to be called with an affine combination
> that contains only a single value, of 64-bit integral type.
>
> Because this is not a pointer type, addr_to_parts interprets this
> value as "index", not "base".  (I'm not quite sure I understand
> how this is intended to work anyway: it seems to me that loop IVs
> use (nearly?) always integral types.  Why does move_pointer_to_base
> check for pointer type then?)
>
> But add_to_parts will always convert "index" to sizetype.  In the
> case where the incoming type is larger than sizetype, this leads
> to the value being silently truncated.  This behaviour seems to
> be mandated by the definition of TARGET_MEM_REF, which currently
> requires all elements (except base) to be of type sizetype ...
>
>> But I don't see anyone doing the required work.
>
> I guess I can try to look into this.  Do you have any further
> suggestions what needs to be done?

No.  The main issue is forcing all pointer offsets to sizetype
by POINTER_PLUS_EXPR (and TARGET_MEM_REF as you
noticed).  I expect that most of the fallout if you remove this
restriction and allow arbitrary integer types as offset will
be in fold and ivopts.  I would expect that it also might uncover
missing canonicalization for constant offsets and thus
missed CSE opportunities at the tree level for example.

You will also hit the interesting case that you'd need to do
type promotion in the middle-end if you want to re-associate
for example (ptr + short) + int (which would be valid then).

Thus, I would allow any offset type for POINTER_PLUS_EXPR
but define precisely how it is supposed to be expanded.
Which would be (implicitly) sign-/zero-extend the offset
according to its signedness to pointer width and then
perform the addition.  So the short + int case would have
to be promoted the same, (intptr_t)short + (intptr_t)int.

Thanks for considering to do the work!

Richard.

> Thanks,
> Ulrich
>
> --
>  Dr. Ulrich Weigand
>  GNU Toolchain for Linux on System z and Cell BE
>  Ulrich.Weigand@de.ibm.com
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Fix PR tree-optimization/41857 (Re: m32c support for named addr spaces branch)
  2009-10-28 11:29                         ` Richard Guenther
@ 2009-10-29 18:32                           ` Ulrich Weigand
  2009-10-30  9:51                             ` Richard Guenther
  2009-10-30 15:55                           ` m32c support for named addr spaces branch Ulrich Weigand
  1 sibling, 1 reply; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-29 18:32 UTC (permalink / raw)
  To: Richard Guenther; +Cc: DJ Delorie, gcc-patches

> On Tue, Oct 27, 2009 at 7:22 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> > I now seem to be running into a related problem with __ea on SPU, in a
> > loop where the loop optimizer decides to use a DImode IV to implement
> > a 64-bit __ea pointer.
> >
> > This causes create_mem_ref to be called with an affine combination
> > that contains only a single value, of 64-bit integral type.
> >
> > Because this is not a pointer type, addr_to_parts interprets this
> > value as "index", not "base".  (I'm not quite sure I understand
> > how this is intended to work anyway: it seems to me that loop IVs
> > use (nearly?) always integral types.  Why does move_pointer_to_base
> > check for pointer type then?)

I've now opened PR 41857 for this particular problem.

The core problem in this case is that pointers may be converted to
sizetype by loop IV optimizations.  This is particularly aggravated
by the fact that create_mem_ref has a hard time determining which
of the variables in the affine expression it gets as input
represents the base of the reference.

The heuristics used to determine this looks for variables of pointer
type.  However, due to problems related to undefined overflow, the
IV optimizations have switched to always using integer types for
induction variables, even those that represent memory addresses.
This makes the create_mem_ref heuristics mostly useless in many
cases ...

However, rewrite_use_address (the call site of create_mem_ref) does
actually have the information; it knows whether the IV candidate
is based on a memory object.  The information is simply not passed
to create_mem_ref.  The patch below changes this by adding a new
BASE_HINT argument to create_mem_ref, which is set to the IV that
is to be used as base of the reference, if any.

create_mem_ref and its subroutines then use this variable (casted
to the appropriate pointer type) as base.

As a side effect, the patch also fixes a FIXME in
most_expensive_mult_to_index.

While not a complete fix to the general sizetype problem, this
patch fixes the ICE-on-valid bug on the testcase in the PR, and
it seems a good idea to properly identify the base anyway; this
is needed (or at least beneficial) on some platforms.

Tested on s390x-ibm-linux and spu-elf.
OK for mainline?

Bye,
Ulrich


ChangeLog:

gcc/
	PR tree-optimization/41857
	* tree-flow.h (rewrite_use_address): Add BASE_HINT argument.
	* tree-ssa-loop-ivopts.c (rewrite_use_address): Pass base hint
	to create_mem_ref.
	* tree-ssa-address.c (move_hint_to_base): New function.
	(most_expensive_mult_to_index): Add TYPE argument.  Use mode and
	address space associated with TYPE.
	(addr_to_parts): Add TYPE and BASE_HINT arguments.  Pass TYPE to
	most_expensive_mult_to_index.  Call move_hint_to_base.
	(create_mem_ref): Add BASE_HINT argument.  Pass BASE_HINT and
	TYPE to addr_to_parts.

gcc/testsuite/
	PR tree-optimization/41857
	* gcc.target/spu/ea/pr41857.c: New file.


Index: gcc/tree-ssa-loop-ivopts.c
===================================================================
*** gcc/tree-ssa-loop-ivopts.c	(revision 153683)
--- gcc/tree-ssa-loop-ivopts.c	(working copy)
*************** rewrite_use_address (struct ivopts_data 
*** 5510,5515 ****
--- 5510,5516 ----
  {
    aff_tree aff;
    gimple_stmt_iterator bsi = gsi_for_stmt (use->stmt);
+   tree base_hint = NULL_TREE;
    tree ref;
    bool ok;
  
*************** rewrite_use_address (struct ivopts_data 
*** 5517,5523 ****
    gcc_assert (ok);
    unshare_aff_combination (&aff);
  
!   ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff, data->speed);
    copy_ref_info (ref, *use->op_p);
    *use->op_p = ref;
  }
--- 5518,5539 ----
    gcc_assert (ok);
    unshare_aff_combination (&aff);
  
!   /* To avoid undefined overflow problems, all IV candidates use unsigned
!      integer types.  The drawback is that this makes it impossible for
!      create_mem_ref to distinguish an IV that is based on a memory object
!      from one that represents simply an offset.
! 
!      To work around this problem, we pass a hint to create_mem_ref that
!      indicates which variable (if any) in aff is an IV based on a memory
!      object.  Note that we only consider the candidate.  If this is not
!      based on an object, the base of the reference is in some subexpression
!      of the use -- but these will use pointer types, so they are recognized
!      by the create_mem_ref heuristics anyway.  */
!   if (cand->iv->base_object)
!     base_hint = var_at_stmt (data->current_loop, cand, use->stmt);
! 
!   ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff, base_hint,
! 			data->speed);
    copy_ref_info (ref, *use->op_p);
    *use->op_p = ref;
  }
Index: gcc/tree-ssa-address.c
===================================================================
*** gcc/tree-ssa-address.c	(revision 153683)
--- gcc/tree-ssa-address.c	(working copy)
*************** move_fixed_address_to_symbol (struct mem
*** 392,397 ****
--- 392,424 ----
    aff_combination_remove_elt (addr, i);
  }
  
+ /* If ADDR contains an instance of BASE_HINT, move it to PARTS->base.  */
+ 
+ static void
+ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
+ 		   aff_tree *addr)
+ {
+   unsigned i;
+   tree val = NULL_TREE;
+ 
+   for (i = 0; i < addr->n; i++)
+     {
+       if (!double_int_one_p (addr->elts[i].coef))
+ 	continue;
+ 
+       val = addr->elts[i].val;
+       if (operand_equal_p (val, base_hint, 0))
+ 	break;
+     }
+ 
+   if (i == addr->n)
+     return;
+ 
+   /* Cast value to appropriate pointer type.  */
+   parts->base = fold_convert (build_pointer_type (type), val);
+   aff_combination_remove_elt (addr, i);
+ }
+ 
  /* If ADDR contains an address of a dereferenced pointer, move it to
     PARTS->base.  */
  
*************** add_to_parts (struct mem_address *parts,
*** 453,461 ****
     element(s) to PARTS.  */
  
  static void
! most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
! 			      bool speed)
  {
    HOST_WIDE_INT coef;
    double_int best_mult, amult, amult_neg;
    unsigned best_mult_cost = 0, acost;
--- 480,490 ----
     element(s) to PARTS.  */
  
  static void
! most_expensive_mult_to_index (tree type, struct mem_address *parts,
! 			      aff_tree *addr, bool speed)
  {
+   addr_space_t as = TYPE_ADDR_SPACE (type);
+   enum machine_mode address_mode = targetm.addr_space.address_mode (as);
    HOST_WIDE_INT coef;
    double_int best_mult, amult, amult_neg;
    unsigned best_mult_cost = 0, acost;
*************** most_expensive_mult_to_index (struct mem
*** 469,483 ****
        if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
  	continue;
  
-       /* FIXME: Should use the correct memory mode rather than Pmode.  */
- 
        coef = double_int_to_shwi (addr->elts[i].coef);
        if (coef == 1
! 	  || !multiplier_allowed_in_address_p (coef, Pmode,
! 					       ADDR_SPACE_GENERIC))
  	continue;
  
!       acost = multiply_by_cost (coef, Pmode, speed);
  
        if (acost > best_mult_cost)
  	{
--- 498,509 ----
        if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
  	continue;
  
        coef = double_int_to_shwi (addr->elts[i].coef);
        if (coef == 1
! 	  || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
  	continue;
  
!       acost = multiply_by_cost (coef, address_mode, speed);
  
        if (acost > best_mult_cost)
  	{
*************** most_expensive_mult_to_index (struct mem
*** 520,527 ****
    parts->step = double_int_to_tree (sizetype, best_mult);
  }
  
! /* Splits address ADDR into PARTS.
!    
     TODO -- be more clever about the distribution of the elements of ADDR
     to PARTS.  Some architectures do not support anything but single
     register in address, possibly with a small integer offset; while
--- 546,555 ----
    parts->step = double_int_to_tree (sizetype, best_mult);
  }
  
! /* Splits address ADDR for a memory access of type TYPE into PARTS.
!    If BASE_HINT is non-NULL, it specifies an SSA name to be used
!    preferentially as base of the reference.
! 
     TODO -- be more clever about the distribution of the elements of ADDR
     to PARTS.  Some architectures do not support anything but single
     register in address, possibly with a small integer offset; while
*************** most_expensive_mult_to_index (struct mem
*** 530,536 ****
     addressing modes is useless.  */
  
  static void
! addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
  {
    tree part;
    unsigned i;
--- 558,565 ----
     addressing modes is useless.  */
  
  static void
! addr_to_parts (tree type, aff_tree *addr, tree base_hint,
! 	       struct mem_address *parts, bool speed)
  {
    tree part;
    unsigned i;
*************** addr_to_parts (aff_tree *addr, struct me
*** 550,561 ****
  
    /* First move the most expensive feasible multiplication
       to index.  */
!   most_expensive_mult_to_index (parts, addr, speed);
  
    /* Try to find a base of the reference.  Since at the moment
       there is no reliable way how to distinguish between pointer and its
       offset, this is just a guess.  */
!   if (!parts->symbol)
      move_pointer_to_base (parts, addr);
  
    /* Then try to process the remaining elements.  */
--- 579,592 ----
  
    /* First move the most expensive feasible multiplication
       to index.  */
!   most_expensive_mult_to_index (type, parts, addr, speed);
  
    /* Try to find a base of the reference.  Since at the moment
       there is no reliable way how to distinguish between pointer and its
       offset, this is just a guess.  */
!   if (!parts->symbol && base_hint)
!     move_hint_to_base (type, parts, base_hint, addr);
!   if (!parts->symbol && !parts->base)
      move_pointer_to_base (parts, addr);
  
    /* Then try to process the remaining elements.  */
*************** gimplify_mem_ref_parts (gimple_stmt_iter
*** 592,604 ****
  
  tree
  create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
! 		bool speed)
  {
    tree mem_ref, tmp;
    tree atype;
    struct mem_address parts;
  
!   addr_to_parts (addr, &parts, speed);
    gimplify_mem_ref_parts (gsi, &parts);
    mem_ref = create_mem_ref_raw (type, &parts);
    if (mem_ref)
--- 623,635 ----
  
  tree
  create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
! 		tree base_hint, bool speed)
  {
    tree mem_ref, tmp;
    tree atype;
    struct mem_address parts;
  
!   addr_to_parts (type, addr, base_hint, &parts, speed);
    gimplify_mem_ref_parts (gsi, &parts);
    mem_ref = create_mem_ref_raw (type, &parts);
    if (mem_ref)
Index: gcc/tree-flow.h
===================================================================
*** gcc/tree-flow.h	(revision 153683)
--- gcc/tree-flow.h	(working copy)
*************** struct mem_address
*** 921,927 ****
  
  struct affine_tree_combination;
  tree create_mem_ref (gimple_stmt_iterator *, tree, 
! 		     struct affine_tree_combination *, bool);
  rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool);
  void get_address_description (tree, struct mem_address *);
  tree maybe_fold_tmr (tree);
--- 921,927 ----
  
  struct affine_tree_combination;
  tree create_mem_ref (gimple_stmt_iterator *, tree, 
! 		     struct affine_tree_combination *, tree, bool);
  rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool);
  void get_address_description (tree, struct mem_address *);
  tree maybe_fold_tmr (tree);
*** /dev/null	2009-10-07 18:17:03.469375344 +0200
--- gcc/testsuite/gcc.target/spu/ea/pr41857.c	2009-10-29 14:11:18.000000000 +0100
***************
*** 0 ****
--- 1,29 ----
+ /* Copyright (C) 2009 Free Software Foundation, Inc.
+ 
+    This file is free software; you can redistribute it and/or modify it under
+    the terms of the GNU General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your option)
+    any later version.
+ 
+    This file is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this file; see the file COPYING3.  If not see
+    <http://www.gnu.org/licenses/>.  */
+ 
+ /* { dg-do compile } */
+ 
+ __ea char *strchr_ea (__ea const char *s, int c);
+ __ea char *foo (__ea char *s)
+ {
+   __ea char *ret = s;
+   int i;
+ 
+   for (i = 0; i < 3; i++)
+     ret = strchr_ea (ret, s[i]);
+  
+   return ret;
+ }


-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch)
  2009-10-19 14:50         ` Ulrich Weigand
@ 2009-10-29 18:37           ` Ulrich Weigand
  2009-10-29 19:54             ` DJ Delorie
  2009-10-29 20:18             ` DJ Delorie
  0 siblings, 2 replies; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-29 18:37 UTC (permalink / raw)
  To: dj; +Cc: gcc-patches

> DJ Delorie wrote:
> 
> > How do I tell gcc which registers are legal base registers for the
> > __far addressing mode?  It tries $a1 and $r0, but only $a0 is allowed.
> > 
> > It works just fine without the "__far", and in fact chooses $a0
> > although $a1 *would* work then.
> 
> As far as I can see, there's two things to consider:
> 
> - The legitimate_address target macro, when called in "strict" mode,
>   must refuse addresses that use invalid base registers for the
>   given address space.
> 
> - The base_reg_class and ok_for_base_p_1 routines in addresses.h should
>   take the target address space into account.
> 
> The first should be easily doable with the current address-space-aware
> variant of legitimate_address.
> 
> The second, however, seems to require additional changes:  the callers
> of the base_reg_class / ok_for_base_p_1 routines need to be adapted to
> pass the address space, and we need to define new target macros as
> variants of MODE_CODE_BASE_REG_CLASS / REGNO_MODE_CODE_OK_FOR_BASE_P
> that take an address space.

I've now implemented this idea with the following patch.  Could you
try whether this solves the problem for you?

Bye,
Ulrich


ChangeLog:

	* doc/tm.texi (MODE_CODE_BASE_REG_CLASS): Add address space
	argument.
	(REGNO_MODE_CODE_OK_FOR_BASE_P): Likewise.

	* config/cris/cris.h (MODE_CODE_BASE_REG_CLASS): Add address
	space argument.
	(REGNO_MODE_CODE_OK_FOR_BASE_P): Likewise.
	* config/bfin/bfin.h (MODE_CODE_BASE_REG_CLASS): Likewise.
	(REGNO_MODE_CODE_OK_FOR_BASE_P): Likewise.

	* addresses.h (base_reg_class): Add address space argument.
	Pass to MODE_CODE_BASE_REG_CLASS.
	(ok_for_base_p_1): Add address space argument.  Pass to
	REGNO_MODE_CODE_OK_FOR_BASE_P.
	(regno_ok_for_base_p): Add address space argument.  Pass to
	ok_for_base_p_1.

	* regrename.c (scan_rtx_address): Add address space argument.
	Pass address space to regno_ok_for_base_p and base_reg_class.
	Update recursive calls.
	(scan_rtx): Pass address space to scan_rtx_address.
	(build_def_use): Likewise.
	* regcprop.c (replace_oldest_value_addr): Add address space
	argument.  Pass to regno_ok_for_base_p and base_reg_class.
	Update recursive calls.
	(replace_oldest_value_mem): Pass address space to
	replace_oldest_value_addr.
	(copyprop_hardreg_forward_1): Likewise.

	* reload.c (find_reloads_address_1): Add address space argument.
	Pass address space to base_reg_class and regno_ok_for_base_p.
	Update recursive calls.
	(find_reloads_address): Pass address space to base_reg_class,
	regno_ok_for_base_p, and find_reloads_address_1.
	(find_reloads): Pass address space to base_reg_class.
	(find_reloads_subreg_address): Likewise.

	* ira-costs.c (record_reg_classes): Update calls to base_reg_class.
	(ok_for_base_p_nonstrict): Add address space argument.  Pass to
	ok_for_base_p_1.
	(record_address_regs): Add address space argument.  Pass to
	base_reg_class and ok_for_base_p_nonstrict.  Update recursive calls.
	(record_operand_costs): Pass address space to record_address_regs.
	(scan_one_insn): Likewise.

	* caller-save.c (init_caller_save): Update call to base_reg_class.
	* ira-conflicts.c (ira_build_conflicts): Likewise.
	* reload1.c (maybe_fix_stack_asms): Likewise.


Index: gcc/regrename.c
===================================================================
*** gcc/regrename.c	(revision 153564)
--- gcc/regrename.c	(working copy)
*************** static void do_replace (struct du_chain 
*** 83,89 ****
  static void scan_rtx_reg (rtx, rtx *, enum reg_class,
  			  enum scan_actions, enum op_type, int);
  static void scan_rtx_address (rtx, rtx *, enum reg_class,
! 			      enum scan_actions, enum machine_mode);
  static void scan_rtx (rtx, rtx *, enum reg_class, enum scan_actions,
  		      enum op_type, int);
  static struct du_chain *build_def_use (basic_block);
--- 83,90 ----
  static void scan_rtx_reg (rtx, rtx *, enum reg_class,
  			  enum scan_actions, enum op_type, int);
  static void scan_rtx_address (rtx, rtx *, enum reg_class,
! 			      enum scan_actions, enum machine_mode,
! 			      addr_space_t);
  static void scan_rtx (rtx, rtx *, enum reg_class, enum scan_actions,
  		      enum op_type, int);
  static struct du_chain *build_def_use (basic_block);
*************** scan_rtx_reg (rtx insn, rtx *loc, enum r
*** 527,533 ****
  
  static void
  scan_rtx_address (rtx insn, rtx *loc, enum reg_class cl,
! 		  enum scan_actions action, enum machine_mode mode)
  {
    rtx x = *loc;
    RTX_CODE code = GET_CODE (x);
--- 528,535 ----
  
  static void
  scan_rtx_address (rtx insn, rtx *loc, enum reg_class cl,
! 		  enum scan_actions action, enum machine_mode mode,
! 		  addr_space_t as)
  {
    rtx x = *loc;
    RTX_CODE code = GET_CODE (x);
*************** scan_rtx_address (rtx insn, rtx *loc, en
*** 595,609 ****
  	    unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
  
  	    if (REGNO_OK_FOR_INDEX_P (regno1)
! 		&& regno_ok_for_base_p (regno0, mode, PLUS, REG))
  	      index_op = 1;
  	    else if (REGNO_OK_FOR_INDEX_P (regno0)
! 		     && regno_ok_for_base_p (regno1, mode, PLUS, REG))
  	      index_op = 0;
! 	    else if (regno_ok_for_base_p (regno0, mode, PLUS, REG)
  		     || REGNO_OK_FOR_INDEX_P (regno1))
  	      index_op = 1;
! 	    else if (regno_ok_for_base_p (regno1, mode, PLUS, REG))
  	      index_op = 0;
  	    else
  	      index_op = 1;
--- 597,611 ----
  	    unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
  
  	    if (REGNO_OK_FOR_INDEX_P (regno1)
! 		&& regno_ok_for_base_p (regno0, mode, as, PLUS, REG))
  	      index_op = 1;
  	    else if (REGNO_OK_FOR_INDEX_P (regno0)
! 		     && regno_ok_for_base_p (regno1, mode, as, PLUS, REG))
  	      index_op = 0;
! 	    else if (regno_ok_for_base_p (regno0, mode, as, PLUS, REG)
  		     || REGNO_OK_FOR_INDEX_P (regno1))
  	      index_op = 1;
! 	    else if (regno_ok_for_base_p (regno1, mode, as, PLUS, REG))
  	      index_op = 0;
  	    else
  	      index_op = 1;
*************** scan_rtx_address (rtx insn, rtx *loc, en
*** 626,635 ****
  	  }
  
  	if (locI)
! 	  scan_rtx_address (insn, locI, INDEX_REG_CLASS, action, mode);
  	if (locB)
! 	  scan_rtx_address (insn, locB, base_reg_class (mode, PLUS, index_code),
! 			    action, mode);
  
  	return;
        }
--- 628,638 ----
  	  }
  
  	if (locI)
! 	  scan_rtx_address (insn, locI, INDEX_REG_CLASS, action, mode, as);
  	if (locB)
! 	  scan_rtx_address (insn, locB,
! 			    base_reg_class (mode, as, PLUS, index_code),
! 			    action, mode, as);
  
  	return;
        }
*************** scan_rtx_address (rtx insn, rtx *loc, en
*** 649,656 ****
  
      case MEM:
        scan_rtx_address (insn, &XEXP (x, 0),
! 			base_reg_class (GET_MODE (x), MEM, SCRATCH), action,
! 			GET_MODE (x));
        return;
  
      case REG:
--- 652,660 ----
  
      case MEM:
        scan_rtx_address (insn, &XEXP (x, 0),
! 			base_reg_class (GET_MODE (x), MEM_ADDR_SPACE (x),
! 					MEM, SCRATCH),
! 			action, GET_MODE (x), MEM_ADDR_SPACE (x));
        return;
  
      case REG:
*************** scan_rtx_address (rtx insn, rtx *loc, en
*** 665,674 ****
    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
      {
        if (fmt[i] == 'e')
! 	scan_rtx_address (insn, &XEXP (x, i), cl, action, mode);
        else if (fmt[i] == 'E')
  	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
! 	  scan_rtx_address (insn, &XVECEXP (x, i, j), cl, action, mode);
      }
  }
  
--- 669,678 ----
    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
      {
        if (fmt[i] == 'e')
! 	scan_rtx_address (insn, &XEXP (x, i), cl, action, mode, as);
        else if (fmt[i] == 'E')
  	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
! 	  scan_rtx_address (insn, &XVECEXP (x, i, j), cl, action, mode, as);
      }
  }
  
*************** scan_rtx (rtx insn, rtx *loc, enum reg_c
*** 701,708 ****
  
      case MEM:
        scan_rtx_address (insn, &XEXP (x, 0),
! 			base_reg_class (GET_MODE (x), MEM, SCRATCH), action,
! 			GET_MODE (x));
        return;
  
      case SET:
--- 705,713 ----
  
      case MEM:
        scan_rtx_address (insn, &XEXP (x, 0),
! 			base_reg_class (GET_MODE (x), MEM_ADDR_SPACE (x),
! 					MEM, SCRATCH),
! 			action, GET_MODE (x), MEM_ADDR_SPACE (x));
        return;
  
      case SET:
*************** build_def_use (basic_block bb)
*** 891,897 ****
  		continue;
  
  	      if (recog_op_alt[opn][alt].is_address)
! 		scan_rtx_address (insn, loc, cl, mark_read, VOIDmode);
  	      else
  		scan_rtx (insn, loc, cl, mark_read, type, 0);
  	    }
--- 896,903 ----
  		continue;
  
  	      if (recog_op_alt[opn][alt].is_address)
! 		scan_rtx_address (insn, loc, cl, mark_read,
! 				  VOIDmode, ADDR_SPACE_GENERIC);
  	      else
  		scan_rtx (insn, loc, cl, mark_read, type, 0);
  	    }
Index: gcc/doc/tm.texi
===================================================================
*** gcc/doc/tm.texi	(revision 153571)
--- gcc/doc/tm.texi	(working copy)
*************** register address.  You should define thi
*** 2495,2506 ****
  addresses have different requirements than other base register uses.
  @end defmac
  
! @defmac MODE_CODE_BASE_REG_CLASS (@var{mode}, @var{outer_code}, @var{index_code})
  A C expression whose value is the register class to which a valid
! base register must belong.  @var{outer_code} and @var{index_code} define the
! context in which the base register occurs.  @var{outer_code} is the code of
! the immediately enclosing expression (@code{MEM} for the top level of an
! address, @code{ADDRESS} for something that occurs in an
  @code{address_operand}).  @var{index_code} is the code of the corresponding
  index expression if @var{outer_code} is @code{PLUS}; @code{SCRATCH} otherwise.
  @end defmac
--- 2495,2507 ----
  addresses have different requirements than other base register uses.
  @end defmac
  
! @defmac MODE_CODE_BASE_REG_CLASS (@var{mode}, @var{address_space}, @var{outer_code}, @var{index_code})
  A C expression whose value is the register class to which a valid
! base register for a memory reference in mode @var{mode} to address
! space @var{address_space} must belong.  @var{outer_code} and @var{index_code}
! define the context in which the base register occurs.  @var{outer_code} is
! the code of the immediately enclosing expression (@code{MEM} for the top level
! of an address, @code{ADDRESS} for something that occurs in an
  @code{address_operand}).  @var{index_code} is the code of the corresponding
  index expression if @var{outer_code} is @code{PLUS}; @code{SCRATCH} otherwise.
  @end defmac
*************** Use of this macro is deprecated; please 
*** 2555,2562 ****
  This macro also has strict and non-strict variants.
  @end defmac
  
! @defmac REGNO_MODE_CODE_OK_FOR_BASE_P (@var{num}, @var{mode}, @var{outer_code}, @var{index_code})
! A C expression that is just like @code{REGNO_MODE_OK_FOR_BASE_P}, except
  that that expression may examine the context in which the register
  appears in the memory reference.  @var{outer_code} is the code of the
  immediately enclosing expression (@code{MEM} if at the top level of the
--- 2556,2566 ----
  This macro also has strict and non-strict variants.
  @end defmac
  
! @defmac REGNO_MODE_CODE_OK_FOR_BASE_P (@var{num}, @var{mode}, @var{address_space}, @var{outer_code}, @var{index_code})
! A C expression which is nonzero if register number @var{num} is
! suitable for use as a base register in operand addresses, accessing
! memory in mode @var{mode} in address space @var{address_space}.
! This is similar to @code{REGNO_MODE_OK_FOR_BASE_P}, except
  that that expression may examine the context in which the register
  appears in the memory reference.  @var{outer_code} is the code of the
  immediately enclosing expression (@code{MEM} if at the top level of the
Index: gcc/ira-conflicts.c
===================================================================
*** gcc/ira-conflicts.c	(revision 153564)
--- gcc/ira-conflicts.c	(working copy)
*************** ira_debug_conflicts (bool reg_p)
*** 761,766 ****
--- 761,767 ----
  void
  ira_build_conflicts (void)
  {
+   enum reg_class base;
    ira_allocno_t a;
    ira_allocno_iterator ai;
    HARD_REG_SET temp_hard_reg_set;
*************** ira_build_conflicts (void)
*** 787,798 ****
  	  ira_free (conflicts);
  	}
      }
!   if (! CLASS_LIKELY_SPILLED_P (base_reg_class (VOIDmode, ADDRESS, SCRATCH)))
      CLEAR_HARD_REG_SET (temp_hard_reg_set);
    else
      {
!       COPY_HARD_REG_SET (temp_hard_reg_set,
! 			 reg_class_contents[base_reg_class (VOIDmode, ADDRESS, SCRATCH)]);
        AND_COMPL_HARD_REG_SET (temp_hard_reg_set, ira_no_alloc_regs);
        AND_HARD_REG_SET (temp_hard_reg_set, call_used_reg_set);
      }
--- 788,800 ----
  	  ira_free (conflicts);
  	}
      }
! 
!   base = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, ADDRESS, SCRATCH);
!   if (! CLASS_LIKELY_SPILLED_P (base))
      CLEAR_HARD_REG_SET (temp_hard_reg_set);
    else
      {
!       COPY_HARD_REG_SET (temp_hard_reg_set, reg_class_contents[base]);
        AND_COMPL_HARD_REG_SET (temp_hard_reg_set, ira_no_alloc_regs);
        AND_HARD_REG_SET (temp_hard_reg_set, call_used_reg_set);
      }
Index: gcc/reload.c
===================================================================
*** gcc/reload.c	(revision 153564)
--- gcc/reload.c	(working copy)
*************** static int find_reloads_address (enum ma
*** 275,281 ****
  static rtx subst_reg_equivs (rtx, rtx);
  static rtx subst_indexed_address (rtx);
  static void update_auto_inc_notes (rtx, int, int);
! static int find_reloads_address_1 (enum machine_mode, rtx, int,
  				   enum rtx_code, enum rtx_code, rtx *,
  				   int, enum reload_type,int, rtx);
  static void find_reloads_address_part (rtx, rtx *, enum reg_class,
--- 275,281 ----
  static rtx subst_reg_equivs (rtx, rtx);
  static rtx subst_indexed_address (rtx);
  static void update_auto_inc_notes (rtx, int, int);
! static int find_reloads_address_1 (enum machine_mode, addr_space_t, rtx, int,
  				   enum rtx_code, enum rtx_code, rtx *,
  				   int, enum reload_type,int, rtx);
  static void find_reloads_address_part (rtx, rtx *, enum reg_class,
*************** find_reloads (rtx insn, int replace, int
*** 3227,3234 ****
  	      case 'p':
  		/* All necessary reloads for an address_operand
  		   were handled in find_reloads_address.  */
! 		this_alternative[i] = base_reg_class (VOIDmode, ADDRESS,
! 						      SCRATCH);
  		win = 1;
  		badop = 0;
  		break;
--- 3227,3235 ----
  	      case 'p':
  		/* All necessary reloads for an address_operand
  		   were handled in find_reloads_address.  */
! 		this_alternative[i]
! 		  = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
! 				    ADDRESS, SCRATCH);
  		win = 1;
  		badop = 0;
  		break;
*************** find_reloads (rtx insn, int replace, int
*** 3433,3441 ****
  
  			/* If we didn't already win, we can reload
  			   the address into a base register.  */
! 			this_alternative[i] = base_reg_class (VOIDmode,
! 							      ADDRESS,
! 							      SCRATCH);
  			badop = 0;
  			break;
  		      }
--- 3434,3442 ----
  
  			/* If we didn't already win, we can reload
  			   the address into a base register.  */
! 			this_alternative[i]
! 			  = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
! 					    ADDRESS, SCRATCH);
  			badop = 0;
  			break;
  		      }
*************** find_reloads (rtx insn, int replace, int
*** 3989,4006 ****
  	    /* If the address to be reloaded is a VOIDmode constant,
  	       use the default address mode as mode of the reload register,
  	       as would have been done by find_reloads_address.  */
  	    enum machine_mode address_mode;
  	    address_mode = GET_MODE (XEXP (recog_data.operand[i], 0));
  	    if (address_mode == VOIDmode)
! 	      {
! 		addr_space_t as = MEM_ADDR_SPACE (recog_data.operand[i]);
! 		address_mode = targetm.addr_space.address_mode (as);
! 	      }
  
  	    operand_reloadnum[i]
  	      = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX,
  			     &XEXP (recog_data.operand[i], 0), (rtx*) 0,
! 			     base_reg_class (VOIDmode, MEM, SCRATCH),
  			     address_mode,
  			     VOIDmode, 0, 0, i, RELOAD_FOR_INPUT);
  	    rld[operand_reloadnum[i]].inc
--- 3990,4005 ----
  	    /* If the address to be reloaded is a VOIDmode constant,
  	       use the default address mode as mode of the reload register,
  	       as would have been done by find_reloads_address.  */
+ 	    addr_space_t as = MEM_ADDR_SPACE (recog_data.operand[i]);
  	    enum machine_mode address_mode;
  	    address_mode = GET_MODE (XEXP (recog_data.operand[i], 0));
  	    if (address_mode == VOIDmode)
! 	      address_mode = targetm.addr_space.address_mode (as);
  
  	    operand_reloadnum[i]
  	      = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX,
  			     &XEXP (recog_data.operand[i], 0), (rtx*) 0,
! 			     base_reg_class (VOIDmode, as, MEM, SCRATCH),
  			     address_mode,
  			     VOIDmode, 0, 0, i, RELOAD_FOR_INPUT);
  	    rld[operand_reloadnum[i]].inc
*************** find_reloads_address (enum machine_mode 
*** 4897,4903 ****
        if (reg_equiv_constant[regno] != 0)
  	{
  	  find_reloads_address_part (reg_equiv_constant[regno], loc,
! 				     base_reg_class (mode, MEM, SCRATCH),
  				     GET_MODE (ad), opnum, type, ind_levels);
  	  return 1;
  	}
--- 4896,4902 ----
        if (reg_equiv_constant[regno] != 0)
  	{
  	  find_reloads_address_part (reg_equiv_constant[regno], loc,
! 				     base_reg_class (mode, as, MEM, SCRATCH),
  				     GET_MODE (ad), opnum, type, ind_levels);
  	  return 1;
  	}
*************** find_reloads_address (enum machine_mode 
*** 4960,4971 ****
  	 subject of a CLOBBER in this insn.  */
  
        else if (regno < FIRST_PSEUDO_REGISTER
! 	       && regno_ok_for_base_p (regno, mode, MEM, SCRATCH)
  	       && ! regno_clobbered_p (regno, this_insn, mode, 0))
  	return 0;
  
        /* If we do not have one of the cases above, we must do the reload.  */
!       push_reload (ad, NULL_RTX, loc, (rtx*) 0, base_reg_class (mode, MEM, SCRATCH),
  		   GET_MODE (ad), VOIDmode, 0, 0, opnum, type);
        return 1;
      }
--- 4959,4971 ----
  	 subject of a CLOBBER in this insn.  */
  
        else if (regno < FIRST_PSEUDO_REGISTER
! 	       && regno_ok_for_base_p (regno, mode, as, MEM, SCRATCH)
  	       && ! regno_clobbered_p (regno, this_insn, mode, 0))
  	return 0;
  
        /* If we do not have one of the cases above, we must do the reload.  */
!       push_reload (ad, NULL_RTX, loc, (rtx*) 0,
! 		   base_reg_class (mode, as, MEM, SCRATCH),
  		   GET_MODE (ad), VOIDmode, 0, 0, opnum, type);
        return 1;
      }
*************** find_reloads_address (enum machine_mode 
*** 5066,5072 ****
  	  /* Must use TEM here, not AD, since it is the one that will
  	     have any subexpressions reloaded, if needed.  */
  	  push_reload (tem, NULL_RTX, loc, (rtx*) 0,
! 		       base_reg_class (mode, MEM, SCRATCH), GET_MODE (tem),
  		       VOIDmode, 0,
  		       0, opnum, type);
  	  return ! removed_and;
--- 5066,5072 ----
  	  /* Must use TEM here, not AD, since it is the one that will
  	     have any subexpressions reloaded, if needed.  */
  	  push_reload (tem, NULL_RTX, loc, (rtx*) 0,
! 		       base_reg_class (mode, as, MEM, SCRATCH), GET_MODE (tem),
  		       VOIDmode, 0,
  		       0, opnum, type);
  	  return ! removed_and;
*************** find_reloads_address (enum machine_mode 
*** 5084,5090 ****
  	   && REG_P (XEXP (ad, 0))
  	   && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
  	   && CONST_INT_P (XEXP (ad, 1))
! 	   && regno_ok_for_base_p (REGNO (XEXP (ad, 0)), mode, PLUS,
  				   CONST_INT))
  
      {
--- 5084,5090 ----
  	   && REG_P (XEXP (ad, 0))
  	   && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
  	   && CONST_INT_P (XEXP (ad, 1))
! 	   && regno_ok_for_base_p (REGNO (XEXP (ad, 0)), mode, as, PLUS,
  				   CONST_INT))
  
      {
*************** find_reloads_address (enum machine_mode 
*** 5115,5121 ****
  	     reload the sum into a base reg.
  	     That will at least work.  */
  	  find_reloads_address_part (ad, loc,
! 				     base_reg_class (mode, MEM, SCRATCH),
  				     GET_MODE (ad), opnum, type, ind_levels);
  	}
        return ! removed_and;
--- 5115,5121 ----
  	     reload the sum into a base reg.
  	     That will at least work.  */
  	  find_reloads_address_part (ad, loc,
! 				     base_reg_class (mode, as, MEM, SCRATCH),
  				     GET_MODE (ad), opnum, type, ind_levels);
  	}
        return ! removed_and;
*************** find_reloads_address (enum machine_mode 
*** 5167,5173 ****
  
        addend = XEXP (XEXP (ad, 0), 1 - op_index);
  
!       if ((regno_ok_for_base_p (REGNO (operand), mode, inner_code,
  				GET_CODE (addend))
  	   || operand == frame_pointer_rtx
  #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
--- 5167,5173 ----
  
        addend = XEXP (XEXP (ad, 0), 1 - op_index);
  
!       if ((regno_ok_for_base_p (REGNO (operand), mode, as, inner_code,
  				GET_CODE (addend))
  	   || operand == frame_pointer_rtx
  #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
*************** find_reloads_address (enum machine_mode 
*** 5196,5206 ****
  				 op_index == 0 ? addend : offset_reg);
  	  *loc = ad;
  
! 	  cls = base_reg_class (mode, MEM, GET_CODE (addend));
  	  find_reloads_address_part (XEXP (ad, op_index), 
  				     &XEXP (ad, op_index), cls,
  				     GET_MODE (ad), opnum, type, ind_levels);
! 	  find_reloads_address_1 (mode,
  				  XEXP (ad, 1 - op_index), 1, GET_CODE (ad),
  				  GET_CODE (XEXP (ad, op_index)),
  				  &XEXP (ad, 1 - op_index), opnum,
--- 5196,5206 ----
  				 op_index == 0 ? addend : offset_reg);
  	  *loc = ad;
  
! 	  cls = base_reg_class (mode, as, MEM, GET_CODE (addend));
  	  find_reloads_address_part (XEXP (ad, op_index), 
  				     &XEXP (ad, op_index), cls,
  				     GET_MODE (ad), opnum, type, ind_levels);
! 	  find_reloads_address_1 (mode, as,
  				  XEXP (ad, 1 - op_index), 1, GET_CODE (ad),
  				  GET_CODE (XEXP (ad, op_index)),
  				  &XEXP (ad, 1 - op_index), opnum,
*************** find_reloads_address (enum machine_mode 
*** 5253,5265 ****
  	    loc = &XEXP (*loc, 0);
  	}
  
!       find_reloads_address_part (ad, loc, base_reg_class (mode, MEM, SCRATCH),
  				 address_mode, opnum, type, ind_levels);
        return ! removed_and;
      }
  
!   return find_reloads_address_1 (mode, ad, 0, MEM, SCRATCH, loc, opnum, type,
! 				 ind_levels, insn);
  }
  \f
  /* Find all pseudo regs appearing in AD
--- 5253,5266 ----
  	    loc = &XEXP (*loc, 0);
  	}
  
!       find_reloads_address_part (ad, loc,
! 				 base_reg_class (mode, as, MEM, SCRATCH),
  				 address_mode, opnum, type, ind_levels);
        return ! removed_and;
      }
  
!   return find_reloads_address_1 (mode, as, ad, 0, MEM, SCRATCH, loc,
! 				 opnum, type, ind_levels, insn);
  }
  \f
  /* Find all pseudo regs appearing in AD
*************** update_auto_inc_notes (rtx insn ATTRIBUT
*** 5492,5505 ****
     handles those cases gracefully.  */
  
  static int
! find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
  			enum rtx_code outer_code, enum rtx_code index_code,
  			rtx *loc, int opnum, enum reload_type type,
  			int ind_levels, rtx insn)
  {
! #define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE, OUTER, INDEX)		\
    ((CONTEXT) == 0							\
!    ? regno_ok_for_base_p (REGNO, MODE, OUTER, INDEX)			\
     : REGNO_OK_FOR_INDEX_P (REGNO))					
  
    enum reg_class context_reg_class;
--- 5493,5507 ----
     handles those cases gracefully.  */
  
  static int
! find_reloads_address_1 (enum machine_mode mode, addr_space_t as,
! 			rtx x, int context,
  			enum rtx_code outer_code, enum rtx_code index_code,
  			rtx *loc, int opnum, enum reload_type type,
  			int ind_levels, rtx insn)
  {
! #define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE, AS, OUTER, INDEX)	\
    ((CONTEXT) == 0							\
!    ? regno_ok_for_base_p (REGNO, MODE, AS, OUTER, INDEX)		\
     : REGNO_OK_FOR_INDEX_P (REGNO))					
  
    enum reg_class context_reg_class;
*************** find_reloads_address_1 (enum machine_mod
*** 5508,5514 ****
    if (context == 1)
      context_reg_class = INDEX_REG_CLASS;
    else
!     context_reg_class = base_reg_class (mode, outer_code, index_code);
  
    switch (code)
      {
--- 5510,5516 ----
    if (context == 1)
      context_reg_class = INDEX_REG_CLASS;
    else
!     context_reg_class = base_reg_class (mode, as, outer_code, index_code);
  
    switch (code)
      {
*************** find_reloads_address_1 (enum machine_mod
*** 5565,5574 ****
  	if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
  	    || code0 == ZERO_EXTEND || code1 == MEM)
  	  {
! 	    find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
  				    &XEXP (x, 0), opnum, type, ind_levels,
  				    insn);
! 	    find_reloads_address_1 (mode, orig_op1, 0, PLUS, code0,
  				    &XEXP (x, 1), opnum, type, ind_levels,
  				    insn);
  	  }
--- 5567,5576 ----
  	if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
  	    || code0 == ZERO_EXTEND || code1 == MEM)
  	  {
! 	    find_reloads_address_1 (mode, as, orig_op0, 1, PLUS, SCRATCH,
  				    &XEXP (x, 0), opnum, type, ind_levels,
  				    insn);
! 	    find_reloads_address_1 (mode, as, orig_op1, 0, PLUS, code0,
  				    &XEXP (x, 1), opnum, type, ind_levels,
  				    insn);
  	  }
*************** find_reloads_address_1 (enum machine_mod
*** 5576,5631 ****
  	else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
  		 || code1 == ZERO_EXTEND || code0 == MEM)
  	  {
! 	    find_reloads_address_1 (mode, orig_op0, 0, PLUS, code1,
  				    &XEXP (x, 0), opnum, type, ind_levels,
  				    insn);
! 	    find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
  				    &XEXP (x, 1), opnum, type, ind_levels,
  				    insn);
  	  }
  
  	else if (code0 == CONST_INT || code0 == CONST
  		 || code0 == SYMBOL_REF || code0 == LABEL_REF)
! 	  find_reloads_address_1 (mode, orig_op1, 0, PLUS, code0,
  				  &XEXP (x, 1), opnum, type, ind_levels,
  				  insn);
  
  	else if (code1 == CONST_INT || code1 == CONST
  		 || code1 == SYMBOL_REF || code1 == LABEL_REF)
! 	  find_reloads_address_1 (mode, orig_op0, 0, PLUS, code1,
  				  &XEXP (x, 0), opnum, type, ind_levels,
  				  insn);
  
  	else if (code0 == REG && code1 == REG)
  	  {
  	    if (REGNO_OK_FOR_INDEX_P (REGNO (op1))
! 		&& regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
  	      return 0;
  	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op0))
! 		     && regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
  	      return 0;
! 	    else if (regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
! 	      find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
  				      &XEXP (x, 1), opnum, type, ind_levels,
  				      insn);
  	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op1)))
! 	      find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
  				      &XEXP (x, 0), opnum, type, ind_levels,
  				      insn);
! 	    else if (regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
! 	      find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
  				      &XEXP (x, 0), opnum, type, ind_levels,
  				      insn);
  	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op0)))
! 	      find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
  				      &XEXP (x, 1), opnum, type, ind_levels,
  				      insn);
  	    else
  	      {
! 		find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
  					&XEXP (x, 0), opnum, type, ind_levels,
  					insn);
! 		find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
  					&XEXP (x, 1), opnum, type, ind_levels,
  					insn);
  	      }
--- 5578,5633 ----
  	else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
  		 || code1 == ZERO_EXTEND || code0 == MEM)
  	  {
! 	    find_reloads_address_1 (mode, as, orig_op0, 0, PLUS, code1,
  				    &XEXP (x, 0), opnum, type, ind_levels,
  				    insn);
! 	    find_reloads_address_1 (mode, as, orig_op1, 1, PLUS, SCRATCH,
  				    &XEXP (x, 1), opnum, type, ind_levels,
  				    insn);
  	  }
  
  	else if (code0 == CONST_INT || code0 == CONST
  		 || code0 == SYMBOL_REF || code0 == LABEL_REF)
! 	  find_reloads_address_1 (mode, as, orig_op1, 0, PLUS, code0,
  				  &XEXP (x, 1), opnum, type, ind_levels,
  				  insn);
  
  	else if (code1 == CONST_INT || code1 == CONST
  		 || code1 == SYMBOL_REF || code1 == LABEL_REF)
! 	  find_reloads_address_1 (mode, as, orig_op0, 0, PLUS, code1,
  				  &XEXP (x, 0), opnum, type, ind_levels,
  				  insn);
  
  	else if (code0 == REG && code1 == REG)
  	  {
  	    if (REGNO_OK_FOR_INDEX_P (REGNO (op1))
! 		&& regno_ok_for_base_p (REGNO (op0), mode, as, PLUS, REG))
  	      return 0;
  	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op0))
! 		     && regno_ok_for_base_p (REGNO (op1), mode, as, PLUS, REG))
  	      return 0;
! 	    else if (regno_ok_for_base_p (REGNO (op0), mode, as, PLUS, REG))
! 	      find_reloads_address_1 (mode, as, orig_op1, 1, PLUS, SCRATCH,
  				      &XEXP (x, 1), opnum, type, ind_levels,
  				      insn);
  	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op1)))
! 	      find_reloads_address_1 (mode, as, orig_op0, 0, PLUS, REG,
  				      &XEXP (x, 0), opnum, type, ind_levels,
  				      insn);
! 	    else if (regno_ok_for_base_p (REGNO (op1), mode, as, PLUS, REG))
! 	      find_reloads_address_1 (mode, as, orig_op0, 1, PLUS, SCRATCH,
  				      &XEXP (x, 0), opnum, type, ind_levels,
  				      insn);
  	    else if (REGNO_OK_FOR_INDEX_P (REGNO (op0)))
! 	      find_reloads_address_1 (mode, as, orig_op1, 0, PLUS, REG,
  				      &XEXP (x, 1), opnum, type, ind_levels,
  				      insn);
  	    else
  	      {
! 		find_reloads_address_1 (mode, as, orig_op0, 0, PLUS, REG,
  					&XEXP (x, 0), opnum, type, ind_levels,
  					insn);
! 		find_reloads_address_1 (mode, as, orig_op1, 1, PLUS, SCRATCH,
  					&XEXP (x, 1), opnum, type, ind_levels,
  					insn);
  	      }
*************** find_reloads_address_1 (enum machine_mod
*** 5633,5652 ****
  
  	else if (code0 == REG)
  	  {
! 	    find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
  				    &XEXP (x, 0), opnum, type, ind_levels,
  				    insn);
! 	    find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
  				    &XEXP (x, 1), opnum, type, ind_levels,
  				    insn);
  	  }
  
  	else if (code1 == REG)
  	  {
! 	    find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
  				    &XEXP (x, 1), opnum, type, ind_levels,
  				    insn);
! 	    find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
  				    &XEXP (x, 0), opnum, type, ind_levels,
  				    insn);
  	  }
--- 5635,5654 ----
  
  	else if (code0 == REG)
  	  {
! 	    find_reloads_address_1 (mode, as, orig_op0, 1, PLUS, SCRATCH,
  				    &XEXP (x, 0), opnum, type, ind_levels,
  				    insn);
! 	    find_reloads_address_1 (mode, as, orig_op1, 0, PLUS, REG,
  				    &XEXP (x, 1), opnum, type, ind_levels,
  				    insn);
  	  }
  
  	else if (code1 == REG)
  	  {
! 	    find_reloads_address_1 (mode, as, orig_op1, 1, PLUS, SCRATCH,
  				    &XEXP (x, 1), opnum, type, ind_levels,
  				    insn);
! 	    find_reloads_address_1 (mode, as, orig_op0, 0, PLUS, REG,
  				    &XEXP (x, 0), opnum, type, ind_levels,
  				    insn);
  	  }
*************** find_reloads_address_1 (enum machine_mod
*** 5688,5694 ****
  	if ((REG_P (XEXP (op1, 1))
  	     && !REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
  	    || GET_CODE (XEXP (op1, 1)) == PLUS)
! 	  find_reloads_address_1 (mode, XEXP (op1, 1), 1, code, SCRATCH,
  				  &XEXP (op1, 1), opnum, RELOAD_OTHER,
  				  ind_levels, insn);
  
--- 5690,5696 ----
  	if ((REG_P (XEXP (op1, 1))
  	     && !REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
  	    || GET_CODE (XEXP (op1, 1)) == PLUS)
! 	  find_reloads_address_1 (mode, as, XEXP (op1, 1), 1, code, SCRATCH,
  				  &XEXP (op1, 1), opnum, RELOAD_OTHER,
  				  ind_levels, insn);
  
*************** find_reloads_address_1 (enum machine_mod
*** 5730,5737 ****
  		   register.  */
  		reloadnum = push_reload (tem, tem, &XEXP (x, 0),
  					 &XEXP (op1, 0),
! 					 base_reg_class (mode, code,
! 							 index_code),
  					 GET_MODE (x), GET_MODE (x), 0,
  					 0, opnum, RELOAD_OTHER);
  
--- 5732,5739 ----
  		   register.  */
  		reloadnum = push_reload (tem, tem, &XEXP (x, 0),
  					 &XEXP (op1, 0),
! 					 base_reg_class (mode, as,
! 							 code, index_code),
  					 GET_MODE (x), GET_MODE (x), 0,
  					 0, opnum, RELOAD_OTHER);
  
*************** find_reloads_address_1 (enum machine_mod
*** 5744,5754 ****
  	  regno = reg_renumber[regno];
  
  	/* We require a base register here...  */
! 	if (!regno_ok_for_base_p (regno, GET_MODE (x), code, index_code))
  	  {
  	    reloadnum = push_reload (XEXP (op1, 0), XEXP (x, 0),
  				     &XEXP (op1, 0), &XEXP (x, 0),
! 				     base_reg_class (mode, code, index_code),
  				     GET_MODE (x), GET_MODE (x), 0, 0,
  				     opnum, RELOAD_OTHER);
  
--- 5746,5757 ----
  	  regno = reg_renumber[regno];
  
  	/* We require a base register here...  */
! 	if (!regno_ok_for_base_p (regno, GET_MODE (x), as, code, index_code))
  	  {
  	    reloadnum = push_reload (XEXP (op1, 0), XEXP (x, 0),
  				     &XEXP (op1, 0), &XEXP (x, 0),
! 				     base_reg_class (mode, as,
! 						     code, index_code),
  				     GET_MODE (x), GET_MODE (x), 0, 0,
  				     opnum, RELOAD_OTHER);
  
*************** find_reloads_address_1 (enum machine_mod
*** 5814,5820 ****
  	  if (reg_renumber[regno] >= 0)
  	    regno = reg_renumber[regno];
  	  if (regno >= FIRST_PSEUDO_REGISTER
! 	      || !REG_OK_FOR_CONTEXT (context, regno, mode, code,
  				      index_code))
  	    {
  	      int reloadnum;
--- 5817,5823 ----
  	  if (reg_renumber[regno] >= 0)
  	    regno = reg_renumber[regno];
  	  if (regno >= FIRST_PSEUDO_REGISTER
! 	      || !REG_OK_FOR_CONTEXT (context, regno, mode, as, code,
  				      index_code))
  	    {
  	      int reloadnum;
*************** find_reloads_address_1 (enum machine_mod
*** 5886,5892 ****
  	 reloaded.  Targets that are better off reloading just either part
  	 (or perhaps even a different part of an outer expression), should
  	 define LEGITIMIZE_RELOAD_ADDRESS.  */
!       find_reloads_address_1 (GET_MODE (XEXP (x, 0)), XEXP (x, 0),
  			      context, code, SCRATCH, &XEXP (x, 0), opnum,
  			      type, ind_levels, insn);
        push_reload (x, NULL_RTX, loc, (rtx*) 0,
--- 5889,5895 ----
  	 reloaded.  Targets that are better off reloading just either part
  	 (or perhaps even a different part of an outer expression), should
  	 define LEGITIMIZE_RELOAD_ADDRESS.  */
!       find_reloads_address_1 (GET_MODE (XEXP (x, 0)), as, XEXP (x, 0),
  			      context, code, SCRATCH, &XEXP (x, 0), opnum,
  			      type, ind_levels, insn);
        push_reload (x, NULL_RTX, loc, (rtx*) 0,
*************** find_reloads_address_1 (enum machine_mod
*** 5957,5963 ****
  	  regno = reg_renumber[regno];
  
  	if (regno >= FIRST_PSEUDO_REGISTER
! 	    || !REG_OK_FOR_CONTEXT (context, regno, mode, outer_code,
  				    index_code))
  	  {
  	    push_reload (x, NULL_RTX, loc, (rtx*) 0,
--- 5960,5966 ----
  	  regno = reg_renumber[regno];
  
  	if (regno >= FIRST_PSEUDO_REGISTER
! 	    || !REG_OK_FOR_CONTEXT (context, regno, mode, as, outer_code,
  				    index_code))
  	  {
  	    push_reload (x, NULL_RTX, loc, (rtx*) 0,
*************** find_reloads_address_1 (enum machine_mod
*** 5990,5996 ****
  	    {
  	      int regno ATTRIBUTE_UNUSED = subreg_regno (x);
  
! 	      if (!REG_OK_FOR_CONTEXT (context, regno, mode, outer_code,
  				       index_code))
  		{
  		  push_reload (x, NULL_RTX, loc, (rtx*) 0,
--- 5993,5999 ----
  	    {
  	      int regno ATTRIBUTE_UNUSED = subreg_regno (x);
  
! 	      if (!REG_OK_FOR_CONTEXT (context, regno, mode, as, outer_code,
  				       index_code))
  		{
  		  push_reload (x, NULL_RTX, loc, (rtx*) 0,
*************** find_reloads_address_1 (enum machine_mod
*** 6031,6038 ****
  	if (fmt[i] == 'e')
  	  /* Pass SCRATCH for INDEX_CODE, since CODE can never be a PLUS once
  	     we get here.  */
! 	  find_reloads_address_1 (mode, XEXP (x, i), context, code, SCRATCH,
! 				  &XEXP (x, i), opnum, type, ind_levels, insn);
        }
    }
  
--- 6034,6042 ----
  	if (fmt[i] == 'e')
  	  /* Pass SCRATCH for INDEX_CODE, since CODE can never be a PLUS once
  	     we get here.  */
! 	  find_reloads_address_1 (mode, as, XEXP (x, i), context,
! 				  code, SCRATCH, &XEXP (x, i),
! 				  opnum, type, ind_levels, insn);
        }
    }
  
*************** find_reloads_subreg_address (rtx x, int 
*** 6203,6209 ****
  			(GET_MODE (x), XEXP (reg_equiv_mem[regno], 0),
  			 MEM_ADDR_SPACE (reg_equiv_mem[regno])))
  		push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
! 			     base_reg_class (GET_MODE (tem), MEM, SCRATCH),
  			     GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0,
  			     opnum, type);
  
--- 6207,6215 ----
  			(GET_MODE (x), XEXP (reg_equiv_mem[regno], 0),
  			 MEM_ADDR_SPACE (reg_equiv_mem[regno])))
  		push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
! 			     base_reg_class (GET_MODE (tem),
! 					     MEM_ADDR_SPACE (tem),
! 					     MEM, SCRATCH),
  			     GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0,
  			     opnum, type);
  
Index: gcc/caller-save.c
===================================================================
*** gcc/caller-save.c	(revision 153564)
--- gcc/caller-save.c	(working copy)
*************** init_caller_save (void)
*** 246,252 ****
    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
      if (TEST_HARD_REG_BIT
  	(reg_class_contents
! 	 [(int) base_reg_class (regno_save_mode[i][1], PLUS, CONST_INT)], i))
        break;
  
    gcc_assert (i < FIRST_PSEUDO_REGISTER);
--- 246,253 ----
    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
      if (TEST_HARD_REG_BIT
  	(reg_class_contents
! 	 [(int) base_reg_class (regno_save_mode[i][1], ADDR_SPACE_GENERIC,
! 				PLUS, CONST_INT)], i))
        break;
  
    gcc_assert (i < FIRST_PSEUDO_REGISTER);
Index: gcc/recog.c
===================================================================
*** gcc/recog.c	(revision 153564)
--- gcc/recog.c	(working copy)
*************** preprocess_constraints (void)
*** 2243,2249 ****
  		case 'p':
  		  op_alt[j].is_address = 1;
  		  op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
! 		      [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
  		  break;
  
  		case 'g':
--- 2243,2250 ----
  		case 'p':
  		  op_alt[j].is_address = 1;
  		  op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
! 		      [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
! 					     ADDRESS, SCRATCH)];
  		  break;
  
  		case 'g':
*************** preprocess_constraints (void)
*** 2264,2271 ****
  		      op_alt[j].cl
  			= (reg_class_subunion
  			   [(int) op_alt[j].cl]
! 			   [(int) base_reg_class (VOIDmode, ADDRESS,
! 						  SCRATCH)]);
  		      break;
  		    }
  
--- 2265,2272 ----
  		      op_alt[j].cl
  			= (reg_class_subunion
  			   [(int) op_alt[j].cl]
! 			   [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
! 						  ADDRESS, SCRATCH)]);
  		      break;
  		    }
  
Index: gcc/ira-costs.c
===================================================================
*** gcc/ira-costs.c	(revision 153564)
--- gcc/ira-costs.c	(working copy)
*************** record_reg_classes (int n_alts, int n_op
*** 398,404 ****
  		     base of an address, i.e. BASE_REG_CLASS.  */
  		  classes[i]
  		    = ira_reg_class_union[classes[i]]
! 		      [base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
  		  break;
  
  		case 'm':  case 'o':  case 'V':
--- 398,405 ----
  		     base of an address, i.e. BASE_REG_CLASS.  */
  		  classes[i]
  		    = ira_reg_class_union[classes[i]]
! 		      [base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
! 				       ADDRESS, SCRATCH)];
  		  break;
  
  		case 'm':  case 'o':  case 'V':
*************** record_reg_classes (int n_alts, int n_op
*** 513,519 ****
  			 i.e. BASE_REG_CLASS.  */
  		      classes[i]
  			= ira_reg_class_union[classes[i]]
! 			  [base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
  		    }
  #endif
  		  break;
--- 514,521 ----
  			 i.e. BASE_REG_CLASS.  */
  		      classes[i]
  			= ira_reg_class_union[classes[i]]
! 			  [base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
! 					   ADDRESS, SCRATCH)];
  		    }
  #endif
  		  break;
*************** ok_for_index_p_nonstrict (rtx reg)
*** 727,740 ****
     pseudo-registers should count as OK.  Arguments as for
     regno_ok_for_base_p.  */
  static inline bool
! ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode,
  			 enum rtx_code outer_code, enum rtx_code index_code)
  {
    unsigned regno = REGNO (reg);
  
    if (regno >= FIRST_PSEUDO_REGISTER)
      return true;
!   return ok_for_base_p_1 (regno, mode, outer_code, index_code);
  }
  
  /* Record the pseudo registers we must reload into hard registers in a
--- 729,742 ----
     pseudo-registers should count as OK.  Arguments as for
     regno_ok_for_base_p.  */
  static inline bool
! ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as,
  			 enum rtx_code outer_code, enum rtx_code index_code)
  {
    unsigned regno = REGNO (reg);
  
    if (regno >= FIRST_PSEUDO_REGISTER)
      return true;
!   return ok_for_base_p_1 (regno, mode, as, outer_code, index_code);
  }
  
  /* Record the pseudo registers we must reload into hard registers in a
*************** ok_for_base_p_nonstrict (rtx reg, enum m
*** 743,758 ****
     If CONTEXT is 0, we are looking at the base part of an address,
     otherwise we are looking at the index part.
  
!    MODE is the mode of the memory reference; OUTER_CODE and INDEX_CODE
!    give the context that the rtx appears in.  These three arguments
!    are passed down to base_reg_class.
  
     SCALE is twice the amount to multiply the cost by (it is twice so
     we can represent half-cost adjustments).  */
  static void
! record_address_regs (enum machine_mode mode, rtx x, int context,
! 		     enum rtx_code outer_code, enum rtx_code index_code,
! 		     int scale)
  {
    enum rtx_code code = GET_CODE (x);
    enum reg_class rclass;
--- 745,760 ----
     If CONTEXT is 0, we are looking at the base part of an address,
     otherwise we are looking at the index part.
  
!    MODE and AS are the mode and address space of the memory reference;
!    OUTER_CODE and INDEX_CODE give the context that the rtx appears in.
!    These four arguments are passed down to base_reg_class.
  
     SCALE is twice the amount to multiply the cost by (it is twice so
     we can represent half-cost adjustments).  */
  static void
! record_address_regs (enum machine_mode mode, addr_space_t as, rtx x,
! 		     int context, enum rtx_code outer_code,
! 		     enum rtx_code index_code, int scale)
  {
    enum rtx_code code = GET_CODE (x);
    enum reg_class rclass;
*************** record_address_regs (enum machine_mode m
*** 760,766 ****
    if (context == 1)
      rclass = INDEX_REG_CLASS;
    else
!     rclass = base_reg_class (mode, outer_code, index_code);
  
    switch (code)
      {
--- 762,768 ----
    if (context == 1)
      rclass = INDEX_REG_CLASS;
    else
!     rclass = base_reg_class (mode, as, outer_code, index_code);
  
    switch (code)
      {
*************** record_address_regs (enum machine_mode m
*** 799,865 ****
  	/* If this machine only allows one register per address, it
  	   must be in the first operand.  */
  	if (MAX_REGS_PER_ADDRESS == 1)
! 	  record_address_regs (mode, arg0, 0, PLUS, code1, scale);
  
  	/* If index and base registers are the same on this machine,
  	   just record registers in any non-constant operands.  We
  	   assume here, as well as in the tests below, that all
  	   addresses are in canonical form.  */
! 	else if (INDEX_REG_CLASS == base_reg_class (VOIDmode, PLUS, SCRATCH))
  	  {
! 	    record_address_regs (mode, arg0, context, PLUS, code1, scale);
  	    if (! CONSTANT_P (arg1))
! 	      record_address_regs (mode, arg1, context, PLUS, code0, scale);
  	  }
  
  	/* If the second operand is a constant integer, it doesn't
  	   change what class the first operand must be.  */
  	else if (code1 == CONST_INT || code1 == CONST_DOUBLE)
! 	  record_address_regs (mode, arg0, context, PLUS, code1, scale);
  	/* If the second operand is a symbolic constant, the first
  	   operand must be an index register.  */
  	else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
! 	  record_address_regs (mode, arg0, 1, PLUS, code1, scale);
  	/* If both operands are registers but one is already a hard
  	   register of index or reg-base class, give the other the
  	   class that the hard register is not.  */
  	else if (code0 == REG && code1 == REG
  		 && REGNO (arg0) < FIRST_PSEUDO_REGISTER
! 		 && (ok_for_base_p_nonstrict (arg0, mode, PLUS, REG)
  		     || ok_for_index_p_nonstrict (arg0)))
! 	  record_address_regs (mode, arg1,
! 			       ok_for_base_p_nonstrict (arg0, mode, PLUS, REG)
! 			       ? 1 : 0,
  			       PLUS, REG, scale);
  	else if (code0 == REG && code1 == REG
  		 && REGNO (arg1) < FIRST_PSEUDO_REGISTER
! 		 && (ok_for_base_p_nonstrict (arg1, mode, PLUS, REG)
  		     || ok_for_index_p_nonstrict (arg1)))
! 	  record_address_regs (mode, arg0,
! 			       ok_for_base_p_nonstrict (arg1, mode, PLUS, REG)
! 			       ? 1 : 0,
  			       PLUS, REG, scale);
  	/* If one operand is known to be a pointer, it must be the
  	   base with the other operand the index.  Likewise if the
  	   other operand is a MULT.  */
  	else if ((code0 == REG && REG_POINTER (arg0)) || code1 == MULT)
  	  {
! 	    record_address_regs (mode, arg0, 0, PLUS, code1, scale);
! 	    record_address_regs (mode, arg1, 1, PLUS, code0, scale);
  	  }
  	else if ((code1 == REG && REG_POINTER (arg1)) || code0 == MULT)
  	  {
! 	    record_address_regs (mode, arg0, 1, PLUS, code1, scale);
! 	    record_address_regs (mode, arg1, 0, PLUS, code0, scale);
  	  }
  	/* Otherwise, count equal chances that each might be a base or
  	   index register.  This case should be rare.  */
  	else
  	  {
! 	    record_address_regs (mode, arg0, 0, PLUS, code1, scale / 2);
! 	    record_address_regs (mode, arg0, 1, PLUS, code1, scale / 2);
! 	    record_address_regs (mode, arg1, 0, PLUS, code0, scale / 2);
! 	    record_address_regs (mode, arg1, 1, PLUS, code0, scale / 2);
  	  }
        }
        break;
--- 801,868 ----
  	/* If this machine only allows one register per address, it
  	   must be in the first operand.  */
  	if (MAX_REGS_PER_ADDRESS == 1)
! 	  record_address_regs (mode, as, arg0, 0, PLUS, code1, scale);
  
  	/* If index and base registers are the same on this machine,
  	   just record registers in any non-constant operands.  We
  	   assume here, as well as in the tests below, that all
  	   addresses are in canonical form.  */
! 	else if (INDEX_REG_CLASS
! 		 == base_reg_class (VOIDmode, as, PLUS, SCRATCH))
  	  {
! 	    record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
  	    if (! CONSTANT_P (arg1))
! 	      record_address_regs (mode, as, arg1, context, PLUS, code0, scale);
  	  }
  
  	/* If the second operand is a constant integer, it doesn't
  	   change what class the first operand must be.  */
  	else if (code1 == CONST_INT || code1 == CONST_DOUBLE)
! 	  record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
  	/* If the second operand is a symbolic constant, the first
  	   operand must be an index register.  */
  	else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
! 	  record_address_regs (mode, as, arg0, 1, PLUS, code1, scale);
  	/* If both operands are registers but one is already a hard
  	   register of index or reg-base class, give the other the
  	   class that the hard register is not.  */
  	else if (code0 == REG && code1 == REG
  		 && REGNO (arg0) < FIRST_PSEUDO_REGISTER
! 		 && (ok_for_base_p_nonstrict (arg0, mode, as, PLUS, REG)
  		     || ok_for_index_p_nonstrict (arg0)))
! 	  record_address_regs (mode, as, arg1,
! 			       ok_for_base_p_nonstrict (arg0, mode, as,
! 							PLUS, REG) ? 1 : 0,
  			       PLUS, REG, scale);
  	else if (code0 == REG && code1 == REG
  		 && REGNO (arg1) < FIRST_PSEUDO_REGISTER
! 		 && (ok_for_base_p_nonstrict (arg1, mode, as, PLUS, REG)
  		     || ok_for_index_p_nonstrict (arg1)))
! 	  record_address_regs (mode, as, arg0,
! 			       ok_for_base_p_nonstrict (arg1, mode, as,
! 							PLUS, REG) ? 1 : 0,
  			       PLUS, REG, scale);
  	/* If one operand is known to be a pointer, it must be the
  	   base with the other operand the index.  Likewise if the
  	   other operand is a MULT.  */
  	else if ((code0 == REG && REG_POINTER (arg0)) || code1 == MULT)
  	  {
! 	    record_address_regs (mode, as, arg0, 0, PLUS, code1, scale);
! 	    record_address_regs (mode, as, arg1, 1, PLUS, code0, scale);
  	  }
  	else if ((code1 == REG && REG_POINTER (arg1)) || code0 == MULT)
  	  {
! 	    record_address_regs (mode, as, arg0, 1, PLUS, code1, scale);
! 	    record_address_regs (mode, as, arg1, 0, PLUS, code0, scale);
  	  }
  	/* Otherwise, count equal chances that each might be a base or
  	   index register.  This case should be rare.  */
  	else
  	  {
! 	    record_address_regs (mode, as, arg0, 0, PLUS, code1, scale / 2);
! 	    record_address_regs (mode, as, arg0, 1, PLUS, code1, scale / 2);
! 	    record_address_regs (mode, as, arg1, 0, PLUS, code0, scale / 2);
! 	    record_address_regs (mode, as, arg1, 1, PLUS, code0, scale / 2);
  	  }
        }
        break;
*************** record_address_regs (enum machine_mode m
*** 869,878 ****
  	 up in the wrong place.  */
      case POST_MODIFY:
      case PRE_MODIFY:
!       record_address_regs (mode, XEXP (x, 0), 0, code,
  			   GET_CODE (XEXP (XEXP (x, 1), 1)), 2 * scale);
        if (REG_P (XEXP (XEXP (x, 1), 1)))
! 	record_address_regs (mode, XEXP (XEXP (x, 1), 1), 1, code, REG,
  			     2 * scale);
        break;
  
--- 872,881 ----
  	 up in the wrong place.  */
      case POST_MODIFY:
      case PRE_MODIFY:
!       record_address_regs (mode, as, XEXP (x, 0), 0, code,
  			   GET_CODE (XEXP (XEXP (x, 1), 1)), 2 * scale);
        if (REG_P (XEXP (XEXP (x, 1), 1)))
! 	record_address_regs (mode, as, XEXP (XEXP (x, 1), 1), 1, code, REG,
  			     2 * scale);
        break;
  
*************** record_address_regs (enum machine_mode m
*** 889,895 ****
  	  && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER)
  	in_inc_dec[COST_INDEX (REGNO (XEXP (x, 0)))] = true;
  #endif
!       record_address_regs (mode, XEXP (x, 0), 0, code, SCRATCH, 2 * scale);
        break;
  
      case REG:
--- 892,898 ----
  	  && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER)
  	in_inc_dec[COST_INDEX (REGNO (XEXP (x, 0)))] = true;
  #endif
!       record_address_regs (mode, as, XEXP (x, 0), 0, code, SCRATCH, 2 * scale);
        break;
  
      case REG:
*************** record_address_regs (enum machine_mode m
*** 920,926 ****
  	int i;
  	for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
  	  if (fmt[i] == 'e')
! 	    record_address_regs (mode, XEXP (x, i), context, code, SCRATCH,
  				 scale);
        }
      }
--- 923,929 ----
  	int i;
  	for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
  	  if (fmt[i] == 'e')
! 	    record_address_regs (mode, as, XEXP (x, i), context, code, SCRATCH,
  				 scale);
        }
      }
*************** record_operand_costs (rtx insn, struct c
*** 956,968 ****
  
        if (MEM_P (recog_data.operand[i]))
  	record_address_regs (GET_MODE (recog_data.operand[i]),
  			     XEXP (recog_data.operand[i], 0),
  			     0, MEM, SCRATCH, frequency * 2);
        else if (constraints[i][0] == 'p'
  	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0],
  					    constraints[i]))
! 	record_address_regs (VOIDmode, recog_data.operand[i], 0, ADDRESS,
! 			     SCRATCH, frequency * 2);
      }
  
    /* Check for commutative in a separate loop so everything will have
--- 959,973 ----
  
        if (MEM_P (recog_data.operand[i]))
  	record_address_regs (GET_MODE (recog_data.operand[i]),
+ 			     MEM_ADDR_SPACE (recog_data.operand[i]),
  			     XEXP (recog_data.operand[i], 0),
  			     0, MEM, SCRATCH, frequency * 2);
        else if (constraints[i][0] == 'p'
  	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0],
  					    constraints[i]))
! 	record_address_regs (VOIDmode, ADDR_SPACE_GENERIC,
! 			     recog_data.operand[i], 0, ADDRESS, SCRATCH,
! 			     frequency * 2);
      }
  
    /* Check for commutative in a separate loop so everything will have
*************** scan_one_insn (rtx insn)
*** 1028,1035 ****
  	cl = pref[num];
        COSTS (costs, num)->mem_cost
  	-= ira_memory_move_cost[GET_MODE (reg)][cl][1] * frequency;
!       record_address_regs (GET_MODE (SET_SRC (set)), XEXP (SET_SRC (set), 0),
! 			   0, MEM, SCRATCH, frequency * 2);
      }
  
    record_operand_costs (insn, op_costs, pref);
--- 1033,1042 ----
  	cl = pref[num];
        COSTS (costs, num)->mem_cost
  	-= ira_memory_move_cost[GET_MODE (reg)][cl][1] * frequency;
!       record_address_regs (GET_MODE (SET_SRC (set)),
! 			   MEM_ADDR_SPACE (SET_SRC (set)),
! 			   XEXP (SET_SRC (set), 0), 0, MEM, SCRATCH,
! 			   frequency * 2);
      }
  
    record_operand_costs (insn, op_costs, pref);
Index: gcc/addresses.h
===================================================================
*** gcc/addresses.h	(revision 153564)
--- gcc/addresses.h	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 23,33 ****
  
  static inline enum reg_class
  base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
  		enum rtx_code outer_code ATTRIBUTE_UNUSED,
  		enum rtx_code index_code ATTRIBUTE_UNUSED)
  {
  #ifdef MODE_CODE_BASE_REG_CLASS
!   return MODE_CODE_BASE_REG_CLASS (mode, outer_code, index_code);
  #else
  #ifdef MODE_BASE_REG_REG_CLASS
    if (index_code == REG)
--- 23,34 ----
  
  static inline enum reg_class
  base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
+ 		addr_space_t as ATTRIBUTE_UNUSED,
  		enum rtx_code outer_code ATTRIBUTE_UNUSED,
  		enum rtx_code index_code ATTRIBUTE_UNUSED)
  {
  #ifdef MODE_CODE_BASE_REG_CLASS
!   return MODE_CODE_BASE_REG_CLASS (mode, as, outer_code, index_code);
  #else
  #ifdef MODE_BASE_REG_REG_CLASS
    if (index_code == REG)
*************** base_reg_class (enum machine_mode mode A
*** 48,58 ****
  
  static inline bool
  ok_for_base_p_1 (unsigned regno, enum machine_mode mode ATTRIBUTE_UNUSED,
  		 enum rtx_code outer_code ATTRIBUTE_UNUSED,
  		 enum rtx_code index_code ATTRIBUTE_UNUSED)
  {
  #ifdef REGNO_MODE_CODE_OK_FOR_BASE_P
!   return REGNO_MODE_CODE_OK_FOR_BASE_P (regno, mode, outer_code, index_code);
  #else
  #ifdef REGNO_MODE_OK_FOR_REG_BASE_P
    if (index_code == REG)
--- 49,61 ----
  
  static inline bool
  ok_for_base_p_1 (unsigned regno, enum machine_mode mode ATTRIBUTE_UNUSED,
+ 		 addr_space_t as ATTRIBUTE_UNUSED,
  		 enum rtx_code outer_code ATTRIBUTE_UNUSED,
  		 enum rtx_code index_code ATTRIBUTE_UNUSED)
  {
  #ifdef REGNO_MODE_CODE_OK_FOR_BASE_P
!   return REGNO_MODE_CODE_OK_FOR_BASE_P (regno, mode, as,
! 					outer_code, index_code);
  #else
  #ifdef REGNO_MODE_OK_FOR_REG_BASE_P
    if (index_code == REG)
*************** ok_for_base_p_1 (unsigned regno, enum ma
*** 70,80 ****
     complete.  Arguments as for the called function.  */
  
  static inline bool
! regno_ok_for_base_p (unsigned regno, enum machine_mode mode,
  		     enum rtx_code outer_code, enum rtx_code index_code)
  {
    if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0)
      regno = reg_renumber[regno];
  
!   return ok_for_base_p_1 (regno, mode, outer_code, index_code);
  }
--- 73,83 ----
     complete.  Arguments as for the called function.  */
  
  static inline bool
! regno_ok_for_base_p (unsigned regno, enum machine_mode mode, addr_space_t as,
  		     enum rtx_code outer_code, enum rtx_code index_code)
  {
    if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0)
      regno = reg_renumber[regno];
  
!   return ok_for_base_p_1 (regno, mode, as, outer_code, index_code);
  }
Index: gcc/config/cris/cris.h
===================================================================
*** gcc/config/cris/cris.h	(revision 153564)
--- gcc/config/cris/cris.h	(working copy)
*************** enum reg_class
*** 578,584 ****
  
  #define BASE_REG_CLASS GENERAL_REGS
  
! #define MODE_CODE_BASE_REG_CLASS(MODE, OCODE, ICODE)	\
    ((OCODE) != POST_INC ? BASE_REG_CLASS : GENNONACR_REGS)
  
  #define INDEX_REG_CLASS GENERAL_REGS
--- 578,584 ----
  
  #define BASE_REG_CLASS GENERAL_REGS
  
! #define MODE_CODE_BASE_REG_CLASS(MODE, AS, OCODE, ICODE)	\
    ((OCODE) != POST_INC ? BASE_REG_CLASS : GENNONACR_REGS)
  
  #define INDEX_REG_CLASS GENERAL_REGS
*************** enum reg_class
*** 605,611 ****
  
  /* REGNO_OK_FOR_BASE_P seems to be obsolete wrt. this one, but not yet
     documented as such.  */
! #define REGNO_MODE_CODE_OK_FOR_BASE_P(REGNO, MODE, OCODE, ICODE)	\
   (REGNO_OK_FOR_BASE_P (REGNO)						\
    && ((OCODE) != POST_INC						\
        || !((REGNO) == CRIS_ACR_REGNUM					\
--- 605,611 ----
  
  /* REGNO_OK_FOR_BASE_P seems to be obsolete wrt. this one, but not yet
     documented as such.  */
! #define REGNO_MODE_CODE_OK_FOR_BASE_P(REGNO, MODE, AS, OCODE, ICODE)	\
   (REGNO_OK_FOR_BASE_P (REGNO)						\
    && ((OCODE) != POST_INC						\
        || !((REGNO) == CRIS_ACR_REGNUM					\
Index: gcc/config/bfin/bfin.h
===================================================================
*** gcc/config/bfin/bfin.h	(revision 153564)
--- gcc/config/bfin/bfin.h	(working copy)
*************** enum reg_class
*** 690,696 ****
     || (OUTER) == POST_DEC || (OUTER) == PRE_DEC		     \
     || (OUTER) == MEM || (OUTER) == ADDRESS)
  
! #define MODE_CODE_BASE_REG_CLASS(MODE, OUTER, INDEX)			\
    ((MODE) == HImode && IREG_POSSIBLE_P (OUTER) ? IPREGS : PREGS)
  
  #define INDEX_REG_CLASS         PREGS
--- 690,696 ----
     || (OUTER) == POST_DEC || (OUTER) == PRE_DEC		     \
     || (OUTER) == MEM || (OUTER) == ADDRESS)
  
! #define MODE_CODE_BASE_REG_CLASS(MODE, AS, OUTER, INDEX)	\
    ((MODE) == HImode && IREG_POSSIBLE_P (OUTER) ? IPREGS : PREGS)
  
  #define INDEX_REG_CLASS         PREGS
*************** enum reg_class
*** 705,714 ****
     || REGNO_OK_FOR_BASE_STRICT_P (X, MODE, OUTER, INDEX))
  
  #ifdef REG_OK_STRICT
! #define REGNO_MODE_CODE_OK_FOR_BASE_P(X, MODE, OUTER, INDEX) \
    REGNO_OK_FOR_BASE_STRICT_P (X, MODE, OUTER, INDEX)
  #else
! #define REGNO_MODE_CODE_OK_FOR_BASE_P(X, MODE, OUTER, INDEX) \
    REGNO_OK_FOR_BASE_NONSTRICT_P (X, MODE, OUTER, INDEX)
  #endif
  
--- 705,714 ----
     || REGNO_OK_FOR_BASE_STRICT_P (X, MODE, OUTER, INDEX))
  
  #ifdef REG_OK_STRICT
! #define REGNO_MODE_CODE_OK_FOR_BASE_P(X, MODE, AS, OUTER, INDEX) \
    REGNO_OK_FOR_BASE_STRICT_P (X, MODE, OUTER, INDEX)
  #else
! #define REGNO_MODE_CODE_OK_FOR_BASE_P(X, MODE, AS, OUTER, INDEX) \
    REGNO_OK_FOR_BASE_NONSTRICT_P (X, MODE, OUTER, INDEX)
  #endif
  
Index: gcc/regcprop.c
===================================================================
*** gcc/regcprop.c	(revision 153564)
--- gcc/regcprop.c	(working copy)
*************** static rtx find_oldest_value_reg (enum r
*** 82,88 ****
  static bool replace_oldest_value_reg (rtx *, enum reg_class, rtx,
  				      struct value_data *);
  static bool replace_oldest_value_addr (rtx *, enum reg_class,
! 				       enum machine_mode, rtx,
  				       struct value_data *);
  static bool replace_oldest_value_mem (rtx, rtx, struct value_data *);
  static bool copyprop_hardreg_forward_1 (basic_block, struct value_data *);
--- 82,88 ----
  static bool replace_oldest_value_reg (rtx *, enum reg_class, rtx,
  				      struct value_data *);
  static bool replace_oldest_value_addr (rtx *, enum reg_class,
! 				       enum machine_mode, addr_space_t, rtx,
  				       struct value_data *);
  static bool replace_oldest_value_mem (rtx, rtx, struct value_data *);
  static bool copyprop_hardreg_forward_1 (basic_block, struct value_data *);
*************** replace_oldest_value_reg (rtx *loc, enum
*** 462,469 ****
  
  static bool
  replace_oldest_value_addr (rtx *loc, enum reg_class cl,
! 			   enum machine_mode mode, rtx insn,
! 			   struct value_data *vd)
  {
    rtx x = *loc;
    RTX_CODE code = GET_CODE (x);
--- 462,469 ----
  
  static bool
  replace_oldest_value_addr (rtx *loc, enum reg_class cl,
! 			   enum machine_mode mode, addr_space_t as,
! 			   rtx insn, struct value_data *vd)
  {
    rtx x = *loc;
    RTX_CODE code = GET_CODE (x);
*************** replace_oldest_value_addr (rtx *loc, enu
*** 532,546 ****
  	    unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
  
  	    if (REGNO_OK_FOR_INDEX_P (regno1)
! 		&& regno_ok_for_base_p (regno0, mode, PLUS, REG))
  	      index_op = 1;
  	    else if (REGNO_OK_FOR_INDEX_P (regno0)
! 		     && regno_ok_for_base_p (regno1, mode, PLUS, REG))
  	      index_op = 0;
! 	    else if (regno_ok_for_base_p (regno0, mode, PLUS, REG)
  		     || REGNO_OK_FOR_INDEX_P (regno1))
  	      index_op = 1;
! 	    else if (regno_ok_for_base_p (regno1, mode, PLUS, REG))
  	      index_op = 0;
  	    else
  	      index_op = 1;
--- 532,546 ----
  	    unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
  
  	    if (REGNO_OK_FOR_INDEX_P (regno1)
! 		&& regno_ok_for_base_p (regno0, mode, as, PLUS, REG))
  	      index_op = 1;
  	    else if (REGNO_OK_FOR_INDEX_P (regno0)
! 		     && regno_ok_for_base_p (regno1, mode, as, PLUS, REG))
  	      index_op = 0;
! 	    else if (regno_ok_for_base_p (regno0, mode, as, PLUS, REG)
  		     || REGNO_OK_FOR_INDEX_P (regno1))
  	      index_op = 1;
! 	    else if (regno_ok_for_base_p (regno1, mode, as, PLUS, REG))
  	      index_op = 0;
  	    else
  	      index_op = 1;
*************** replace_oldest_value_addr (rtx *loc, enu
*** 563,575 ****
  	  }
  
  	if (locI)
! 	  changed |= replace_oldest_value_addr (locI, INDEX_REG_CLASS, mode,
! 						insn, vd);
  	if (locB)
  	  changed |= replace_oldest_value_addr (locB,
! 						base_reg_class (mode, PLUS,
  								index_code),
! 						mode, insn, vd);
  	return changed;
        }
  
--- 563,575 ----
  	  }
  
  	if (locI)
! 	  changed |= replace_oldest_value_addr (locI, INDEX_REG_CLASS,
! 						mode, as, insn, vd);
  	if (locB)
  	  changed |= replace_oldest_value_addr (locB,
! 						base_reg_class (mode, as, PLUS,
  								index_code),
! 						mode, as, insn, vd);
  	return changed;
        }
  
*************** replace_oldest_value_addr (rtx *loc, enu
*** 595,606 ****
    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
      {
        if (fmt[i] == 'e')
! 	changed |= replace_oldest_value_addr (&XEXP (x, i), cl, mode,
  					      insn, vd);
        else if (fmt[i] == 'E')
  	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
  	  changed |= replace_oldest_value_addr (&XVECEXP (x, i, j), cl,
! 						mode, insn, vd);
      }
  
    return changed;
--- 595,606 ----
    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
      {
        if (fmt[i] == 'e')
! 	changed |= replace_oldest_value_addr (&XEXP (x, i), cl, mode, as,
  					      insn, vd);
        else if (fmt[i] == 'E')
  	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
  	  changed |= replace_oldest_value_addr (&XVECEXP (x, i, j), cl,
! 						mode, as, insn, vd);
      }
  
    return changed;
*************** replace_oldest_value_mem (rtx x, rtx ins
*** 616,625 ****
    if (DEBUG_INSN_P (insn))
      cl = ALL_REGS;
    else
!     cl = base_reg_class (GET_MODE (x), MEM, SCRATCH);
  
    return replace_oldest_value_addr (&XEXP (x, 0), cl,
! 				    GET_MODE (x), insn, vd);
  }
  
  /* Perform the forward copy propagation on basic block BB.  */
--- 616,626 ----
    if (DEBUG_INSN_P (insn))
      cl = ALL_REGS;
    else
!     cl = base_reg_class (GET_MODE (x), MEM_ADDR_SPACE (x), MEM, SCRATCH);
  
    return replace_oldest_value_addr (&XEXP (x, 0), cl,
! 				    GET_MODE (x), MEM_ADDR_SPACE (x),
! 				    insn, vd);
  }
  
  /* Perform the forward copy propagation on basic block BB.  */
*************** copyprop_hardreg_forward_1 (basic_block 
*** 646,652 ****
  	      if (!VAR_LOC_UNKNOWN_P (loc)
  		  && replace_oldest_value_addr (&INSN_VAR_LOCATION_LOC (insn),
  						ALL_REGS, GET_MODE (loc),
! 						insn, vd))
  		{
  		  changed = apply_change_group ();
  		  gcc_assert (changed);
--- 647,653 ----
  	      if (!VAR_LOC_UNKNOWN_P (loc)
  		  && replace_oldest_value_addr (&INSN_VAR_LOCATION_LOC (insn),
  						ALL_REGS, GET_MODE (loc),
! 						ADDR_SPACE_GENERIC, insn, vd))
  		{
  		  changed = apply_change_group ();
  		  gcc_assert (changed);
*************** copyprop_hardreg_forward_1 (basic_block 
*** 790,796 ****
  		replaced[i]
  		  = replace_oldest_value_addr (recog_data.operand_loc[i],
  					       recog_op_alt[i][alt].cl,
! 					       VOIDmode, insn, vd);
  	      else if (REG_P (recog_data.operand[i]))
  		replaced[i]
  		  = replace_oldest_value_reg (recog_data.operand_loc[i],
--- 791,798 ----
  		replaced[i]
  		  = replace_oldest_value_addr (recog_data.operand_loc[i],
  					       recog_op_alt[i][alt].cl,
! 					       VOIDmode, ADDR_SPACE_GENERIC,
! 					       insn, vd);
  	      else if (REG_P (recog_data.operand[i]))
  		replaced[i]
  		  = replace_oldest_value_reg (recog_data.operand_loc[i],
Index: gcc/reload1.c
===================================================================
*** gcc/reload1.c	(revision 153564)
--- gcc/reload1.c	(working copy)
*************** maybe_fix_stack_asms (void)
*** 1535,1541 ****
  
  		case 'p':
  		  cls = (int) reg_class_subunion[cls]
! 		      [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
  		  break;
  
  		case 'g':
--- 1535,1542 ----
  
  		case 'p':
  		  cls = (int) reg_class_subunion[cls]
! 		      [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
! 					     ADDRESS, SCRATCH)];
  		  break;
  
  		case 'g':
*************** maybe_fix_stack_asms (void)
*** 1546,1552 ****
  		default:
  		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
  		    cls = (int) reg_class_subunion[cls]
! 		      [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
  		  else
  		    cls = (int) reg_class_subunion[cls]
  		      [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
--- 1547,1554 ----
  		default:
  		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
  		    cls = (int) reg_class_subunion[cls]
! 		      [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
! 					     ADDRESS, SCRATCH)];
  		  else
  		    cls = (int) reg_class_subunion[cls]
  		      [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];


-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch)
  2009-10-29 18:37           ` [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch) Ulrich Weigand
@ 2009-10-29 19:54             ` DJ Delorie
  2009-10-29 20:18             ` DJ Delorie
  1 sibling, 0 replies; 34+ messages in thread
From: DJ Delorie @ 2009-10-29 19:54 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gcc-patches


I assume I need to add the suitable m32c macros?

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch)
  2009-10-29 18:37           ` [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch) Ulrich Weigand
  2009-10-29 19:54             ` DJ Delorie
@ 2009-10-29 20:18             ` DJ Delorie
  2009-10-29 21:33               ` Ulrich Weigand
  1 sibling, 1 reply; 34+ messages in thread
From: DJ Delorie @ 2009-10-29 20:18 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gcc-patches


Nope.  Here's the m32c part so far...  You can build for m32c-elf and test with this:

./cc1 -quiet -Os dj.c -o dj.s

extern char __far far_char_array[50];
void
far_array_set (int i)
{
  far_char_array[i+10] = 0;
}



Index: gcc/config/m32c/m32c.c
===================================================================
--- gcc/config/m32c/m32c.c	(revision 153725)
+++ gcc/config/m32c/m32c.c	(working copy)
@@ -57,12 +57,14 @@ typedef enum
 {
   PP_pushm,
   PP_popm,
   PP_justcount
 } Push_Pop_Type;
 
+rtx dj(rtx x) { return x; }
+
 static bool m32c_function_needs_enter (void);
 static tree interrupt_handler (tree *, tree, tree, int, bool *);
 static tree function_vector_handler (tree *, tree, tree, int, bool *);
 static int interrupt_p (tree node);
 static int bank_switch_p (tree node);
 static int fast_interrupt_p (tree node);
@@ -70,12 +72,13 @@ static int interrupt_p (tree node);
 static bool m32c_asm_integer (rtx, unsigned int, int);
 static int m32c_comp_type_attributes (const_tree, const_tree);
 static bool m32c_fixed_condition_code_regs (unsigned int *, unsigned int *);
 static struct machine_function *m32c_init_machine_status (void);
 static void m32c_insert_attributes (tree, tree *);
 static bool m32c_legitimate_address_p (enum machine_mode, rtx, bool);
+static bool m32c_addr_space_legitimate_address_p (enum machine_mode, rtx, bool, addr_space_t);
 static bool m32c_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
 				    const_tree, bool);
 static bool m32c_promote_prototypes (const_tree);
 static int m32c_pushm_popm (Push_Pop_Type);
 static bool m32c_strict_argument_naming (CUMULATIVE_ARGS *);
 static rtx m32c_struct_value_rtx (tree, int);
@@ -114,12 +117,24 @@ static GTY(()) rtx patternr[30];
 #define IS_MEM_REGNO(regno) ((regno) >= MEM0_REGNO && (regno) <= MEM7_REGNO)
 #define IS_MEM_REG(rtx) (GET_CODE (rtx) == REG && IS_MEM_REGNO (REGNO (rtx)))
 
 #define IS_CR_REGNO(regno) ((regno) >= SB_REGNO && (regno) <= PC_REGNO)
 #define IS_CR_REG(rtx) (GET_CODE (rtx) == REG && IS_CR_REGNO (REGNO (rtx)))
 
+static int
+far_addr_space_p (rtx x)
+{
+  if (GET_CODE (x) != MEM)
+    return 0;
+#if DEBUG0
+  fprintf(stderr, "\033[35mfar_addr_space: "); debug_rtx(x);
+  fprintf(stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR);
+#endif
+  return MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR;
+}
+
 /* We do most RTX matching by converting the RTX into a string, and
    using string compares.  This vastly simplifies the logic in many of
    the functions in this file.
 
    On exit, pattern[] has the encoded string (use RTX_IS("...") to
    compare it) and patternr[] has pointers to the nodes in the RTX
@@ -156,12 +171,22 @@ encode_pattern_1 (rtx x)
       break;
     case MEM:
       *patternp++ = 'm';
     case CONST:
       encode_pattern_1 (XEXP (x, 0));
       break;
+    case SIGN_EXTEND:
+      *patternp++ = '^';
+      *patternp++ = '^S';
+      encode_pattern_1 (XEXP (x, 0));
+      break;
+    case ZERO_EXTEND:
+      *patternp++ = '^';
+      *patternp++ = '^Z';
+      encode_pattern_1 (XEXP (x, 0));
+      break;
     case PLUS:
       *patternp++ = '+';
       encode_pattern_1 (XEXP (x, 0));
       encode_pattern_1 (XEXP (x, 1));
       break;
     case PRE_DEC:
@@ -224,19 +249,26 @@ encode_pattern_1 (rtx x)
 #endif
       break;
     }
 }
 
 static void
-encode_pattern (rtx x)
+djencode_pattern (rtx x, const char *func)
 {
+  memset (patternr, 0, sizeof(patternr));
   patternp = pattern;
   encode_pattern_1 (x);
   *patternp = 0;
+#if DEBUG1
+  debug_rtx(x);
+  fprintf(stderr, "%s: \033[32m\"%s\"\033[0m\n", func, pattern);
+#endif
 }
 
+#define encode_pattern(x) djencode_pattern(x, __FUNCTION__)
+
 /* Since register names indicate the mode they're used in, we need a
    way to determine which name to refer to the register with.  Called
    by print_operand().  */
 
 static const char *
 reg_name_with_mode (int regno, enum machine_mode mode)
@@ -507,12 +539,18 @@ m32c_conditional_register_usage (void)
 	{
 	  fixed_regs[MEM0_REGNO + i] = 1;
 	  CLEAR_HARD_REG_BIT (reg_class_contents[MEM_REGS], MEM0_REGNO + i);
 	}
     }
 
+  if (TARGET_A16)
+    {
+      SET_HARD_REG_BIT (reg_class_contents[SI_REGS], A0_REGNO);
+      SET_HARD_REG_BIT (reg_class_contents[SI_REGS], A1_REGNO);
+    }
+
   /* M32CM and M32C preserve more registers across function calls.  */
   if (TARGET_A24)
     {
       call_used_regs[R1_REGNO] = 0;
       call_used_regs[R2_REGNO] = 0;
       call_used_regs[R3_REGNO] = 0;
@@ -538,13 +576,13 @@ m32c_hard_regno_nregs_1 (int regno, enum
     return (GET_MODE_SIZE (mode) + 1) / 2;
 
   if (GET_MODE_SIZE (mode) <= 1)
     return nregs_table[regno].qi_regs;
   if (GET_MODE_SIZE (mode) <= 2)
     return nregs_table[regno].hi_regs;
-  if (regno == A0_REGNO && mode == PSImode && TARGET_A16)
+  if (regno == A0_REGNO && mode == SImode && TARGET_A16)
     return 2;
   if ((GET_MODE_SIZE (mode) <= 3 || mode == PSImode) && TARGET_A24)
     return nregs_table[regno].pi_regs;
   if (GET_MODE_SIZE (mode) <= 4)
     return nregs_table[regno].si_regs;
   if (GET_MODE_SIZE (mode) <= 8)
@@ -706,17 +744,27 @@ m32c_reg_class_from_constraint (char c A
 
   return NO_REGS;
 }
 
 /* Implements REGNO_OK_FOR_BASE_P.  */
 int
-m32c_regno_ok_for_base_p (int regno)
+m32c_regno_ok_for_base_p (int regno, int addr_space)
 {
-  if (regno == A0_REGNO
-      || regno == A1_REGNO || regno >= FIRST_PSEUDO_REGISTER)
-    return 1;
+  if (addr_space == ADDR_SPACE_FAR)
+    {
+      if (regno == A0_REGNO
+	  || regno >= FIRST_PSEUDO_REGISTER)
+	return 1;
+    }
+  else
+    {
+      if (regno == A0_REGNO
+	  || regno == A1_REGNO
+	  || regno >= FIRST_PSEUDO_REGISTER)
+	return 1;
+    }
   return 0;
 }
 
 #define DEBUG_RELOAD 0
 
 /* Implements PREFERRED_RELOAD_CLASS.  In general, prefer general
@@ -724,13 +772,13 @@ m32c_regno_ok_for_base_p (int regno)
 int
 m32c_preferred_reload_class (rtx x, int rclass)
 {
   int newclass = rclass;
 
 #if DEBUG_RELOAD
-  fprintf (stderr, "\npreferred_reload_class for %s is ",
+  fprintf (stderr, "\n\033[34mpreferred_reload_class for %s is \033[0m",
 	   class_names[rclass]);
 #endif
   if (rclass == NO_REGS)
     rclass = GET_MODE (x) == QImode ? HL_REGS : R03_REGS;
 
   if (classes_intersect (rclass, CR_REGS))
@@ -780,13 +828,13 @@ m32c_preferred_output_reload_class (rtx 
    address registers for reloads since they're needed for address
    reloads.  */
 int
 m32c_limit_reload_class (enum machine_mode mode, int rclass)
 {
 #if DEBUG_RELOAD
-  fprintf (stderr, "limit_reload_class for %s: %s ->",
+  fprintf (stderr, "\033[34mlimit_reload_class for %s: %s ->\033[0m",
 	   mode_name[mode], class_names[rclass]);
 #endif
 
   if (mode == QImode)
     rclass = reduce_class (rclass, HL_REGS, rclass);
   else if (mode == HImode)
@@ -973,19 +1021,44 @@ m32c_const_ok_for_constraint_p (HOST_WID
     {
       return (value == 0);
     }
   return 0;
 }
 
+#define A0_OR_PSEUDO(x) (IS_REG(x, A0_REGNO) || REGNO (x) >= FIRST_PSEUDO_REGISTER)
+
 /* Implements EXTRA_CONSTRAINT_STR (see next function too).  'S' is
    for memory constraints, plus "Rpa" for PARALLEL rtx's we use for
    call return values.  */
 int
 m32c_extra_constraint_p2 (rtx value, char c ATTRIBUTE_UNUSED, const char *str)
 {
   encode_pattern (value);
+
+  if (far_addr_space_p (value))
+    {
+      if (memcmp (str, "SF", 2) == 0)
+	{
+	  return (   (RTX_IS ("mr")
+		      && A0_OR_PSEUDO (patternr[1])
+		      && GET_MODE (patternr[1]) == SImode)
+		     || (RTX_IS ("m+^Zri")
+			 && A0_OR_PSEUDO (patternr[4])
+			 && GET_MODE (patternr[4]) == HImode)
+		     || (RTX_IS ("m+^Zrs")
+			 && A0_OR_PSEUDO (patternr[4])
+			 && GET_MODE (patternr[4]) == HImode)
+		     || (RTX_IS ("m+^Z+ris")
+			 && A0_OR_PSEUDO (patternr[5])
+			 && GET_MODE (patternr[5]) == HImode)
+		     || RTX_IS ("ms")
+		     );
+	}
+      return 0;
+    }
+
   if (memcmp (str, "Sd", 2) == 0)
     {
       /* This is the common "src/dest" address */
       rtx r;
       if (GET_CODE (value) == MEM && CONSTANT_P (XEXP (value, 0)))
 	return 1;
@@ -1047,12 +1120,16 @@ m32c_extra_constraint_p2 (rtx value, cha
 	      && !(INTVAL (patternr[1]) & ~0x1fff));
     }
   else if (memcmp (str, "S1", 2) == 0)
     {
       return r1h_operand (value, QImode);
     }
+  else if (memcmp (str, "SF", 2) == 0)
+    {
+      return 0;
+    }
 
   gcc_assert (str[0] != 'S');
 
   if (memcmp (str, "Rpa", 2) == 0)
     return GET_CODE (value) == PARALLEL;
 
@@ -1061,16 +1138,21 @@ m32c_extra_constraint_p2 (rtx value, cha
 
 /* This is for when we're debugging the above.  */
 int
 m32c_extra_constraint_p (rtx value, char c, const char *str)
 {
   int rv = m32c_extra_constraint_p2 (value, c, str);
-#if DEBUG0
-  fprintf (stderr, "\nconstraint %.*s: %d\n", CONSTRAINT_LEN (c, str), str,
-	   rv);
-  debug_rtx (value);
+#if DEBUG1
+  if (memcmp (str, "SF", 2) == 0)
+    {
+      fprintf(stderr, "\033[33m");
+      fprintf (stderr, "\nconstraint %.*s: %d\n", CONSTRAINT_LEN (c, str), str,
+	       rv);
+      debug_rtx (value);
+      fprintf(stderr, "\033[0m");
+    }
 #endif
   return rv;
 }
 
 /* Implements EXTRA_MEMORY_CONSTRAINT.  Currently, we only use strings
    starting with 'S'.  */
@@ -1809,12 +1891,17 @@ bool
 m32c_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
 {
   int mode_adjust;
   if (CONSTANT_P (x))
     return 1;
 
+  if (TARGET_A16 && GET_MODE (x) != HImode)
+    return 0;
+  if (TARGET_A24 && GET_MODE (x) != PSImode)
+    return 0;
+
   /* Wide references to memory will be split after reload, so we must
      ensure that all parts of such splits remain legitimate
      addresses.  */
   mode_adjust = GET_MODE_SIZE (mode) - 1;
 
   /* allowing PLUS yields mem:HI(plus:SI(mem:SI(plus:SI in m32c_split_move */
@@ -1907,16 +1994,20 @@ m32c_legitimate_address_p (enum machine_
 	case A0_REGNO:
 	case A1_REGNO:
 	  /* $sb needs a secondary reload, but since it's involved in
 	     memory address reloads too, we don't deal with it very
 	     well.  */
 	  /*    case SB_REGNO: */
+	  fprintf(stderr, "ok\n");
 	  return 1;
 	default:
 	  if (IS_PSEUDO (reg, strict))
+	    {
+	  fprintf(stderr, "ok\n");
 	    return 1;
+	    }
 	  return 0;
 	}
     }
   return 0;
 }
 
@@ -2069,12 +2160,211 @@ int
 m32c_legitimate_constant_p (rtx x ATTRIBUTE_UNUSED)
 {
   return 1;
 }
 
 
+/* Return the appropriate mode for a named address pointer.  */
+#undef TARGET_ADDR_SPACE_POINTER_MODE
+#define TARGET_ADDR_SPACE_POINTER_MODE m32c_addr_space_pointer_mode
+static enum machine_mode
+m32c_addr_space_pointer_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+      return TARGET_A24 ? PSImode : HImode;
+    case ADDR_SPACE_FAR:
+      return SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Return the appropriate mode for a named address address.  */
+#undef TARGET_ADDR_SPACE_ADDRESS_MODE
+#define TARGET_ADDR_SPACE_ADDRESS_MODE m32c_addr_space_address_mode
+static enum machine_mode
+m32c_addr_space_address_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+      return TARGET_A24 ? PSImode : HImode;
+    case ADDR_SPACE_FAR:
+      return SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Like m32c_legitimate_address_p, except with named addresses.  */
+#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
+#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \
+  m32c_addr_space_legitimate_address_p
+static bool
+_m32c_addr_space_legitimate_address_p (enum machine_mode mode, rtx x,
+				      bool strict, addr_space_t as)
+{
+  if (as == ADDR_SPACE_FAR)
+    {
+      if (TARGET_A24)
+	return 0;
+      encode_pattern (x);
+      if (RTX_IS ("r"))
+	{
+	  if (GET_MODE (x) != SImode)
+	    return 0;
+	  switch (REGNO (patternr[0]))
+	    {
+	    case A0_REGNO:
+	      return 1;
+
+	    default:
+	      if (IS_PSEUDO (patternr[0], strict))
+		return 1;
+	      return 0;
+	    }
+	}
+      if (RTX_IS ("+^Zri"))
+	{
+	  int rn = REGNO (patternr[3]);
+	  HOST_WIDE_INT offs = INTVAL (patternr[4]);
+	  if (GET_MODE (patternr[3]) != HImode)
+	    return 0;
+	  switch (rn)
+	    {
+	    case A0_REGNO:
+	      return (offs >= 0 && offs <= 0xfffff);
+
+	    default:
+	      if (IS_PSEUDO (patternr[3], strict))
+		return 1;
+	      return 0;
+	    }
+	}
+      if (RTX_IS ("+^Zrs"))
+	{
+	  int rn = REGNO (patternr[3]);
+	  if (GET_MODE (patternr[3]) != HImode)
+	    return 0;
+	  switch (rn)
+	    {
+	    case A0_REGNO:
+	      return 1;
+
+	    default:
+	      if (IS_PSEUDO (patternr[3], strict))
+		return 1;
+	      return 0;
+	    }
+	}
+      if (RTX_IS ("+^Z+ris"))
+	{
+	  int rn = REGNO (patternr[4]);
+	  if (GET_MODE (patternr[4]) != HImode)
+	    return 0;
+	  switch (rn)
+	    {
+	    case A0_REGNO:
+	      return 1;
+
+	    default:
+	      if (IS_PSEUDO (patternr[4], strict))
+		return 1;
+	      return 0;
+	    }
+	}
+      if (RTX_IS ("s"))
+	{
+	  return 1;
+	}
+      return 0;
+    }
+
+  else if (as != ADDR_SPACE_GENERIC)
+    gcc_unreachable ();
+
+  return m32c_legitimate_address_p (mode, x, strict);
+}
+static bool
+m32c_addr_space_legitimate_address_p (enum machine_mode mode, rtx x,
+				      bool strict, addr_space_t as)
+{
+  bool r = _m32c_addr_space_legitimate_address_p (mode, x, strict, as);
+  printf(" => %d\n", r);
+  return r;
+}
+/* Like m32c_legitimate_address, except with named address support.  */
+#undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS
+#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS m32c_addr_space_legitimize_address
+static rtx
+m32c_addr_space_legitimize_address (rtx x, rtx oldx, enum machine_mode mode,
+				    addr_space_t as)
+{
+  if (as != ADDR_SPACE_GENERIC)
+    {
+      if (GET_CODE (x) != REG)
+	{
+	  x = force_reg (SImode, x);
+	}
+      return x;
+    }
+
+  return m32c_legitimize_address (x, oldx, mode);
+}
+
+/* Determine if one named address space is a subset of another.  */
+#undef TARGET_ADDR_SPACE_SUBSET_P
+#define TARGET_ADDR_SPACE_SUBSET_P m32c_addr_space_subset_p
+static bool
+m32c_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
+{
+  gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_FAR);
+  gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_FAR);
+
+  if (subset == superset)
+    return true;
+
+  else
+    return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_FAR);
+}
+
+#undef TARGET_ADDR_SPACE_CONVERT
+#define TARGET_ADDR_SPACE_CONVERT m32c_addr_space_convert
+/* Convert from one address space to another.  */
+static rtx
+m32c_addr_space_convert (rtx op, tree from_type, tree to_type)
+{
+  addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
+  addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
+  rtx result;
+
+  gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_FAR);
+  gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_FAR);
+
+  if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_FAR)
+    {
+      /* This is unpredictable, as we're truncating off usable address
+	 bits.  */
+
+      result = gen_reg_rtx (HImode);
+      emit_move_insn (result, simplify_subreg (HImode, op, SImode, 0));
+      return result;
+    }
+  else if (to_as == ADDR_SPACE_FAR && from_as == ADDR_SPACE_GENERIC)
+    {
+      /* This always works.  */
+      result = gen_reg_rtx (SImode);
+      emit_insn (gen_zero_extendhisi2 (result, op));
+      return result;
+    }
+  else
+    gcc_unreachable ();
+}
+
 /* Condition Code Status */
 
 #undef TARGET_FIXED_CONDITION_CODE_REGS
 #define TARGET_FIXED_CONDITION_CODE_REGS m32c_fixed_condition_code_regs
 static bool
 m32c_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
@@ -2221,14 +2511,15 @@ m32c_rtx_costs (rtx x, int code, int out
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST m32c_address_cost
 static int
 m32c_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
 {
   int i;
-  /*  fprintf(stderr, "\naddress_cost\n");
-      debug_rtx(addr);*/
+    fprintf(stderr, "\n\033[31maddress_cost\n");
+      debug_rtx(addr);
+      fprintf(stderr, "\033[0m");
   switch (GET_CODE (addr))
     {
     case CONST_INT:
       i = INTVAL (addr);
       if (i == 0)
 	return COSTS_N_INSNS(1);
@@ -2307,12 +2598,15 @@ static struct
 const conversions[] = {
   { 0, "r", "0" },
 
   { 0, "mr", "z[1]" },
   { 0, "m+ri", "3[2]" },
   { 0, "m+rs", "3[2]" },
+  { 0, "m+^Zrs", "5[4]" },
+  { 0, "m+^Zri", "5[4]" },
+  { 0, "m+^Z+ris", "7+6[5]" },
   { 0, "m+r+si", "4+5[2]" },
   { 0, "ms", "1" },
   { 0, "mi", "1" },
   { 0, "m+si", "2+3" },
 
   { 0, "mmr", "[z[2]]" },
@@ -3231,12 +3525,17 @@ m32c_subreg (enum machine_mode outer,
 
 /* Used to emit move instructions.  We split some moves,
    and avoid mem-mem moves.  */
 int
 m32c_prepare_move (rtx * operands, enum machine_mode mode)
 {
+  if (far_addr_space_p (operands[0])
+      && CONSTANT_P (operands[1]))
+    {
+      operands[1] = force_reg (GET_MODE (operands[0]), operands[1]);
+    }
   if (TARGET_A16 && mode == PSImode)
     return m32c_split_move (operands, mode, 1);
   if ((GET_CODE (operands[0]) == MEM)
       && (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY))
     {
       rtx pmv = XEXP (operands[0], 0);
@@ -3336,12 +3635,17 @@ m32c_split_move (rtx * operands, enum ma
      point, so it's safe to set it to 3 even with define_insn.  */
   /* None of the chips can move SI operands to sp-relative addresses,
      so we always split those.  */
   if (m32c_extra_constraint_p (operands[0], 'S', "Ss"))
     split_all = 3;
 
+  if (TARGET_A16
+      && (far_addr_space_p (operands[0])
+	  || far_addr_space_p (operands[1])))
+    split_all |= 1;
+
   /* We don't need to split these.  */
   if (TARGET_A24
       && split_all != 3
       && (mode == SImode || mode == PSImode)
       && !(GET_CODE (operands[1]) == MEM
 	   && GET_CODE (XEXP (operands[1], 0)) == POST_INC))
Index: gcc/config/m32c/m32c.h
===================================================================
--- gcc/config/m32c/m32c.h	(revision 153725)
+++ gcc/config/m32c/m32c.h	(working copy)
@@ -390,12 +390,15 @@ enum reg_class
 #define REGNO_REG_CLASS(R) m32c_regno_reg_class (R)
 
 /* We support simple displacements off address registers, nothing else.  */
 #define BASE_REG_CLASS A_REGS
 #define INDEX_REG_CLASS NO_REGS
 
+#define MODE_CODE_BASE_REG_CLASS(MODE,ASPACE,OCODE,ICODE) \
+  ((ASPACE) == ADDR_SPACE_FAR ? A0_REGS : A_REGS)
+
 /* We primarily use the new "long" constraint names, with the initial
    letter classifying the constraint type and following letters
    specifying which.  The types are:
 
    I - integer values
    R - register classes
@@ -409,13 +412,15 @@ enum reg_class
 	 : (CHAR) == 'S' ? 2 \
 	 : (CHAR) == 'A' ? 2 \
 	 : DEFAULT_CONSTRAINT_LEN(CHAR,STR))
 #define REG_CLASS_FROM_CONSTRAINT(CHAR,STR) \
 	m32c_reg_class_from_constraint (CHAR, STR)
 
-#define REGNO_OK_FOR_BASE_P(NUM) m32c_regno_ok_for_base_p (NUM)
+#define REGNO_OK_FOR_BASE_P(NUM) m32c_regno_ok_for_base_p (NUM, 0)
+#define REGNO_MODE_CODE_OK_FOR_BASE_P(NUM,MODE,ASPACE,OCODE,ICODE) m32c_regno_ok_for_base_p (NUM,ASPACE)
+
 #define REGNO_OK_FOR_INDEX_P(NUM) 0
 
 #define PREFERRED_RELOAD_CLASS(X,CLASS) m32c_preferred_reload_class (X, CLASS)
 #define PREFERRED_OUTPUT_RELOAD_CLASS(X,CLASS) m32c_preferred_output_reload_class (X, CLASS)
 #define LIMIT_RELOAD_CLASS(MODE,CLASS) m32c_limit_reload_class (MODE, CLASS)
 
@@ -579,12 +584,19 @@ typedef struct m32c_cumulative_args
 #define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \
 	if (m32c_legitimize_reload_address(&(X),MODE,OPNUM,TYPE,IND_LEVELS)) \
 	  goto WIN;
 
 #define LEGITIMATE_CONSTANT_P(X) m32c_legitimate_constant_p (X)
 
+/* Address spaces.  */
+#define ADDR_SPACE_FAR	1
+
+/* Named address space keywords.  */
+#define TARGET_ADDR_SPACE_KEYWORDS ADDR_SPACE_KEYWORD ("__far", ADDR_SPACE_FAR)
+
+
 /* Condition Code Status */
 
 #define REVERSIBLE_CC_MODE(MODE) 1
 
 /* Describing Relative Costs of Operations */
 
Index: gcc/config/m32c/mov.md
===================================================================
--- gcc/config/m32c/mov.md	(revision 153725)
+++ gcc/config/m32c/mov.md	(working copy)
@@ -29,51 +29,54 @@
 ;; the stack.
 
 ;; Match push/pop before mov.b for passing char as arg,
 ;; e.g. stdlib/efgcvt.c.
 (define_insn "movqi_op"
   [(set (match_operand:QI 0 "m32c_nonimmediate_operand"
-			  "=Rqi*Rmm, <,          RqiSd*Rmm, SdSs,    Rqi*Rmm, Sd")
+			  "=SF,Rhi*RmmSd, Rqi*Rmm, <,          RqiSd*Rmm, SdSs,    Rqi*Rmm, Sd")
 	(match_operand:QI 1 "m32c_any_operand"
-			  "iRqi*Rmm, iRqiSd*Rmm, >,         Rqi*Rmm, SdSs,    i"))]
+			  "Rhi*RmmSd,SF, iRqi*Rmm, iRqiSd*Rmm, >,         Rqi*Rmm, SdSs,    i"))]
   "m32c_mov_ok (operands, QImode)"
   "@
+    lde.b\t%1,%0
+    ste.b\t%1,%0
     mov.b\t%1,%0
     push.b\t%1
     pop.b\t%0
     mov.b\t%1,%0
     mov.b\t%1,%0
     mov.b\t%1,%0"
-  [(set_attr "flags" "sz,*,*,sz,sz,sz")]
+  [(set_attr "flags" "sz,sz,sz,*,*,sz,sz,sz")]
   )
 
 (define_expand "movqi"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=RqiSd*Rmm")
 	(match_operand:QI 1 "general_operand" "iRqiSd*Rmm"))]
   ""
   "if (m32c_prepare_move (operands, QImode)) DONE;"
   )
 
-
 (define_insn "movhi_op"
   [(set (match_operand:HI 0 "m32c_nonimmediate_operand"
-			  "=Rhi*Rmm,     Sd, SdSs,   *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr")
+			  "=SF,Rhi*RmmSd, Rhi*Rmm,     Sd, SdSs,   *Rcr, RhiSd*Rmm, <, RhiSd*Rmm, <, *Rcr")
 	(match_operand:HI 1 "m32c_any_operand"
-			  "iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))]
+			  " Rhi*RmmSd,SF, iRhi*RmmSdSs, i, Rhi*Rmm, RhiSd*Rmm, *Rcr, iRhiSd*Rmm, >, *Rcr, >"))]
   "m32c_mov_ok (operands, HImode)"
   "@
+   lde.w\t%1,%0
+   ste.w\t%1,%0
    mov.w\t%1,%0
    mov.w\t%1,%0
    mov.w\t%1,%0
    ldc\t%1,%0
    stc\t%1,%0
    push.w\t%1
    pop.w\t%0
    pushc\t%1
    popc\t%0"
-  [(set_attr "flags" "sz,sz,sz,n,n,n,n,n,n")]
+  [(set_attr "flags" "sz,sz,sz,sz,sz,n,n,n,n,n,n")]
   )
 
 (define_expand "movhi"
   [(set (match_operand:HI 0 "m32c_nonimmediate_operand" "=RhiSd*Rmm")
 	(match_operand:HI 1 "m32c_any_operand" "iRhiSd*Rmm"))]
   ""
Index: gcc/config/m32c/addsub.md
===================================================================
--- gcc/config/m32c/addsub.md	(revision 153725)
+++ gcc/config/m32c/addsub.md	(working copy)
@@ -90,15 +90,23 @@
     { 
     case 0:
       return \"add.w %X2,%h0\;adcf.w %H0\";
     case 1:
       return \"add.w %X2,%h0\;adcf.w %H0\";
     case 2:
-      output_asm_insn (\"add.w %X2,%h0\",operands);
-      operands[2]= GEN_INT (INTVAL (operands[2]) >> 16);
-      return \"adc.w %X2,%H0\";
+      if (GET_CODE (operands[2]) == SYMBOL_REF)
+        {
+          output_asm_insn (\"add.w #%%lo(%d2),%h0\",operands);
+          return \"adc.w #%%hi(%d2),%H0\";
+        }
+      else
+        {
+          output_asm_insn (\"add.w %X2,%h0\",operands);
+          operands[2]= GEN_INT (INTVAL (operands[2]) >> 16);
+          return \"adc.w %X2,%H0\";
+        }
     case 3:
       return \"add.w %h2,%h0\;adc.w %H2,%H0\";
     case 4:
       output_asm_insn (\"add.w %X2,%h0\",operands);
       operands[2]= GEN_INT (INTVAL (operands[2]) >> 16);
       return \"adc.w %X2,%H0\";
Index: gcc/config/m32c/m32c-protos.h
===================================================================
--- gcc/config/m32c/m32c-protos.h	(revision 153725)
+++ gcc/config/m32c/m32c-protos.h	(working copy)
@@ -39,13 +39,13 @@ void m32c_output_reg_pop (FILE *, int);
 void m32c_output_reg_push (FILE *, int);
 void m32c_override_options (void);
 int  m32c_print_operand_punct_valid_p (int);
 int  m32c_push_rounding (int);
 int  m32c_reg_class_from_constraint (char, const char *);
 void m32c_register_pragmas (void);
-int  m32c_regno_ok_for_base_p (int);
+int  m32c_regno_ok_for_base_p (int,int);
 int  m32c_trampoline_alignment (void);
 int  m32c_trampoline_size (void);
 
 #if defined(RTX_CODE) && defined(TREE_CODE)
 
 rtx  m32c_function_arg (CUMULATIVE_ARGS *, MM, tree, int);

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch)
  2009-10-29 20:18             ` DJ Delorie
@ 2009-10-29 21:33               ` Ulrich Weigand
  2009-10-29 22:50                 ` DJ Delorie
  0 siblings, 1 reply; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-29 21:33 UTC (permalink / raw)
  To: DJ Delorie; +Cc: gcc-patches

DJ Delorie wrote:

> Nope.  Here's the m32c part so far...  You can build for m32c-elf and test with this:

Well, this seems to be a back-end problem.  I'm getting:

dj.c: In function 'far_array_set':
dj.c:8:1: error: unable to find a register to spill in class 'A0_REGS'
dj.c:8:1: error: this is the insn:
(insn 11 10 14 2 dj.c:7 (set (mem/s/j:QI (reg/f:SI 2 r1 [30]) [0 far_char_array S1 A8 AS1])
        (const_int 0 [0x0])) 89 {movqi_op} (expr_list:REG_DEAD (reg/f:SI 2 r1 [30])
        (expr_list:REG_EQUAL (const_int 0 [0x0])
            (nil))))

Note that reload now understands it must use class A0_REGS.  However,
this is not possible, because:
- the address is SImode according to m32c_addr_space_address_mode
- SImode does not fit in A0, only in the pair A0 / A1 according
  to m32c_hard_regno_nregs
- but A1 is not in class A0_REGS and hence not usable as base
  register

It seems to me that use of SImode as address_mode for far pointers
isn't correct, if they need to fit into a 24-bit base register ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch)
  2009-10-29 21:33               ` Ulrich Weigand
@ 2009-10-29 22:50                 ` DJ Delorie
  2009-10-30 14:51                   ` Ulrich Weigand
  0 siblings, 1 reply; 34+ messages in thread
From: DJ Delorie @ 2009-10-29 22:50 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gcc-patches


> dj.c:8:1: error: unable to find a register to spill in class 'A0_REGS'

> It seems to me that use of SImode as address_mode for far pointers
> isn't correct, if they need to fit into a 24-bit base register ...

In r8c/m16c mode, A0/A1 are 16 bit, and pointers are normally 16 bit.
There are extra opcodes for load/store with 32-bit pointers in A1A0.
In m32cm/m32c mode, pointers are normally 24 bit, A0 and A1 are 24
bit, and there are no extra opcodes.

The extra opcodes support 32-bit pointers *without* offsets, or 16-bit
pointers *with* 24-bit offsets.  In either case, A0 is the only base
register (or A1A0 for 32-bit pointers).

Note that the base register class was A_REGS (A1 and A0) before, and
it picked R1.  Go figure.

I tried allowing A_REGS for the appropriate cases, now I get:

dj.c: In function 'far_array_set':
dj.c:76:1: error: unrecognizable insn:
(insn 20 19 14 2 dj.c:75 (set (mem/s/j:QI (plus:SI (reg:SI 0 r0)
                (symbol_ref:SI ("far_char_array") [flags 0x40] <var_decl 0xb7e93170 far_char_array>)) [0 far_char_array S1 A8 AS1])
        (reg:QI 2 r1)) -1 (nil))


It seems to be trying every register EXCEPT the ones in the base
class.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fix PR tree-optimization/41857 (Re: m32c support for named addr   spaces branch)
  2009-10-29 18:32                           ` Fix PR tree-optimization/41857 (Re: m32c support for named addr spaces branch) Ulrich Weigand
@ 2009-10-30  9:51                             ` Richard Guenther
  2009-11-02  9:38                               ` Zdenek Dvorak
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Guenther @ 2009-10-30  9:51 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: DJ Delorie, gcc-patches, Zdenek Dvorak

On Thu, Oct 29, 2009 at 7:29 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
>> On Tue, Oct 27, 2009 at 7:22 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
>> > I now seem to be running into a related problem with __ea on SPU, in a
>> > loop where the loop optimizer decides to use a DImode IV to implement
>> > a 64-bit __ea pointer.
>> >
>> > This causes create_mem_ref to be called with an affine combination
>> > that contains only a single value, of 64-bit integral type.
>> >
>> > Because this is not a pointer type, addr_to_parts interprets this
>> > value as "index", not "base".  (I'm not quite sure I understand
>> > how this is intended to work anyway: it seems to me that loop IVs
>> > use (nearly?) always integral types.  Why does move_pointer_to_base
>> > check for pointer type then?)
>
> I've now opened PR 41857 for this particular problem.
>
> The core problem in this case is that pointers may be converted to
> sizetype by loop IV optimizations.  This is particularly aggravated
> by the fact that create_mem_ref has a hard time determining which
> of the variables in the affine expression it gets as input
> represents the base of the reference.
>
> The heuristics used to determine this looks for variables of pointer
> type.  However, due to problems related to undefined overflow, the
> IV optimizations have switched to always using integer types for
> induction variables, even those that represent memory addresses.
> This makes the create_mem_ref heuristics mostly useless in many
> cases ...
>
> However, rewrite_use_address (the call site of create_mem_ref) does
> actually have the information; it knows whether the IV candidate
> is based on a memory object.  The information is simply not passed
> to create_mem_ref.  The patch below changes this by adding a new
> BASE_HINT argument to create_mem_ref, which is set to the IV that
> is to be used as base of the reference, if any.
>
> create_mem_ref and its subroutines then use this variable (casted
> to the appropriate pointer type) as base.
>
> As a side effect, the patch also fixes a FIXME in
> most_expensive_mult_to_index.
>
> While not a complete fix to the general sizetype problem, this
> patch fixes the ICE-on-valid bug on the testcase in the PR, and
> it seems a good idea to properly identify the base anyway; this
> is needed (or at least beneficial) on some platforms.
>
> Tested on s390x-ibm-linux and spu-elf.
> OK for mainline?

This looks good to me, though I'd like Zdenek to have a 2nd look.

Thanks,
Richard.

> Bye,
> Ulrich
>
>
> ChangeLog:
>
> gcc/
>        PR tree-optimization/41857
>        * tree-flow.h (rewrite_use_address): Add BASE_HINT argument.
>        * tree-ssa-loop-ivopts.c (rewrite_use_address): Pass base hint
>        to create_mem_ref.
>        * tree-ssa-address.c (move_hint_to_base): New function.
>        (most_expensive_mult_to_index): Add TYPE argument.  Use mode and
>        address space associated with TYPE.
>        (addr_to_parts): Add TYPE and BASE_HINT arguments.  Pass TYPE to
>        most_expensive_mult_to_index.  Call move_hint_to_base.
>        (create_mem_ref): Add BASE_HINT argument.  Pass BASE_HINT and
>        TYPE to addr_to_parts.
>
> gcc/testsuite/
>        PR tree-optimization/41857
>        * gcc.target/spu/ea/pr41857.c: New file.
>
>
> Index: gcc/tree-ssa-loop-ivopts.c
> ===================================================================
> *** gcc/tree-ssa-loop-ivopts.c  (revision 153683)
> --- gcc/tree-ssa-loop-ivopts.c  (working copy)
> *************** rewrite_use_address (struct ivopts_data
> *** 5510,5515 ****
> --- 5510,5516 ----
>  {
>    aff_tree aff;
>    gimple_stmt_iterator bsi = gsi_for_stmt (use->stmt);
> +   tree base_hint = NULL_TREE;
>    tree ref;
>    bool ok;
>
> *************** rewrite_use_address (struct ivopts_data
> *** 5517,5523 ****
>    gcc_assert (ok);
>    unshare_aff_combination (&aff);
>
> !   ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff, data->speed);
>    copy_ref_info (ref, *use->op_p);
>    *use->op_p = ref;
>  }
> --- 5518,5539 ----
>    gcc_assert (ok);
>    unshare_aff_combination (&aff);
>
> !   /* To avoid undefined overflow problems, all IV candidates use unsigned
> !      integer types.  The drawback is that this makes it impossible for
> !      create_mem_ref to distinguish an IV that is based on a memory object
> !      from one that represents simply an offset.
> !
> !      To work around this problem, we pass a hint to create_mem_ref that
> !      indicates which variable (if any) in aff is an IV based on a memory
> !      object.  Note that we only consider the candidate.  If this is not
> !      based on an object, the base of the reference is in some subexpression
> !      of the use -- but these will use pointer types, so they are recognized
> !      by the create_mem_ref heuristics anyway.  */
> !   if (cand->iv->base_object)
> !     base_hint = var_at_stmt (data->current_loop, cand, use->stmt);
> !
> !   ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff, base_hint,
> !                       data->speed);
>    copy_ref_info (ref, *use->op_p);
>    *use->op_p = ref;
>  }
> Index: gcc/tree-ssa-address.c
> ===================================================================
> *** gcc/tree-ssa-address.c      (revision 153683)
> --- gcc/tree-ssa-address.c      (working copy)
> *************** move_fixed_address_to_symbol (struct mem
> *** 392,397 ****
> --- 392,424 ----
>    aff_combination_remove_elt (addr, i);
>  }
>
> + /* If ADDR contains an instance of BASE_HINT, move it to PARTS->base.  */
> +
> + static void
> + move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
> +                  aff_tree *addr)
> + {
> +   unsigned i;
> +   tree val = NULL_TREE;
> +
> +   for (i = 0; i < addr->n; i++)
> +     {
> +       if (!double_int_one_p (addr->elts[i].coef))
> +       continue;
> +
> +       val = addr->elts[i].val;
> +       if (operand_equal_p (val, base_hint, 0))
> +       break;
> +     }
> +
> +   if (i == addr->n)
> +     return;
> +
> +   /* Cast value to appropriate pointer type.  */
> +   parts->base = fold_convert (build_pointer_type (type), val);
> +   aff_combination_remove_elt (addr, i);
> + }
> +
>  /* If ADDR contains an address of a dereferenced pointer, move it to
>     PARTS->base.  */
>
> *************** add_to_parts (struct mem_address *parts,
> *** 453,461 ****
>     element(s) to PARTS.  */
>
>  static void
> ! most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr,
> !                             bool speed)
>  {
>    HOST_WIDE_INT coef;
>    double_int best_mult, amult, amult_neg;
>    unsigned best_mult_cost = 0, acost;
> --- 480,490 ----
>     element(s) to PARTS.  */
>
>  static void
> ! most_expensive_mult_to_index (tree type, struct mem_address *parts,
> !                             aff_tree *addr, bool speed)
>  {
> +   addr_space_t as = TYPE_ADDR_SPACE (type);
> +   enum machine_mode address_mode = targetm.addr_space.address_mode (as);
>    HOST_WIDE_INT coef;
>    double_int best_mult, amult, amult_neg;
>    unsigned best_mult_cost = 0, acost;
> *************** most_expensive_mult_to_index (struct mem
> *** 469,483 ****
>        if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
>        continue;
>
> -       /* FIXME: Should use the correct memory mode rather than Pmode.  */
> -
>        coef = double_int_to_shwi (addr->elts[i].coef);
>        if (coef == 1
> !         || !multiplier_allowed_in_address_p (coef, Pmode,
> !                                              ADDR_SPACE_GENERIC))
>        continue;
>
> !       acost = multiply_by_cost (coef, Pmode, speed);
>
>        if (acost > best_mult_cost)
>        {
> --- 498,509 ----
>        if (!double_int_fits_in_shwi_p (addr->elts[i].coef))
>        continue;
>
>        coef = double_int_to_shwi (addr->elts[i].coef);
>        if (coef == 1
> !         || !multiplier_allowed_in_address_p (coef, TYPE_MODE (type), as))
>        continue;
>
> !       acost = multiply_by_cost (coef, address_mode, speed);
>
>        if (acost > best_mult_cost)
>        {
> *************** most_expensive_mult_to_index (struct mem
> *** 520,527 ****
>    parts->step = double_int_to_tree (sizetype, best_mult);
>  }
>
> ! /* Splits address ADDR into PARTS.
> !
>     TODO -- be more clever about the distribution of the elements of ADDR
>     to PARTS.  Some architectures do not support anything but single
>     register in address, possibly with a small integer offset; while
> --- 546,555 ----
>    parts->step = double_int_to_tree (sizetype, best_mult);
>  }
>
> ! /* Splits address ADDR for a memory access of type TYPE into PARTS.
> !    If BASE_HINT is non-NULL, it specifies an SSA name to be used
> !    preferentially as base of the reference.
> !
>     TODO -- be more clever about the distribution of the elements of ADDR
>     to PARTS.  Some architectures do not support anything but single
>     register in address, possibly with a small integer offset; while
> *************** most_expensive_mult_to_index (struct mem
> *** 530,536 ****
>     addressing modes is useless.  */
>
>  static void
> ! addr_to_parts (aff_tree *addr, struct mem_address *parts, bool speed)
>  {
>    tree part;
>    unsigned i;
> --- 558,565 ----
>     addressing modes is useless.  */
>
>  static void
> ! addr_to_parts (tree type, aff_tree *addr, tree base_hint,
> !              struct mem_address *parts, bool speed)
>  {
>    tree part;
>    unsigned i;
> *************** addr_to_parts (aff_tree *addr, struct me
> *** 550,561 ****
>
>    /* First move the most expensive feasible multiplication
>       to index.  */
> !   most_expensive_mult_to_index (parts, addr, speed);
>
>    /* Try to find a base of the reference.  Since at the moment
>       there is no reliable way how to distinguish between pointer and its
>       offset, this is just a guess.  */
> !   if (!parts->symbol)
>      move_pointer_to_base (parts, addr);
>
>    /* Then try to process the remaining elements.  */
> --- 579,592 ----
>
>    /* First move the most expensive feasible multiplication
>       to index.  */
> !   most_expensive_mult_to_index (type, parts, addr, speed);
>
>    /* Try to find a base of the reference.  Since at the moment
>       there is no reliable way how to distinguish between pointer and its
>       offset, this is just a guess.  */
> !   if (!parts->symbol && base_hint)
> !     move_hint_to_base (type, parts, base_hint, addr);
> !   if (!parts->symbol && !parts->base)
>      move_pointer_to_base (parts, addr);
>
>    /* Then try to process the remaining elements.  */
> *************** gimplify_mem_ref_parts (gimple_stmt_iter
> *** 592,604 ****
>
>  tree
>  create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
> !               bool speed)
>  {
>    tree mem_ref, tmp;
>    tree atype;
>    struct mem_address parts;
>
> !   addr_to_parts (addr, &parts, speed);
>    gimplify_mem_ref_parts (gsi, &parts);
>    mem_ref = create_mem_ref_raw (type, &parts);
>    if (mem_ref)
> --- 623,635 ----
>
>  tree
>  create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
> !               tree base_hint, bool speed)
>  {
>    tree mem_ref, tmp;
>    tree atype;
>    struct mem_address parts;
>
> !   addr_to_parts (type, addr, base_hint, &parts, speed);
>    gimplify_mem_ref_parts (gsi, &parts);
>    mem_ref = create_mem_ref_raw (type, &parts);
>    if (mem_ref)
> Index: gcc/tree-flow.h
> ===================================================================
> *** gcc/tree-flow.h     (revision 153683)
> --- gcc/tree-flow.h     (working copy)
> *************** struct mem_address
> *** 921,927 ****
>
>  struct affine_tree_combination;
>  tree create_mem_ref (gimple_stmt_iterator *, tree,
> !                    struct affine_tree_combination *, bool);
>  rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool);
>  void get_address_description (tree, struct mem_address *);
>  tree maybe_fold_tmr (tree);
> --- 921,927 ----
>
>  struct affine_tree_combination;
>  tree create_mem_ref (gimple_stmt_iterator *, tree,
> !                    struct affine_tree_combination *, tree, bool);
>  rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool);
>  void get_address_description (tree, struct mem_address *);
>  tree maybe_fold_tmr (tree);
> *** /dev/null   2009-10-07 18:17:03.469375344 +0200
> --- gcc/testsuite/gcc.target/spu/ea/pr41857.c   2009-10-29 14:11:18.000000000 +0100
> ***************
> *** 0 ****
> --- 1,29 ----
> + /* Copyright (C) 2009 Free Software Foundation, Inc.
> +
> +    This file is free software; you can redistribute it and/or modify it under
> +    the terms of the GNU General Public License as published by the Free
> +    Software Foundation; either version 3 of the License, or (at your option)
> +    any later version.
> +
> +    This file is distributed in the hope that it will be useful, but WITHOUT
> +    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +    for more details.
> +
> +    You should have received a copy of the GNU General Public License
> +    along with this file; see the file COPYING3.  If not see
> +    <http://www.gnu.org/licenses/>.  */
> +
> + /* { dg-do compile } */
> +
> + __ea char *strchr_ea (__ea const char *s, int c);
> + __ea char *foo (__ea char *s)
> + {
> +   __ea char *ret = s;
> +   int i;
> +
> +   for (i = 0; i < 3; i++)
> +     ret = strchr_ea (ret, s[i]);
> +
> +   return ret;
> + }
>
>
> --
>  Dr. Ulrich Weigand
>  GNU Toolchain for Linux on System z and Cell BE
>  Ulrich.Weigand@de.ibm.com
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch)
  2009-10-29 22:50                 ` DJ Delorie
@ 2009-10-30 14:51                   ` Ulrich Weigand
  0 siblings, 0 replies; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-30 14:51 UTC (permalink / raw)
  To: DJ Delorie; +Cc: gcc-patches

DJ Delorie wrote:

> In r8c/m16c mode, A0/A1 are 16 bit, and pointers are normally 16 bit.
> There are extra opcodes for load/store with 32-bit pointers in A1A0.
> In m32cm/m32c mode, pointers are normally 24 bit, A0 and A1 are 24
> bit, and there are no extra opcodes.
> 
> The extra opcodes support 32-bit pointers *without* offsets, or 16-bit
> pointers *with* 24-bit offsets.  In either case, A0 is the only base
> register (or A1A0 for 32-bit pointers).

Ah, thanks for the explanation.  I think what you need to do to model
this in MODE_CODE_BASE_REG_CLASS is to look at the OUTER_CODE: if this
is a ZERO_EXTEND, the actual base variable is HImode, and you need to
restrict the base-reg class to A0_REGS.  Otherwise, the base variable
is SImode and you need to allow A_REGS.

In either case, REGNO_MODE_CODE_OK_FOR_BASE_P should accept only the
register A0.

> Note that the base register class was A_REGS (A1 and A0) before, and
> it picked R1.  Go figure.
> 
> I tried allowing A_REGS for the appropriate cases, now I get:
> 
> dj.c: In function 'far_array_set':
> dj.c:76:1: error: unrecognizable insn:
> (insn 20 19 14 2 dj.c:75 (set (mem/s/j:QI (plus:SI (reg:SI 0 r0)
>                 (symbol_ref:SI ("far_char_array") [flags 0x40] <var_decl 0xb7e93170 far_char_array>)) [0 far_char_array S1 A8 AS1])
>         (reg:QI 2 r1)) -1 (nil))
> 
> 
> It seems to be trying every register EXCEPT the ones in the base
> class.

I cannot reproduce this; can you send me the exact patch you're using
to get this?

I've tried your test case with the modification to MODE_CODE_BASE_REG_CLASS
as above.  I'm now running into a different problem:

dj.c: In function 'far_array_set':
dj.c:8:1: error: insn does not satisfy its constraints:
(insn 11 16 14 2 dj.c:7 (set (mem/s/j:QI (reg:SI 4 a0) [0 far_char_array S1 A8 AS1])
        (const_int 0 [0x0])) 89 {movqi_op} (expr_list:REG_EQUAL (const_int 0 [0x0])
        (nil)))
dj.c:8:1: internal compiler error: in reload_cse_simplify_operands, at postreload.c:396

What has happened here is that reload thought it could use the 7th alternative (Sd / i)
of the movqi_op insn pattern:

(define_insn "movqi_op"
  [(set (match_operand:QI 0 "m32c_nonimmediate_operand"
                          "=SF,Rhi*RmmSd, Rqi*Rmm, <,          RqiSd*Rmm, SdSs,    Rqi*Rmm, Sd")
        (match_operand:QI 1 "m32c_any_operand"
                          "Rhi*RmmSd,SF, iRqi*Rmm, iRqiSd*Rmm, >,         Rqi*Rmm, SdSs,    i"))]
  "m32c_mov_ok (operands, QImode)"

Now, Sd rejects the operand because it only support generic addresses.
However, Sd is marked as EXTRA_MEMORY_CONSTRAINT, which per definition
means that *every* memory reference whose address is simply a base register
must be accepted.  Reload relies on that promise and reloads the address
into a base register (note that is does choose A0 as requested), but then
Sd still rejects the reloaded value ...

The problem is that the definition of EXTRA_MEMORY_CONSTRAINT really does
not take address spaces into account.  In the presence of multiple address
spaces, a promise to accept every memory reference (of any address space)
whose address is simply a base register is probably hard to fulfil.

I see two ways to resolve this issue:

- Either we make memory (and address) constraints address-space aware.
  For example, we could have a new target macro EXTRA_CONSTRAINT_ADDR_SPACE
  that returns the (sole) address space which is accepted by the constraint.
  (Generic constraints would only accept the generic address space.)

- Or else, we say this must be resolved by the back-end by never accepting
  memory operands of different address spaces in the same insn.  In general,
  there's probably not much use to this anyway -- reload will never be able
  to replace a memory operand of one address space with one of another.
  This means the back-end would need to provide different insn patterns
  to deal with different address spaces, and would need to enforce this
  at the predicate level, not the constraint level.

Thoughts?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: m32c support for named addr spaces branch
  2009-10-28 11:29                         ` Richard Guenther
  2009-10-29 18:32                           ` Fix PR tree-optimization/41857 (Re: m32c support for named addr spaces branch) Ulrich Weigand
@ 2009-10-30 15:55                           ` Ulrich Weigand
  1 sibling, 0 replies; 34+ messages in thread
From: Ulrich Weigand @ 2009-10-30 15:55 UTC (permalink / raw)
  To: Richard Guenther; +Cc: DJ Delorie, gcc-patches

Richard Guenther wrote:

> No.  The main issue is forcing all pointer offsets to sizetype
> by POINTER_PLUS_EXPR (and TARGET_MEM_REF as you
> noticed).  I expect that most of the fallout if you remove this
> restriction and allow arbitrary integer types as offset will
> be in fold and ivopts.  I would expect that it also might uncover
> missing canonicalization for constant offsets and thus
> missed CSE opportunities at the tree level for example.
> 
> You will also hit the interesting case that you'd need to do
> type promotion in the middle-end if you want to re-associate
> for example (ptr + short) + int (which would be valid then).

OK, thanks for the hints.

> Thus, I would allow any offset type for POINTER_PLUS_EXPR
> but define precisely how it is supposed to be expanded.
> Which would be (implicitly) sign-/zero-extend the offset
> according to its signedness to pointer width and then
> perform the addition.  So the short + int case would have
> to be promoted the same, (intptr_t)short + (intptr_t)int.

It seems a significant part of the effort will be to audit
all places where POINTER_PLUS_EXPR are generated today,
because many of them implicitly rely on the current
"always sign-extend" rule.

Maybe there is a way to (at least for the interim) keep the
always sign-extend rule for *sizetype* operands, while still
now allowing non-sizetype integer operands which would use
the new extension rule ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Fix PR tree-optimization/41857 (Re: m32c support for named  addr spaces branch)
  2009-10-30  9:51                             ` Richard Guenther
@ 2009-11-02  9:38                               ` Zdenek Dvorak
  2009-11-16 20:07                                 ` [patch] Fix regression (Re: Fix PR tree-optimization/41857) Ulrich Weigand
  0 siblings, 1 reply; 34+ messages in thread
From: Zdenek Dvorak @ 2009-11-02  9:38 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Ulrich Weigand, DJ Delorie, gcc-patches

Hi,

> > create_mem_ref and its subroutines then use this variable (casted
> > to the appropriate pointer type) as base.
> >
> > As a side effect, the patch also fixes a FIXME in
> > most_expensive_mult_to_index.
> >
> > While not a complete fix to the general sizetype problem, this
> > patch fixes the ICE-on-valid bug on the testcase in the PR, and
> > it seems a good idea to properly identify the base anyway; this
> > is needed (or at least beneficial) on some platforms.
> >
> > Tested on s390x-ibm-linux and spu-elf.
> > OK for mainline?
> 
> This looks good to me, though I'd like Zdenek to have a 2nd look.

fine with me,

Zdenek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [patch] Fix regression (Re: Fix PR tree-optimization/41857)
  2009-11-02  9:38                               ` Zdenek Dvorak
@ 2009-11-16 20:07                                 ` Ulrich Weigand
  2009-11-17 15:40                                   ` Richard Guenther
  0 siblings, 1 reply; 34+ messages in thread
From: Ulrich Weigand @ 2009-11-16 20:07 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Guenther, Zdenek Dvorak

Hello,

the fix to PR 41857 unfortunately introduced a regression.

The move_hint_to_base routine now casts the base register to a pointer
type whose target type is the type of the final memory reference.
However, this may cause alignment issues.  When the base register is
gimplified, a DECL_RTL is allocated for its value by the routine
expand_one_register_var.  The resulting register RTX will be marked
as pointer that is aligned to its target type alignment:

  if (POINTER_TYPE_P (type))
    mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (type)));

This is usually correct.  However, in this particular case, the IV
optimizations only guarantee that the *full* memory address is
properly aligned; a single component like the base may by itself
be *not* aligned.

This means the register RTX may be marked with an incorrect alignment.
As the SPU back-end relies on the REGNO_POINTER_ALIGN information for
correct code generation, this can cause broken output.

To fix this, while still keeping the fix for 41857 in place, the
patch below changes move_hint_to_base to cast the base to a void
pointer (using the appropriate address space), instead of a pointer
to the target type.

Tested on s390-ibm-linux and spu-elf with no regressions.
OK for mainline?

Bye,
Ulrich


ChangeLog:

	PR tree-optimization/41857
	* tree-ssa-address.c (move_hint_to_base): Use void pointer to
	TYPE's address space instead of pointer to TYPE.


Index: gcc/tree-ssa-address.c
===================================================================
*** gcc/tree-ssa-address.c	(revision 154075)
--- gcc/tree-ssa-address.c	(working copy)
*************** move_hint_to_base (tree type, struct mem
*** 400,405 ****
--- 400,406 ----
  {
    unsigned i;
    tree val = NULL_TREE;
+   int qual;
  
    for (i = 0; i < addr->n; i++)
      {
*************** move_hint_to_base (tree type, struct mem
*** 414,420 ****
    if (i == addr->n)
      return;
  
!   /* Cast value to appropriate pointer type.  */
    parts->base = fold_convert (build_pointer_type (type), val);
    aff_combination_remove_elt (addr, i);
  }
--- 415,426 ----
    if (i == addr->n)
      return;
  
!   /* Cast value to appropriate pointer type.  We cannot use a pointer
!      to TYPE directly, as the back-end will assume registers of pointer
!      type are aligned, and just the base itself may not actually be.
!      We use void pointer to the type's address space instead.  */
!   qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
!   type = build_qualified_type (void_type_node, qual);
    parts->base = fold_convert (build_pointer_type (type), val);
    aff_combination_remove_elt (addr, i);
  }
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Fix regression (Re: Fix PR tree-optimization/41857)
  2009-11-16 20:07                                 ` [patch] Fix regression (Re: Fix PR tree-optimization/41857) Ulrich Weigand
@ 2009-11-17 15:40                                   ` Richard Guenther
  2009-11-17 16:03                                     ` Zdenek Dvorak
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Guenther @ 2009-11-17 15:40 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gcc-patches, Zdenek Dvorak

On Mon, Nov 16, 2009 at 9:05 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> Hello,
>
> the fix to PR 41857 unfortunately introduced a regression.
>
> The move_hint_to_base routine now casts the base register to a pointer
> type whose target type is the type of the final memory reference.
> However, this may cause alignment issues.  When the base register is
> gimplified, a DECL_RTL is allocated for its value by the routine
> expand_one_register_var.  The resulting register RTX will be marked
> as pointer that is aligned to its target type alignment:
>
>  if (POINTER_TYPE_P (type))
>    mark_reg_pointer (x, TYPE_ALIGN (TREE_TYPE (type)));
>
> This is usually correct.  However, in this particular case, the IV
> optimizations only guarantee that the *full* memory address is
> properly aligned; a single component like the base may by itself
> be *not* aligned.
>
> This means the register RTX may be marked with an incorrect alignment.
> As the SPU back-end relies on the REGNO_POINTER_ALIGN information for
> correct code generation, this can cause broken output.
>
> To fix this, while still keeping the fix for 41857 in place, the
> patch below changes move_hint_to_base to cast the base to a void
> pointer (using the appropriate address space), instead of a pointer
> to the target type.
>
> Tested on s390-ibm-linux and spu-elf with no regressions.
> OK for mainline?

Ugh.  Well, good enough for now :(

I think TMR is broken as it basically treats the base pointer
as "value" compared to everywhere else where pointers have
semantics attached (like target type, ref-all status, etc.).
Thus, TMR misses 1) alignment, 2) TBAA info, 3) a working
way to query points-to info, 4) a way to recover a base pointer
from TMR_ORIGINAL.

For 4.6 I hope we can dump TMRs alltogether.

Richard.

> Bye,
> Ulrich
>
>
> ChangeLog:
>
>        PR tree-optimization/41857
>        * tree-ssa-address.c (move_hint_to_base): Use void pointer to
>        TYPE's address space instead of pointer to TYPE.
>
>
> Index: gcc/tree-ssa-address.c
> ===================================================================
> *** gcc/tree-ssa-address.c      (revision 154075)
> --- gcc/tree-ssa-address.c      (working copy)
> *************** move_hint_to_base (tree type, struct mem
> *** 400,405 ****
> --- 400,406 ----
>  {
>    unsigned i;
>    tree val = NULL_TREE;
> +   int qual;
>
>    for (i = 0; i < addr->n; i++)
>      {
> *************** move_hint_to_base (tree type, struct mem
> *** 414,420 ****
>    if (i == addr->n)
>      return;
>
> !   /* Cast value to appropriate pointer type.  */
>    parts->base = fold_convert (build_pointer_type (type), val);
>    aff_combination_remove_elt (addr, i);
>  }
> --- 415,426 ----
>    if (i == addr->n)
>      return;
>
> !   /* Cast value to appropriate pointer type.  We cannot use a pointer
> !      to TYPE directly, as the back-end will assume registers of pointer
> !      type are aligned, and just the base itself may not actually be.
> !      We use void pointer to the type's address space instead.  */
> !   qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
> !   type = build_qualified_type (void_type_node, qual);
>    parts->base = fold_convert (build_pointer_type (type), val);
>    aff_combination_remove_elt (addr, i);
>  }
> --
>  Dr. Ulrich Weigand
>  GNU Toolchain for Linux on System z and Cell BE
>  Ulrich.Weigand@de.ibm.com
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Fix regression (Re: Fix PR tree-optimization/41857)
  2009-11-17 15:40                                   ` Richard Guenther
@ 2009-11-17 16:03                                     ` Zdenek Dvorak
  2009-11-17 16:14                                       ` Richard Guenther
  0 siblings, 1 reply; 34+ messages in thread
From: Zdenek Dvorak @ 2009-11-17 16:03 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Ulrich Weigand, gcc-patches

Hi,

> > Tested on s390-ibm-linux and spu-elf with no regressions.
> > OK for mainline?
> 
> Ugh.  Well, good enough for now :(
> 
> I think TMR is broken as it basically treats the base pointer
> as "value" compared to everywhere else where pointers have
> semantics attached (like target type, ref-all status, etc.).

I think you paint TMRs too much evil.  It's whole point is to be
a lower-level representation of memory access, corresponding to
the addressing modes available on the target.  Thus, you should
expect to lose some information in the lowering.

I think part of the problem is that TMR and higher-level representation of
memory accesses are used at the same time, thus confusing the expectations.
It might be better to lower all memory references to TMRs at some point,
to make the separation clear.

Anyway,

> Thus, TMR misses 1) alignment,

I don't see how TMR misses alignment information any more than the original
memory access did.

> 2) TBAA info, 3) a working way to query points-to info,

This is IMHO because we store TBAA + points-to information in a wrong way
(associated with the pointers, rather than with the memory references; and in a
language-dependent form).

> 4) a way to recover a base pointer from TMR_ORIGINAL.

Why would you want to do that?

> For 4.6 I hope we can dump TMRs alltogether.

How do you plan to represent the choices ivopts mades (taking the addressing modes
into account)?  Without a gimple-level representation of addressing modes, the only
option I see is moving the induction variable optimizations to RTL, which would be
somewhat difficult,

Zdenek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Fix regression (Re: Fix PR tree-optimization/41857)
  2009-11-17 16:03                                     ` Zdenek Dvorak
@ 2009-11-17 16:14                                       ` Richard Guenther
  2009-11-17 16:29                                         ` Zdenek Dvorak
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Guenther @ 2009-11-17 16:14 UTC (permalink / raw)
  To: Zdenek Dvorak; +Cc: Ulrich Weigand, gcc-patches

On Tue, Nov 17, 2009 at 4:53 PM, Zdenek Dvorak <rakdver@kam.mff.cuni.cz> wrote:
> Hi,
>
>> > Tested on s390-ibm-linux and spu-elf with no regressions.
>> > OK for mainline?
>>
>> Ugh.  Well, good enough for now :(
>>
>> I think TMR is broken as it basically treats the base pointer
>> as "value" compared to everywhere else where pointers have
>> semantics attached (like target type, ref-all status, etc.).
>
> I think you paint TMRs too much evil.  It's whole point is to be
> a lower-level representation of memory access, corresponding to
> the addressing modes available on the target.  Thus, you should
> expect to lose some information in the lowering.

But then why try so hard and preserve TMR_ORIGINAL at all?

> I think part of the problem is that TMR and higher-level representation of
> memory accesses are used at the same time, thus confusing the expectations.
> It might be better to lower all memory references to TMRs at some point,
> to make the separation clear.
>
> Anyway,
>
>> Thus, TMR misses 1) alignment,
>
> I don't see how TMR misses alignment information any more than the original
> memory access did.

Fair enough - we do have standard means to extract alignment
from memory reference trees though, but not for TMRs (same
for other standard means to query properties about memory
references - see how the alias-oracle is complicated by TMRs).

>> 2) TBAA info, 3) a working way to query points-to info,
>
> This is IMHO because we store TBAA + points-to information in a wrong way
> (associated with the pointers, rather than with the memory references; and in a
> language-dependent form).

I agree, TBAA should be with the memory access (like we have
on RTL).  But points-to information inherently is associated with
a pointer.  Of course we can stick it onto a memory reference
as well if we like to.

>> 4) a way to recover a base pointer from TMR_ORIGINAL.
>
> Why would you want to do that?

Because of the way TMRs are translated to RTL MEM_REFs.

>> For 4.6 I hope we can dump TMRs alltogether.
>
> How do you plan to represent the choices ivopts mades (taking the addressing modes
> into account)?  Without a gimple-level representation of addressing modes, the only
> option I see is moving the induction variable optimizations to RTL, which would be
> somewhat difficult,

I am toying with the idea to move ivopts right before expansion.
That would also keep the passes that are now inbetween ivopts and
expansion happy instead of punting on all TMRs.

Of course a clear point of lowering our gimple form is ok with me
as well, just then we should drop this TMR_ORIGINAL stuff.
The middle-end alias-oracle part of the RTL oracle could very well
deal with a TMR as MEM_EXPR, but the RTL part does not.

Thus, it all needs a little TLC, too late for 4.5.

Richard.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Fix regression (Re: Fix PR tree-optimization/41857)
  2009-11-17 16:14                                       ` Richard Guenther
@ 2009-11-17 16:29                                         ` Zdenek Dvorak
  2009-11-17 16:31                                           ` Richard Guenther
  0 siblings, 1 reply; 34+ messages in thread
From: Zdenek Dvorak @ 2009-11-17 16:29 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Ulrich Weigand, gcc-patches

Hi,

> >> > Tested on s390-ibm-linux and spu-elf with no regressions.
> >> > OK for mainline?
> >>
> >> Ugh.  Well, good enough for now :(
> >>
> >> I think TMR is broken as it basically treats the base pointer
> >> as "value" compared to everywhere else where pointers have
> >> semantics attached (like target type, ref-all status, etc.).
> >
> > I think you paint TMRs too much evil.  It's whole point is to be
> > a lower-level representation of memory access, corresponding to
> > the addressing modes available on the target.  Thus, you should
> > expect to lose some information in the lowering.
> 
> But then why try so hard and preserve TMR_ORIGINAL at all?

because alias analysis uses it.  Of course, another option would be to throw it
away completely and use some safe default.  A better option would be to have a
representation of alias analysis information that would be independent on the
shape of the memory reference.

> >> 4) a way to recover a base pointer from TMR_ORIGINAL.
> >
> > Why would you want to do that?
> 
> Because of the way TMRs are translated to RTL MEM_REFs.

Can you please explain in more details?  TMR_ORIGINAL was only ment
as a quick hack to allow the existing alias analysis cope with TMRs,
I did not know it started to be used for anything else.

> >> For 4.6 I hope we can dump TMRs alltogether.
> >
> > How do you plan to represent the choices ivopts mades (taking the addressing modes
> > into account)?  Without a gimple-level representation of addressing modes, the only
> > option I see is moving the induction variable optimizations to RTL, which would be
> > somewhat difficult,
> 
> I am toying with the idea to move ivopts right before expansion.
> That would also keep the passes that are now inbetween ivopts and
> expansion happy instead of punting on all TMRs.
> 
> Of course a clear point of lowering our gimple form is ok with me
> as well, just then we should drop this TMR_ORIGINAL stuff.

Yes, TMR_ORIGINAL definitely should go away.

Zdenek

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Fix regression (Re: Fix PR tree-optimization/41857)
  2009-11-17 16:29                                         ` Zdenek Dvorak
@ 2009-11-17 16:31                                           ` Richard Guenther
  2009-11-17 16:51                                             ` Zdenek Dvorak
  0 siblings, 1 reply; 34+ messages in thread
From: Richard Guenther @ 2009-11-17 16:31 UTC (permalink / raw)
  To: Zdenek Dvorak; +Cc: Ulrich Weigand, gcc-patches

2009/11/17 Zdenek Dvorak <rakdver@kam.mff.cuni.cz>:
> Hi,
>
>> >> > Tested on s390-ibm-linux and spu-elf with no regressions.
>> >> > OK for mainline?
>> >>
>> >> Ugh.  Well, good enough for now :(
>> >>
>> >> I think TMR is broken as it basically treats the base pointer
>> >> as "value" compared to everywhere else where pointers have
>> >> semantics attached (like target type, ref-all status, etc.).
>> >
>> > I think you paint TMRs too much evil.  It's whole point is to be
>> > a lower-level representation of memory access, corresponding to
>> > the addressing modes available on the target.  Thus, you should
>> > expect to lose some information in the lowering.
>>
>> But then why try so hard and preserve TMR_ORIGINAL at all?
>
> because alias analysis uses it.  Of course, another option would be to throw it
> away completely and use some safe default.  A better option would be to have a
> representation of alias analysis information that would be independent on the
> shape of the memory reference.

We do have that now ...

>> >> 4) a way to recover a base pointer from TMR_ORIGINAL.
>> >
>> > Why would you want to do that?
>>
>> Because of the way TMRs are translated to RTL MEM_REFs.
>
> Can you please explain in more details?  TMR_ORIGINAL was only ment
> as a quick hack to allow the existing alias analysis cope with TMRs,
> I did not know it started to be used for anything else.

well, unfortunately with TMRs we use all kinds of pointers as
base objects that are not related (type-wise) to the access itself.
But we have flags on the _pointer_ that influence TBAA ...
(like TYPE_REF_CAN_ALIAS_ALL).  Also TBAA tries to
disambiguate based on the base object alias-set which is also
gone here.

The RTL alias-analysis now uses the "tree" oracle to be able to
benefit from PTA.  The communication with the "tree" oracle
is done with ao_refs which is basically a decomposed reference.
See ao_ref_from_mem in alias.c.  It should pretty much match
what we have in MEM_EXPRs if we'd not have the fancy
random stripping of handled components there.  In the end
I would have liked to generate ao_refs directly at expansion
time and replace the existing MEM_EXPR / MEM_OFFSET
and friends.  But that was too a big can of worms.

We can also consolidate some duplicate disambiguation done
by the "tree" oracle and the old RTL oracle.  In the end only
one should survive.

Btw, on the tree level even before eventually lowering memory
references we should transition TBAA related pointer type flags
to flags on the INDIRECT_REF at access sites.  That way
we should be able to finally treat pointers as special integer
types, get rid of most pointer type conversions and even handle
some must-alias TBAA violations gracefully for free.

Richard.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [patch] Fix regression (Re: Fix PR tree-optimization/41857)
  2009-11-17 16:31                                           ` Richard Guenther
@ 2009-11-17 16:51                                             ` Zdenek Dvorak
  0 siblings, 0 replies; 34+ messages in thread
From: Zdenek Dvorak @ 2009-11-17 16:51 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Ulrich Weigand, gcc-patches

Hi,

> >> >> > Tested on s390-ibm-linux and spu-elf with no regressions.
> >> >> > OK for mainline?
> >> >>
> >> >> Ugh.  Well, good enough for now :(
> >> >>
> >> >> I think TMR is broken as it basically treats the base pointer
> >> >> as "value" compared to everywhere else where pointers have
> >> >> semantics attached (like target type, ref-all status, etc.).
> >> >
> >> > I think you paint TMRs too much evil.  It's whole point is to be
> >> > a lower-level representation of memory access, corresponding to
> >> > the addressing modes available on the target.  Thus, you should
> >> > expect to lose some information in the lowering.
> >>
> >> But then why try so hard and preserve TMR_ORIGINAL at all?
> >
> > because alias analysis uses it.  Of course, another option would be to throw it
> > away completely and use some safe default.  A better option would be to have a
> > representation of alias analysis information that would be independent on the
> > shape of the memory reference.
> 
> We do have that now ...

well, almost.  get_alias_set still seems to rely quite heavily on the memory reference
shape, which seems to be the only serious reason for keeping TMR_ORIGINAL at the moment
(other places where TMR_ORIGINAL are used are tree_could_trap_p, which could be solved
easily by adding a flag to TMR),

Zdenek

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2009-11-17 16:48 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-10-15  4:17 m32c support for named addr spaces branch DJ Delorie
2009-10-15 18:07 ` Ulrich Weigand
2009-10-15 18:11   ` DJ Delorie
2009-10-16 14:19     ` Ulrich Weigand
2009-10-16 18:22       ` DJ Delorie
2009-10-16 22:05       ` DJ Delorie
2009-10-19 14:28         ` Ulrich Weigand
2009-10-19 14:36           ` Richard Guenther
2009-10-19 17:45             ` Ulrich Weigand
2009-10-19 20:57               ` DJ Delorie
2009-10-20  9:27                 ` Richard Guenther
2009-10-20 18:10                   ` DJ Delorie
2009-10-21 10:20                     ` Richard Guenther
2009-10-27 18:32                       ` Ulrich Weigand
2009-10-28 11:29                         ` Richard Guenther
2009-10-29 18:32                           ` Fix PR tree-optimization/41857 (Re: m32c support for named addr spaces branch) Ulrich Weigand
2009-10-30  9:51                             ` Richard Guenther
2009-11-02  9:38                               ` Zdenek Dvorak
2009-11-16 20:07                                 ` [patch] Fix regression (Re: Fix PR tree-optimization/41857) Ulrich Weigand
2009-11-17 15:40                                   ` Richard Guenther
2009-11-17 16:03                                     ` Zdenek Dvorak
2009-11-17 16:14                                       ` Richard Guenther
2009-11-17 16:29                                         ` Zdenek Dvorak
2009-11-17 16:31                                           ` Richard Guenther
2009-11-17 16:51                                             ` Zdenek Dvorak
2009-10-30 15:55                           ` m32c support for named addr spaces branch Ulrich Weigand
2009-10-16 23:57       ` DJ Delorie
2009-10-19 14:50         ` Ulrich Weigand
2009-10-29 18:37           ` [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch) Ulrich Weigand
2009-10-29 19:54             ` DJ Delorie
2009-10-29 20:18             ` DJ Delorie
2009-10-29 21:33               ` Ulrich Weigand
2009-10-29 22:50                 ` DJ Delorie
2009-10-30 14:51                   ` Ulrich Weigand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).