This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch)
- From: DJ Delorie <dj at redhat dot com>
- To: "Ulrich Weigand" <uweigand at de dot ibm dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Thu, 29 Oct 2009 15:53:59 -0400
- Subject: Re: [patch] Address-space-aware base registers (Re: m32c support for named addr spaces branch)
- References: <200910291832.n9TIWENj028460@d12av02.megacenter.de.ibm.com>
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);