This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[x86-64] Large code models (static and PIC)


Hi,
this patch implements large PIC and non-PIC models for x86-64.  These
models allow code segment (including single function) to exceed 2GB.
While originally they were added to ABI for completeness to settle down
relocations needed for possible future growth and GCC can't produce
function body exceeding 2GB, there is some interest in it in order to
produce code compatible with compiler that do. This is also important as
reference implementation of the ABI.

Jakub/Uros, can I ask you for peer-review?  The patch is about 2 years
old now and it is easy to get details wrong that would nullify it's
value as reference implementation.

Jakub, I would be also curious what would be your preferred
implementation of TLS in PIC.  At the moment I get ICE from binutils on
tls_global_dynamic_64, I've had it sort of working but it apparently
broke in meantime, so I've dropped it from this patch and will handle
TLS incrementally.

The basic idea of non-PIC large model is to make references to variables
use movabs or indirect addresses, function calls to be indirect.  I made
no attempt to add support for function body itself to exceed 2GB (ie
make local jumps to use indirect addresses) as this would be pretty
intrusive to the backend and is not needed for compatibility with other
compilers. (and GCC explode on about any attempt to make 2GB function
body except for inserting insanely large asm statements of NOPs).  We
still can have many functions to sum up into text segment exceeding 2GB.
(but arguable code like that can be split into multiple DSOs and result
would be faster and smaller binarry).

The testcase:

static int a;
int b;
__attribute__ ((noinline))
static t()
{
  p(a);
}
main()
{
  a=1;
  b=1;
  t();
}

Is compiled as:
t:
.LFB2:
	movabsq	$a, %rax  <- 64bit safe ways of loading adresses
	movabsq	$p, %r11
	movl	(%rax), %edi   <- We don't use movabsq since destination must be edi.
	xorl	%eax, %eax
	jmp	*%r11     <- Only way to make 64bit safe call.
.LFE2:
	.size	t, .-t
	.p2align 4,,15
.globl main
	.type	main, @function
main:
.LFB3:
	movl	$1, %eax
	movabsq	$t, %r11
	movabsl	%eax, a
	movabsl	%eax, b
	xorl	%eax, %eax
	jmp	*%r11
..
.LSFDE1:
	.long	.LEFDE1-.LASFDE1  <- 64bit safe EH.
.LASFDE1:
	.long	.LASFDE1-.Lframe1
	.quad	.LFB2
	.quad	.LFE2-.LFB2
	.align 8

For large PIC several new relocations are needed - 64bit GOT to address
GOT table entries,  GOTOFF to compute GOT pointer relative addresses,
PLTOFF to access PLT and GOTPCREL to compute PC relative way address of
GOT.  The binutils support was merged some time ago already.  The basic
idea is to immitate i386 way of doing PIC, just by using 64bit
immediates everywhere loaded via movabs and taking advantage for RIP
relative addressing for GOT computation.

.L3:
	leaq	.L3(%rip), %rcx
	movabsq	$_GLOBAL_OFFSET_TABLE_-.L3, %r11 <- GOT computation prologue
	movabsq	$a@GOTOFF, %rax			 <- GOT relative addressing of static variable
	addq	%r11, %rcx
	movabsq	$p@PLTOFF, %r11			 <- 64bit PLT
	movl	(%rcx,%rax), %edi
	addq	%rcx, %r11
	xorl	%eax, %eax
	jmp	*%r11
.LFE2:
	.size	t, .-t
	.p2align 4,,15
.globl main
	.type	main, @function
main:
.LFB3:
.L6:
	leaq	.L6(%rip), %rcx
	movabsq	$_GLOBAL_OFFSET_TABLE_-.L6, %r11
	movabsq	$a@GOTOFF, %rax
	addq	%r11, %rcx
	movabsq	$t@GOTOFF, %r11
	movl	$1, (%rcx,%rax)			  <- 64bit GOT table lookup
	movabsq	$b@GOT, %rax
	addq	%rcx, %r11
	movq	(%rcx,%rax), %rax
	movl	$1, (%rax)
	xorl	%eax, %eax
	jmp	*%r11

The patch was bootstrapped/regtested with large model enabled by
default.  I am running i386/non-large model bootstrap/regtest now just
to verify that I didn't break something else.
Honza

	* 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.
