From 91bb873f6a9999799bfc4242b9bd4e13c47bf820 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Aug 1998 05:23:51 -0700 Subject: [PATCH] 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 --- gcc/ChangeLog | 14 ++ gcc/config/i386/i386.c | 277 +++++++++++++++++++++++++--------------- gcc/config/i386/i386.h | 7 +- gcc/config/i386/i386.md | 3 + gcc/reload.c | 15 ++- 5 files changed, 206 insertions(+), 110 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c7197ec2eee..4e1dd654b93 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +Tue Aug 25 12:23:20 PDT 1998 Richard Henderson + + * 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 * alias.c: Include output.h. 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. diff --git a/gcc/reload.c b/gcc/reload.c index b1483d19440..d3dc14f6930 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -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. */ -- 2.30.2