reload.c (operands_match_p): Handle rtvecs.

* reload.c (operands_match_p): Handle rtvecs.
        * i386.c (legitimate_pic_address_disp_p): New.
        (legitimate_address_p): Use it.
        (legitimize_pic_address): Use unspecs to represent @GOT and @GOTOFF.
        Handle constant pool symbols just like statics.
        (emit_pic_move): Use Pmode not SImode for clarity.
        (output_pic_addr_const) [SYMBOL_REF]: Remove @GOT and @GOTOFF hacks.
        [UNSPEC]: New, handling what we killed above.
        [PLUS]: Detect and abort on invalid symbol arithmetic.
        * i386.h (CONSTANT_ADDRESS_P): Remove HIGH.

From-SVN: r21968
This commit is contained in:
Richard Henderson 1998-08-25 05:23:51 -07:00 committed by Richard Henderson
parent 264fac3496
commit 91bb873f6a
5 changed files with 208 additions and 112 deletions

View File

@ -1,3 +1,17 @@
Tue Aug 25 12:23:20 PDT 1998 Richard Henderson <rth@cygnus.com>
* reload.c (operands_match_p): Handle rtvecs.
* i386.c (legitimate_pic_address_disp_p): New.
(legitimate_address_p): Use it.
(legitimize_pic_address): Use unspecs to represent @GOT and @GOTOFF.
Handle constant pool symbols just like statics.
(emit_pic_move): Use Pmode not SImode for clarity.
(output_pic_addr_const) [SYMBOL_REF]: Remove @GOT and @GOTOFF hacks.
[UNSPEC]: New, handling what we killed above.
[PLUS]: Detect and abort on invalid symbol arithmetic.
* i386.h (CONSTANT_ADDRESS_P): Remove HIGH.
Tue Aug 25 12:02:23 1998 Mark Mitchell <mark@markmitchell.com>
* alias.c: Include output.h.

View File

