diff options
author | Kuan-Lin Chen <kuanlinchentw@gmail.com> | 2018-05-19 11:03:20 +0000 |
---|---|---|
committer | Chung-Ju Wu <jasonwucj@gmail.com> | 2018-05-19 11:03:20 +0000 |
commit | e4f31d9ea58884d4b70cf0206ef0913d968d31d3 (patch) | |
tree | fbaf49796a3f7b78f7384f1df19ef7eb651bda5f /gcc/config/nds32/nds32.c | |
parent | f1766e7b6febfbc2c867273b0e5fd6cb74e90ba8 (diff) |
[NDS32] Support PIC and TLS.
gcc/
* config/nds32/constants.md: Add TP_REGNUM constant.
(unspec_element): Add UNSPEC_GOTINIT, UNSPEC_GOT, UNSPEC_GOTOFF,
UNSPEC_PLT, UNSPEC_TLSGD, UNSPEC_TLSLD, UNSPEC_TLSIE, UNSPEC_TLSLE and
UNSPEC_ADD32.
* config/nds32/nds32-doubleword.md: Consider flag_pic.
* config/nds32/nds32-dspext.md (mov<mode>): Expand TLS and PIC cases.
* config/nds32/nds32-predicates.c (nds32_const_unspec_p): New.
* config/nds32/nds32-md-auxiliary.c: Implementation that support TLS
and PIC code generation.
* config/nds32/nds32-protos.h: Declarations that support TLS and PIC
code generation.
* config/nds32/nds32-relax-opt.c: Consider TLS and PIC for relax
optimization.
* config/nds32/nds32.md: Support TLS and PIC.
* config/nds32/nds32.c: Support TLS and PIC.
* config/nds32/nds32.h (nds32_relax_insn_type): New enum type.
* config/nds32/predicates.md (nds32_nonunspec_symbolic_operand): New
predicate.
git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@260393 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/nds32/nds32.c')
-rw-r--r-- | gcc/config/nds32/nds32.c | 185 |
1 files changed, 170 insertions, 15 deletions
diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index fe97854fe73..b705ae6a77a 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -435,7 +435,8 @@ nds32_compute_stack_frame (void) /* If $gp value is required to be saved on stack, it needs 4 bytes space. Check whether we are using PIC code genration. */ - cfun->machine->gp_size = (flag_pic) ? 4 : 0; + cfun->machine->gp_size = + (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) ? 4 : 0; /* If $lp value is required to be saved on stack, it needs 4 bytes space. Check whether $lp is ever live. */ @@ -520,7 +521,8 @@ nds32_compute_stack_frame (void) && cfun->machine->callee_saved_last_fpr_regno == SP_REGNUM && !df_regs_ever_live_p (FP_REGNUM) && !df_regs_ever_live_p (LP_REGNUM) - && cfun->machine->local_size == 0)) + && cfun->machine->local_size == 0 + && !flag_pic)) { /* Set this function 'naked_p' and other functions can check this flag. Note that in nds32 port, the 'naked_p = 1' JUST means there is no @@ -1262,6 +1264,32 @@ nds32_emit_stack_v3pop (unsigned Rb, REG_NOTES (parallel_insn) = dwarf; } +static void +nds32_emit_load_gp (void) +{ + rtx got_symbol, pat; + + /* Initial GLOBAL OFFSET TABLE don't do the scheduling. */ + emit_insn (gen_blockage ()); + + got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); + /* sethi $gp, _GLOBAL_OFFSET_TABLE_ -8 */ + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, got_symbol), UNSPEC_GOTINIT); + pat = gen_rtx_CONST (SImode, gen_rtx_PLUS (Pmode, pat, GEN_INT (-8))); + emit_insn (gen_sethi (pic_offset_table_rtx,pat)); + + /* ori $gp, $gp, _GLOBAL_OFFSET_TABLE_ -4 */ + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, got_symbol), UNSPEC_GOTINIT); + pat = gen_rtx_CONST (SImode, gen_rtx_PLUS (Pmode, pat, GEN_INT (-4))); + emit_insn (gen_lo_sum (pic_offset_table_rtx, pic_offset_table_rtx, pat)); + + /* add5.pc $gp */ + emit_insn (gen_add_pc (pic_offset_table_rtx, pic_offset_table_rtx)); + + /* Initial GLOBAL OFFSET TABLE don't do the scheduling. */ + emit_insn (gen_blockage ()); +} + /* Function that may creates more instructions for large value on adjusting stack pointer. @@ -2213,6 +2241,26 @@ nds32_asm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, ? 1 : 0); + if (flag_pic) + { + fprintf (file, "\tsmw.adm\t$r31, [$r31], $r31, 4\n"); + fprintf (file, "\tsethi\t%s, hi20(_GLOBAL_OFFSET_TABLE_-8)\n", + reg_names [PIC_OFFSET_TABLE_REGNUM]); + fprintf (file, "\tori\t%s, %s, lo12(_GLOBAL_OFFSET_TABLE_-4)\n", + reg_names [PIC_OFFSET_TABLE_REGNUM], + reg_names [PIC_OFFSET_TABLE_REGNUM]); + + if (TARGET_ISA_V3) + fprintf (file, "\tadd5.pc\t$gp\n"); + else + { + fprintf (file, "\tmfusr\t$ta, $pc\n"); + fprintf (file, "\tadd\t%s, $ta, %s\n", + reg_names [PIC_OFFSET_TABLE_REGNUM], + reg_names [PIC_OFFSET_TABLE_REGNUM]); + } + } + if (delta != 0) { if (satisfies_constraint_Is15 (GEN_INT (delta))) @@ -2237,9 +2285,23 @@ nds32_asm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, } } - fprintf (file, "\tb\t"); - assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); - fprintf (file, "\n"); + if (flag_pic) + { + fprintf (file, "\tla\t$ta, "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "@PLT\n"); + fprintf (file, "\t! epilogue\n"); + fprintf (file, "\tlwi.bi\t%s, [%s], 4\n", + reg_names[PIC_OFFSET_TABLE_REGNUM], + reg_names[STACK_POINTER_REGNUM]); + fprintf (file, "\tbr\t$ta\n"); + } + else + { + fprintf (file, "\tb\t"); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "\n"); + } final_end_function (); } @@ -2260,10 +2322,12 @@ nds32_function_ok_for_sibcall (tree decl, 3. We don't want to apply sibling call optimization for indirect sibcall because the pop behavior in epilogue may pollute the content of caller-saved regsiter when the register is used for - indirect sibcall. */ + indirect sibcall. + 4. In pic mode, it may use some registers for PLT call. */ return (!TARGET_V3PUSH && (cfun->machine->va_args_size == 0) - && decl); + && decl + && !flag_pic); } /* Determine whether we need to enable warning for function return check. */ @@ -2579,6 +2643,10 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) case SYMBOL_REF: /* (mem (symbol_ref A)) => [symbol_ref] */ + + if (flag_pic || SYMBOL_REF_TLS_MODEL (x)) + return false; + if (TARGET_ICT_MODEL_LARGE && nds32_indirect_call_referenced_p (x)) return false; @@ -2593,7 +2661,8 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) the 'symbol_ref' is not a valid address during or after LRA/reload phase. */ if (TARGET_CMODEL_MEDIUM - && NDS32_SYMBOL_REF_RODATA_P (x) + && (NDS32_SYMBOL_REF_RODATA_P (x) + || CONSTANT_POOL_ADDRESS_P (x)) && (reload_completed || reload_in_progress || lra_in_progress)) @@ -2615,6 +2684,10 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) { /* Now we see the [ + const_addr ] pattern, but we need some further checking. */ + + if (flag_pic) + return false; + /* If -mcmodel=large, the 'const_addr' is not a valid address during or after LRA/reload phase. */ if (TARGET_CMODEL_LARGE @@ -2692,9 +2765,18 @@ 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 (plus (symbol_ref) (reg)))) */ + /* TLS case: (mem (lo_sum (reg) (const (unspec symbol_ref X)))) */ + /* The LO_SUM is a valid address if and only if we would like to + generate 32-bit full address memory access with any of following + circumstance: + 1. -mcmodel=large. + 2. -mcmodel=medium and the symbol_ref references to rodata. */ { rtx sym = NULL_RTX; + if (flag_pic) + return false; + if (!REG_P (XEXP (x, 0))) return false; @@ -2736,7 +2818,11 @@ 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)) + if (nds32_tls_referenced_p (x)) + x = nds32_legitimize_tls_address (x); + else if (flag_pic && SYMBOLIC_CONST_P (x)) + x = nds32_legitimize_pic_address (x); + else if (TARGET_ICT_MODEL_LARGE && nds32_indirect_call_referenced_p (x)) x = nds32_legitimize_ict_address (x); return x; @@ -2766,6 +2852,13 @@ nds32_legitimate_constant_p (machine_mode mode, rtx x) { switch (XINT (x, 1)) { + case UNSPEC_GOT: + case UNSPEC_GOTOFF: + case UNSPEC_PLT: + case UNSPEC_TLSGD: + case UNSPEC_TLSLD: + case UNSPEC_TLSIE: + case UNSPEC_TLSLE: case UNSPEC_ICT: return false; default: @@ -2773,6 +2866,12 @@ nds32_legitimate_constant_p (machine_mode mode, rtx x) } } break; + case SYMBOL_REF: + /* TLS symbols need a call to resolve in + precompute_register_parameters. */ + if (SYMBOL_REF_TLS_MODEL (x)) + return false; + break; default: return true; } @@ -2798,6 +2897,14 @@ nds32_delegitimize_address (rtx x) { switch (XINT (inner, 1)) { + case UNSPEC_GOTINIT: + case UNSPEC_GOT: + case UNSPEC_GOTOFF: + case UNSPEC_PLT: + case UNSPEC_TLSGD: + case UNSPEC_TLSLD: + case UNSPEC_TLSIE: + case UNSPEC_TLSLE: case UNSPEC_ICT: x = XVECEXP (inner, 0, 0); break; @@ -2838,11 +2945,17 @@ nds32_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) /* 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) + if (flag_pic + || SYMBOL_REF_TLS_MODEL (x) || TARGET_CMODEL_SMALL || TARGET_CMODEL_MEDIUM) return true; break; + case CONST_INT: + case CONST_DOUBLE: + if (flag_pic && (lra_in_progress || reload_completed)) + return true; + break; default: return false; } @@ -2986,6 +3099,9 @@ nds32_asm_file_start (void) { default_file_start (); + if (flag_pic) + fprintf (asm_out_file, "\t.pic\n"); + /* Tell assembler which ABI we are using. */ fprintf (asm_out_file, "\t! ABI version\n"); if (TARGET_HARD_FLOAT) @@ -3102,6 +3218,37 @@ nds32_asm_output_addr_const_extra (FILE *file, rtx x) { switch (XINT (x, 1)) { + case UNSPEC_GOTINIT: + output_addr_const (file, XVECEXP (x, 0, 0)); + break; + case UNSPEC_GOTOFF: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@GOTOFF", file); + break; + case UNSPEC_GOT: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@GOT", file); + break; + case UNSPEC_PLT: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@PLT", file); + break; + case UNSPEC_TLSGD: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@TLSDESC", file); + break; + case UNSPEC_TLSLD: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@TLSDESC", file); + break; + case UNSPEC_TLSIE: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@GOTTPOFF", file); + break; + case UNSPEC_TLSLE: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@TPOFF", file); + break; case UNSPEC_ICT: output_addr_const (file, XVECEXP (x, 0, 0)); fputs ("@ICT", file); @@ -3870,6 +4017,9 @@ nds32_option_override (void) target_flags &= ~MASK_EXT_PERF2; /* Under V3M ISA, we need to strictly disable TARGET_EXT_STRING. */ target_flags &= ~MASK_EXT_STRING; + + if (flag_pic) + error ("not support -fpic option for v3m toolchain"); } /* See if we are using reduced-set registers: @@ -3903,9 +4053,6 @@ nds32_option_override (void) "must be enable '-mext-fpu-sp' or '-mext-fpu-dp'"); } - /* Currently, we don't support PIC code generation yet. */ - if (flag_pic) - sorry ("position-independent code not supported"); nds32_register_passes (); } @@ -4328,7 +4475,7 @@ nds32_expand_prologue (void) /* If the function is 'naked', we do not have to generate prologue code fragment. */ - if (cfun->machine->naked_p) + if (cfun->machine->naked_p && !flag_pic) return; /* Get callee_first_regno and callee_last_regno. */ @@ -4457,6 +4604,10 @@ nds32_expand_prologue (void) -1 * sp_adjust); } + /* Emit gp setup instructions for -fpic. */ + if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) + nds32_emit_load_gp (); + /* Prevent the instruction scheduler from moving instructions across the boundary. */ emit_insn (gen_blockage ()); @@ -4700,7 +4851,7 @@ nds32_expand_prologue_v3push (void) /* If the function is 'naked', we do not have to generate prologue code fragment. */ - if (cfun->machine->naked_p) + if (cfun->machine->naked_p && !flag_pic) return; /* Get callee_first_regno and callee_last_regno. */ @@ -4828,6 +4979,10 @@ nds32_expand_prologue_v3push (void) -1 * sp_adjust); } + /* Emit gp setup instructions for -fpic. */ + if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) + nds32_emit_load_gp (); + /* Prevent the instruction scheduler from moving instructions across the boundary. */ emit_insn (gen_blockage ()); |