Index: reg-stack.c
===================================================================
--- reg-stack.c	(revision 121034)
+++ reg-stack.c	(working copy)
@@ -3120,7 +3120,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)
+  if ((flag_pic && !TARGET_64BIT)
+      || ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
     not_a_num = CONST0_RTX (SFmode);
   else
     {
Index: config/i386/i386.h
===================================================================
--- config/i386/i386.h	(revision 121034)
+++ config/i386/i386.h	(working copy)
@@ -1777,7 +1777,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
@@ -2138,7 +2139,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: config/i386/i386.md
===================================================================
--- config/i386/i386.md	(revision 121034)
+++ config/i386/i386.md	(working copy)
@@ -61,6 +61,7 @@
    (UNSPEC_DTPOFF		6)
    (UNSPEC_GOTNTPOFF		7)
    (UNSPEC_INDNTPOFF		8)
+   (UNSPEC_PLTOFF		9)
 
    ; Prologue support
    (UNSPEC_STACK_ALLOC		11)
@@ -68,86 +69,88 @@
    (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_PFRCPIT1		40)
-   (UNSPEC_PFRCPIT2		41)
-   (UNSPEC_PFRSQRT		42)
-   (UNSPEC_PFRSQIT1		43)
-   (UNSPEC_MFENCE		44)
-   (UNSPEC_LFENCE		45)
-   (UNSPEC_PSADBW		46)
-   (UNSPEC_LDDQU		47)
+   (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		50)
+   (UNSPEC_PFRCPIT2		51)
+   (UNSPEC_PFRSQRT		52)
+   (UNSPEC_PFRSQIT1		53)
+   (UNSPEC_MFENCE		54)
+   (UNSPEC_LFENCE		55)
+   (UNSPEC_PSADBW		56)
+   (UNSPEC_LDDQU		57)
 
    ; Generic math support
-   (UNSPEC_COPYSIGN		50)
-   (UNSPEC_IEEE_MIN		51)	; not commutative
-   (UNSPEC_IEEE_MAX		52)	; not commutative
+   (UNSPEC_COPYSIGN		60)
+   (UNSPEC_IEEE_MIN		61)	; not commutative
+   (UNSPEC_IEEE_MAX		62)	; not commutative
 
    ; x87 Floating point
-   (UNSPEC_SIN			60)
-   (UNSPEC_COS			61)
-   (UNSPEC_FPATAN		62)
-   (UNSPEC_FYL2X		63)
-   (UNSPEC_FYL2XP1		64)
-   (UNSPEC_FRNDINT		65)
-   (UNSPEC_FIST			66)
-   (UNSPEC_F2XM1		67)
-   (UNSPEC_TAN			68)
+   (UNSPEC_SIN			70)
+   (UNSPEC_COS			71)
+   (UNSPEC_FPATAN		72)
+   (UNSPEC_FYL2X		73)
+   (UNSPEC_FYL2XP1		74)
+   (UNSPEC_FRNDINT		75)
+   (UNSPEC_FIST			76)
+   (UNSPEC_F2XM1		77)
+   (UNSPEC_TAN			78)
 
    ; x87 Rounding
-   (UNSPEC_FRNDINT_FLOOR	70)
-   (UNSPEC_FRNDINT_CEIL 	71)
-   (UNSPEC_FRNDINT_TRUNC	72)
-   (UNSPEC_FRNDINT_MASK_PM	73)
-   (UNSPEC_FIST_FLOOR		74)
-   (UNSPEC_FIST_CEIL 		75)
+   (UNSPEC_FRNDINT_FLOOR	80)
+   (UNSPEC_FRNDINT_CEIL 	81)
+   (UNSPEC_FRNDINT_TRUNC	82)
+   (UNSPEC_FRNDINT_MASK_PM	83)
+   (UNSPEC_FIST_FLOOR		84)
+   (UNSPEC_FIST_CEIL 		85)
 
    ; x87 Double output FP
-   (UNSPEC_SINCOS_COS		80)
-   (UNSPEC_SINCOS_SIN		81)
-   (UNSPEC_XTRACT_FRACT		84)
-   (UNSPEC_XTRACT_EXP		85)
-   (UNSPEC_FSCALE_FRACT		86)
-   (UNSPEC_FSCALE_EXP		87)
-   (UNSPEC_FPREM_F		88)
-   (UNSPEC_FPREM_U		89)
-   (UNSPEC_FPREM1_F		90)
-   (UNSPEC_FPREM1_U		91)
+   (UNSPEC_SINCOS_COS		90)
+   (UNSPEC_SINCOS_SIN		91)
+   (UNSPEC_XTRACT_FRACT		94)
+   (UNSPEC_XTRACT_EXP		95)
+   (UNSPEC_FSCALE_FRACT		96)
+   (UNSPEC_FSCALE_EXP		97)
+   (UNSPEC_FPREM_F		98)
+   (UNSPEC_FPREM_U		99)
+   (UNSPEC_FPREM1_F		100)
+   (UNSPEC_FPREM1_U		101)
 
    ; SSP patterns
-   (UNSPEC_SP_SET		100)
-   (UNSPEC_SP_TEST		101)
-   (UNSPEC_SP_TLS_SET		102)
-   (UNSPEC_SP_TLS_TEST		103)
+   (UNSPEC_SP_SET		110)
+   (UNSPEC_SP_TEST		111)
+   (UNSPEC_SP_TLS_SET		112)
+   (UNSPEC_SP_TLS_TEST		113)
 
    ; SSSE3
    (UNSPEC_PSHUFB		120)
@@ -14187,7 +14190,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";
@@ -14195,6 +14199,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 "" ""))]
@@ -14411,6 +14422,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)]
   ""
