diff options
Diffstat (limited to 'contrib/gcc/emit-rtl.c')
-rw-r--r-- | contrib/gcc/emit-rtl.c | 876 |
1 files changed, 502 insertions, 374 deletions
diff --git a/contrib/gcc/emit-rtl.c b/contrib/gcc/emit-rtl.c index 9600f2f..2ca007a 100644 --- a/contrib/gcc/emit-rtl.c +++ b/contrib/gcc/emit-rtl.c @@ -1,5 +1,5 @@ /* Emit RTL for the GNU C-Compiler expander. - Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc. This file is part of GNU CC. @@ -40,42 +40,27 @@ Boston, MA 02111-1307, USA. */ #else #include <varargs.h> #endif +#include "system.h" #include "rtl.h" #include "tree.h" #include "flags.h" +#include "except.h" #include "function.h" #include "expr.h" #include "regs.h" +#include "hard-reg-set.h" #include "insn-config.h" +#include "recog.h" #include "real.h" #include "obstack.h" - -#include "bytecode.h" -#include "machmode.h" -#include "bc-opcode.h" -#include "bc-typecd.h" -#include "bc-optab.h" -#include "bc-emit.h" - -#include <stdio.h> - - -/* Opcode names */ -#ifdef BCDEBUG_PRINT_CODE -char *opcode_name[] = -{ -#include "bc-opname.h" - -"***END***" -}; -#endif - +#include "bitmap.h" /* Commonly used modes. */ -enum machine_mode byte_mode; /* Mode whose width is BITS_PER_UNIT. */ -enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD. */ -enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */ +enum machine_mode byte_mode; /* Mode whose width is BITS_PER_UNIT. */ +enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD. */ +enum machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE. */ +enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */ /* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function. After rtl generation, it is 1 plus the largest register number used. */ @@ -111,14 +96,19 @@ static int no_line_numbers; All of these except perhaps the floating-point CONST_DOUBLEs are unique; no other rtx-object will be equal to any of these. */ -rtx pc_rtx; /* (PC) */ -rtx cc0_rtx; /* (CC0) */ -rtx cc1_rtx; /* (CC1) (not actually used nowadays) */ -rtx const0_rtx; /* (CONST_INT 0) */ -rtx const1_rtx; /* (CONST_INT 1) */ -rtx const2_rtx; /* (CONST_INT 2) */ -rtx constm1_rtx; /* (CONST_INT -1) */ -rtx const_true_rtx; /* (CONST_INT STORE_FLAG_VALUE) */ +struct _global_rtl global_rtl = +{ + {PC, VOIDmode}, /* pc_rtx */ + {CC0, VOIDmode}, /* cc0_rtx */ + {REG}, /* stack_pointer_rtx */ + {REG}, /* frame_pointer_rtx */ + {REG}, /* hard_frame_pointer_rtx */ + {REG}, /* arg_pointer_rtx */ + {REG}, /* virtual_incoming_args_rtx */ + {REG}, /* virtual_stack_vars_rtx */ + {REG}, /* virtual_stack_dynamic_rtx */ + {REG}, /* virtual_outgoing_args_rtx */ +}; /* We record floating-point CONST_DOUBLEs in each floating-point mode for the values of 0, 1, and 2. For the integer entries and VOIDmode, we @@ -126,6 +116,8 @@ rtx const_true_rtx; /* (CONST_INT STORE_FLAG_VALUE) */ rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE]; +rtx const_true_rtx; + REAL_VALUE_TYPE dconst0; REAL_VALUE_TYPE dconst1; REAL_VALUE_TYPE dconst2; @@ -149,29 +141,22 @@ REAL_VALUE_TYPE dconstm1; In an inline procedure, the stack and frame pointer rtxs may not be used for anything else. */ -rtx stack_pointer_rtx; /* (REG:Pmode STACK_POINTER_REGNUM) */ -rtx frame_pointer_rtx; /* (REG:Pmode FRAME_POINTER_REGNUM) */ -rtx hard_frame_pointer_rtx; /* (REG:Pmode HARD_FRAME_POINTER_REGNUM) */ -rtx arg_pointer_rtx; /* (REG:Pmode ARG_POINTER_REGNUM) */ rtx struct_value_rtx; /* (REG:Pmode STRUCT_VALUE_REGNUM) */ rtx struct_value_incoming_rtx; /* (REG:Pmode STRUCT_VALUE_INCOMING_REGNUM) */ rtx static_chain_rtx; /* (REG:Pmode STATIC_CHAIN_REGNUM) */ rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */ rtx pic_offset_table_rtx; /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */ -rtx virtual_incoming_args_rtx; /* (REG:Pmode VIRTUAL_INCOMING_ARGS_REGNUM) */ -rtx virtual_stack_vars_rtx; /* (REG:Pmode VIRTUAL_STACK_VARS_REGNUM) */ -rtx virtual_stack_dynamic_rtx; /* (REG:Pmode VIRTUAL_STACK_DYNAMIC_REGNUM) */ -rtx virtual_outgoing_args_rtx; /* (REG:Pmode VIRTUAL_OUTGOING_ARGS_REGNUM) */ +/* This is used to implement __builtin_return_address for some machines. + See for instance the MIPS port. */ +rtx return_address_pointer_rtx; /* (REG:Pmode RETURN_ADDRESS_POINTER_REGNUM) */ /* We make one copy of (const_int C) where C is in [- MAX_SAVED_CONST_INT, MAX_SAVED_CONST_INT] to save space during the compilation and simplify comparisons of integers. */ -#define MAX_SAVED_CONST_INT 64 - -static rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1]; +struct rtx_def const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1]; /* The ends of the doubly-linked chain of rtl for the current function. Both are reset to null at the start of rtl generation for the function. @@ -208,6 +193,11 @@ static char *last_filename = 0; char *regno_pointer_flag; int regno_pointer_flag_length; +/* Indexed by pseudo register number, if nonzero gives the known alignment + for that pseudo (if regno_pointer_flag is set). + Allocated in parallel with regno_pointer_flag. */ +char *regno_pointer_align; + /* Indexed by pseudo register number, gives the rtx for that pseudo. Allocated in parallel with regno_pointer_flag. */ @@ -240,6 +230,9 @@ struct sequence_stack *sequence_stack; static struct sequence_stack *sequence_element_free_list; static rtx sequence_result[SEQUENCE_RESULT_SIZE]; +/* During RTL generation, we also keep a list of free INSN rtl codes. */ +static rtx free_insn; + extern int rtx_equal_function_value_matters; /* Filename and line number of last line-number note, @@ -247,14 +240,82 @@ extern int rtx_equal_function_value_matters; extern char *emit_filename; extern int emit_lineno; -rtx change_address (); -void init_emit (); +static rtx make_jump_insn_raw PROTO((rtx)); +static rtx make_call_insn_raw PROTO((rtx)); +static rtx find_line_note PROTO((rtx)); -extern struct obstack *rtl_obstack; +rtx +gen_rtx_CONST_INT (mode, arg) + enum machine_mode mode; + HOST_WIDE_INT arg; +{ + if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT) + return &const_int_rtx[arg + MAX_SAVED_CONST_INT]; + +#if STORE_FLAG_VALUE != 1 && STORE_FLAG_VALUE != -1 + if (const_true_rtx && arg == STORE_FLAG_VALUE) + return const_true_rtx; +#endif + + return gen_rtx_raw_CONST_INT (mode, arg); +} + +rtx +gen_rtx_REG (mode, regno) + enum machine_mode mode; + int regno; +{ + /* In case the MD file explicitly references the frame pointer, have + all such references point to the same frame pointer. This is + used during frame pointer elimination to distinguish the explicit + references to these registers from pseudos that happened to be + assigned to them. + + If we have eliminated the frame pointer or arg pointer, we will + be using it as a normal register, for example as a spill + register. In such cases, we might be accessing it in a mode that + is not Pmode and therefore cannot use the pre-allocated rtx. + + Also don't do this when we are making new REGs in reload, since + we don't want to get confused with the real pointers. */ + + if (mode == Pmode && !reload_in_progress) + { + if (regno == FRAME_POINTER_REGNUM) + return frame_pointer_rtx; +#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + if (regno == HARD_FRAME_POINTER_REGNUM) + return hard_frame_pointer_rtx; +#endif +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + if (regno == ARG_POINTER_REGNUM) + return arg_pointer_rtx; +#endif +#ifdef RETURN_ADDRESS_POINTER_REGNUM + if (regno == RETURN_ADDRESS_POINTER_REGNUM) + return return_address_pointer_rtx; +#endif + if (regno == STACK_POINTER_REGNUM) + return stack_pointer_rtx; + } + + return gen_rtx_raw_REG (mode, regno); +} + +rtx +gen_rtx_MEM (mode, addr) + enum machine_mode mode; + rtx addr; +{ + rtx rt = gen_rtx_raw_MEM (mode, addr); + + /* This field is not cleared by the mere allocation of the rtx, so + we clear it here. */ + MEM_ALIAS_SET (rt) = 0; + + return rt; +} -extern int stack_depth; -extern int max_stack_depth; - /* rtx gen_rtx (code, mode, [element1, ..., elementn]) ** ** This routine generates an RTX of the size specified by @@ -302,60 +363,11 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...)) #endif if (code == CONST_INT) - { - HOST_WIDE_INT arg = va_arg (p, HOST_WIDE_INT); - - if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT) - return const_int_rtx[arg + MAX_SAVED_CONST_INT]; - - if (const_true_rtx && arg == STORE_FLAG_VALUE) - return const_true_rtx; - - rt_val = rtx_alloc (code); - INTVAL (rt_val) = arg; - } + rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT)); else if (code == REG) - { - int regno = va_arg (p, int); - - /* In case the MD file explicitly references the frame pointer, have - all such references point to the same frame pointer. This is used - during frame pointer elimination to distinguish the explicit - references to these registers from pseudos that happened to be - assigned to them. - - If we have eliminated the frame pointer or arg pointer, we will - be using it as a normal register, for example as a spill register. - In such cases, we might be accessing it in a mode that is not - Pmode and therefore cannot use the pre-allocated rtx. - - Also don't do this when we are making new REGs in reload, - since we don't want to get confused with the real pointers. */ - - if (frame_pointer_rtx && regno == FRAME_POINTER_REGNUM && mode == Pmode - && ! reload_in_progress) - return frame_pointer_rtx; -#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM - if (hard_frame_pointer_rtx && regno == HARD_FRAME_POINTER_REGNUM - && mode == Pmode && ! reload_in_progress) - return hard_frame_pointer_rtx; -#endif -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - if (arg_pointer_rtx && regno == ARG_POINTER_REGNUM && mode == Pmode - && ! reload_in_progress) - return arg_pointer_rtx; -#endif - if (stack_pointer_rtx && regno == STACK_POINTER_REGNUM && mode == Pmode - && ! reload_in_progress) - return stack_pointer_rtx; - else - { - rt_val = rtx_alloc (code); - rt_val->mode = mode; - REGNO (rt_val) = regno; - return rt_val; - } - } + rt_val = gen_rtx_REG (mode, va_arg (p, int)); + else if (code == MEM) + rt_val = gen_rtx_MEM (mode, va_arg (p, rtx)); else { rt_val = rtx_alloc (code); /* Allocate the storage space. */ @@ -390,6 +402,14 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...)) XVEC (rt_val, i) = va_arg (p, rtvec); break; + case 'b': /* A bitmap? */ + XBITMAP (rt_val, i) = va_arg (p, bitmap); + break; + + case 't': /* A tree? */ + XTREE (rt_val, i) = va_arg (p, tree); + break; + default: abort (); } @@ -452,6 +472,25 @@ gen_rtvec_v (n, argp) return rt_val; } + +rtvec +gen_rtvec_vv (n, argp) + int n; + rtunion *argp; +{ + register int i; + register rtvec rt_val; + + if (n == 0) + return NULL_RTVEC; /* Don't allocate an empty rtvec... */ + + rt_val = rtvec_alloc (n); /* Allocate an rtvec... */ + + for (i = 0; i < n; i++) + rt_val->elem[i].rtx = (argp++)->rtx; + + return rt_val; +} /* Generate a REG rtx for a new pseudo register of mode MODE. This pseudo is assigned the next sequential register number. */ @@ -487,7 +526,7 @@ gen_reg_rtx (mode) realpart = gen_reg_rtx (partmode); imagpart = gen_reg_rtx (partmode); - return gen_rtx (CONCAT, mode, realpart, imagpart); + return gen_rtx_CONCAT (mode, realpart, imagpart); } /* Make sure regno_pointer_flag and regno_reg_rtx are large @@ -497,12 +536,17 @@ gen_reg_rtx (mode) { rtx *new1; char *new = - (char *) oballoc (regno_pointer_flag_length * 2); + (char *) savealloc (regno_pointer_flag_length * 2); bcopy (regno_pointer_flag, new, regno_pointer_flag_length); bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length); regno_pointer_flag = new; - new1 = (rtx *) oballoc (regno_pointer_flag_length * 2 * sizeof (rtx)); + new = (char *) savealloc (regno_pointer_flag_length * 2); + bcopy (regno_pointer_align, new, regno_pointer_flag_length); + bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length); + regno_pointer_align = new; + + new1 = (rtx *) savealloc (regno_pointer_flag_length * 2 * sizeof (rtx)); bcopy ((char *) regno_reg_rtx, (char *) new1, regno_pointer_flag_length * sizeof (rtx)); bzero ((char *) &new1[regno_pointer_flag_length], @@ -512,18 +556,40 @@ gen_reg_rtx (mode) regno_pointer_flag_length *= 2; } - val = gen_rtx (REG, mode, reg_rtx_no); + val = gen_rtx_raw_REG (mode, reg_rtx_no); regno_reg_rtx[reg_rtx_no++] = val; return val; } -/* Identify REG as a probable pointer register. */ +/* Identify REG (which may be a CONCAT) as a user register. */ + +void +mark_user_reg (reg) + rtx reg; +{ + if (GET_CODE (reg) == CONCAT) + { + REG_USERVAR_P (XEXP (reg, 0)) = 1; + REG_USERVAR_P (XEXP (reg, 1)) = 1; + } + else if (GET_CODE (reg) == REG) + REG_USERVAR_P (reg) = 1; + else + abort (); +} + +/* Identify REG as a probable pointer register and show its alignment + as ALIGN, if nonzero. */ void -mark_reg_pointer (reg) +mark_reg_pointer (reg, align) rtx reg; + int align; { REGNO_POINTER_FLAG (REGNO (reg)) = 1; + + if (align) + REGNO_POINTER_ALIGN (REGNO (reg)) = align; } /* Return 1 plus largest pseudo reg number used in the current function. */ @@ -602,16 +668,27 @@ gen_lowpart_common (mode, x) else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))) return gen_lowpart_common (mode, XEXP (x, 0)); else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))) - return gen_rtx (GET_CODE (x), mode, XEXP (x, 0)); + return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0)); } else if (GET_CODE (x) == SUBREG && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD || GET_MODE_SIZE (mode) == GET_MODE_UNIT_SIZE (GET_MODE (x)))) return (GET_MODE (SUBREG_REG (x)) == mode && SUBREG_WORD (x) == 0 ? SUBREG_REG (x) - : gen_rtx (SUBREG, mode, SUBREG_REG (x), SUBREG_WORD (x))); + : gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + word)); else if (GET_CODE (x) == REG) { + /* Let the backend decide how many registers to skip. This is needed + in particular for Sparc64 where fp regs are smaller than a word. */ + /* ??? Note that subregs are now ambiguous, in that those against + pseudos are sized by the Word Size, while those against hard + regs are sized by the underlying register size. Better would be + to always interpret the subreg offset parameter as bytes or bits. */ + + if (WORDS_BIG_ENDIAN && REGNO (x) < FIRST_PSEUDO_REGISTER) + word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)) + - HARD_REGNO_NREGS (REGNO (x), mode)); + /* If the register is not valid for MODE, return 0. If we don't do this, there is no way to fix up the resulting REG later. But we do do this if the current REG is not valid for its @@ -626,6 +703,14 @@ gen_lowpart_common (mode, x) /* integrate.c can't handle parts of a return value register. */ && (! REG_FUNCTION_VALUE_P (x) || ! rtx_equal_function_value_matters) +#ifdef CLASS_CANNOT_CHANGE_SIZE + && ! (GET_MODE_SIZE (mode) != GET_MODE_SIZE (GET_MODE (x)) + && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_INT + && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_FLOAT + && (TEST_HARD_REG_BIT + (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE], + REGNO (x)))) +#endif /* We want to keep the stack, frame, and arg pointers special. */ && x != frame_pointer_rtx @@ -633,9 +718,9 @@ gen_lowpart_common (mode, x) && x != arg_pointer_rtx #endif && x != stack_pointer_rtx) - return gen_rtx (REG, mode, REGNO (x) + word); + return gen_rtx_REG (mode, REGNO (x) + word); else - return gen_rtx (SUBREG, mode, x, word); + return gen_rtx_SUBREG (mode, x, word); } /* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits from the low-order part of the constant. */ @@ -661,14 +746,13 @@ gen_lowpart_common (mode, x) : GEN_INT (CONST_DOUBLE_LOW (x))); else { - /* MODE must be narrower than HOST_BITS_PER_INT. */ + /* MODE must be narrower than HOST_BITS_PER_WIDE_INT. */ int width = GET_MODE_BITSIZE (mode); HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x) : CONST_DOUBLE_LOW (x)); - if (((val & ((HOST_WIDE_INT) (-1) << (width - 1))) - != ((HOST_WIDE_INT) (-1) << (width - 1)))) - val &= ((HOST_WIDE_INT) 1 << width) - 1; + /* Sign extend to HOST_WIDE_INT. */ + val = val << (HOST_BITS_PER_WIDE_INT - width) >> (HOST_BITS_PER_WIDE_INT - width); return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x : GEN_INT (val)); @@ -726,7 +810,7 @@ gen_lowpart_common (mode, x) low = CONST_DOUBLE_LOW (x), high = CONST_DOUBLE_HIGH (x); /* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the - target machine. */ + target machine. */ if (WORDS_BIG_ENDIAN) i[0] = high, i[1] = low; else @@ -754,6 +838,22 @@ gen_lowpart_common (mode, x) return CONST_DOUBLE_FROM_REAL_VALUE (u.d, mode); } #endif + + /* We need an extra case for machines where HOST_BITS_PER_WIDE_INT is the + same as sizeof (double) or when sizeof (float) is larger than the + size of a word on the target machine. */ +#ifdef REAL_ARITHMETIC + else if (mode == SFmode && GET_CODE (x) == CONST_INT) + { + REAL_VALUE_TYPE r; + HOST_WIDE_INT i; + + i = INTVAL (x); + r = REAL_VALUE_FROM_TARGET_SINGLE (i); + return CONST_DOUBLE_FROM_REAL_VALUE (r, mode); + } +#endif + /* Similarly, if this is converting a floating-point value into a single-word integer. Only do this is the host and target parameters are compatible. */ @@ -766,7 +866,7 @@ gen_lowpart_common (mode, x) && GET_CODE (x) == CONST_DOUBLE && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT && GET_MODE_BITSIZE (mode) == BITS_PER_WORD) - return operand_subword (x, 0, 0, GET_MODE (x)); + return operand_subword (x, word, 0, GET_MODE (x)); /* Similarly, if this is converting a floating-point value into a two-word integer, we can do this one word at a time and make an @@ -782,8 +882,10 @@ gen_lowpart_common (mode, x) && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT && GET_MODE_BITSIZE (mode) == 2 * BITS_PER_WORD) { - rtx lowpart = operand_subword (x, WORDS_BIG_ENDIAN, 0, GET_MODE (x)); - rtx highpart = operand_subword (x, ! WORDS_BIG_ENDIAN, 0, GET_MODE (x)); + rtx lowpart + = operand_subword (x, word + WORDS_BIG_ENDIAN, 0, GET_MODE (x)); + rtx highpart + = operand_subword (x, word + ! WORDS_BIG_ENDIAN, 0, GET_MODE (x)); if (lowpart && GET_CODE (lowpart) == CONST_INT && highpart && GET_CODE (highpart) == CONST_INT) @@ -863,6 +965,7 @@ gen_lowpart (mode, x) result = gen_lowpart_common (mode, copy_to_reg (x)); if (result == 0) abort (); + return result; } else if (GET_CODE (x) == MEM) { @@ -880,6 +983,8 @@ gen_lowpart (mode, x) return change_address (x, mode, plus_constant (XEXP (x, 0), offset)); } + else if (GET_CODE (x) == ADDRESSOF) + return gen_lowpart (mode, force_reg (GET_MODE (x), x)); else abort (); } @@ -902,10 +1007,13 @@ gen_highpart (mode, x) && GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT #endif ) - return gen_rtx (CONST_INT, VOIDmode, - CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode)); + return GEN_INT (CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode)); else if (GET_CODE (x) == CONST_INT) - return const0_rtx; + { + if (HOST_BITS_PER_WIDE_INT <= BITS_PER_WORD) + return const0_rtx; + return GEN_INT (INTVAL (x) >> (HOST_BITS_PER_WIDE_INT - BITS_PER_WORD)); + } else if (GET_CODE (x) == MEM) { register int offset = 0; @@ -932,22 +1040,27 @@ gen_highpart (mode, x) } else if (GET_CODE (x) == REG) { - int word = 0; + int word; + + /* Let the backend decide how many registers to skip. This is needed + in particular for sparc64 where fp regs are smaller than a word. */ + /* ??? Note that subregs are now ambiguous, in that those against + pseudos are sized by the word size, while those against hard + regs are sized by the underlying register size. Better would be + to always interpret the subreg offset parameter as bytes or bits. */ - if (! WORDS_BIG_ENDIAN - && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) + if (WORDS_BIG_ENDIAN) + word = 0; + else if (REGNO (x) < FIRST_PSEUDO_REGISTER) + word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)) + - HARD_REGNO_NREGS (REGNO (x), mode)); + else word = ((GET_MODE_SIZE (GET_MODE (x)) - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) / UNITS_PER_WORD); - /* - * ??? This fails miserably for complex values being passed in registers - * where the sizeof the real and imaginary part are not equal to the - * sizeof SImode. FIXME - */ - if (REGNO (x) < FIRST_PSEUDO_REGISTER - /* integrate.c can't handle parts of a return value register. */ + /* integrate.c can't handle parts of a return value register. */ && (! REG_FUNCTION_VALUE_P (x) || ! rtx_equal_function_value_matters) /* We want to keep the stack, frame, and arg pointers special. */ @@ -956,9 +1069,9 @@ gen_highpart (mode, x) && x != arg_pointer_rtx #endif && x != stack_pointer_rtx) - return gen_rtx (REG, mode, REGNO (x) + word); + return gen_rtx_REG (mode, REGNO (x) + word); else - return gen_rtx (SUBREG, mode, x, word); + return gen_rtx_SUBREG (mode, x, word); } else abort (); @@ -974,6 +1087,8 @@ subreg_lowpart_p (x) { if (GET_CODE (x) != SUBREG) return 1; + else if (GET_MODE (SUBREG_REG (x)) == VOIDmode) + return 0; if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD) @@ -1011,6 +1126,7 @@ operand_subword (op, i, validate_address, mode) { HOST_WIDE_INT val; int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD; + int bits_per_word = BITS_PER_WORD; if (mode == VOIDmode) mode = GET_MODE (op); @@ -1047,12 +1163,12 @@ operand_subword (op, i, validate_address, mode) || op == arg_pointer_rtx #endif || op == stack_pointer_rtx) - return gen_rtx (SUBREG, word_mode, op, i); + return gen_rtx_SUBREG (word_mode, op, i); else - return gen_rtx (REG, word_mode, REGNO (op) + i); + return gen_rtx_REG (word_mode, REGNO (op) + i); } else if (GET_CODE (op) == SUBREG) - return gen_rtx (SUBREG, word_mode, SUBREG_REG (op), i + SUBREG_WORD (op)); + return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op)); else if (GET_CODE (op) == CONCAT) { int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD; @@ -1079,7 +1195,7 @@ operand_subword (op, i, validate_address, mode) addr = memory_address (word_mode, addr); } - new = gen_rtx (MEM, word_mode, addr); + new = gen_rtx_MEM (word_mode, addr); MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op); MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op); @@ -1124,7 +1240,7 @@ operand_subword (op, i, validate_address, mode) { long value; value = k[i >> 1]; - if ((i & 0x1) == 0) + if ((i & 0x1) == !WORDS_BIG_ENDIAN) value >>= 16; value &= 0xffff; return GEN_INT ((HOST_WIDE_INT) value); @@ -1132,6 +1248,20 @@ operand_subword (op, i, validate_address, mode) else abort (); } + else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_BITSIZE (mode) > 64 + && GET_CODE (op) == CONST_DOUBLE) + { + long k[4]; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); + + if (BITS_PER_WORD == 32) + return GEN_INT ((HOST_WIDE_INT) k[i]); + } #else /* no REAL_ARITHMETIC */ if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) @@ -1167,12 +1297,20 @@ operand_subword (op, i, validate_address, mode) REAL_VALUE_FROM_CONST_DOUBLE (rv, op); REAL_VALUE_TO_TARGET_SINGLE (rv, l); + + if (BITS_PER_WORD == 16) + { + if ((i & 0x1) == !WORDS_BIG_ENDIAN) + l >>= 16; + l &= 0xffff; + } return GEN_INT ((HOST_WIDE_INT) l); } #else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) || flag_pretend_float) + && sizeof (float) * 8 == HOST_BITS_PER_WIDE_INT && GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE_SIZE (mode) == UNITS_PER_WORD && GET_CODE (op) == CONST_DOUBLE) @@ -1185,6 +1323,22 @@ operand_subword (op, i, validate_address, mode) u.f = d; return GEN_INT (u.i); } + if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT + && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD) + || flag_pretend_float) + && sizeof (double) * 8 == HOST_BITS_PER_WIDE_INT + && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) == UNITS_PER_WORD + && GET_CODE (op) == CONST_DOUBLE) + { + double d; + union {double d; HOST_WIDE_INT i; } u; + + REAL_VALUE_FROM_CONST_DOUBLE (d, op); + + u.d = d; + return GEN_INT (u.i); + } #endif /* no REAL_ARITHMETIC */ /* The only remaining cases that we can handle are integers. @@ -1213,11 +1367,30 @@ operand_subword (op, i, validate_address, mode) : (GET_CODE (op) == CONST_INT ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op))); - /* If BITS_PER_WORD is smaller than an int, get the appropriate bits. */ + /* Get the value we want into the low bits of val. */ if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT) - val = ((val >> ((i % size_ratio) * BITS_PER_WORD)) - & (((HOST_WIDE_INT) 1 - << (BITS_PER_WORD % HOST_BITS_PER_WIDE_INT)) - 1)); + val = ((val >> ((i % size_ratio) * BITS_PER_WORD))); + + /* Clear the bits that don't belong in our mode, unless they and our sign + bit are all one. So we get either a reasonable negative value or a + reasonable unsigned value for this mode. */ + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT + && ((val & ((HOST_WIDE_INT) (-1) << (bits_per_word - 1))) + != ((HOST_WIDE_INT) (-1) << (bits_per_word - 1)))) + val &= ((HOST_WIDE_INT) 1 << bits_per_word) - 1; + + /* If this would be an entire word for the target, but is not for + the host, then sign-extend on the host so that the number will look + the same way on the host that it would on the target. + + For example, when building a 64 bit alpha hosted 32 bit sparc + targeted compiler, then we want the 32 bit unsigned value -1 to be + represented as a 64 bit value -1, and not as 0x00000000ffffffff. + The later confuses the sparc backend. */ + + if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT + && (val & ((HOST_WIDE_INT) 1 << (bits_per_word - 1)))) + val |= ((HOST_WIDE_INT) (-1) << bits_per_word); return GEN_INT (val); } @@ -1242,7 +1415,14 @@ operand_subword_force (op, i, mode) return result; if (mode != BLKmode && mode != VOIDmode) - op = force_reg (mode, op); + { + /* If this is a register which can not be accessed by words, copy it + to a pseudo register. */ + if (GET_CODE (op) == REG) + op = copy_to_reg (op); + else + op = force_reg (mode, op); + } result = operand_subword (op, i, 1, mode); if (result == 0) @@ -1275,8 +1455,7 @@ reverse_comparison (insn) } else { - rtx new = gen_rtx (COMPARE, VOIDmode, - CONST0_RTX (GET_MODE (comp)), comp); + rtx new = gen_rtx_COMPARE (VOIDmode, CONST0_RTX (GET_MODE (comp)), comp); if (GET_CODE (body) == SET) SET_SRC (body) = new; else @@ -1314,7 +1493,10 @@ change_address (memref, mode, addr) else addr = memory_address (mode, addr); - new = gen_rtx (MEM, mode, addr); + if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref)) + return memref; + + new = gen_rtx_MEM (mode, addr); MEM_VOLATILE_P (new) = MEM_VOLATILE_P (memref); RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (memref); MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (memref); @@ -1328,9 +1510,8 @@ gen_label_rtx () { register rtx label; - label = (output_bytecode - ? gen_rtx (CODE_LABEL, VOIDmode, NULL, bc_get_bytecode_label ()) - : gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, label_num++, NULL_PTR)); + label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX, + NULL_RTX, label_num++, NULL_PTR); LABEL_NUSES (label) = 0; return label; @@ -1346,7 +1527,8 @@ gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size, pops_args, stack_slots, forced_labels, function_flags, outgoing_args_size, original_arg_vector, - original_decl_initial) + original_decl_initial, regno_rtx, regno_flag, + regno_align, parm_reg_stack_loc) rtx first_insn, first_parm_insn; int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size; int pops_args; @@ -1356,27 +1538,43 @@ gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno, int outgoing_args_size; rtvec original_arg_vector; rtx original_decl_initial; -{ - rtx header = gen_rtx (INLINE_HEADER, VOIDmode, - cur_insn_uid++, NULL_RTX, - first_insn, first_parm_insn, - first_labelno, last_labelno, - max_parm_regnum, max_regnum, args_size, pops_args, - stack_slots, forced_labels, function_flags, - outgoing_args_size, - original_arg_vector, original_decl_initial); + rtvec regno_rtx; + char *regno_flag; + char *regno_align; + rtvec parm_reg_stack_loc; +{ + rtx header = gen_rtx_INLINE_HEADER (VOIDmode, + cur_insn_uid++, NULL_RTX, + first_insn, first_parm_insn, + first_labelno, last_labelno, + max_parm_regnum, max_regnum, args_size, + pops_args, stack_slots, forced_labels, + function_flags, outgoing_args_size, + original_arg_vector, + original_decl_initial, + regno_rtx, regno_flag, regno_align, + parm_reg_stack_loc); return header; } /* Install new pointers to the first and last insns in the chain. + Also, set cur_insn_uid to one higher than the last in use. Used for an inline-procedure after copying the insn chain. */ void set_new_first_and_last_insn (first, last) rtx first, last; { + rtx insn; + first_insn = first; last_insn = last; + cur_insn_uid = 0; + + for (insn = first; insn; insn = NEXT_INSN (insn)) + cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn)); + + cur_insn_uid++; } /* Set the range of label numbers found in the current function. @@ -1408,6 +1606,7 @@ save_emit_status (p) p->last_linenum = last_linenum; p->last_filename = last_filename; p->regno_pointer_flag = regno_pointer_flag; + p->regno_pointer_align = regno_pointer_align; p->regno_pointer_flag_length = regno_pointer_flag_length; p->regno_reg_rtx = regno_reg_rtx; } @@ -1432,13 +1631,17 @@ restore_emit_status (p) last_linenum = p->last_linenum; last_filename = p->last_filename; regno_pointer_flag = p->regno_pointer_flag; + regno_pointer_align = p->regno_pointer_align; regno_pointer_flag_length = p->regno_pointer_flag_length; regno_reg_rtx = p->regno_reg_rtx; - /* Clear our cache of rtx expressions for start_sequence and gen_sequence. */ + /* Clear our cache of rtx expressions for start_sequence and + gen_sequence. */ sequence_element_free_list = 0; for (i = 0; i < SEQUENCE_RESULT_SIZE; i++) sequence_result[i] = 0; + + free_insn = 0; } /* Go through all the RTL insn bodies and copy any invalid shared structure. @@ -1500,7 +1703,7 @@ copy_rtx_if_shared (orig) case PC: case CC0: case SCRATCH: - /* SCRATCH must be shared because they represent distinct values. */ + /* SCRATCH must be shared because they represent distinct values. */ return x; case CONST: @@ -1540,6 +1743,10 @@ copy_rtx_if_shared (orig) x->used = 1; return x; } + break; + + default: + break; } /* This rtx may not be shared. If it has already been seen, @@ -1580,7 +1787,7 @@ copy_rtx_if_shared (orig) int len = XVECLEN (x, i); if (copied && len > 0) - XVEC (x, i) = gen_rtvec_v (len, &XVECEXP (x, i, 0)); + XVEC (x, i) = gen_rtvec_vv (len, XVEC (x, i)->elem); for (j = 0; j < len; j++) XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j)); } @@ -1629,6 +1836,9 @@ reset_used_flags (x) case BARRIER: /* The chain of insns is not being copied. */ return; + + default: + break; } x->used = 0; @@ -1811,7 +2021,7 @@ prev_nonnote_insn (insn) /* Return the next INSN, CALL_INSN or JUMP_INSN after INSN; or 0, if there is none. This routine does not look inside - SEQUENCEs. */ + SEQUENCEs. */ rtx next_real_insn (insn) @@ -1938,9 +2148,8 @@ link_cc0_insns (insn) if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE) user = XVECEXP (PATTERN (user), 0, 0); - REG_NOTES (user) = gen_rtx (INSN_LIST, REG_CC_SETTER, insn, - REG_NOTES (user)); - REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_CC_USER, user, REG_NOTES (insn)); + REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn, REG_NOTES (user)); + REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn)); } /* Return the next insn that uses CC0 after INSN, which is assumed to @@ -1980,7 +2189,6 @@ prev_cc0_setter (insn) rtx insn; { rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); - rtx link; if (note) return XEXP (note, 0); @@ -2086,9 +2294,17 @@ make_insn_raw (pattern) { register rtx insn; - insn = rtx_alloc (INSN); - INSN_UID (insn) = cur_insn_uid++; + /* If in RTL generation phase, see if FREE_INSN can be used. */ + if (free_insn != 0 && rtx_equal_function_value_matters) + { + insn = free_insn; + free_insn = NEXT_INSN (free_insn); + PUT_CODE (insn, INSN); + } + else + insn = rtx_alloc (INSN); + INSN_UID (insn) = cur_insn_uid++; PATTERN (insn) = pattern; INSN_CODE (insn) = -1; LOG_LINKS (insn) = NULL; @@ -2776,13 +2992,6 @@ emit_line_note (file, line) char *file; int line; { - if (output_bytecode) - { - /* FIXME: for now we do nothing, but eventually we will have to deal with - debugging information. */ - return 0; - } - emit_filename = file; emit_lineno = line; @@ -2975,7 +3184,7 @@ push_to_sequence (first) void push_topmost_sequence () { - struct sequence_stack *stack, *top; + struct sequence_stack *stack, *top = NULL; start_sequence (); @@ -2993,7 +3202,7 @@ push_topmost_sequence () void pop_topmost_sequence () { - struct sequence_stack *stack, *top; + struct sequence_stack *stack, *top = NULL; for (stack = sequence_stack; stack; stack = stack->next) top = stack; @@ -3055,12 +3264,17 @@ gen_sequence () (Now that we cache SEQUENCE expressions, it isn't worth special-casing the case of an empty list.) */ if (len == 1 + && ! RTX_FRAME_RELATED_P (first_insn) && (GET_CODE (first_insn) == INSN || GET_CODE (first_insn) == JUMP_INSN /* Don't discard the call usage field. */ || (GET_CODE (first_insn) == CALL_INSN && CALL_INSN_FUNCTION_USAGE (first_insn) == NULL_RTX))) - return PATTERN (first_insn); + { + NEXT_INSN (first_insn) = free_insn; + free_insn = first_insn; + return PATTERN (first_insn); + } /* Put them in a vector. See if we already have a SEQUENCE of the appropriate length around. */ @@ -3072,7 +3286,7 @@ gen_sequence () cache it. */ push_obstacks_nochange (); rtl_in_saveable_obstack (); - result = gen_rtx (SEQUENCE, VOIDmode, rtvec_alloc (len)); + result = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (len)); pop_obstacks (); } @@ -3082,145 +3296,6 @@ gen_sequence () return result; } -/* Set up regno_reg_rtx, reg_rtx_no and regno_pointer_flag - according to the chain of insns starting with FIRST. - - Also set cur_insn_uid to exceed the largest uid in that chain. - - This is used when an inline function's rtl is saved - and passed to rest_of_compilation later. */ - -static void restore_reg_data_1 (); - -void -restore_reg_data (first) - rtx first; -{ - register rtx insn; - int i; - register int max_uid = 0; - - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - if (INSN_UID (insn) >= max_uid) - max_uid = INSN_UID (insn); - - switch (GET_CODE (insn)) - { - case NOTE: - case CODE_LABEL: - case BARRIER: - break; - - case JUMP_INSN: - case CALL_INSN: - case INSN: - restore_reg_data_1 (PATTERN (insn)); - break; - } - } - - /* Don't duplicate the uids already in use. */ - cur_insn_uid = max_uid + 1; - - /* If any regs are missing, make them up. - - ??? word_mode is not necessarily the right mode. Most likely these REGs - are never used. At some point this should be checked. */ - - for (i = FIRST_PSEUDO_REGISTER; i < reg_rtx_no; i++) - if (regno_reg_rtx[i] == 0) - regno_reg_rtx[i] = gen_rtx (REG, word_mode, i); -} - -static void -restore_reg_data_1 (orig) - rtx orig; -{ - register rtx x = orig; - register int i; - register enum rtx_code code; - register char *format_ptr; - - code = GET_CODE (x); - - switch (code) - { - case QUEUED: - case CONST_INT: - case CONST_DOUBLE: - case SYMBOL_REF: - case CODE_LABEL: - case PC: - case CC0: - case LABEL_REF: - return; - - case REG: - if (REGNO (x) >= FIRST_PSEUDO_REGISTER) - { - /* Make sure regno_pointer_flag and regno_reg_rtx are large - enough to have an element for this pseudo reg number. */ - if (REGNO (x) >= reg_rtx_no) - { - reg_rtx_no = REGNO (x); - - if (reg_rtx_no >= regno_pointer_flag_length) - { - int newlen = MAX (regno_pointer_flag_length * 2, - reg_rtx_no + 30); - rtx *new1; - char *new = (char *) oballoc (newlen); - bzero (new, newlen); - bcopy (regno_pointer_flag, new, regno_pointer_flag_length); - - new1 = (rtx *) oballoc (newlen * sizeof (rtx)); - bzero ((char *) new1, newlen * sizeof (rtx)); - bcopy ((char *) regno_reg_rtx, (char *) new1, - regno_pointer_flag_length * sizeof (rtx)); - - regno_pointer_flag = new; - regno_reg_rtx = new1; - regno_pointer_flag_length = newlen; - } - reg_rtx_no ++; - } - regno_reg_rtx[REGNO (x)] = x; - } - return; - - case MEM: - if (GET_CODE (XEXP (x, 0)) == REG) - mark_reg_pointer (XEXP (x, 0)); - restore_reg_data_1 (XEXP (x, 0)); - return; - } - - /* Now scan the subexpressions recursively. */ - - format_ptr = GET_RTX_FORMAT (code); - - for (i = 0; i < GET_RTX_LENGTH (code); i++) - { - switch (*format_ptr++) - { - case 'e': - restore_reg_data_1 (XEXP (x, i)); - break; - - case 'E': - if (XVEC (x, i) != NULL) - { - register int j; - - for (j = 0; j < XVECLEN (x, i); j++) - restore_reg_data_1 (XVECEXP (x, i, j)); - } - break; - } - } -} - /* Initialize data structures and variables in this file before generating rtl for each function. */ @@ -3244,17 +3319,22 @@ init_emit () sequence_element_free_list = 0; for (i = 0; i < SEQUENCE_RESULT_SIZE; i++) sequence_result[i] = 0; + free_insn = 0; /* Init the tables that describe all the pseudo regs. */ regno_pointer_flag_length = LAST_VIRTUAL_REGISTER + 101; regno_pointer_flag - = (char *) oballoc (regno_pointer_flag_length); + = (char *) savealloc (regno_pointer_flag_length); bzero (regno_pointer_flag, regno_pointer_flag_length); + regno_pointer_align + = (char *) savealloc (regno_pointer_flag_length); + bzero (regno_pointer_align, regno_pointer_flag_length); + regno_reg_rtx - = (rtx *) oballoc (regno_pointer_flag_length * sizeof (rtx)); + = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx)); bzero ((char *) regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx)); /* Put copies of all the virtual register rtx into regno_reg_rtx. */ @@ -3275,6 +3355,23 @@ init_emit () REGNO_POINTER_FLAG (VIRTUAL_STACK_DYNAMIC_REGNUM) = 1; REGNO_POINTER_FLAG (VIRTUAL_OUTGOING_ARGS_REGNUM) = 1; +#ifdef STACK_BOUNDARY + REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT; + + REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; + REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM) + = STACK_BOUNDARY / BITS_PER_UNIT; +#endif + #ifdef INIT_EXPANDERS INIT_EXPANDERS; #endif @@ -3289,6 +3386,7 @@ init_emit_once (line_numbers) { int i; enum machine_mode mode; + enum machine_mode double_mode; no_line_numbers = ! line_numbers; @@ -3298,6 +3396,7 @@ init_emit_once (line_numbers) byte_mode = VOIDmode; word_mode = VOIDmode; + double_mode = VOIDmode; for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) @@ -3311,35 +3410,39 @@ init_emit_once (line_numbers) word_mode = mode; } +#ifndef DOUBLE_TYPE_SIZE +#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) +#endif + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE + && double_mode == VOIDmode) + double_mode = mode; + } + ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0); /* Create the unique rtx's for certain rtx codes and operand values. */ - pc_rtx = gen_rtx (PC, VOIDmode); - cc0_rtx = gen_rtx (CC0, VOIDmode); - - /* Don't use gen_rtx here since gen_rtx in this case - tries to use these variables. */ for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++) { - const_int_rtx[i + MAX_SAVED_CONST_INT] = rtx_alloc (CONST_INT); - PUT_MODE (const_int_rtx[i + MAX_SAVED_CONST_INT], VOIDmode); - INTVAL (const_int_rtx[i + MAX_SAVED_CONST_INT]) = i; + PUT_CODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], CONST_INT); + PUT_MODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], VOIDmode); + INTVAL (&const_int_rtx[i + MAX_SAVED_CONST_INT]) = i; } - /* These four calls obtain some of the rtx expressions made above. */ - const0_rtx = GEN_INT (0); - const1_rtx = GEN_INT (1); - const2_rtx = GEN_INT (2); - constm1_rtx = GEN_INT (-1); - - /* This will usually be one of the above constants, but may be a new rtx. */ - const_true_rtx = GEN_INT (STORE_FLAG_VALUE); + if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT + && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT) + const_true_rtx = &const_int_rtx[STORE_FLAG_VALUE + MAX_SAVED_CONST_INT]; + else + const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE); - dconst0 = REAL_VALUE_ATOF ("0", DFmode); - dconst1 = REAL_VALUE_ATOF ("1", DFmode); - dconst2 = REAL_VALUE_ATOF ("2", DFmode); - dconstm1 = REAL_VALUE_ATOF ("-1", DFmode); + dconst0 = REAL_VALUE_ATOF ("0", double_mode); + dconst1 = REAL_VALUE_ATOF ("1", double_mode); + dconst2 = REAL_VALUE_ATOF ("2", double_mode); + dconstm1 = REAL_VALUE_ATOF ("-1", double_mode); for (i = 0; i <= 2; i++) { @@ -3375,39 +3478,42 @@ init_emit_once (line_numbers) mode = GET_MODE_WIDER_MODE (mode)) const_tiny_rtx[0][(int) mode] = const0_rtx; - stack_pointer_rtx = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM); - frame_pointer_rtx = gen_rtx (REG, Pmode, FRAME_POINTER_REGNUM); - if (HARD_FRAME_POINTER_REGNUM == FRAME_POINTER_REGNUM) - hard_frame_pointer_rtx = frame_pointer_rtx; - else - hard_frame_pointer_rtx = gen_rtx (REG, Pmode, HARD_FRAME_POINTER_REGNUM); - - if (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM) - arg_pointer_rtx = frame_pointer_rtx; - else if (HARD_FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM) - arg_pointer_rtx = hard_frame_pointer_rtx; - else if (STACK_POINTER_REGNUM == ARG_POINTER_REGNUM) - arg_pointer_rtx = stack_pointer_rtx; - else - arg_pointer_rtx = gen_rtx (REG, Pmode, ARG_POINTER_REGNUM); + /* Assign register numbers to the globally defined register rtx. + This must be done at runtime because the register number field + is in a union and some compilers can't initialize unions. */ - /* Create the virtual registers. Do so here since the following objects - might reference them. */ + REGNO (stack_pointer_rtx) = STACK_POINTER_REGNUM; + PUT_MODE (stack_pointer_rtx, Pmode); + REGNO (frame_pointer_rtx) = FRAME_POINTER_REGNUM; + PUT_MODE (frame_pointer_rtx, Pmode); +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + REGNO (hard_frame_pointer_rtx) = HARD_FRAME_POINTER_REGNUM; + PUT_MODE (hard_frame_pointer_rtx, Pmode); +#endif +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + REGNO (arg_pointer_rtx) = ARG_POINTER_REGNUM; + PUT_MODE (arg_pointer_rtx, Pmode); +#endif - virtual_incoming_args_rtx = gen_rtx (REG, Pmode, - VIRTUAL_INCOMING_ARGS_REGNUM); - virtual_stack_vars_rtx = gen_rtx (REG, Pmode, - VIRTUAL_STACK_VARS_REGNUM); - virtual_stack_dynamic_rtx = gen_rtx (REG, Pmode, - VIRTUAL_STACK_DYNAMIC_REGNUM); - virtual_outgoing_args_rtx = gen_rtx (REG, Pmode, - VIRTUAL_OUTGOING_ARGS_REGNUM); + REGNO (virtual_incoming_args_rtx) = VIRTUAL_INCOMING_ARGS_REGNUM; + PUT_MODE (virtual_incoming_args_rtx, Pmode); + REGNO (virtual_stack_vars_rtx) = VIRTUAL_STACK_VARS_REGNUM; + PUT_MODE (virtual_stack_vars_rtx, Pmode); + REGNO (virtual_stack_dynamic_rtx) = VIRTUAL_STACK_DYNAMIC_REGNUM; + PUT_MODE (virtual_stack_dynamic_rtx, Pmode); + REGNO (virtual_outgoing_args_rtx) = VIRTUAL_OUTGOING_ARGS_REGNUM; + PUT_MODE (virtual_outgoing_args_rtx, Pmode); + +#ifdef RETURN_ADDRESS_POINTER_REGNUM + return_address_pointer_rtx + = gen_rtx_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM); +#endif #ifdef STRUCT_VALUE struct_value_rtx = STRUCT_VALUE; #else - struct_value_rtx = gen_rtx (REG, Pmode, STRUCT_VALUE_REGNUM); + struct_value_rtx = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM); #endif #ifdef STRUCT_VALUE_INCOMING @@ -3415,18 +3521,18 @@ init_emit_once (line_numbers) #else #ifdef STRUCT_VALUE_INCOMING_REGNUM struct_value_incoming_rtx - = gen_rtx (REG, Pmode, STRUCT_VALUE_INCOMING_REGNUM); + = gen_rtx_REG (Pmode, STRUCT_VALUE_INCOMING_REGNUM); #else struct_value_incoming_rtx = struct_value_rtx; #endif #endif #ifdef STATIC_CHAIN_REGNUM - static_chain_rtx = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM); + static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); #ifdef STATIC_CHAIN_INCOMING_REGNUM if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM) - static_chain_incoming_rtx = gen_rtx (REG, Pmode, STATIC_CHAIN_INCOMING_REGNUM); + static_chain_incoming_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM); else #endif static_chain_incoming_rtx = static_chain_rtx; @@ -3443,6 +3549,28 @@ init_emit_once (line_numbers) #endif #ifdef PIC_OFFSET_TABLE_REGNUM - pic_offset_table_rtx = gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM); + pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); #endif } + +/* Query and clear/ restore no_line_numbers. This is used by the + switch / case handling in stmt.c to give proper line numbers in + warnings about unreachable code. */ + +int +force_line_numbers () +{ + int old = no_line_numbers; + + no_line_numbers = 0; + if (old) + force_next_line_note (); + return old; +} + +void +restore_line_number_status (old_value) + int old_value; +{ + no_line_numbers = old_value; +} |