s390.c (legitimize_pic_address): Access local symbols relative to the GOT instead of relative to the literal...

* config/s390/s390.c (legitimize_pic_address): Access local symbols
	relative to the GOT instead of relative to the literal pool base.
	(s390_output_symbolic_const): Handle new GOT-relative accesses.
	* config/s390/s390.md ("call"): Access local functions and PLT stubs
	relative to the GOT instead of relative to the literal pool base.
	("call_value"): Likewise.
	("call_value_tls"): Likewise.

	* config/s390/s390.c (s390_chunkify_start): Remove pool anchor
	reloading.  Support LTREL_BASE / LTREL_OFFSET construct.
	(s390_chunkify_finish): Likewise.
	(s390_chunkify_cancel): Likewise.
	(s390_reorg): Adapt caller.
	(find_base_register_in_addr,
	find_base_register_ref, replace_base_register_ref): Delete.
	(find_ltrel_base, replace_ltrel_base): New functions.
	(find_constant_pool_ref): Handle LTREL_BASE unspecs.
	(s390_decompose_address): Handle LTREL_BASE unspecs.  Optimize
	base vs. index register usage.
	(struct constant_pool): Remove 'anchor'.
	(s390_add_anchor): Delete.
	(s390_dump_pool): Remove anchor handling.
	* config/s390/s390.md ("reload_anchor"): Remove.

	* config/s390/s390.c (s390_split_branches): Use LTREL_BASE/OFFSET.
	(s390_load_got): New function.  Use LTREL_BASE/OFFSET.
	(s390_emit_prologue): Use it.
	* config/s390/s390.md ("builtin_longjmp", "builtin_setjmp_setup",
	"builtin_setjmp_receiver"): Cleanup.  Use s390_load_got.  Do not
	hard-code register 14.
	* config/s390/s390-protos.h (s390_load_got): Declare.

	* config/s390/s390.c (NR_C_MODES, constant_modes, gen_consttable):
	Support TImode constants.
	* config/s390/s390.md ("consttable_ti"): New.
	("consttable_si", "consttable_di"): Handle TLS symbols correctly.

	* config/s390/s390.md (UNSPEC_LTREL_OFFSET, UNSPEC_LTREL_BASE,
	UNSPEC_GOTENT, UNSPEC_GOT, UNSPEC_GOTOFF, UNSPEC_PLT, UNSPEC_PLTOFF,
	UNSPEC_RELOAD_BASE, UNSPECV_POOL, UNSPECV_POOL_START, UNSPECV_POOL_END,
	UNSPECV_POOL_QI, UNSPECV_POOL_HI, UNSPECV_POOL_SI, UNSPECV_POOL_DI,
	UNSPECV_POOL_TI, UNSPECV_POOL_SF, UNSPECV_POOL_DF, UNSPECV_MAIN_POOL):
	New symbolic constants.
	("consttable_qi", "consttable_hi", "consttable_si", "consttable_di",
	"consttable_sf", "consttable_df", "pool_start_31", "pool_end_31",
	"pool_start_64", "pool_end_64", "reload_base_31", "reload_base_64",
	"pool", "literal_pool_31", "literal_pool_64"): Cleanup.  Use
	symbolic UNSPEC values.
	* config/s390/s390.c (larl_operand, s390_short_displacement,
	bras_sym_operand, s390_cannot_force_const_mem,
	s390_delegitimize_address, s390_decompose_address,
	legitimize_pic_address, s390_output_symbolic_const,
	s390_function_profiler): Use symbolic UNSPEC values.

From-SVN: r69592
This commit is contained in:
Ulrich Weigand 2003-07-19 16:06:52 +00:00 committed by Ulrich Weigand
parent 35a6c8736a
commit fd7643fbe4
4 changed files with 385 additions and 420 deletions

View File

@ -1,3 +1,59 @@
2003-07-19 Ulrich Weigand <uweigand@de.ibm.com>
* config/s390/s390.c (legitimize_pic_address): Access local symbols
relative to the GOT instead of relative to the literal pool base.
(s390_output_symbolic_const): Handle new GOT-relative accesses.
* config/s390/s390.md ("call"): Access local functions and PLT stubs
relative to the GOT instead of relative to the literal pool base.
("call_value"): Likewise.
("call_value_tls"): Likewise.
* config/s390/s390.c (s390_chunkify_start): Remove pool anchor
reloading. Support LTREL_BASE / LTREL_OFFSET construct.
(s390_chunkify_finish): Likewise.
(s390_chunkify_cancel): Likewise.
(s390_reorg): Adapt caller.
(find_base_register_in_addr,
find_base_register_ref, replace_base_register_ref): Delete.
(find_ltrel_base, replace_ltrel_base): New functions.
(find_constant_pool_ref): Handle LTREL_BASE unspecs.
(s390_decompose_address): Handle LTREL_BASE unspecs. Optimize
base vs. index register usage.
(struct constant_pool): Remove 'anchor'.
(s390_add_anchor): Delete.
(s390_dump_pool): Remove anchor handling.
* config/s390/s390.md ("reload_anchor"): Remove.
* config/s390/s390.c (s390_split_branches): Use LTREL_BASE/OFFSET.
(s390_load_got): New function. Use LTREL_BASE/OFFSET.
(s390_emit_prologue): Use it.
* config/s390/s390.md ("builtin_longjmp", "builtin_setjmp_setup",
"builtin_setjmp_receiver"): Cleanup. Use s390_load_got. Do not
hard-code register 14.
* config/s390/s390-protos.h (s390_load_got): Declare.
* config/s390/s390.c (NR_C_MODES, constant_modes, gen_consttable):
Support TImode constants.
* config/s390/s390.md ("consttable_ti"): New.
("consttable_si", "consttable_di"): Handle TLS symbols correctly.
* config/s390/s390.md (UNSPEC_LTREL_OFFSET, UNSPEC_LTREL_BASE,
UNSPEC_GOTENT, UNSPEC_GOT, UNSPEC_GOTOFF, UNSPEC_PLT, UNSPEC_PLTOFF,
UNSPEC_RELOAD_BASE, UNSPECV_POOL, UNSPECV_POOL_START, UNSPECV_POOL_END,
UNSPECV_POOL_QI, UNSPECV_POOL_HI, UNSPECV_POOL_SI, UNSPECV_POOL_DI,
UNSPECV_POOL_TI, UNSPECV_POOL_SF, UNSPECV_POOL_DF, UNSPECV_MAIN_POOL):
New symbolic constants.
("consttable_qi", "consttable_hi", "consttable_si", "consttable_di",
"consttable_sf", "consttable_df", "pool_start_31", "pool_end_31",
"pool_start_64", "pool_end_64", "reload_base_31", "reload_base_64",
"pool", "literal_pool_31", "literal_pool_64"): Cleanup. Use
symbolic UNSPEC values.
* config/s390/s390.c (larl_operand, s390_short_displacement,
bras_sym_operand, s390_cannot_force_const_mem,
s390_delegitimize_address, s390_decompose_address,
legitimize_pic_address, s390_output_symbolic_const,
s390_function_profiler): Use symbolic UNSPEC values.
2003-07-19 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* alias.c alloc-pool.c bitmap.c bitmap.h bt-load.c builtins.c

