diff options
Diffstat (limited to 'gcc/config/m32c')
-rw-r--r-- | gcc/config/m32c/m32c-pragma.c | 38 | ||||
-rw-r--r-- | gcc/config/m32c/m32c-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/m32c/m32c.c | 113 | ||||
-rw-r--r-- | gcc/config/m32c/m32c.h | 7 | ||||
-rw-r--r-- | gcc/config/m32c/predicates.md | 10 |
5 files changed, 166 insertions, 5 deletions
diff --git a/gcc/config/m32c/m32c-pragma.c b/gcc/config/m32c/m32c-pragma.c index 49fe023..b576152 100644 --- a/gcc/config/m32c/m32c-pragma.c +++ b/gcc/config/m32c/m32c-pragma.c @@ -87,9 +87,47 @@ m32c_pragma_memregs (cpp_reader * reader ATTRIBUTE_UNUSED) error ("#pragma GCC memregs takes a number [0..16]"); } +/* Implements the "pragma ADDRESS" pragma. This pragma takes a + variable name and an address, and arranges for that variable to be + "at" that address. The variable is also made volatile. */ +static void +m32c_pragma_address (cpp_reader * reader ATTRIBUTE_UNUSED) +{ + /* on off */ + tree var, addr; + enum cpp_ttype type; + const char *var_str; + + type = pragma_lex (&var); + if (type == CPP_NAME) + { + var_str = IDENTIFIER_POINTER (var); + + type = pragma_lex (&addr); + if (type == CPP_NUMBER) + { + if (var != error_mark_node) + { + unsigned uaddr = tree_low_cst (addr, 1); + m32c_note_pragma_address (IDENTIFIER_POINTER (var), uaddr); + } + + type = pragma_lex (&var); + if (type != CPP_EOF) + { + error ("junk at end of #pragma ADDRESS"); + } + return; + } + } + error ("malformed #pragma ADDRESS variable address"); +} + /* Implements REGISTER_TARGET_PRAGMAS. */ void m32c_register_pragmas (void) { c_register_pragma ("GCC", "memregs", m32c_pragma_memregs); + c_register_pragma (NULL, "ADDRESS", m32c_pragma_address); + c_register_pragma (NULL, "address", m32c_pragma_address); } diff --git a/gcc/config/m32c/m32c-protos.h b/gcc/config/m32c/m32c-protos.h index 42b92fe..89231fc 100644 --- a/gcc/config/m32c/m32c-protos.h +++ b/gcc/config/m32c/m32c-protos.h @@ -42,6 +42,7 @@ 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); +void m32c_note_pragma_address (const char *, unsigned); int m32c_regno_ok_for_base_p (int); int m32c_trampoline_alignment (void); int m32c_trampoline_size (void); @@ -104,6 +105,8 @@ tree m32c_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); void m32c_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); bool m32c_promote_function_return (const_tree); int m32c_special_page_vector_p (tree); +void m32c_output_aligned_common (FILE *, tree, const char *, + int, int, int); #endif diff --git a/gcc/config/m32c/m32c.c b/gcc/config/m32c/m32c.c index 3280d14..443325f 100644 --- a/gcc/config/m32c/m32c.c +++ b/gcc/config/m32c/m32c.c @@ -83,6 +83,9 @@ static int need_to_save (int); static rtx m32c_function_value (const_tree, const_tree, bool); static rtx m32c_libcall_value (enum machine_mode, const_rtx); +/* Returns true if an address is specified, else false. */ +static bool m32c_get_pragma_address (const char *varname, unsigned *addr); + int current_function_special_page_vector (rtx); #define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0) @@ -2929,7 +2932,107 @@ static void m32c_insert_attributes (tree node ATTRIBUTE_UNUSED, tree * attr_ptr ATTRIBUTE_UNUSED) { - /* Nothing to do here. */ + unsigned addr; + /* See if we need to make #pragma address variables volatile. */ + + if (TREE_CODE (node) == VAR_DECL) + { + char *name = IDENTIFIER_POINTER (DECL_NAME (node)); + if (m32c_get_pragma_address (name, &addr)) + { + TREE_THIS_VOLATILE (node) = true; + } + } +} + + +struct GTY(()) pragma_entry { + const char *varname; + unsigned address; +}; +typedef struct pragma_entry pragma_entry; + +/* Hash table of pragma info. */ +static GTY((param_is (pragma_entry))) htab_t pragma_htab; + +static int +pragma_entry_eq (const void *p1, const void *p2) +{ + const pragma_entry *old = (const pragma_entry *) p1; + const char *new_name = (const char *) p2; + + return strcmp (old->varname, new_name) == 0; +} + +static hashval_t +pragma_entry_hash (const void *p) +{ + const pragma_entry *old = (const pragma_entry *) p; + return htab_hash_string (old->varname); +} + +void +m32c_note_pragma_address (const char *varname, unsigned address) +{ + pragma_entry **slot; + + if (!pragma_htab) + pragma_htab = htab_create_ggc (31, pragma_entry_hash, + pragma_entry_eq, NULL); + + slot = (pragma_entry **) + htab_find_slot_with_hash (pragma_htab, varname, + htab_hash_string (varname), INSERT); + + if (!*slot) + { + *slot = ggc_alloc_pragma_entry (); + (*slot)->varname = ggc_strdup (varname); + } + (*slot)->address = address; +} + +static bool +m32c_get_pragma_address (const char *varname, unsigned *address) +{ + pragma_entry **slot; + + if (!pragma_htab) + return false; + + slot = (pragma_entry **) + htab_find_slot_with_hash (pragma_htab, varname, + htab_hash_string (varname), NO_INSERT); + if (slot && *slot) + { + *address = (*slot)->address; + return true; + } + return false; +} + +void +m32c_output_aligned_common (FILE *stream, tree decl, const char *name, + int size, int align, int global) +{ + unsigned address; + + if (m32c_get_pragma_address (name, &address)) + { + /* We never output these as global. */ + assemble_name (stream, name); + fprintf (stream, " = 0x%04x\n", address); + return; + } + if (!global) + { + fprintf (stream, "\t.local\t"); + assemble_name (stream, name); + fprintf (stream, "\n"); + } + fprintf (stream, "\t.comm\t"); + assemble_name (stream, name); + fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT); } /* Predicates */ @@ -2960,7 +3063,7 @@ static const struct { }; /* Returns TRUE if OP is a subreg of a hard reg which we don't - support. */ + support. We also bail on MEMs with illegal addresses. */ bool m32c_illegal_subreg_p (rtx op) { @@ -2968,6 +3071,12 @@ m32c_illegal_subreg_p (rtx op) unsigned int i; int src_mode, dest_mode; + if (GET_CODE (op) == MEM + && ! m32c_legitimate_address_p (Pmode, XEXP (op, 0), false)) + { + return true; + } + if (GET_CODE (op) != SUBREG) return false; diff --git a/gcc/config/m32c/m32c.h b/gcc/config/m32c/m32c.h index 85dc2d1..a98005c 100644 --- a/gcc/config/m32c/m32c.h +++ b/gcc/config/m32c/m32c.h @@ -644,6 +644,13 @@ typedef struct m32c_cumulative_args #define ASM_OUTPUT_REG_PUSH(S,R) m32c_output_reg_push (S, R) #define ASM_OUTPUT_REG_POP(S,R) m32c_output_reg_pop (S, R) +#define ASM_OUTPUT_ALIGNED_DECL_COMMON(STREAM, DECL, NAME, SIZE, ALIGNMENT) \ + m32c_output_aligned_common (STREAM, DECL, NAME, SIZE, ALIGNMENT, 1) + +#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGNMENT) \ + m32c_output_aligned_common (STREAM, DECL, NAME, SIZE, ALIGNMENT, 0) + + /* Output of Dispatch Tables */ #define ASM_OUTPUT_ADDR_VEC_ELT(S,V) \ diff --git a/gcc/config/m32c/predicates.md b/gcc/config/m32c/predicates.md index 321debf..98a1c16 100644 --- a/gcc/config/m32c/predicates.md +++ b/gcc/config/m32c/predicates.md @@ -26,7 +26,7 @@ (define_predicate "m32c_any_operand" (ior (match_operand 0 "general_operand") - (match_operand 1 "memory_operand")) + (match_code "mem,const_int,const_double")) { return ! m32c_illegal_subreg_p (op); } @@ -36,7 +36,11 @@ (define_predicate "m32c_nonimmediate_operand" (ior (match_operand 0 "nonimmediate_operand") - (match_operand 1 "memory_operand"))) + (match_code "mem")) + { + return ! m32c_illegal_subreg_p (op); + } +) ; TRUE if the operand is a pseudo-register. (define_predicate "m32c_pseudo" @@ -135,7 +139,7 @@ ; Likewise, plus TRUE for memory references. (define_predicate "mra_operand" - (and (and (match_operand 0 "nonimmediate_operand" "") + (and (and (match_operand 0 "m32c_nonimmediate_operand" "") (not (match_operand 1 "cr_operand" ""))) (not (match_operand 2 "m32c_wide_subreg" "")))) |