summaryrefslogtreecommitdiff
path: root/gcc/config/i386
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1998-08-25 12:23:51 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1998-08-25 12:23:51 +0000
commit4e39a270cde5c77f033e631925b8d05ca133394a (patch)
treee0bd10855584387801668f18203fd9790527c2e3 /gcc/config/i386
parenta068b2a9571bd9c8c7b7e911d0be6a9c5d813d1f (diff)
downloadgcc-4e39a270cde5c77f033e631925b8d05ca133394a.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@21968 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/i386')
-rw-r--r--gcc/config/i386/i386.c277
-rw-r--r--gcc/config/i386/i386.h7
-rw-r--r--gcc/config/i386/i386.md3
3 files changed, 178 insertions, 109 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 73036ea4f09..b3161309240 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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));
+ current_function_uses_pic_offset_table = 1;
+ 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);
+ if (reg != 0)
+ {
emit_move_insn (reg, new);
+ new = reg;
}
- current_function_uses_pic_offset_table = 1;
- return reg;
}
-
- else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
+ else if (GET_CODE (addr) == SYMBOL_REF)
{
- rtx base;
+ /* This symbol must be referenced via a load from the
+ Global Offset Table (@GOT). */
+
+ 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);
+ emit_move_insn (reg, new);
+ new = reg;
+ }
+ else
+ {
if (GET_CODE (addr) == CONST)
{
addr = XEXP (addr, 0);
- if (GET_CODE (addr) != PLUS)
- abort ();
+ 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);
+
+ /* 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 (XEXP (addr, 0) == pic_offset_table_rtx)
- return orig;
-
- 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 (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 (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
- {
- base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
- addr = XEXP (addr, 1);
+ 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 gen_rtx (PLUS, Pmode, base, addr);
}
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");
}
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 540cfec35f5..75e0298885d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -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. */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index ca63bf49ba6..e65ca1c019c 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -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.