This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[x86-64] Large code models (static and PIC)
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-patches at gcc dot gnu dot org, jakub at redhat dot com, ubizjak at gmail dot com
- Date: Mon, 22 Jan 2007 20:54:52 +0100
- Subject: [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