/* Subroutines for code generation on Motorola 68HC11 and 68HC12.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
Contributed by Stephane Carrez (stcarrez@nerim.fr)
This file is part of GCC.
static void m68hc11_asm_out_destructor (rtx, int);
static void m68hc11_file_start (void);
static void m68hc11_encode_section_info (tree, rtx, int);
+static const char *m68hc11_strip_name_encoding (const char* str);
static unsigned int m68hc11_section_type_flags (tree, const char*, int);
static int autoinc_mode (rtx);
static int m68hc11_make_autoinc_notes (rtx *, void *);
#define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_callee_copies_named
+
+#undef TARGET_STRIP_NAME_ENCODING
+#define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
struct gcc_target targetm = TARGET_INITIALIZER;
\f
flag_pic = 0;
}
+ /* Do not enable -fweb because it breaks the 32-bit shift patterns
+ by breaking the match_dup of those patterns. The shift patterns
+ will no longer be recognized after that. */
+ flag_web = 0;
+
/* Configure for a 68hc11 processor. */
if (TARGET_M6811)
{
/* If the offset is out of range, we have to compute the address
with a separate add instruction. We try to do with with an 8-bit
add on the A register. This is possible only if the lowest part
- of the offset (ie, big_offset % 256) is a valid constant offset
+ of the offset (i.e., big_offset % 256) is a valid constant offset
with respect to the mode. If it's not, we have to generate a
16-bit add on the D register. From:
}
int
+splitable_operand (rtx operand, enum machine_mode mode)
+{
+ if (general_operand (operand, mode) == 0)
+ return 0;
+
+ if (push_operand (operand, mode) == 1)
+ return 0;
+
+ /* Reject a (MEM (MEM X)) because the patterns that use non_push_operand
+ need to split such addresses to access the low and high part but it
+ is not possible to express a valid address for the low part. */
+ if (mode != QImode && GET_CODE (operand) == MEM
+ && GET_CODE (XEXP (operand, 0)) == MEM)
+ return 0;
+ return 1;
+}
+
+int
reg_or_some_mem_operand (rtx operand, enum machine_mode mode)
{
if (GET_CODE (operand) == MEM)
rtx op = XEXP (operand, 0);
int addr_mode;
+ if (m68hc11_page0_symbol_p (op))
+ return 1;
+
if (symbolic_memory_operand (op, mode))
return TARGET_M6812;
\f
/* Declaration of types. */
+/* Handle an "tiny_data" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+m68hc11_handle_page0_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ tree decl = *node;
+
+ if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ {
+ DECL_SECTION_NAME (decl) = build_string (6, ".page0");
+ }
+ else
+ {
+ warning ("%qs attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
const struct attribute_spec m68hc11_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
{ "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
{ "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
{ "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
+ { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
&& TREE_CODE (*node) != FIELD_DECL
&& TREE_CODE (*node) != TYPE_DECL)
{
- warning ("`%s' attribute only applies to functions",
+ warning ("%qs attribute only applies to functions",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
return NULL_TREE;
}
+/* Undo the effects of the above. */
+
+static const char *
+m68hc11_strip_name_encoding (const char *str)
+{
+ return str + (*str == '*' || *str == '@' || *str == '&');
+}
+
+static void
+m68hc11_encode_label (tree decl)
+{
+ const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+ int len = strlen (str);
+ char *newstr = alloca (len + 2);
+
+ newstr[0] = '@';
+ strcpy (&newstr[1], str);
+
+ XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
+}
+
+/* Return 1 if this is a symbol in page0 */
+int
+m68hc11_page0_symbol_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case SYMBOL_REF:
+ return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
+
+ case CONST:
+ return m68hc11_page0_symbol_p (XEXP (x, 0));
+
+ case PLUS:
+ if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
+ return 0;
+
+ return GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) < 256
+ && INTVAL (XEXP (x, 1)) >= 0;
+
+ default:
+ return 0;
+ }
+}
/* We want to recognize trap handlers so that we handle calls to traps
in a special manner (by issuing the trap). This information is stored
int trap_handler;
int is_far = 0;
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
+ m68hc11_encode_label (decl);
+ return;
+ }
+
if (TREE_CODE (decl) != FUNCTION_DECL)
return;
trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
if (trap_handler && is_far)
{
- warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
+ warning ("%<trap%> and %<far%> attributes are not compatible, ignoring %<far%>");
trap_handler = 0;
}
if (trap_handler)
{
if (trap_handler_symbol != 0)
- warning ("`trap' attribute is already used");
+ warning ("%<trap%> attribute is already used");
else
trap_handler_symbol = XEXP (rtl, 0);
}
/* Argument support functions. */
-/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
- Arrays are passed by references and other types by value.
-
- SCz: I tried to pass DImode by reference but it seems that this
- does not work very well. */
-int
-m68hc11_function_arg_pass_by_reference (const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type,
- int named ATTRIBUTE_UNUSED)
-{
- return ((type && TREE_CODE (type) == ARRAY_TYPE)
- /* Consider complex values as aggregates, so care for TCmode. */
- /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
- /*|| (type && AGGREGATE_TYPE_P (type))) */ );
-}
-
-
/* Define the offset between two registers, one to be eliminated, and the
other its replacement, at the start of a routine. */
int
break;
case EQ:
- code1 = NIL;
+ code1 = UNKNOWN;
code2 = NE;
break;
case NE:
- code2 = NIL;
+ code2 = UNKNOWN;
break;
default:
* if (lo(a) < lo(b)) goto true;
* false:
*/
- if (code1 != NIL)
+ if (code1 != UNKNOWN)
m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
- if (code2 != NIL)
+ if (code2 != UNKNOWN)
m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
- if (code2 != NIL)
+ if (code2 != UNKNOWN)
emit_label (label2);
return 0;
}
&& cc_status.value2
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
cc_status.value2 = 0;
+
+ else if (cc_status.value1 && side_effects_p (cc_status.value1))
+ cc_status.value1 = 0;
+
+ else if (cc_status.value2 && side_effects_p (cc_status.value2))
+ cc_status.value2 = 0;
}
/* The current instruction does not affect the flags but changes
}
}
- life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
+ life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
}
z_replacement_completed = 2;