diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-08-25 12:23:51 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-08-25 12:23:51 +0000 |
commit | 4e39a270cde5c77f033e631925b8d05ca133394a (patch) | |
tree | e0bd10855584387801668f18203fd9790527c2e3 /gcc/config/i386 | |
parent | a068b2a9571bd9c8c7b7e911d0be6a9c5d813d1f (diff) | |
download | gcc-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.c | 277 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 7 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 3 |
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. |