From: Kuan-Lin Chen Date: Sat, 19 May 2018 08:57:57 +0000 (+0000) Subject: [NDS32] Implment indirect funciton call attribute. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=85a980769ebbe1b8b7de983a9ba20d714c7431c0;p=gcc.git [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. Co-Authored-By: Chung-Ju Wu From-SVN: r260390 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 145c3aa468a..ceabfc19b62 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,43 @@ +2018-05-19 Kuan-Lin Chen + Chung-Ju Wu + + * 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. + 2018-05-18 Kito Cheng Monk Chiang Jim Wilson 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" @@ -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")