aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/nds32
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
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')
-rw-r--r--gcc/config/nds32/constants.md1
-rw-r--r--gcc/config/nds32/nds32-md-auxiliary.c104
-rw-r--r--gcc/config/nds32/nds32-opts.h7
-rw-r--r--gcc/config/nds32/nds32-protos.h16
-rw-r--r--gcc/config/nds32/nds32-relax-opt.c14
-rw-r--r--gcc/config/nds32/nds32.c234
-rw-r--r--gcc/config/nds32/nds32.h11
-rw-r--r--gcc/config/nds32/nds32.md82
-rw-r--r--gcc/config/nds32/nds32.opt13
-rw-r--r--gcc/config/nds32/predicates.md4
10 files changed, 461 insertions, 25 deletions
diff --git a/gcc/config/nds32/constants.md b/gcc/config/nds32/constants.md
index cba989f99a6..c4cde8d7ebe 100644
--- a/gcc/config/nds32/constants.md
+++ b/gcc/config/nds32/constants.md
@@ -83,6 +83,7 @@
UNSPEC_LOOP_END
UNSPEC_TLS_DESC
UNSPEC_TLS_IE
+ UNSPEC_ICT
UNSPEC_KADDH
UNSPEC_KSUBH
])
diff --git a/gcc/config/nds32/nds32-md-auxiliary.c b/gcc/config/nds32/nds32-md-auxiliary.c
index 96966115402..99beff6d828 100644
--- a/gcc/config/nds32/nds32-md-auxiliary.c
+++ b/gcc/config/nds32/nds32-md-auxiliary.c
@@ -39,6 +39,9 @@
#include "expr.h"
#include "emit-rtl.h"
#include "explow.h"
+#include "stringpool.h"
+#include "attribs.h"
+
/* ------------------------------------------------------------------------ */
@@ -2970,16 +2973,6 @@ nds32_output_unpkd8 (rtx output, rtx input,
return "";
}
-/* Return true if SYMBOL_REF X binds locally. */
-
-static bool
-nds32_symbol_binds_local_p (const_rtx x)
-{
- return (SYMBOL_REF_DECL (x)
- ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
- : SYMBOL_REF_LOCAL_P (x));
-}
-
const char *
nds32_output_call (rtx insn, rtx *operands, rtx symbol, const char *long_call,
const char *call, bool align_p)
@@ -3400,11 +3393,100 @@ nds32_split_rotatertdi3 (rtx dst, rtx src, rtx shiftamount)
emit_insn (gen_cmovnsi (dst_high_part, select_reg,
dst_high_part_l32, dst_high_part_g32));
}
+
+/* Return true if OP contains a symbol reference. */
+bool
+symbolic_reference_mentioned_p (rtx op)
+{
+ const char *fmt;
+ int i;
+
+ if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
+ return true;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (op));
+ for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (op, i) - 1; j >= 0; j--)
+ if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
+ return true;
+ }
+
+ else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
+ return true;
+ }
+
+ return false;
+}
+
+/* Expand ICT symbol.
+ Example for @ICT and ICT model=large:
+
+ la $r0, symbol@ICT
+ -> sethi $rt, hi20(symbol@ICT)
+ lwi $r0, [$rt + lo12(symbol@ICT)]
+
+*/
+rtx
+nds32_legitimize_ict_address (rtx x)
+{
+ rtx symbol = x;
+ rtx addr = x;
+ rtx reg = gen_reg_rtx (Pmode);
+ gcc_assert (GET_CODE (x) == SYMBOL_REF
+ && nds32_indirect_call_referenced_p (x));
+
+ addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, symbol), UNSPEC_ICT);
+ addr = gen_rtx_CONST (SImode, addr);
+ emit_insn (gen_sethi (reg, addr));
+
+ x = gen_const_mem (SImode, gen_rtx_LO_SUM (Pmode, reg, addr));
+
+ return x;
+}
+
+void
+nds32_expand_ict_move (rtx *operands)
+{
+ rtx src = operands[1];
+
+ src = nds32_legitimize_ict_address (src);
+
+ emit_move_insn (operands[0], src);
+}
+
+/* Return true X is a indirect call symbol. */
+bool
+nds32_indirect_call_referenced_p (rtx x)
+{
+ if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_ICT)
+ x = XVECEXP (x, 0, 0);
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ tree decl = SYMBOL_REF_DECL (x);
+
+ return decl
+ && (lookup_attribute("indirect_call",
+ DECL_ATTRIBUTES(decl))
+ != NULL);
+ }
+
+ return false;
+}
+
/* Return true X is need use long call. */
bool
nds32_long_call_p (rtx symbol)
{
- return TARGET_CMODEL_LARGE;
+ if (nds32_indirect_call_referenced_p (symbol))
+ return TARGET_ICT_MODEL_LARGE;
+ else
+ return TARGET_CMODEL_LARGE;
}
void
diff --git a/gcc/config/nds32/nds32-opts.h b/gcc/config/nds32/nds32-opts.h
index e0400655757..e75e75f4332 100644
--- a/gcc/config/nds32/nds32-opts.h
+++ b/gcc/config/nds32/nds32-opts.h
@@ -57,6 +57,13 @@ enum nds32_cmodel_type
CMODEL_LARGE
};
+/* The code model defines the address generation strategy. */
+enum nds32_ict_model_type
+{
+ ICT_MODEL_SMALL,
+ ICT_MODEL_LARGE
+};
+
/* Multiply instruction configuration. */
enum nds32_mul_type
{
diff --git a/gcc/config/nds32/nds32-protos.h b/gcc/config/nds32/nds32-protos.h
index a7d679e01f0..4bf82f1f723 100644
--- a/gcc/config/nds32/nds32-protos.h
+++ b/gcc/config/nds32/nds32-protos.h
@@ -183,9 +183,25 @@ extern void nds32_expand_float_movcc (rtx *);
extern enum nds32_expand_result_type nds32_expand_extv (rtx *);
extern enum nds32_expand_result_type nds32_expand_insv (rtx *);
+/* Auxiliary functions for expand ICT instruction. */
+
+extern void nds32_expand_ict_move (rtx *);
+
+/* Auxiliary functions to legitimize address for indirect-call symbol. */
+
+extern rtx nds32_legitimize_ict_address (rtx);
+
+/* Auxiliary functions to identify indirect-call symbol. */
+
+extern bool nds32_indirect_call_referenced_p (rtx);
+
/* Auxiliary functions to identify long-call symbol. */
extern bool nds32_long_call_p (rtx);
+/* Auxiliary functions to identify SYMBOL_REF and LABEL_REF pattern. */
+
+extern bool symbolic_reference_mentioned_p (rtx);
+
/* Auxiliary functions to identify conditional move comparison operand. */
extern int nds32_cond_move_p (rtx);
diff --git a/gcc/config/nds32/nds32-relax-opt.c b/gcc/config/nds32/nds32-relax-opt.c
index 0349be4725d..0a878aaff9f 100644
--- a/gcc/config/nds32/nds32-relax-opt.c
+++ b/gcc/config/nds32/nds32-relax-opt.c
@@ -185,6 +185,17 @@ nds32_plus_reg_load_store_p (rtx_insn *insn)
return false;
}
+/* Return true if x is const and the referance is ict symbol. */
+static bool
+nds32_ict_const_p (rtx x)
+{
+ if (GET_CODE (x) == CONST)
+ {
+ x = XEXP (x, 0);
+ return nds32_indirect_call_referenced_p (x);
+ }
+ return FALSE;
+}
/* Group the relax candidates with group id. */
static void
nds32_group_insns (rtx sethi)
@@ -271,7 +282,8 @@ nds32_relax_group (void)
/* Find sethi ra, symbol instruction. */
if (recog_memoized (insn) == CODE_FOR_sethi
&& nds32_symbolic_operand (XEXP (SET_SRC (PATTERN (insn)), 0),
- SImode))
+ SImode)
+ && !nds32_ict_const_p (XEXP (SET_SRC (PATTERN (insn)), 0)))
nds32_group_insns (insn);
}
}
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. */
diff --git a/gcc/config/nds32/nds32.h b/gcc/config/nds32/nds32.h
index 229012a9965..481c196e30c 100644
--- a/gcc/config/nds32/nds32.h
+++ b/gcc/config/nds32/nds32.h
@@ -855,6 +855,12 @@ enum nds32_builtins
#define TARGET_CMODEL_LARGE \
(nds32_cmodel_option == CMODEL_LARGE)
+#define TARGET_ICT_MODEL_SMALL \
+ (nds32_ict_model == ICT_MODEL_SMALL)
+
+#define TARGET_ICT_MODEL_LARGE \
+ (nds32_ict_model == ICT_MODEL_LARGE)
+
/* When -mcmodel=small or -mcmodel=medium,
compiler may generate gp-base instruction directly. */
#define TARGET_GP_DIRECT \
@@ -1461,6 +1467,11 @@ enum reg_class
#define PIC_OFFSET_TABLE_REGNUM GP_REGNUM
+#define SYMBOLIC_CONST_P(X) \
+(GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == LABEL_REF \
+ || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X)))
+
/* Defining the Output Assembler Language. */
diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md
index 6379212550e..a4f204b0ed2 100644
--- a/gcc/config/nds32/nds32.md
+++ b/gcc/config/nds32/nds32.md
@@ -215,6 +215,17 @@
low12_int));
DONE;
}
+
+ if ((REG_P (operands[0]) || GET_CODE (operands[0]) == SUBREG)
+ && SYMBOLIC_CONST_P (operands[1]))
+ {
+ if (TARGET_ICT_MODEL_LARGE
+ && nds32_indirect_call_referenced_p (operands[1]))
+ {
+ nds32_expand_ict_move (operands);
+ DONE;
+ }
+ }
})
(define_insn "*mov<mode>"
@@ -1479,7 +1490,26 @@
(clobber (reg:SI LP_REGNUM))
(clobber (reg:SI TA_REGNUM))])]
""
- ""
+ {
+ rtx insn;
+ rtx sym = XEXP (operands[0], 0);
+
+ if (TARGET_ICT_MODEL_LARGE
+ && nds32_indirect_call_referenced_p (sym))
+ {
+ rtx reg = gen_reg_rtx (Pmode);
+ emit_move_insn (reg, sym);
+ operands[0] = gen_const_mem (Pmode, reg);
+ }
+
+ if (flag_pic)
+ {
+ insn = emit_call_insn (gen_call_internal
+ (XEXP (operands[0], 0), GEN_INT (0)));
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+ DONE;
+ }
+ }
)
(define_insn "call_internal"
@@ -1543,7 +1573,29 @@
(match_operand 2)))
(clobber (reg:SI LP_REGNUM))
(clobber (reg:SI TA_REGNUM))])]
- "")
+ ""
+ {
+ rtx insn;
+ rtx sym = XEXP (operands[1], 0);
+
+ if (TARGET_ICT_MODEL_LARGE
+ && nds32_indirect_call_referenced_p (sym))
+ {
+ rtx reg = gen_reg_rtx (Pmode);
+ emit_move_insn (reg, sym);
+ operands[1] = gen_const_mem (Pmode, reg);
+ }
+
+ if (flag_pic)
+ {
+ insn =
+ emit_call_insn (gen_call_value_internal
+ (operands[0], XEXP (operands[1], 0), GEN_INT (0)));
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+ DONE;
+ }
+ }
+)
(define_insn "call_value_internal"
[(parallel [(set (match_operand 0)
@@ -1634,7 +1686,18 @@
(const_int 0))
(clobber (reg:SI TA_REGNUM))
(return)])]
- "")
+ ""
+{
+ rtx sym = XEXP (operands[0], 0);
+
+ if (TARGET_ICT_MODEL_LARGE
+ && nds32_indirect_call_referenced_p (sym))
+ {
+ rtx reg = gen_reg_rtx (Pmode);
+ emit_move_insn (reg, sym);
+ operands[0] = gen_const_mem (Pmode, reg);
+ }
+})
(define_insn "sibcall_internal"
[(parallel [(call (mem (match_operand:SI 0 "nds32_call_address_operand" "r, i"))
@@ -1684,7 +1747,18 @@
(const_int 0)))
(clobber (reg:SI TA_REGNUM))
(return)])]
- "")
+ ""
+{
+ rtx sym = XEXP (operands[1], 0);
+
+ if (TARGET_ICT_MODEL_LARGE
+ && nds32_indirect_call_referenced_p (sym))
+ {
+ rtx reg = gen_reg_rtx (Pmode);
+ emit_move_insn (reg, sym);
+ operands[1] = gen_const_mem (Pmode, reg);
+ }
+})
(define_insn "sibcall_value_internal"
[(parallel [(set (match_operand 0)
diff --git a/gcc/config/nds32/nds32.opt b/gcc/config/nds32/nds32.opt
index f1c1bf91895..9e481549d9d 100644
--- a/gcc/config/nds32/nds32.opt
+++ b/gcc/config/nds32/nds32.opt
@@ -85,6 +85,19 @@ mlittle-endian
Target Undocumented RejectNegative Negative(mbig-endian) InverseMask(BIG_ENDIAN)
Generate code in little-endian mode.
+mict-model=
+Target Undocumented RejectNegative Joined Enum(nds32_ict_model_type) Var(nds32_ict_model) Init(ICT_MODEL_SMALL)
+Specify the address generation strategy for ICT call's code model.
+
+Enum
+Name(nds32_ict_model_type) Type(enum nds32_ict_model_type)
+Known cmodel types (for use with the -mict-model= option):
+
+EnumValue
+Enum(nds32_ict_model_type) String(small) Value(ICT_MODEL_SMALL)
+
+EnumValue
+Enum(nds32_ict_model_type) String(large) Value(ICT_MODEL_LARGE)
mcmov
Target Report Mask(CMOV)
diff --git a/gcc/config/nds32/predicates.md b/gcc/config/nds32/predicates.md
index e5f7ba4a3da..59292da8328 100644
--- a/gcc/config/nds32/predicates.md
+++ b/gcc/config/nds32/predicates.md
@@ -40,7 +40,9 @@
(match_code "mult,and,ior,xor"))
(define_predicate "nds32_symbolic_operand"
- (match_code "const,symbol_ref,label_ref"))
+ (and (match_code "const,symbol_ref,label_ref")
+ (match_test "!(TARGET_ICT_MODEL_LARGE
+ && nds32_indirect_call_referenced_p (op))")))
(define_predicate "nds32_reg_constant_operand"
(ior (match_operand 0 "register_operand")