OSDN Git Service

* reg-stack.c (reg_to_stack): Large models don't allow NAN to be
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 6 Mar 2007 16:38:43 +0000 (16:38 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 6 Mar 2007 16:38:43 +0000 (16:38 +0000)
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
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/config/i386/predicates.md
gcc/doc/invoke.texi
gcc/reg-stack.c

index bc27cf5..a9a0565 100644 (file)
@@ -1,3 +1,36 @@
+2007-03-06  Jan Hubicka  <jh@suse.cz>
+
+       * 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  <rth@redhat.com>
 
        * config/i386/i386.c (x86_use_leave, x86_push_memory,
index 24655fe..a3a0f66 100644 (file)
@@ -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);
index cf3b3ff..9cc2144 100644 (file)
@@ -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 %<large%> 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);
index 8e3032c..4c322bc 100644 (file)
@@ -1851,7 +1851,8 @@ do {                                                                      \
 \f
 /* 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;
index 409ce0c..f66318b 100644 (file)
@@ -58,6 +58,7 @@
    (UNSPEC_DTPOFF              6)
    (UNSPEC_GOTNTPOFF           7)
    (UNSPEC_INDNTPOFF           8)
+   (UNSPEC_PLTOFF              9)
 
    ; Prologue support
    (UNSPEC_STACK_ALLOC         11)
    (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)
 (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";
 }
   [(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 "" ""))]
   [(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)]
   ""
   [(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";
 }
   [(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" ""))
index ea2eb69..6ac3622 100644 (file)
 
 ;; 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.
index 84dd396..7e15dbf 100644 (file)
@@ -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
index 7a7a0e5..e6802b1 100644 (file)
@@ -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
     {