@@ -20173,7 +20200,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";
@@ -20181,6 +20209,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" ""))
Index: config/i386/predicates.md
===================================================================
--- config/i386/predicates.md	(revision 121034)
+++ config/i386/predicates.md	(working copy)
@@ -481,8 +481,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.
Index: config/i386/i386-protos.h
===================================================================
--- config/i386/i386-protos.h	(revision 121034)
+++ config/i386/i386-protos.h	(working copy)
@@ -243,5 +243,6 @@ extern void x86_elf_aligned_common (FILE
 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: config/i386/i386.c
===================================================================
--- config/i386/i386.c	(revision 121034)
+++ config/i386/i386.c	(working copy)
@@ -1850,14 +1850,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);
     }
@@ -1880,8 +1880,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);
@@ -5696,7 +5694,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));
 
@@ -6251,7 +6267,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:
@@ -6349,7 +6367,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);
@@ -6407,7 +6427,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;
 
@@ -6425,7 +6446,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
@@ -6842,7 +6864,7 @@ legitimize_pic_address (rtx orig, rtx re
     }
   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);
@@ -6866,6 +6888,8 @@ legitimize_pic_address (rtx orig, rtx re
 	    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 ());
@@ -7428,6 +7452,9 @@ output_pic_addr_const (FILE *file, rtx x
 	case UNSPEC_GOTOFF:
 	  fputs ("@GOTOFF", file);
 	  break;
+	case UNSPEC_PLTOFF:
+	  fputs ("@PLTOFF", file);
+	  break;
 	case UNSPEC_GOTPCREL:
 	  fputs ("@GOTPCREL(%rip)", file);
 	  break;
@@ -9042,9 +9069,17 @@ ix86_output_addr_vec_elt (FILE *file, in
 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
@@ -9164,8 +9199,8 @@ ix86_expand_move (enum machine_mode mode
 	{
 	  if (GET_CODE (op0) == MEM)
 	    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
@@ -14326,6 +14361,22 @@ ix86_expand_strlensi_unroll_1 (rtx out, 
   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,
@@ -14347,7 +14398,7 @@ ix86_expand_call (rtx retval, rtx fnaddr
   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);
@@ -14360,7 +14411,12 @@ ix86_expand_call (rtx retval, rtx fnaddr
       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: doc/invoke.texi
===================================================================
*** doc/invoke.texi	(revision 121034)
--- doc/invoke.texi	(working copy)
*************** building of shared libraries are not sup
*** 9872,9879 ****
  @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.
  @end table
  
  @node IA-64 Options
--- 9872,9878 ----
  @item -mcmodel=large
  @opindex mcmodel=large
  Generate code for the large model: This model makes no assumptions
! about addresses and sizes of sections.  
  @end table
  
  @node IA-64 Options


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]