aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/nds32/nds32.c
diff options
context:
space:
mode:
authorKuan-Lin Chen <kuanlinchentw@gmail.com>2018-05-19 08:57:57 +0000
committerChung-Ju Wu <jasonwucj@gmail.com>2018-05-19 08:57:57 +0000
commit918250052162a4804c44f9c6d66b2be7a2982fd7 (patch)
tree8181124edca780d039889214a3cb55fb651ecd9d /gcc/config/nds32/nds32.c
parent8a3c41d3c70e48876731a9aa32414c153842dfca (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.c234
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. */