View File

@ -24,6 +24,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
extern void optimization_options PARAMS ((int, int));
extern void override_options PARAMS ((void));
extern int s390_arg_frame_offset PARAMS ((void));
extern void s390_load_got PARAMS ((int));
extern void s390_emit_prologue PARAMS ((void));
extern void s390_emit_epilogue PARAMS ((void));
extern void s390_function_profiler PARAMS ((FILE *, int));

View File

@ -215,9 +215,8 @@ static int addr_generation_dependency_p PARAMS ((rtx, rtx));
static int s390_split_branches PARAMS ((rtx, bool *));
static void find_constant_pool_ref PARAMS ((rtx, rtx *));
static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx));
static int find_base_register_in_addr PARAMS ((struct s390_address *));
static bool find_base_register_ref PARAMS ((rtx));
static void replace_base_register_ref PARAMS ((rtx *, rtx));
static rtx find_ltrel_base PARAMS ((rtx));
static void replace_ltrel_base PARAMS ((rtx *, rtx));
static void s390_optimize_prolog PARAMS ((int));
static bool s390_fixup_clobbered_return_reg PARAMS ((rtx));
static int find_unused_clobbered_reg PARAMS ((void));
@ -1134,10 +1133,10 @@ larl_operand (op, mode)
/* Now we must have a @GOTENT offset or @PLT stub
or an @INDNTPOFF TLS offset. */
if (GET_CODE (op) == UNSPEC
&& XINT (op, 1) == 111)
&& XINT (op, 1) == UNSPEC_GOTENT)
return 1;
if (GET_CODE (op) == UNSPEC
&& XINT (op, 1) == 113)
&& XINT (op, 1) == UNSPEC_PLT)
return 1;
if (GET_CODE (op) == UNSPEC
&& XINT (op, 1) == UNSPEC_INDNTPOFF)
@ -1249,7 +1248,7 @@ s390_short_displacement (disp)
/* GOT offset is not OK, the GOT can be large. */
if (GET_CODE (disp) == CONST
&& GET_CODE (XEXP (disp, 0)) == UNSPEC
&& XINT (XEXP (disp, 0), 1) == 110)
&& XINT (XEXP (disp, 0), 1) == UNSPEC_GOT)
return 0;
/* All other symbolic constants are literal pool references,
@ -1455,7 +1454,7 @@ bras_sym_operand (op, mode)
/* Allow @PLT stubs. */
if (code == CONST
&& GET_CODE (XEXP (op, 0)) == UNSPEC
&& XINT (XEXP (op, 0), 1) == 113)
&& XINT (XEXP (op, 0), 1) == UNSPEC_PLT)
return 1;
return 0;
}
@ -1749,10 +1748,10 @@ s390_cannot_force_const_mem (x)
switch (XINT (x, 1))
{
/* Only lt-relative or GOT-relative UNSPECs are OK. */
case 100:
case 104:
case 112:
case 114:
case UNSPEC_LTREL_OFFSET:
case UNSPEC_GOT:
case UNSPEC_GOTOFF:
case UNSPEC_PLTOFF:
case UNSPEC_TLSGD:
case UNSPEC_TLSLDM:
case UNSPEC_NTPOFF:
@ -1996,6 +1995,8 @@ s390_decompose_address (addr, out)
rtx indx = NULL_RTX;
rtx disp = NULL_RTX;
int pointer = FALSE;
int base_ptr = FALSE;
int indx_ptr = FALSE;
/* Decompose address into base + index + displacement. */
@ -2041,35 +2042,18 @@ s390_decompose_address (addr, out)
disp = addr; /* displacement */
/* Prefer to use pointer as base, not index. */
if (base && indx)
{
int base_ptr = GET_CODE (base) == UNSPEC
|| (REG_P (base) && REG_POINTER (base));
int indx_ptr = GET_CODE (indx) == UNSPEC
|| (REG_P (indx) && REG_POINTER (indx));
if (!base_ptr && indx_ptr)
{
rtx tmp = base;
base = indx;
indx = tmp;
}
}
/* Validate base register. */
if (base)
{
if (GET_CODE (base) == UNSPEC)
{
if (XVECLEN (base, 0) != 1 || XINT (base, 1) != 101)
return FALSE;
base = XVECEXP (base, 0, 0);
pointer = TRUE;
if (XVECLEN (base, 0) != 1 || XINT (base, 1) != UNSPEC_LTREL_BASE)
return FALSE;
base = gen_rtx_REG (Pmode, BASE_REGISTER);
}
if (GET_CODE (base) != REG || GET_MODE (base) != Pmode)
return FALSE;
return FALSE;
if (REGNO (base) == BASE_REGISTER
|| REGNO (base) == STACK_POINTER_REGNUM
@ -2082,7 +2066,7 @@ s390_decompose_address (addr, out)
&& REGNO (base) <= LAST_VIRTUAL_REGISTER)
|| (flag_pic
&& REGNO (base) == PIC_OFFSET_TABLE_REGNUM))
pointer = TRUE;
pointer = base_ptr = TRUE;
}
/* Validate index register. */
@ -2090,14 +2074,13 @@ s390_decompose_address (addr, out)
{
if (GET_CODE (indx) == UNSPEC)
{
if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != 101)
return FALSE;
indx = XVECEXP (indx, 0, 0);
pointer = TRUE;
if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != UNSPEC_LTREL_BASE)
return FALSE;
indx = gen_rtx_REG (Pmode, BASE_REGISTER);
}
if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode)
return FALSE;
return FALSE;
if (REGNO (indx) == BASE_REGISTER
|| REGNO (indx) == STACK_POINTER_REGNUM
@ -2110,7 +2093,16 @@ s390_decompose_address (addr, out)
&& REGNO (indx) <= LAST_VIRTUAL_REGISTER)
|| (flag_pic
&& REGNO (indx) == PIC_OFFSET_TABLE_REGNUM))
pointer = TRUE;
pointer = indx_ptr = TRUE;
}
/* Prefer to use pointer as base, not index. */
if (base && indx && !base_ptr
&& (indx_ptr || (!REG_POINTER (base) && REG_POINTER (indx))))
{
rtx tmp = base;
base = indx;
indx = tmp;
}
/* Validate displacement. */
@ -2134,11 +2126,11 @@ s390_decompose_address (addr, out)
}
}
/* In the small-PIC case, the linker converts @GOT12
/* In the small-PIC case, the linker converts @GOT
and @GOTNTPOFF offsets to possible displacements. */
else if (GET_CODE (disp) == CONST
&& GET_CODE (XEXP (disp, 0)) == UNSPEC
&& (XINT (XEXP (disp, 0), 1) == 110
&& (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT
|| XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF))
{
if (flag_pic != 1)
@ -2205,7 +2197,8 @@ s390_decompose_address (addr, out)
else
base = gen_rtx_REG (Pmode, BASE_REGISTER);
disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp), 100);
disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
UNSPEC_LTREL_OFFSET);
disp = gen_rtx_CONST (Pmode, disp);
if (offset)
@ -2356,19 +2349,19 @@ legitimize_pic_address (orig, reg)
}
else
{
/* Access local symbols relative to the literal pool. */
/* Access local symbols relative to the GOT. */
rtx temp = reg? reg : gen_reg_rtx (Pmode);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 100);
if (reload_in_progress || reload_completed)
regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
base = gen_rtx_REG (Pmode, BASE_REGISTER);
base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101);
new = gen_rtx_PLUS (Pmode, base, temp);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
emit_move_insn (reg, new);
@ -2384,12 +2377,12 @@ legitimize_pic_address (orig, reg)
if (flag_pic == 1)
{
/* Assume GOT offset < 4k. This is handled the same way
in both 31- and 64-bit code (@GOT12). */
in both 31- and 64-bit code (@GOT). */
if (reload_in_progress || reload_completed)
regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 110);
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
new = gen_rtx_CONST (Pmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
new = gen_rtx_MEM (Pmode, new);
@ -2404,7 +2397,7 @@ legitimize_pic_address (orig, reg)
rtx temp = gen_reg_rtx (Pmode);
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 111);
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT);
new = gen_rtx_CONST (Pmode, new);
emit_move_insn (temp, new);
@ -2423,7 +2416,7 @@ legitimize_pic_address (orig, reg)
if (reload_in_progress || reload_completed)
regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 112);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
@ -2446,35 +2439,41 @@ legitimize_pic_address (orig, reg)
abort ();
switch (XINT (addr, 1))
{
/* If someone moved an @GOT or lt-relative UNSPEC
/* If someone moved a GOT-relative UNSPEC
out of the literal pool, force them back in. */
case 100:
case 112:
case 114:
case UNSPEC_GOTOFF:
case UNSPEC_PLTOFF:
new = force_const_mem (Pmode, orig);
break;
/* @GOT is OK as is if small. */
case UNSPEC_GOT:
if (flag_pic == 2)
new = force_const_mem (Pmode, orig);
break;
/* @GOTENT is OK as is. */
case 111:
case UNSPEC_GOTENT:
break;
/* @PLT is OK as is on 64-bit, must be converted to
lt-relative PLT on 31-bit. */
case 113:
GOT-relative @PLTOFF on 31-bit. */
case UNSPEC_PLT:
if (!TARGET_64BIT)
{
rtx temp = reg? reg : gen_reg_rtx (Pmode);
if (reload_in_progress || reload_completed)
regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
addr = XVECEXP (addr, 0, 0);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 114);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
UNSPEC_PLTOFF);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
base = gen_rtx_REG (Pmode, BASE_REGISTER);
base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101);
new = gen_rtx_PLUS (Pmode, base, temp);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
emit_move_insn (reg, new);
@ -2533,20 +2532,21 @@ legitimize_pic_address (orig, reg)
}
else
{
/* Access local symbols relative to the literal pool. */
/* Access local symbols relative to the GOT. */
rtx temp = reg? reg : gen_reg_rtx (Pmode);
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 100);
if (reload_in_progress || reload_completed)
regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
UNSPEC_GOTOFF);
addr = gen_rtx_PLUS (Pmode, addr, op1);
addr = gen_rtx_CONST (Pmode, addr);
addr = force_const_mem (Pmode, addr);
emit_move_insn (temp, addr);
base = gen_rtx_REG (Pmode, BASE_REGISTER);
base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101);
new = gen_rtx_PLUS (Pmode, base, temp);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
emit_move_insn (reg, new);
@ -2555,7 +2555,7 @@ legitimize_pic_address (orig, reg)
}
}
/* Now, check whether it is an LT-relative symbol plus offset
/* Now, check whether it is a GOT relative symbol plus offset
that was pulled out of the literal pool. Force it back in. */
else if (GET_CODE (op0) == UNSPEC
@ -2563,7 +2563,7 @@ legitimize_pic_address (orig, reg)
{
if (XVECLEN (op0, 0) != 1)
abort ();
if (XINT (op0, 1) != 100)
if (XINT (op0, 1) != UNSPEC_GOTOFF)
abort ();
new = force_const_mem (Pmode, orig);
@ -3279,7 +3279,7 @@ s390_delegitimize_address (orig_x)
{
y = XEXP (XEXP (x, 1), 0);
if (GET_CODE (y) == UNSPEC
&& XINT (y, 1) == 110)
&& XINT (y, 1) == UNSPEC_GOT)
return XVECEXP (y, 0, 0);
return orig_x;
}
@ -3288,7 +3288,7 @@ s390_delegitimize_address (orig_x)
{
y = XEXP (x, 0);
if (GET_CODE (y) == UNSPEC
&& XINT (y, 1) == 111)
&& XINT (y, 1) == UNSPEC_GOTENT)
return XVECEXP (y, 0, 0);
return orig_x;
}
@ -3378,37 +3378,30 @@ s390_output_symbolic_const (file, x)
output_operand_lossage ("invalid UNSPEC as operand (1)");
switch (XINT (x, 1))
{
case 100:
case 104:
case UNSPEC_LTREL_OFFSET:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
fprintf (file, "-");
s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
break;
case 105:
s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
fprintf (file, "-");
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
break;
case 110:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
fprintf (file, "@GOT12");
break;
case 111:
case UNSPEC_GOTENT:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
fprintf (file, "@GOTENT");
break;
case 112:
case UNSPEC_GOT:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
fprintf (file, "@GOT");
break;
case 113:
case UNSPEC_GOTOFF:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
fprintf (file, "@GOTOFF");
break;
case UNSPEC_PLT:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
fprintf (file, "@PLT");
break;
case 114:
case UNSPEC_PLTOFF:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
fprintf (file, "@PLT-");
s390_output_symbolic_const (file, cfun->machine->literal_pool_label);
fprintf (file, "@PLTOFF");
break;
case UNSPEC_TLSGD:
s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
@ -3968,14 +3961,16 @@ s390_split_branches (temp_reg, temp_used)
else
{
new_literal = 1;
tmp = gen_rtx_UNSPEC (SImode, gen_rtvec (1, *label), 104);
tmp = gen_rtx_CONST (SImode, tmp);
tmp = force_const_mem (SImode, tmp);
tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn);
target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, *label),
UNSPEC_LTREL_OFFSET);
target = gen_rtx_CONST (Pmode, target);
target = force_const_mem (Pmode, target);
tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn);
INSN_ADDRESSES_NEW (tmp, -1);
target = gen_rtx_REG (Pmode, BASE_REGISTER);
target = gen_rtx_PLUS (Pmode, target, temp_reg);
target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (target, 0)),
UNSPEC_LTREL_BASE);
target = gen_rtx_PLUS (Pmode, temp_reg, target);
}
if (!validate_change (insn, label, target, 0))
@ -4002,6 +3997,11 @@ find_constant_pool_ref (x, ref)
int i, j;
const char *fmt;
/* Ignore LTREL_BASE references. */
if (GET_CODE (x) == UNSPEC
&& XINT (x, 1) == UNSPEC_LTREL_BASE)
return;
if (GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x))
{
@ -4100,135 +4100,58 @@ replace_constant_pool_ref (x, ref, addr)
}
}
/* Check whether ADDR is an address that uses the base register,
without actually constituting a literal pool access. (This happens
in 31-bit PIC mode, where the base register is used as anchor for
relative addressing of local symbols.)
/* Check whether X contains an UNSPEC_LTREL_BASE.
Return its constant pool symbol if found, NULL_RTX otherwise. */
Returns 1 if the base register occupies the base slot,
returns 2 if the base register occupies the index slot,
returns 0 if the address is not of this form. */
static int
find_base_register_in_addr (addr)
struct s390_address *addr;
{
/* If DISP is complex, we might have a literal pool reference. */
if (addr->disp && GET_CODE (addr->disp) != CONST_INT)
return 0;
if (addr->base && REG_P (addr->base) && REGNO (addr->base) == BASE_REGISTER)
return 1;
if (addr->indx && REG_P (addr->indx) && REGNO (addr->indx) == BASE_REGISTER)
return 2;
return 0;
}
/* Return true if X contains an address that uses the base register,
without actually constituting a literal pool access. */
static bool
find_base_register_ref (x)
static rtx
find_ltrel_base (x)
rtx x;
{
bool retv = FALSE;
struct s390_address addr;
int i, j;
const char *fmt;
/* Addresses can only occur inside a MEM ... */
if (GET_CODE (x) == MEM)
{
if (s390_decompose_address (XEXP (x, 0), &addr)
&& find_base_register_in_addr (&addr))
return TRUE;
}
/* ... or a load-address type pattern. */
if (GET_CODE (x) == SET && GET_CODE (SET_DEST (x)) == REG)
{
if (s390_decompose_address (SET_SRC (x), &addr)
&& find_base_register_in_addr (&addr))
return TRUE;
}
if (GET_CODE (x) == UNSPEC
&& XINT (x, 1) == UNSPEC_LTREL_BASE)
return XVECEXP (x, 0, 0);
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
retv |= find_base_register_ref (XEXP (x, i));
rtx fnd = find_ltrel_base (XEXP (x, i));
if (fnd)
return fnd;
}
else if (fmt[i] == 'E')
{
for (j = 0; j < XVECLEN (x, i); j++)
retv |= find_base_register_ref (XVECEXP (x, i, j));
{
rtx fnd = find_ltrel_base (XVECEXP (x, i, j));
if (fnd)
return fnd;
}
}
}
return retv;
return NULL_RTX;
}
/* If X contains an address that uses the base register,
without actually constituting a literal pool access,
replace the base register with REPL in all such cases.
Handles both MEMs and load address patterns. */
/* Replace any occurrence of UNSPEC_LTREL_BASE in X with BASE. */
static void
replace_base_register_ref (x, repl)
replace_ltrel_base (x, base)
rtx *x;
rtx repl;
rtx base;
{
struct s390_address addr;
rtx new_addr;
int i, j, pos;
int i, j;
const char *fmt;
/* Addresses can only occur inside a MEM ... */
if (GET_CODE (*x) == MEM)
if (GET_CODE (*x) == UNSPEC
&& XINT (*x, 1) == UNSPEC_LTREL_BASE)
{
if (s390_decompose_address (XEXP (*x, 0), &addr)
&& (pos = find_base_register_in_addr (&addr)))
{
if (pos == 1)
addr.base = repl;
else
addr.indx = repl;
new_addr = addr.base;
if (addr.indx)
new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.indx);
if (addr.disp)
new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.disp);
*x = replace_equiv_address (*x, new_addr);
return;
}
}
/* ... or a load-address type pattern. */
if (GET_CODE (*x) == SET && GET_CODE (SET_DEST (*x)) == REG)
{
if (s390_decompose_address (SET_SRC (*x), &addr)
&& (pos = find_base_register_in_addr (&addr)))
{
if (pos == 1)
addr.base = repl;
else
addr.indx = repl;
new_addr = addr.base;
if (addr.indx)
new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.indx);
if (addr.disp)
new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.disp);
SET_SRC (*x) = new_addr;
return;
}
*x = base;
return;
}
fmt = GET_RTX_FORMAT (GET_CODE (*x));
@ -4236,23 +4159,24 @@ replace_base_register_ref (x, repl)
{
if (fmt[i] == 'e')
{
replace_base_register_ref (&XEXP (*x, i), repl);
replace_ltrel_base (&XEXP (*x, i), base);
}
else if (fmt[i] == 'E')
{
for (j = 0; j < XVECLEN (*x, i); j++)
replace_base_register_ref (&XVECEXP (*x, i, j), repl);
replace_ltrel_base (&XVECEXP (*x, i, j), base);
}
}
}
/* We keep a list of constants we which we have to add to internal
/* We keep a list of constants which we have to add to internal
constant tables in the middle of large functions. */
#define NR_C_MODES 6
#define NR_C_MODES 7
enum machine_mode constant_modes[NR_C_MODES] =
{
TImode,
DFmode, DImode,
SFmode, SImode,
HImode,
@ -4261,6 +4185,7 @@ enum machine_mode constant_modes[NR_C_MODES] =
rtx (*gen_consttable[NR_C_MODES])(rtx) =
{
gen_consttable_ti,
gen_consttable_df, gen_consttable_di,
gen_consttable_sf, gen_consttable_si,
gen_consttable_hi,
@ -4284,11 +4209,10 @@ struct constant_pool
struct constant *constants[NR_C_MODES];
rtx label;
int size;
bool anchor;
};
static struct constant_pool * s390_chunkify_start PARAMS ((rtx, bool *));
static void s390_chunkify_finish PARAMS ((struct constant_pool *, rtx));
static struct constant_pool * s390_chunkify_start PARAMS ((void));
static void s390_chunkify_finish PARAMS ((struct constant_pool *));
static void s390_chunkify_cancel PARAMS ((struct constant_pool *));
static struct constant_pool *s390_start_pool PARAMS ((struct constant_pool **, rtx));
@ -4297,7 +4221,6 @@ static void s390_add_pool_insn PARAMS ((struct constant_pool *, rtx));
static struct constant_pool *s390_find_pool PARAMS ((struct constant_pool *, rtx));
static void s390_add_constant PARAMS ((struct constant_pool *, rtx, enum machine_mode));
static rtx s390_find_constant PARAMS ((struct constant_pool *, rtx, enum machine_mode));
static void s390_add_anchor PARAMS ((struct constant_pool *));
static rtx s390_dump_pool PARAMS ((struct constant_pool *));
static void s390_free_pool PARAMS ((struct constant_pool *));
@ -4322,7 +4245,6 @@ s390_start_pool (pool_list, insn)
pool->pool_insn = NULL_RTX;
pool->insns = BITMAP_XMALLOC ();
pool->size = 0;
pool->anchor = FALSE;
for (prev = pool_list; *prev; prev = &(*prev)->next)
;
@ -4439,19 +4361,6 @@ s390_find_constant (pool, val, mode)
return offset;
}
/* Set 'anchor' flag in POOL. */
static void
s390_add_anchor (pool)
struct constant_pool *pool;
{
if (!pool->anchor)
{
pool->anchor = TRUE;
pool->size += 4;
}
}
/* Dump out the constants in POOL. */
static rtx
@ -4473,26 +4382,16 @@ s390_dump_pool (pool)
insn = emit_label_after (pool->label, insn);
INSN_ADDRESSES_NEW (insn, -1);
/* Emit anchor if we need one. */
if (pool->anchor)
{
rtx anchor = gen_rtx_LABEL_REF (VOIDmode, pool->label);
anchor = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, anchor), 105);
anchor = gen_rtx_CONST (VOIDmode, anchor);
insn = emit_insn_after (gen_consttable_si (anchor), insn);
INSN_ADDRESSES_NEW (insn, -1);
}
/* Dump constants in descending alignment requirement order,
ensuring proper alignment for every constant. */
for (i = 0; i < NR_C_MODES; i++)
for (c = pool->constants[i]; c; c = c->next)
{
/* Convert 104 unspecs to pool-relative references. */
/* Convert UNSPEC_LTREL_OFFSET unspecs to pool-relative references. */
rtx value = c->value;
if (GET_CODE (value) == CONST
&& GET_CODE (XEXP (value, 0)) == UNSPEC
&& XINT (XEXP (value, 0), 1) == 104
&& XINT (XEXP (value, 0), 1) == UNSPEC_LTREL_OFFSET
&& XVECLEN (XEXP (value, 0), 0) == 1)
{
value = gen_rtx_MINUS (Pmode, XVECEXP (XEXP (value, 0), 0, 0),
@ -4547,25 +4446,20 @@ s390_free_pool (pool)
}
/* Chunkify the literal pool if required.
Code generated by this routine is allowed to use
TEMP_REG as temporary scratch register. If this is
done, TEMP_USED is set to true. */
/* Chunkify the literal pool if required. */
#define S390_POOL_CHUNK_MIN 0xc00
#define S390_POOL_CHUNK_MAX 0xe00
static struct constant_pool *
s390_chunkify_start (temp_reg, temp_used)
rtx temp_reg;
bool *temp_used;
s390_chunkify_start (void)
{
rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
struct constant_pool *curr_pool = NULL, *pool_list = NULL;
int extra_size = 0;
bitmap far_labels;
rtx pending_ltrel = NULL_RTX;
rtx insn;
rtx (*gen_reload_base) PARAMS ((rtx, rtx)) =
@ -4581,46 +4475,59 @@ s390_chunkify_start (temp_reg, temp_used)
shorten_branches (get_insns ());
/* Scan all insns and move literals to pool chunks.
Also, emit anchor reload insns before every insn that uses
the literal pool base register as anchor pointer. */
/* Scan all insns and move literals to pool chunks. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
/* Check for pending LTREL_BASE. */
if (INSN_P (insn))
{
rtx ltrel_base = find_ltrel_base (PATTERN (insn));
if (ltrel_base)
{
if (ltrel_base == pending_ltrel)
pending_ltrel = NULL_RTX;
else
abort ();
}
}
if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
{
rtx pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref);
if (pool_ref)
{
rtx constant = get_pool_constant (pool_ref);
enum machine_mode mode = get_pool_mode (pool_ref);
if (!curr_pool)
curr_pool = s390_start_pool (&pool_list, insn);
s390_add_constant (curr_pool, get_pool_constant (pool_ref),
get_pool_mode (pool_ref));
s390_add_constant (curr_pool, constant, mode);
s390_add_pool_insn (curr_pool, insn);
}
else if (!TARGET_64BIT && flag_pic
&& find_base_register_ref (PATTERN (insn)))
{
rtx new = gen_reload_anchor (temp_reg, base_reg);
new = emit_insn_before (new, insn);
INSN_ADDRESSES_NEW (new, INSN_ADDRESSES (INSN_UID (insn)));
extra_size += 8;
*temp_used = 1;
if (!curr_pool)
curr_pool = s390_start_pool (&pool_list, new);
s390_add_anchor (curr_pool);
s390_add_pool_insn (curr_pool, insn);
/* Don't split the pool chunk between a LTREL_OFFSET load
and the corresponding LTREL_BASE. */
if (GET_CODE (constant) == CONST
&& GET_CODE (XEXP (constant, 0)) == UNSPEC
&& XINT (XEXP (constant, 0), 1) == UNSPEC_LTREL_OFFSET)
{
if (pending_ltrel)
abort ();
pending_ltrel = pool_ref;
}
}
}
if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CODE_LABEL)
if (curr_pool)
s390_add_pool_insn (curr_pool, insn);
{
if (curr_pool)
s390_add_pool_insn (curr_pool, insn);
/* An LTREL_BASE must follow within the same basic block. */
if (pending_ltrel)
abort ();
}
if (!curr_pool
|| INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn)
@ -4672,10 +4579,9 @@ s390_chunkify_start (temp_reg, temp_used)
if (get_attr_length (insn) == 0)
continue;
/* Don't separate insns created by s390_split_branches. */
if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SET
&& rtx_equal_p (SET_DEST (PATTERN (insn)), temp_reg))
/* Don't separate LTREL_BASE from the corresponding
LTREL_OFFSET load. */
if (pending_ltrel)
continue;
label = gen_label_rtx ();
@ -4698,6 +4604,8 @@ s390_chunkify_start (temp_reg, temp_used)
if (curr_pool)
s390_end_pool (curr_pool, NULL_RTX);
if (pending_ltrel)
abort ();
/* Find all labels that are branched into
@ -4811,15 +4719,11 @@ s390_chunkify_start (temp_reg, temp_used)
/* POOL_LIST is a chunk list as prepared by s390_chunkify_start.
After we have decided to use this list, finish implementing
all changes to the current function as required.
Code generated by this routine is allowed to use
TEMP_REG as temporary scratch register. */
all changes to the current function as required. */
static void
s390_chunkify_finish (pool_list, temp_reg)
s390_chunkify_finish (pool_list)
struct constant_pool *pool_list;
rtx temp_reg;
{
rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
struct constant_pool *curr_pool = NULL;
@ -4830,6 +4734,9 @@ s390_chunkify_finish (pool_list, temp_reg)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
replace_ltrel_base (&PATTERN (insn), base_reg);
curr_pool = s390_find_pool (pool_list, insn);
if (!curr_pool)
continue;
@ -4846,12 +4753,6 @@ s390_chunkify_finish (pool_list, temp_reg)
replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr);
INSN_CODE (insn) = -1;
}
else if (!TARGET_64BIT && flag_pic
&& find_base_register_ref (PATTERN (insn)))
{
replace_base_register_ref (&PATTERN (insn), temp_reg);
}
}
}
@ -4906,7 +4807,7 @@ s390_chunkify_cancel (pool_list)
remove_insn (curr_pool->pool_insn);
}
/* Remove all base/anchor register reload insns. */
/* Remove all base register reload insns. */
for (insn = get_insns (); insn; )
{
@ -4915,8 +4816,7 @@ s390_chunkify_cancel (pool_list)
if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
&& (XINT (SET_SRC (PATTERN (insn)), 1) == 210
|| XINT (SET_SRC (PATTERN (insn)), 1) == 211))
&& XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_RELOAD_BASE)
remove_insn (insn);
insn = next_insn;
@ -5231,7 +5131,7 @@ s390_reorg ()
struct constant_pool *pool_list;
/* Try to chunkify the literal pool. */
pool_list = s390_chunkify_start (temp_reg, &temp_used);
pool_list = s390_chunkify_start ();
/* Split out-of-range branches. If this has created new
literal pool entries, cancel current chunk list and
@ -5262,7 +5162,7 @@ s390_reorg ()
/* If we made it up to here, both conditions are satisfied.
Finish up pool chunkification if required. */
if (pool_list)
s390_chunkify_finish (pool_list, temp_reg);
s390_chunkify_finish (pool_list);
break;
}
@ -5555,6 +5455,52 @@ restore_gprs (base, offset, first, last)
return insn;
}
/* Emit code to load the GOT register. If MAYBE_DEAD is true,
annotate generated insns with REG_MAYBE_DEAD notes. */
static GTY(()) rtx got_symbol;
void
s390_load_got (maybe_dead)
int maybe_dead;
{
if (!got_symbol)
{
got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL;
}
if (TARGET_64BIT)
{
rtx insn = emit_move_insn (pic_offset_table_rtx, got_symbol);
if (maybe_dead)
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
}
else
{
rtx offset, insn;
offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol),
UNSPEC_LTREL_OFFSET);
offset = gen_rtx_CONST (Pmode, offset);
offset = force_const_mem (Pmode, offset);
insn = emit_move_insn (pic_offset_table_rtx, offset);
if (maybe_dead)
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)),
UNSPEC_LTREL_BASE);
offset = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset);
insn = emit_move_insn (pic_offset_table_rtx, offset);
if (maybe_dead)
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
}
}
/* Expand the prologue into a bunch of separate insns. */
void
@ -5724,38 +5670,7 @@ s390_emit_prologue ()
/* Set up got pointer, if needed. */
if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
{
rtx got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL;
if (TARGET_64BIT)
{
insn = emit_insn (gen_movdi (pic_offset_table_rtx,
got_symbol));
/* It can happen that the GOT pointer isn't really needed ... */
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
}
else
{
got_symbol = gen_rtx_UNSPEC (VOIDmode,
gen_rtvec (1, got_symbol), 100);
got_symbol = gen_rtx_CONST (VOIDmode, got_symbol);
got_symbol = force_const_mem (Pmode, got_symbol);
insn = emit_move_insn (pic_offset_table_rtx,
got_symbol);
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
got_symbol = gen_rtx_REG (Pmode, BASE_REGISTER);
got_symbol = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol), 101);
got_symbol = gen_rtx_PLUS (Pmode, got_symbol, pic_offset_table_rtx);
insn = emit_move_insn (pic_offset_table_rtx, got_symbol);
REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
REG_NOTES (insn));
}
}
s390_load_got (true);
}
/* Expand the epilogue into a bunch of separate insns. */
@ -6649,7 +6564,7 @@ s390_function_profiler (file, labelno)
op[4] = gen_rtx_SYMBOL_REF (Pmode, "_mcount");
if (flag_pic)
{
op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), 113);
op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), UNSPEC_PLT);
op[4] = gen_rtx_CONST (Pmode, op[4]);
}
@ -6749,7 +6664,7 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function)
{
nonlocal = 1;
op[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[0]),
TARGET_64BIT ? 113 : flag_pic == 2 ? 112 : 110);
TARGET_64BIT ? UNSPEC_PLT : UNSPEC_GOT);
op[0] = gen_rtx_CONST (Pmode, op[0]);
}