@ -2507,6 +2507,37 @@ do { \
} \
} while (0)
static int
legitimate_pic_address_disp_p (disp)
register rtx disp;
{
if (GET_CODE (disp) != CONST)
return 0;
disp = XEXP (disp, 0);
if (GET_CODE (disp) == PLUS)
{
if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
return 0;
disp = XEXP (disp, 0);
}
if (GET_CODE (disp) != UNSPEC
|| XVECLEN (disp, 0) != 1)
return 0;
/* Must be @GOT or @GOTOFF. */
if (XINT (disp, 1) != 6
&& XINT (disp, 1) != 7)
return 0;
if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF
&& GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF)
return 0;
return 1;
}
int
legitimate_address_p (mode, addr, strict)
enum machine_mode mode;
@ -2668,20 +2699,10 @@ legitimate_address_p (mode, addr, strict)
}
}
/* Validate displacement
Constant pool addresses must be handled special. They are
considered legitimate addresses, but only if not used with regs.
When printed, the output routines know to print the reference with the
PIC reg, even though the PIC reg doesn't appear in the RTL. */
/* Validate displacement. */
if (disp)
{
if (GET_CODE (disp) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (disp)
&& base == 0
&& indx == 0)
;
else if (!CONSTANT_ADDRESS_P (disp))
if (!CONSTANT_ADDRESS_P (disp))
{
ADDR_INVALID ("Displacement is not valid.\n", disp);
return FALSE;
@ -2693,20 +2714,32 @@ legitimate_address_p (mode, addr, strict)
return FALSE;
}
else if (flag_pic && SYMBOLIC_CONST (disp)
&& base != pic_offset_table_rtx
&& (indx != pic_offset_table_rtx || scale != NULL_RTX))
if (flag_pic && SYMBOLIC_CONST (disp))
{
ADDR_INVALID ("Displacement is an invalid pic reference.\n", disp);
return FALSE;
if (! legitimate_pic_address_disp_p (disp))
{
ADDR_INVALID ("Displacement is an invalid PIC construct.\n",
disp);
return FALSE;
}
if (base != pic_offset_table_rtx
&& (indx != pic_offset_table_rtx || scale != NULL_RTX))
{
ADDR_INVALID ("PIC displacement against invalid base.\n", disp);
return FALSE;
}
}
else if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
&& (base != NULL_RTX || indx != NULL_RTX))
else if (HALF_PIC_P ())
{
ADDR_INVALID ("Displacement is an invalid half-pic reference.\n",
disp);
return FALSE;
if (! HALF_PIC_ADDRESS_P (disp)
|| (base != NULL_RTX || indx != NULL_RTX))
{
ADDR_INVALID ("Displacement is an invalid half-pic reference.\n",
disp);
return FALSE;
}
}
}
@ -2720,29 +2753,20 @@ legitimate_address_p (mode, addr, strict)
/* Return a legitimate reference for ORIG (an address) using the
register REG. If REG is 0, a new pseudo is generated.
There are three types of references that must be handled:
There are two types of references that must be handled:
1. Global data references must load the address from the GOT, via
the PIC reg. An insn is emitted to do this load, and the reg is
returned.
2. Static data references must compute the address as an offset
from the GOT, whose base is in the PIC reg. An insn is emitted to
compute the address into a reg, and the reg is returned. Static
data objects have SYMBOL_REF_FLAG set to differentiate them from
global data objects.
3. Constant pool addresses must be handled special. They are
considered legitimate addresses, but only if not used with regs.
When printed, the output routines know to print the reference with the
PIC reg, even though the PIC reg doesn't appear in the RTL.
2. Static data references, constant pool addresses, and code labels
compute the address as an offset from the GOT, whose base is in
the PIC reg. Static data objects have SYMBOL_REF_FLAG set to
differentiate them from global data objects. The returned
address is the PIC reg + an unspec constant.
GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
reg also appears in the address (except for constant pool references,
noted above).
"switch" statements also require special handling when generating
PIC code. See comments by the `casesi' insn in i386.md for details. */
reg also appears in the address. */
rtx
legitimize_pic_address (orig, reg)
@ -2751,60 +2775,99 @@ legitimize_pic_address (orig, reg)
{
rtx addr = orig;
rtx new = orig;
rtx base;
if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
if (GET_CODE (addr) == LABEL_REF
|| (GET_CODE (addr) == SYMBOL_REF
&& (CONSTANT_POOL_ADDRESS_P (addr)
|| SYMBOL_REF_FLAG (addr))))
{
if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
reg = new = orig;
else
{
if (reg == 0)
reg = gen_reg_rtx (Pmode);
/* This symbol may be referenced via a displacement from the PIC
base address (@GOTOFF). */
if ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
|| GET_CODE (addr) == LABEL_REF)
new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
else
new = gen_rtx_MEM (Pmode,
gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig));
emit_move_insn (reg, new);
}
current_function_uses_pic_offset_table = 1;
return reg;
}
new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 7);
new = gen_rtx_CONST (VOIDmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
{
rtx base;
if (GET_CODE (addr) == CONST)
if (reg != 0)
{
addr = XEXP (addr, 0);
if (GET_CODE (addr) != PLUS)
abort ();
emit_move_insn (reg, new);
new = reg;
}
}
else if (GET_CODE (addr) == SYMBOL_REF)
{
/* This symbol must be referenced via a load from the
Global Offset Table (@GOT). */
if (XEXP (addr, 0) == pic_offset_table_rtx)
return orig;
current_function_uses_pic_offset_table = 1;
new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 6);
new = gen_rtx_CONST (VOIDmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
new = gen_rtx_MEM (Pmode, new);
RTX_UNCHANGING_P (new) = 1;
if (reg == 0)
reg = gen_reg_rtx (Pmode);
base = legitimize_pic_address (XEXP (addr, 0), reg);
addr = legitimize_pic_address (XEXP (addr, 1),
base == reg ? NULL_RTX : reg);
if (GET_CODE (addr) == CONST_INT)
return plus_constant (base, INTVAL (addr));
if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
emit_move_insn (reg, new);
new = reg;
}
else
{
if (GET_CODE (addr) == CONST)
{
base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
addr = XEXP (addr, 1);
addr = XEXP (addr, 0);
if (GET_CODE (addr) == UNSPEC)
{
/* Check that the unspec is one of the ones we generate? */
}
else if (GET_CODE (addr) != PLUS)
abort();
}
if (GET_CODE (addr) == PLUS)
{
rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
return gen_rtx (PLUS, Pmode, base, addr);
/* Check first to see if this is a constant offset from a @GOTOFF
symbol reference. */
if ((GET_CODE (op0) == LABEL_REF
|| (GET_CODE (op0) == SYMBOL_REF
&& (CONSTANT_POOL_ADDRESS_P (op0)
|| SYMBOL_REF_FLAG (op0))))
&& GET_CODE (op1) == CONST_INT)
{
current_function_uses_pic_offset_table = 1;
new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, op0), 7);
new = gen_rtx_PLUS (VOIDmode, new, op1);
new = gen_rtx_CONST (VOIDmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
if (reg != 0)
{
emit_move_insn (reg, new);
new = reg;
}
}
else
{
base = legitimize_pic_address (XEXP (addr, 0), reg);
new = legitimize_pic_address (XEXP (addr, 1),
base == reg ? NULL_RTX : reg);
if (GET_CODE (new) == CONST_INT)
new = plus_constant (base, INTVAL (new));
else
{
if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1)))
{
base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0));
new = XEXP (new, 1);
}
new = gen_rtx_PLUS (Pmode, base, new);
}
}
}
}
return new;
}
@ -2819,7 +2882,7 @@ emit_pic_move (operands, mode)
rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
operands[1] = force_reg (SImode, operands[1]);
operands[1] = force_reg (Pmode, operands[1]);
else
operands[1] = legitimize_pic_address (operands[1], temp);
}
@ -3032,31 +3095,14 @@ output_pic_addr_const (file, x, code)
break;
case SYMBOL_REF:
case LABEL_REF:
if (GET_CODE (x) == SYMBOL_REF)
assemble_name (file, XSTR (x, 0));
else
{
ASM_GENERATE_INTERNAL_LABEL (buf, "L",
CODE_LABEL_NUMBER (XEXP (x, 0)));
assemble_name (asm_out_file, buf);
}
if (code == 'X')
; /* No suffix, dammit. */
else if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
fprintf (file, "@GOTOFF(%%ebx)");
else if (code == 'P')
fprintf (file, "@PLT");
else if (GET_CODE (x) == LABEL_REF)
fprintf (file, "@GOTOFF");
else if (! SYMBOL_REF_FLAG (x))
fprintf (file, "@GOT");
else
fprintf (file, "@GOTOFF");
assemble_name (file, XSTR (x, 0));
if (code == 'P' && ! SYMBOL_REF_FLAG (x))
fputs ("@PLT", file);
break;
case LABEL_REF:
x = XEXP (x, 0);
/* FALLTHRU */
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
assemble_name (asm_out_file, buf);
@ -3094,17 +3140,17 @@ output_pic_addr_const (file, x, code)
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
{
output_pic_addr_const (file, XEXP (x, 0), code);
if (INTVAL (XEXP (x, 1)) >= 0)
fprintf (file, "+");
fprintf (file, "+");
output_pic_addr_const (file, XEXP (x, 1), code);
}
else
else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
output_pic_addr_const (file, XEXP (x, 1), code);
if (INTVAL (XEXP (x, 0)) >= 0)
fprintf (file, "+");
fprintf (file, "+");
output_pic_addr_const (file, XEXP (x, 0), code);
}
else
abort ();
break;
case MINUS:
@ -3113,6 +3159,27 @@ output_pic_addr_const (file, x, code)
output_pic_addr_const (file, XEXP (x, 1), code);
break;
case UNSPEC:
if (XVECLEN (x, 0) != 1)
abort ();
output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
switch (XINT (x, 1))
{
case 6:
fputs ("@GOT", file);
break;
case 7:
fputs ("@GOTOFF", file);
break;
case 8:
fputs ("@PLT", file);
break;
default:
output_operand_lossage ("invalid UNSPEC as operand");
break;
}
break;
default:
output_operand_lossage ("invalid expression as operand");
}

