diff options
author | Kuan-Lin Chen <kuanlinchentw@gmail.com> | 2018-05-19 08:57:57 +0000 |
---|---|---|
committer | Chung-Ju Wu <jasonwucj@gmail.com> | 2018-05-19 08:57:57 +0000 |
commit | 918250052162a4804c44f9c6d66b2be7a2982fd7 (patch) | |
tree | 8181124edca780d039889214a3cb55fb651ecd9d /gcc/config/nds32/nds32.c | |
parent | 8a3c41d3c70e48876731a9aa32414c153842dfca (diff) |
[NDS32] Implment indirect funciton call attribute.
* config/nds32/constants.md (unspec_element): Add UNSPEC_ICT.
* config/nds32/nds32-md-auxiliary.c
(symbolic_reference_mentioned_p): New.
(nds32_legitimize_ict_address): New.
(nds32_expand_ict_move): New.
(nds32_indirect_call_referenced_p): New.
(nds32_symbol_binds_local_p): Delete.
(nds32_long_call_p): Modify.
* config/nds32/nds32-opts.h (nds32_ict_model_type): New enum type.
* config/nds32/nds32-protos.h
(symbolic_reference_mentioned_p): Declare.
(nds32_legitimize_ict_address): Declare.
(nds32_expand_ict_move): Declare.
(nds32_indirect_call_referenced_p): Declare.
* config/nds32/nds32-relax-opt.c (nds32_ict_const_p): New.
(nds32_relax_group): Use nds32_ict_const_p as condition.
* config/nds32/nds32.c (nds32_attribute_table): Add "indirect_call".
(nds32_asm_file_start): Output ict_model directive in asm code.
(nds32_legitimate_address_p): Consider indirect call.
(nds32_print_operand): Consider indirect call.
(nds32_print_operand_address): Consider indirect call.
(nds32_insert_attributes): Handle "indirect_call" attribute.
(TARGET_LEGITIMATE_ADDRESS_P): Define.
(TARGET_LEGITIMATE_CONSTANT_P): Define.
(TARGET_CANNOT_FORCE_CONST_MEM): Define.
(TARGET_DELEGITIMIZE_ADDRESS): Define.
(TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA): Define.
* config/nds32/nds32.h (SYMBOLIC_CONST_P): Define.
(TARGET_ICT_MODEL_SMALL): Define.
(TARGET_ICT_MODEL_LARGE): Define.
* config/nds32/nds32.md (movsi): Consider ict model.
(call, call_value): Consider ict model.
(sibcall, sibcall_value): Consider ict model.
* config/nds32/nds32.opt (mict-model): New option.
* config/nds32/predicates.md (nds32_symbolic_operand): Consider ict
model.
git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@260390 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/nds32/nds32.c')
-rw-r--r-- | gcc/config/nds32/nds32.c | 234 |
1 files changed, 226 insertions, 8 deletions
diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index 50eb709aa48..fe97854fe73 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -317,6 +317,9 @@ static const struct attribute_spec nds32_attribute_table[] = /* The attribute telling no prologue/epilogue. */ { "naked", 0, 0, false, false, false, false, NULL, NULL }, + /* The attribute is used to tell this function to be ROM patch. */ + { "indirect_call",0, 0, false, false, false, false, NULL, NULL }, + /* The last attribute spec is set to be NULL. */ { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -2576,6 +2579,9 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) case SYMBOL_REF: /* (mem (symbol_ref A)) => [symbol_ref] */ + if (TARGET_ICT_MODEL_LARGE && nds32_indirect_call_referenced_p (x)) + return false; + /* If -mcmodel=large, the 'symbol_ref' is not a valid address during or after LRA/reload phase. */ if (TARGET_CMODEL_LARGE @@ -2685,19 +2691,124 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) case LO_SUM: /* (mem (lo_sum (reg) (symbol_ref))) */ - /* (mem (lo_sum (reg) (const))) */ - gcc_assert (REG_P (XEXP (x, 0))); - if (GET_CODE (XEXP (x, 1)) == SYMBOL_REF - || GET_CODE (XEXP (x, 1)) == CONST) - return nds32_legitimate_address_p (mode, XEXP (x, 1), strict); - else - return false; + /* (mem (lo_sum (reg) (const (plus (symbol_ref) (reg)))) */ + { + rtx sym = NULL_RTX; + + if (!REG_P (XEXP (x, 0))) + return false; + + if (GET_CODE (XEXP (x, 1)) == SYMBOL_REF) + sym = XEXP (x, 1); + else if (GET_CODE (XEXP (x, 1)) == CONST) + { + rtx plus = XEXP(XEXP (x, 1), 0); + if (GET_CODE (plus) == PLUS) + sym = XEXP (plus, 0); + else if (GET_CODE (plus) == UNSPEC) + sym = XVECEXP (plus, 0, 0); + } + else + return false; + + gcc_assert (GET_CODE (sym) == SYMBOL_REF); + + if (TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (sym)) + return true; + + if (TARGET_CMODEL_LARGE) + return true; + else if (TARGET_CMODEL_MEDIUM + && NDS32_SYMBOL_REF_RODATA_P (sym)) + return true; + else + return false; + } default: return false; } } +static rtx +nds32_legitimize_address (rtx x, + rtx oldx ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED) +{ + if (TARGET_ICT_MODEL_LARGE && nds32_indirect_call_referenced_p (x)) + x = nds32_legitimize_ict_address (x); + + return x; +} + +static bool +nds32_legitimate_constant_p (machine_mode mode, rtx x) +{ + switch (GET_CODE (x)) + { + case CONST_DOUBLE: + if ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) + && (mode == DFmode || mode == SFmode)) + return false; + break; + case CONST: + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS) + { + if (!CONST_INT_P (XEXP (x, 1))) + return false; + x = XEXP (x, 0); + } + + if (GET_CODE (x) == UNSPEC) + { + switch (XINT (x, 1)) + { + case UNSPEC_ICT: + return false; + default: + return true; + } + } + break; + default: + return true; + } + + return true; +} + +/* Reorgnize the UNSPEC CONST and return its direct symbol. */ +static rtx +nds32_delegitimize_address (rtx x) +{ + x = delegitimize_mem_from_attrs (x); + + if (GET_CODE(x) == CONST) + { + rtx inner = XEXP (x, 0); + + /* Handle for GOTOFF. */ + if (GET_CODE (inner) == PLUS) + inner = XEXP (inner, 0); + + if (GET_CODE (inner) == UNSPEC) + { + switch (XINT (inner, 1)) + { + case UNSPEC_ICT: + x = XVECEXP (inner, 0, 0); + break; + default: + break; + } + } + } + return x; +} + static machine_mode nds32_vectorize_preferred_simd_mode (scalar_mode mode) { @@ -2715,6 +2826,29 @@ nds32_vectorize_preferred_simd_mode (scalar_mode mode) } } +static bool +nds32_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) +{ + switch (GET_CODE (x)) + { + case CONST: + return !nds32_legitimate_constant_p (mode, x); + case SYMBOL_REF: + /* All symbols have to be accessed through gp-relative in PIC mode. */ + /* We don't want to force symbol as constant pool in .text section, + because we use the gp-relatived instruction to load in small + or medium model. */ + if (SYMBOL_REF_TLS_MODEL (x) + || TARGET_CMODEL_SMALL + || TARGET_CMODEL_MEDIUM) + return true; + break; + default: + return false; + } + return false; +} + /* Condition Code Status. */ @@ -2862,6 +2996,11 @@ nds32_asm_file_start (void) /* Tell assembler that this asm code is generated by compiler. */ fprintf (asm_out_file, "\t! This asm file is generated by compiler\n"); fprintf (asm_out_file, "\t.flag\tverbatim\n"); + + if (TARGET_ICT_MODEL_LARGE) + fprintf (asm_out_file, "\t.ict_model\tlarge\n"); + else + fprintf (asm_out_file, "\t.ict_model\tsmall\n"); /* Give assembler the size of each vector for interrupt handler. */ fprintf (asm_out_file, "\t! This vector size directive is required " "for checking inconsistency on interrupt handler\n"); @@ -2956,6 +3095,26 @@ nds32_asm_file_end (void) fprintf (asm_out_file, "\t! ------------------------------------\n"); } +static bool +nds32_asm_output_addr_const_extra (FILE *file, rtx x) +{ + if (GET_CODE (x) == UNSPEC) + { + switch (XINT (x, 1)) + { + case UNSPEC_ICT: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@ICT", file); + break; + default: + return false; + } + return true; + } + else + return false; +} + /* -- Output and Generation of Labels. */ static void @@ -3123,8 +3282,15 @@ nds32_print_operand (FILE *stream, rtx x, int code) switch (GET_CODE (x)) { case LABEL_REF: + output_addr_const (stream, x); + break; + case SYMBOL_REF: output_addr_const (stream, x); + + if (nds32_indirect_call_referenced_p (x)) + fprintf (stream, "@ICT"); + break; case REG: @@ -3211,6 +3377,13 @@ nds32_print_operand (FILE *stream, rtx x, int code) fprintf (stream, HOST_WIDE_INT_PRINT_HEX, const_vector_to_hwint (x)); break; + case LO_SUM: + /* This is a special case for inline assembly using memory address 'p'. + The inline assembly code is expected to use pesudo instruction + for the operand. EX: la */ + output_addr_const (stream, XEXP(x, 1)); + break; + default: /* Generally, output_addr_const () is able to handle most cases. We want to see what CODE could appear, @@ -3222,7 +3395,9 @@ nds32_print_operand (FILE *stream, rtx x, int code) } static void -nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) +nds32_print_operand_address (FILE *stream, + machine_mode mode ATTRIBUTE_UNUSED, + rtx x) { rtx op0, op1; @@ -3237,6 +3412,16 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) fputs ("]", stream); break; + case LO_SUM: + /* This is a special case for inline assembly using memory operand 'm'. + The inline assembly code is expected to use pesudo instruction + for the operand. EX: [ls].[bhw] */ + fputs ("[ + ", stream); + op1 = XEXP (x, 1); + output_addr_const (stream, op1); + fputs ("]", stream); + break; + case REG: /* Forbid using static chain register ($r16) on reduced-set registers configuration. */ @@ -3511,6 +3696,24 @@ nds32_merge_decl_attributes (tree olddecl, tree newdecl) static void nds32_insert_attributes (tree decl, tree *attributes) { + /* A "indirect_call" function attribute implies "noinline" and "noclone" + for elf toolchain to support ROM patch mechanism. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && lookup_attribute ("indirect_call", *attributes) != NULL) + { + tree new_attrs = *attributes; + + if (lookup_attribute ("noinline", new_attrs) == NULL) + new_attrs = tree_cons (get_identifier ("noinline"), NULL, new_attrs); + if (lookup_attribute ("noclone", new_attrs) == NULL) + new_attrs = tree_cons (get_identifier ("noclone"), NULL, new_attrs); + + if (!TREE_PUBLIC (decl)) + error("indirect_call attribute can't apply for static function"); + + *attributes = new_attrs; + } + /* For function declaration, we need to check isr-specific attributes: 1. Call nds32_check_isr_attrs_conflict() to check any conflict. 2. Check valid integer value for interrupt/exception. @@ -5149,9 +5352,21 @@ nds32_use_blocks_for_constant_p (machine_mode mode, #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P nds32_legitimate_address_p +#undef TARGET_LEGITIMIZE_ADDRESS +#define TARGET_LEGITIMIZE_ADDRESS nds32_legitimize_address + +#undef TARGET_LEGITIMATE_CONSTANT_P +#define TARGET_LEGITIMATE_CONSTANT_P nds32_legitimate_constant_p + #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE nds32_vectorize_preferred_simd_mode +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM nds32_cannot_force_const_mem + +#undef TARGET_DELEGITIMIZE_ADDRESS +#define TARGET_DELEGITIMIZE_ADDRESS nds32_delegitimize_address + /* Anchored Addresses. */ @@ -5212,6 +5427,9 @@ nds32_use_blocks_for_constant_p (machine_mode mode, #undef TARGET_ASM_ALIGNED_SI_OP #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" +#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA +#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA nds32_asm_output_addr_const_extra + /* -- Output of Uninitialized Variables. */ /* -- Output and Generation of Labels. */ |