View File

@ -50,7 +50,19 @@
;;
(define_constants
[; TLS relocation specifiers
[; GOT/PLT and lt-relative accesses
(UNSPEC_LTREL_OFFSET 100)
(UNSPEC_LTREL_BASE 101)
(UNSPEC_GOTENT 110)
(UNSPEC_GOT 111)
(UNSPEC_GOTOFF 112)
(UNSPEC_PLT 113)
(UNSPEC_PLTOFF 114)
; Literal pool
(UNSPEC_RELOAD_BASE 210)
; TLS relocation specifiers
(UNSPEC_TLSGD 500)
(UNSPEC_TLSLDM 501)
(UNSPEC_NTPOFF 502)
@ -69,7 +81,20 @@
;;
(define_constants
[; TLS support
[; Literal pool
(UNSPECV_POOL 200)
(UNSPECV_POOL_START 201)
(UNSPECV_POOL_END 202)
(UNSPECV_POOL_QI 203)
(UNSPECV_POOL_HI 204)
(UNSPECV_POOL_SI 205)
(UNSPECV_POOL_DI 206)
(UNSPECV_POOL_TI 207)
(UNSPECV_POOL_SF 208)
(UNSPECV_POOL_DF 209)
(UNSPECV_MAIN_POOL 300)
; TLS support
(UNSPECV_SET_TP 500)
])
@ -6382,7 +6407,6 @@
""
"
{
int plt_call = 0;
rtx insn;
/* Direct function calls need special treatment. */
@ -6394,20 +6418,19 @@
replace the symbol itself with the PLT stub. */
if (flag_pic && !SYMBOL_REF_LOCAL_P (sym))
{
sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), 113);
sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
sym = gen_rtx_CONST (Pmode, sym);
plt_call = 1;
}
/* Unless we can use the bras(l) insn, force the
routine address into a register. */
if (!TARGET_SMALL_EXEC && !TARGET_64BIT)
{
rtx target = gen_reg_rtx (Pmode);
emit_move_insn (target, sym);
sym = target;
}
{
if (flag_pic)
sym = legitimize_pic_address (sym, 0);
else
sym = force_reg (Pmode, sym);
}
operands[0] = gen_rtx_MEM (QImode, sym);
}
@ -6415,13 +6438,6 @@
/* Emit insn. */
insn = emit_call_insn (gen_call_exp (operands[0], operands[1],
gen_rtx_REG (Pmode, RETURN_REGNUM)));
/* In 31-bit, we must load the GOT register even if the
compiler doesn't know about it, because the PLT glue
code uses it. In 64-bit, this is not necessary. */
if (plt_call && !TARGET_64BIT)
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
DONE;
}")
@ -6501,7 +6517,6 @@
""
"
{
int plt_call = 0;
rtx insn;
/* Direct function calls need special treatment. */
@ -6513,19 +6528,18 @@
replace the symbol itself with the PLT stub. */
if (flag_pic && !SYMBOL_REF_LOCAL_P (sym))
{
sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), 113);
sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
sym = gen_rtx_CONST (Pmode, sym);
plt_call = 1;
}
/* Unless we can use the bras(l) insn, force the
routine address into a register. */
if (!TARGET_SMALL_EXEC && !TARGET_64BIT)
{
rtx target = gen_reg_rtx (Pmode);
emit_move_insn (target, sym);
sym = target;
if (flag_pic)
sym = legitimize_pic_address (sym, 0);
else
sym = force_reg (Pmode, sym);
}
operands[1] = gen_rtx_MEM (QImode, sym);
@ -6535,13 +6549,6 @@
insn = emit_call_insn (
gen_call_value_exp (operands[0], operands[1], operands[2],
gen_rtx_REG (Pmode, RETURN_REGNUM)));
/* In 31-bit, we must load the GOT register even if the
compiler doesn't know about it, because the PLT glue
code uses it. In 64-bit, this is not necessary. */
if (plt_call && !TARGET_64BIT)
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
DONE;
}")
@ -6694,16 +6701,17 @@
abort ();
sym = s390_tls_get_offset ();
sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), 113);
sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
sym = gen_rtx_CONST (Pmode, sym);
/* Unless we can use the bras(l) insn, force the
routine address into a register. */
if (!TARGET_SMALL_EXEC && !TARGET_64BIT)
{
rtx target = gen_reg_rtx (Pmode);
emit_move_insn (target, sym);
sym = target;
if (flag_pic)
sym = legitimize_pic_address (sym, 0);
else
sym = force_reg (Pmode, sym);
}
sym = gen_rtx_MEM (QImode, sym);
@ -6840,35 +6848,28 @@
;
(define_expand "builtin_setjmp_setup"
[(unspec [(match_operand 0 "register_operand" "a")] 1)]
[(match_operand 0 "register_operand" "")]
""
"
{
rtx base = gen_rtx_MEM (Pmode, plus_constant (operands[0], 4 * GET_MODE_SIZE (Pmode)));
rtx basereg = gen_rtx_REG (Pmode, BASE_REGISTER);
emit_move_insn (base, basereg);
DONE;
}")
})
(define_expand "builtin_setjmp_receiver"
[(unspec_volatile [(label_ref (match_operand 0 "" ""))] 2)]
[(match_operand 0 "" "")]
"flag_pic"
"
{
rtx gotreg = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
rtx got = gen_rtx_SYMBOL_REF (Pmode, \"_GLOBAL_OFFSET_TABLE_\");
SYMBOL_REF_FLAGS (got) = SYMBOL_FLAG_LOCAL;
emit_move_insn (gotreg, got);
emit_insn (gen_rtx_USE (VOIDmode, gotreg));
s390_load_got (false);
emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
DONE;
}")
})
(define_expand "builtin_longjmp"
[(unspec_volatile [(match_operand 0 "register_operand" "r")] 3)]
[(match_operand 0 "register_operand" "")]
""
"
{
/* The elements of the buffer are, in order: */
rtx fp = gen_rtx_MEM (Pmode, operands[0]);
@ -6876,7 +6877,7 @@
rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2 * GET_MODE_SIZE (Pmode)));
rtx base = gen_rtx_MEM (Pmode, plus_constant (operands[0], 4 * GET_MODE_SIZE (Pmode)));
rtx basereg = gen_rtx_REG (Pmode, BASE_REGISTER);
rtx jmp = gen_rtx_REG (Pmode, 14);
rtx jmp = gen_reg_rtx (Pmode);
emit_move_insn (jmp, lab);
emit_move_insn (basereg, base);
@ -6888,7 +6889,7 @@
emit_insn (gen_rtx_USE (VOIDmode, basereg));
emit_indirect_jump (jmp);
DONE;
}")
})
;; These patterns say how to save and restore the stack pointer. We need not
@ -6979,56 +6980,58 @@
;
(define_insn "consttable_qi"
[(unspec_volatile [(match_operand:QI 0 "consttable_operand" "X")] 200)]
[(unspec_volatile [(match_operand:QI 0 "consttable_operand" "X")]
UNSPECV_POOL_QI)]
""
"*
{
assemble_integer (operands[0], 1, BITS_PER_UNIT, 1);
return \"\";
}"
return "";
}
[(set_attr "op_type" "NN")
(set_attr "length" "1")])
(define_insn "consttable_hi"
[(unspec_volatile [(match_operand:HI 0 "consttable_operand" "X")] 201)]
[(unspec_volatile [(match_operand:HI 0 "consttable_operand" "X")]
UNSPECV_POOL_HI)]
""
"*
{
assemble_integer (operands[0], 2, 2*BITS_PER_UNIT, 1);
return \"\";
}"
return "";
}
[(set_attr "op_type" "NN")
(set_attr "length" "2")])
(define_insn "consttable_si"
[(unspec_volatile [(match_operand:SI 0 "consttable_operand" "X")] 202)]
[(unspec_volatile [(match_operand:SI 0 "consttable_operand" "X")]
UNSPECV_POOL_SI)]
""
"*
{
if (!TARGET_64BIT && flag_pic && SYMBOLIC_CONST (operands[0]))
return \".long\\t%0\";
assemble_integer (operands[0], 4, 4*BITS_PER_UNIT, 1);
return \"\";
}"
".long\t%0"
[(set_attr "op_type" "NN")
(set_attr "length" "4")])
(define_insn "consttable_di"
[(unspec_volatile [(match_operand:DI 0 "consttable_operand" "X")] 203)]
[(unspec_volatile [(match_operand:DI 0 "consttable_operand" "X")]
UNSPECV_POOL_DI)]
""
"*
{
assemble_integer (operands[0], 8, 8*BITS_PER_UNIT, 1);
return \"\";
}"
".quad\t%0"
[(set_attr "op_type" "NN")
(set_attr "length" "8")])
(define_insn "consttable_sf"
[(unspec_volatile [(match_operand:SF 0 "consttable_operand" "X")] 204)]
(define_insn "consttable_ti"
[(unspec_volatile [(match_operand:TI 0 "consttable_operand" "X")]
UNSPECV_POOL_TI)]
""
{
assemble_integer (operands[0], 16, 16*BITS_PER_UNIT, 1);
return "";
}
[(set_attr "op_type" "NN")
(set_attr "length" "16")])
(define_insn "consttable_sf"
[(unspec_volatile [(match_operand:SF 0 "consttable_operand" "X")]
UNSPECV_POOL_SF)]
""
"*
{
REAL_VALUE_TYPE r;
@ -7037,15 +7040,15 @@
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
assemble_real (r, SFmode, 4*BITS_PER_UNIT);
return \"\";
}"
return "";
}
[(set_attr "op_type" "NN")
(set_attr "length" "4")])
(define_insn "consttable_df"
[(unspec_volatile [(match_operand:DF 0 "consttable_operand" "X")] 205)]
[(unspec_volatile [(match_operand:DF 0 "consttable_operand" "X")]
UNSPECV_POOL_DF)]
""
"*
{
REAL_VALUE_TYPE r;
@ -7054,34 +7057,34 @@
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
assemble_real (r, DFmode, 8*BITS_PER_UNIT);
return \"\";
}"
return "";
}
[(set_attr "op_type" "NN")
(set_attr "length" "8")])
(define_insn "pool_start_31"
[(unspec_volatile [(const_int 0)] 206)]
[(unspec_volatile [(const_int 0)] UNSPECV_POOL_START)]
"!TARGET_64BIT"
".align\\t4"
[(set_attr "op_type" "NN")
(set_attr "length" "2")])
(define_insn "pool_end_31"
[(unspec_volatile [(const_int 0)] 207)]
[(unspec_volatile [(const_int 0)] UNSPECV_POOL_END)]
"!TARGET_64BIT"
".align\\t2"
[(set_attr "op_type" "NN")
(set_attr "length" "2")])
(define_insn "pool_start_64"
[(unspec_volatile [(const_int 0)] 206)]
[(unspec_volatile [(const_int 0)] UNSPECV_POOL_START)]
"TARGET_64BIT"
".section\\t.rodata\;.align\\t8"
[(set_attr "op_type" "NN")
(set_attr "length" "0")])
(define_insn "pool_end_64"
[(unspec_volatile [(const_int 0)] 207)]
[(unspec_volatile [(const_int 0)] UNSPECV_POOL_END)]
"TARGET_64BIT"
".previous"
[(set_attr "op_type" "NN")
@ -7089,7 +7092,7 @@
(define_insn "reload_base_31"
[(set (match_operand:SI 0 "register_operand" "=a")
(unspec:SI [(label_ref (match_operand 1 "" ""))] 210))]
(unspec:SI [(label_ref (match_operand 1 "" ""))] UNSPEC_RELOAD_BASE))]
"!TARGET_64BIT"
"basr\\t%0,0\;la\\t%0,%1-.(%0)"
[(set_attr "op_type" "NN")
@ -7098,24 +7101,14 @@
(define_insn "reload_base_64"
[(set (match_operand:DI 0 "register_operand" "=a")
(unspec:DI [(label_ref (match_operand 1 "" ""))] 210))]
(unspec:DI [(label_ref (match_operand 1 "" ""))] UNSPEC_RELOAD_BASE))]
"TARGET_64BIT"
"larl\\t%0,%1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")])
(define_insn "reload_anchor"
[(set (match_operand:SI 0 "register_operand" "=a")
(unspec:SI [(match_operand:SI 1 "register_operand" "a")] 211))]
"!TARGET_64BIT"
"l\\t%0,0(%1)\;la\\t%0,0(%0,%1)"
[(set_attr "op_type" "NN")
(set_attr "type" "la")
(set_attr "atype" "agen")
(set_attr "length" "8")])
(define_insn "pool"
[(unspec_volatile [(match_operand 0 "const_int_operand" "n")] 220)]
[(unspec_volatile [(match_operand 0 "const_int_operand" "n")] UNSPECV_POOL)]
""
"* abort ();"
[(set_attr "op_type" "NN")
@ -7164,7 +7157,7 @@
(set_attr "atype" "agen")])
(define_insn "literal_pool_31"
[(unspec_volatile [(const_int 0)] 300)
[(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)
(set (match_operand:SI 0 "register_operand" "=a")
(label_ref (match_operand 1 "" "")))
(use (label_ref (match_operand 2 "" "")))]
@ -7188,7 +7181,7 @@
(set_attr "type" "larl")])
(define_insn "literal_pool_64"
[(unspec_volatile [(const_int 0)] 300)
[(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)
(set (match_operand:DI 0 "register_operand" "=a")
(label_ref (match_operand 1 "" "")))
(use (label_ref (match_operand 2 "" "")))]