View File

@ -1703,10 +1703,9 @@ do { \
#define MAX_REGS_PER_ADDRESS 2
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
|| GET_CODE (X) == HIGH)
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST)
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */

View File

@ -64,6 +64,9 @@
;; prevent insns referencing it being scheduled across the initial
;; decrement of the stack pointer.
;; 5 This is a `bsf' operation.
;; 6 This is the @GOT offset of a PIC address.
;; 7 This is the @GOTOFF offset of a PIC address.
;; 8 This is a reference to a symbol's @PLT address.
;; This shadows the processor_type enumeration, so changes must be made
;; to i386.h at the same time.

View File

@ -2031,7 +2031,7 @@ operands_match_p (x, y)
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
int val;
int val, j;
switch (fmt[i])
{
case 'w':
@ -2057,6 +2057,19 @@ operands_match_p (x, y)
case '0':
break;
case 'E':
if (XVECLEN (x, i) != XVECLEN (y, i))
return 0;
for (j = XVECLEN (x, i) - 1; j >= 0; --j)
{
val = operands_match_p (XVECEXP (x, i, j), XVECEXP (y, i, j));
if (val == 0)
return 0;
if (val == 2)
success_2 = 1;
}
break;
/* It is believed that rtx's at this level will never
contain anything but integers and other rtx's,
except for within LABEL_REFs and SYMBOL_REFs. */