From 5fe80ef0b0a1aafd1eb0175c49c338bea5ee4c35 Mon Sep 17 00:00:00 2001 From: hubicka Date: Tue, 6 Mar 2007 16:38:43 +0000 Subject: [PATCH] * reg-stack.c (reg_to_stack): Large models don't allow NAN to be loaded for constant large models. Non-large 64bit PIC can do. * i386.h (CASE_VECTOR_MODE): Large PIC cases are 64bit. * cmodel.h: Add LARGE PIC. * i386.md (UNSPEC_PLTOFF): New. (UNSPEC_SET_RIP, UNSPEC_SET_GOT_OFFSET): New; renumber other unspecs as needed. (*call_1_rex64): Disable for large models. (*call_1_rex64_large): New. (*call_value_1_rex64): Disable for large models. (*call_value_1_rex64_large): New. (set_rip_rex4): New. (set_got_offset_rex64): New. * predicates.md (constant_call_address_operand): For large model constant calls are not possible. * i386-protos.h (construct_plt_address): Declare. * i386.c (override_options): Accept large models. (ix86_expand_prologue): Expand large PIC GOT pointer load. (legitimate_constant_p): Add new UNSPECs. (legitimate_pic_operand_p): Likewise. (legitimate_pic_address_disp_p): Disallow local symbols for large PICs. (legitimize_pic_address): Do easy RIP relative way for TLS only for non-large model. (output_pic_addr_const): Add PLTOFF. (ix86_output_addr_diff_elt): Output 64bit tables when needed. (ix86_expand_move): Legitimize pic address when in PIC mode. (construct_plt_address): New function. (ix86_expand_call): Offload the address to register and use GOT pointer for large model. * invoke.texi (mcmodel=large): Update documentation. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@122623 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 33 ++++++++++++++++ gcc/config/i386/i386-protos.h | 1 + gcc/config/i386/i386.c | 84 ++++++++++++++++++++++++++++++++++------- gcc/config/i386/i386.h | 6 ++- gcc/config/i386/i386.md | 88 ++++++++++++++++++++++++++++++------------- gcc/config/i386/predicates.md | 5 ++- gcc/doc/invoke.texi | 3 +- gcc/reg-stack.c | 3 +- 8 files changed, 176 insertions(+), 47 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bc27cf5..a9a0565 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,36 @@ +2007-03-06 Jan Hubicka + + * reg-stack.c (reg_to_stack): Large models don't allow NAN to be + loaded for constant large models. Non-large 64bit PIC can do. + * i386.h (CASE_VECTOR_MODE): Large PIC cases are 64bit. + * cmodel.h: Add LARGE PIC. + * i386.md (UNSPEC_PLTOFF): New. + (UNSPEC_SET_RIP, UNSPEC_SET_GOT_OFFSET): New; renumber other unspecs as + needed. + (*call_1_rex64): Disable for large models. + (*call_1_rex64_large): New. + (*call_value_1_rex64): Disable for large models. + (*call_value_1_rex64_large): New. + (set_rip_rex4): New. + (set_got_offset_rex64): New. + * predicates.md (constant_call_address_operand): For large model + constant calls are not possible. + * i386-protos.h (construct_plt_address): Declare. + * i386.c (override_options): Accept large models. + (ix86_expand_prologue): Expand large PIC GOT pointer load. + (legitimate_constant_p): Add new UNSPECs. + (legitimate_pic_operand_p): Likewise. + (legitimate_pic_address_disp_p): Disallow local symbols for large PICs. + (legitimize_pic_address): Do easy RIP relative way for TLS only for + non-large model. + (output_pic_addr_const): Add PLTOFF. + (ix86_output_addr_diff_elt): Output 64bit tables when needed. + (ix86_expand_move): Legitimize pic address when in PIC mode. + (construct_plt_address): New function. + (ix86_expand_call): Offload the address to register and use GOT pointer + for large model. + * invoke.texi (mcmodel=large): Update documentation. + 2007-03-06 Richard Henderson * config/i386/i386.c (x86_use_leave, x86_push_memory, diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 24655fe..a3a0f66 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -249,5 +249,6 @@ extern void x86_elf_aligned_common (FILE *, const char *, extern void ix86_fp_comparison_codes (enum rtx_code code, enum rtx_code *, enum rtx_code *, enum rtx_code *); extern enum rtx_code ix86_fp_compare_code_to_integer (enum rtx_code); +extern rtx construct_plt_address (rtx); #endif extern int asm_preferred_eh_data_format (int, int); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index cf3b3ff..9cc2144 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -2072,14 +2072,14 @@ override_options (void) ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; else if (!strcmp (ix86_cmodel_string, "medium")) ix86_cmodel = flag_pic ? CM_MEDIUM_PIC : CM_MEDIUM; + else if (!strcmp (ix86_cmodel_string, "large")) + ix86_cmodel = flag_pic ? CM_LARGE_PIC : CM_LARGE; else if (flag_pic) - sorry ("code model %s not supported in PIC mode", ix86_cmodel_string); + error ("code model %s does not support PIC mode", ix86_cmodel_string); else if (!strcmp (ix86_cmodel_string, "32")) ix86_cmodel = CM_32; else if (!strcmp (ix86_cmodel_string, "kernel") && !flag_pic) ix86_cmodel = CM_KERNEL; - else if (!strcmp (ix86_cmodel_string, "large") && !flag_pic) - ix86_cmodel = CM_LARGE; else error ("bad value (%s) for -mcmodel= switch", ix86_cmodel_string); } @@ -2102,8 +2102,6 @@ override_options (void) if ((TARGET_64BIT == 0) != (ix86_cmodel == CM_32)) error ("code model %qs not supported in the %s bit mode", ix86_cmodel_string, TARGET_64BIT ? "64" : "32"); - if (ix86_cmodel == CM_LARGE) - sorry ("code model % not supported yet"); if ((TARGET_64BIT != 0) != ((target_flags & MASK_64BIT) != 0)) sorry ("%i-bit mode not compiled in", (target_flags & MASK_64BIT) ? 64 : 32); @@ -5982,7 +5980,25 @@ ix86_expand_prologue (void) if (pic_reg_used) { if (TARGET_64BIT) - insn = emit_insn (gen_set_got_rex64 (pic_offset_table_rtx)); + { + if (ix86_cmodel == CM_LARGE_PIC) + { + rtx tmp_reg = gen_rtx_REG (DImode, + FIRST_REX_INT_REG + 3 /* R11 */); + rtx label = gen_label_rtx (); + emit_label (label); + LABEL_PRESERVE_P (label) = 1; + gcc_assert (REGNO (pic_offset_table_rtx) != REGNO (tmp_reg)); + insn = emit_insn (gen_set_rip_rex64 (pic_offset_table_rtx, label)); + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL); + insn = emit_insn (gen_set_got_offset_rex64 (tmp_reg, label)); + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL); + insn = emit_insn (gen_adddi3 (pic_offset_table_rtx, + pic_offset_table_rtx, tmp_reg)); + } + else + insn = emit_insn (gen_set_got_rex64 (pic_offset_table_rtx)); + } else insn = emit_insn (gen_set_got (pic_offset_table_rtx)); @@ -6537,7 +6553,9 @@ legitimate_constant_p (rtx x) if (GET_CODE (x) == UNSPEC) switch (XINT (x, 1)) { + case UNSPEC_GOT: case UNSPEC_GOTOFF: + case UNSPEC_PLTOFF: return TARGET_64BIT; case UNSPEC_TPOFF: case UNSPEC_NTPOFF: @@ -6635,7 +6653,9 @@ legitimate_pic_operand_p (rtx x) if (GET_CODE (inner) == UNSPEC) switch (XINT (inner, 1)) { + case UNSPEC_GOT: case UNSPEC_GOTOFF: + case UNSPEC_PLTOFF: return TARGET_64BIT; case UNSPEC_TPOFF: x = XVECEXP (inner, 0, 0); @@ -6693,7 +6713,8 @@ legitimate_pic_address_disp_p (rtx disp) /* TLS references should always be enclosed in UNSPEC. */ if (SYMBOL_REF_TLS_MODEL (op0)) return false; - if (!SYMBOL_REF_FAR_ADDR_P (op0) && SYMBOL_REF_LOCAL_P (op0)) + if (!SYMBOL_REF_FAR_ADDR_P (op0) && SYMBOL_REF_LOCAL_P (op0) + && ix86_cmodel != CM_LARGE_PIC) return true; break; @@ -6711,7 +6732,8 @@ legitimate_pic_address_disp_p (rtx disp) of GOT tables. We should not need these anyway. */ if (GET_CODE (disp) != UNSPEC || (XINT (disp, 1) != UNSPEC_GOTPCREL - && XINT (disp, 1) != UNSPEC_GOTOFF)) + && XINT (disp, 1) != UNSPEC_GOTOFF + && XINT (disp, 1) != UNSPEC_PLTOFF)) return 0; if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF @@ -7128,7 +7150,7 @@ legitimize_pic_address (rtx orig, rtx reg) } else if (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (addr) == 0) { - if (TARGET_64BIT) + if (TARGET_64BIT && ix86_cmodel != CM_LARGE_PIC) { new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTPCREL); new = gen_rtx_CONST (Pmode, new); @@ -7152,6 +7174,8 @@ legitimize_pic_address (rtx orig, rtx reg) regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT); new = gen_rtx_CONST (Pmode, new); + if (TARGET_64BIT) + new = force_reg (Pmode, new); new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); new = gen_const_mem (Pmode, new); set_mem_alias_set (new, ix86_GOT_alias_set ()); @@ -7730,6 +7754,9 @@ output_pic_addr_const (FILE *file, rtx x, int code) case UNSPEC_GOTOFF: fputs ("@GOTOFF", file); break; + case UNSPEC_PLTOFF: + fputs ("@PLTOFF", file); + break; case UNSPEC_GOTPCREL: fputs ("@GOTPCREL(%rip)", file); break; @@ -9344,9 +9371,17 @@ ix86_output_addr_vec_elt (FILE *file, int value) void ix86_output_addr_diff_elt (FILE *file, int value, int rel) { + const char *directive = ASM_LONG; + +#ifdef ASM_QUAD + if (TARGET_64BIT && CASE_VECTOR_MODE == DImode) + directive = ASM_QUAD; +#else + gcc_assert (!TARGET_64BIT); +#endif if (TARGET_64BIT) fprintf (file, "%s%s%d-%s%d\n", - ASM_LONG, LPREFIX, value, LPREFIX, rel); + directive, LPREFIX, value, LPREFIX, rel); else if (HAVE_AS_GOTOFF_IN_DATA) fprintf (file, "%s%s%d@GOTOFF\n", ASM_LONG, LPREFIX, value); #if TARGET_MACHO @@ -9466,8 +9501,8 @@ ix86_expand_move (enum machine_mode mode, rtx operands[]) { if (MEM_P (op0)) op1 = force_reg (Pmode, op1); - else - op1 = legitimize_address (op1, op1, Pmode); + else if (!TARGET_64BIT || !x86_64_movabs_operand (op1, Pmode)) + op1 = legitimize_pic_address (op1, op0); } } else @@ -14958,6 +14993,22 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx) emit_label (end_0_label); } +/* For given symbol (function) construct code to compute address of it's PLT + entry in large x86-64 PIC model. */ +rtx +construct_plt_address (rtx symbol) +{ + rtx tmp = gen_reg_rtx (Pmode); + rtx unspec = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, symbol), UNSPEC_PLTOFF); + + gcc_assert (GET_CODE (symbol) == SYMBOL_REF); + gcc_assert (ix86_cmodel == CM_LARGE_PIC); + + emit_move_insn (tmp, gen_rtx_CONST (Pmode, unspec)); + emit_insn (gen_adddi3 (tmp, tmp, pic_offset_table_rtx)); + return tmp; +} + void ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx callarg2 ATTRIBUTE_UNUSED, @@ -14979,7 +15030,7 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, else { /* Static functions and indirect calls don't need the pic register. */ - if (! TARGET_64BIT && flag_pic + if (flag_pic && (!TARGET_64BIT || ix86_cmodel == CM_LARGE_PIC) && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF && ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0))) use_reg (&use, pic_offset_table_rtx); @@ -14992,7 +15043,12 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, use_reg (&use, al); } - if (! call_insn_operand (XEXP (fnaddr, 0), Pmode)) + if (ix86_cmodel == CM_LARGE_PIC + && GET_CODE (fnaddr) == MEM + && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF + && !local_symbolic_operand (XEXP (fnaddr, 0), VOIDmode)) + fnaddr = gen_rtx_MEM (QImode, construct_plt_address (XEXP (fnaddr, 0))); + else if (! call_insn_operand (XEXP (fnaddr, 0), Pmode)) { fnaddr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0)); fnaddr = gen_rtx_MEM (QImode, fnaddr); diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 8e3032c..4c322bc 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1851,7 +1851,8 @@ do { \ /* Specify the machine mode that this machine uses for the index in the tablejump instruction. */ -#define CASE_VECTOR_MODE (!TARGET_64BIT || flag_pic ? SImode : DImode) +#define CASE_VECTOR_MODE \ + (!TARGET_64BIT || (flag_pic && ix86_cmodel != CM_LARGE_PIC) ? SImode : DImode) /* Define this as 1 if `char' should by default be signed; else as 0. */ #define DEFAULT_SIGNED_CHAR 1 @@ -2213,7 +2214,8 @@ enum cmodel { CM_MEDIUM, /* Assumes code fits in the low 31 bits; data unlimited. */ CM_LARGE, /* No assumptions. */ CM_SMALL_PIC, /* Assumes code+data+got/plt fits in a 31 bit region. */ - CM_MEDIUM_PIC /* Assumes code+got/plt fits in a 31 bit region. */ + CM_MEDIUM_PIC,/* Assumes code+got/plt fits in a 31 bit region. */ + CM_LARGE_PIC /* No assumptions. */ }; extern enum cmodel ix86_cmodel; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 409ce0c..f66318b8 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -58,6 +58,7 @@ (UNSPEC_DTPOFF 6) (UNSPEC_GOTNTPOFF 7) (UNSPEC_INDNTPOFF 8) + (UNSPEC_PLTOFF 9) ; Prologue support (UNSPEC_STACK_ALLOC 11) @@ -65,36 +66,38 @@ (UNSPEC_SSE_PROLOGUE_SAVE 13) (UNSPEC_REG_SAVE 14) (UNSPEC_DEF_CFA 15) + (UNSPEC_SET_RIP 16) + (UNSPEC_SET_GOT_OFFSET 17) ; TLS support - (UNSPEC_TP 16) - (UNSPEC_TLS_GD 17) - (UNSPEC_TLS_LD_BASE 18) - (UNSPEC_TLSDESC 19) + (UNSPEC_TP 18) + (UNSPEC_TLS_GD 19) + (UNSPEC_TLS_LD_BASE 20) + (UNSPEC_TLSDESC 21) ; Other random patterns - (UNSPEC_SCAS 20) - (UNSPEC_FNSTSW 21) - (UNSPEC_SAHF 22) - (UNSPEC_FSTCW 23) - (UNSPEC_ADD_CARRY 24) - (UNSPEC_FLDCW 25) - (UNSPEC_REP 26) - (UNSPEC_EH_RETURN 27) - (UNSPEC_LD_MPIC 28) ; load_macho_picbase - (UNSPEC_TRUNC_NOOP 29) + (UNSPEC_SCAS 30) + (UNSPEC_FNSTSW 31) + (UNSPEC_SAHF 32) + (UNSPEC_FSTCW 33) + (UNSPEC_ADD_CARRY 34) + (UNSPEC_FLDCW 35) + (UNSPEC_REP 36) + (UNSPEC_EH_RETURN 37) + (UNSPEC_LD_MPIC 38) ; load_macho_picbase + (UNSPEC_TRUNC_NOOP 39) ; For SSE/MMX support: - (UNSPEC_FIX_NOTRUNC 30) - (UNSPEC_MASKMOV 31) - (UNSPEC_MOVMSK 32) - (UNSPEC_MOVNT 33) - (UNSPEC_MOVU 34) - (UNSPEC_RCP 35) - (UNSPEC_RSQRT 36) - (UNSPEC_SFENCE 37) - (UNSPEC_NOP 38) ; prevents combiner cleverness - (UNSPEC_PFRCP 39) + (UNSPEC_FIX_NOTRUNC 40) + (UNSPEC_MASKMOV 41) + (UNSPEC_MOVMSK 42) + (UNSPEC_MOVNT 43) + (UNSPEC_MOVU 44) + (UNSPEC_RCP 45) + (UNSPEC_RSQRT 46) + (UNSPEC_SFENCE 47) + (UNSPEC_NOP 48) ; prevents combiner cleverness + (UNSPEC_PFRCP 49) (UNSPEC_PFRCPIT1 40) (UNSPEC_PFRCPIT2 41) (UNSPEC_PFRSQRT 42) @@ -14545,7 +14548,8 @@ (define_insn "*call_1_rex64" [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rsm")) (match_operand 1 "" ""))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "!SIBLING_CALL_P (insn) && TARGET_64BIT + && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC" { if (constant_call_address_operand (operands[0], Pmode)) return "call\t%P0"; @@ -14553,6 +14557,13 @@ } [(set_attr "type" "call")]) +(define_insn "*call_1_rex64_large" + [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rm")) + (match_operand 1 "" ""))] + "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "call\t%A0" + [(set_attr "type" "call")]) + (define_insn "*sibcall_1_rex64" [(call (mem:QI (match_operand:DI 0 "constant_call_address_operand" "")) (match_operand 1 "" ""))] @@ -14769,6 +14780,22 @@ [(set_attr "type" "lea") (set_attr "length" "6")]) +(define_insn "set_rip_rex64" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "" "")] UNSPEC_SET_RIP))] + "TARGET_64BIT" + "lea{q}\t%l1(%%rip), %0" + [(set_attr "type" "lea") + (set_attr "length" "6")]) + +(define_insn "set_got_offset_rex64" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "" "")] UNSPEC_SET_GOT_OFFSET))] + "TARGET_64BIT" + "movabs{q}\t$_GLOBAL_OFFSET_TABLE_-%l1, %0" + [(set_attr "type" "imov") + (set_attr "length" "11")]) + (define_expand "epilogue" [(const_int 1)] "" @@ -20941,7 +20968,8 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rsm")) (match_operand:DI 2 "" "")))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "!SIBLING_CALL_P (insn) && TARGET_64BIT + && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC" { if (constant_call_address_operand (operands[1], Pmode)) return "call\t%P1"; @@ -20949,6 +20977,14 @@ } [(set_attr "type" "callv")]) +(define_insn "*call_value_1_rex64_large" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rm")) + (match_operand:DI 2 "" "")))] + "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "call\t%A1" + [(set_attr "type" "callv")]) + (define_insn "*sibcall_value_1_rex64" [(set (match_operand 0 "" "") (call (mem:QI (match_operand:DI 1 "constant_call_address_operand" "")) diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index ea2eb69..6ac3622 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -472,8 +472,9 @@ ;; Test for a pc-relative call operand (define_predicate "constant_call_address_operand" - (ior (match_code "symbol_ref") - (match_operand 0 "local_symbolic_operand"))) + (and (ior (match_code "symbol_ref") + (match_operand 0 "local_symbolic_operand")) + (match_test "ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC"))) ;; True for any non-virtual or eliminable register. Used in places where ;; instantiation of such a register may cause the pattern to not be recognized. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 84dd396..7e15dbf 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10142,8 +10142,7 @@ building of shared libraries are not supported with the medium model. @item -mcmodel=large @opindex mcmodel=large Generate code for the large model: This model makes no assumptions -about addresses and sizes of sections. Currently GCC does not implement -this model. +about addresses and sizes of sections. @end table @node IA-64 Options diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 7a7a0e5..e6802b1 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -3141,7 +3141,8 @@ reg_to_stack (void) the PIC register hasn't been set up. In that case, fall back on zero, which we can get from `ldz'. */ - if (flag_pic && !TARGET_64BIT) + if ((flag_pic && !TARGET_64BIT) + || ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC) not_a_num = CONST0_RTX (SFmode); else { -- 2.7.4