diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0d4cf53b294..efc4457668b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,20 @@ Sun Sep 20 19:01:51 1998 Richard Henderson + * alpha.c (alpha_sr_alias_set): New variable. + (override_options): Set it. + (alpha_expand_prologue, alpha_expand_epilogue): Use it. + (mode_mask_operand): Fix signed-unsigned comparision warning. + (alpha_expand_block_move): Likewise. + (print_operand): Likewise. + (get_aligned_mem): Use change_address. + (alpha_set_memflags, alpha_set_memflags_1): Set the alias set. + (alphaev4_insn_pipe, alphaev4_next_group): New functions. + (alphaev4_next_nop, alphaev5_next_nop): New functions. + (alpha_align_insns): Remade from old alphaev5_align_insns + to handle multiple processors. + (alpha_reorg): Call alpha_align_insns for both ev4 and ev5. + * output.h (label_to_alignment): Prototype. + * tree.c (new_alias_set): New function. * tree.h (new_alias_set): Declare it. * c-common.c (c_get_alias_set): Use it. diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index e4a1f17b3e6..d8f71ad4230 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -100,9 +100,13 @@ int alpha_memory_latency = 3; static int alpha_function_needs_gp; +/* The alias set for prologue/epilogue register save/restore. */ + +static int alpha_sr_alias_set; + /* Declarations of static functions. */ static void alpha_set_memflags_1 - PROTO((rtx, int, int, int)); + PROTO((rtx, int, int, int, int)); static rtx alpha_emit_set_const_1 PROTO((rtx, enum machine_mode, HOST_WIDE_INT, int)); static void alpha_expand_unaligned_load_words @@ -302,6 +306,9 @@ override_options () /* Default the definition of "small data" to 8 bytes. */ if (!g_switch_set) g_switch_value = 8; + + /* Acquire a unique set number for our register saves and restores. */ + alpha_sr_alias_set = new_alias_set (); } /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */ @@ -487,9 +494,9 @@ mode_mask_operand (op, mode) return (GET_CODE (op) == CONST_INT && (INTVAL (op) == 0xff || INTVAL (op) == 0xffff - || INTVAL (op) == 0xffffffff + || INTVAL (op) == (HOST_WIDE_INT)0xffffffff #if HOST_BITS_PER_WIDE_INT == 64 - || INTVAL (op) == 0xffffffffffffffff + || INTVAL (op) == -1 #endif )); } @@ -870,11 +877,8 @@ get_aligned_mem (ref, paligned_mem, pbitnum) if (GET_CODE (base) == PLUS) offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); - *paligned_mem = gen_rtx_MEM (SImode, - plus_constant (base, offset & ~3)); - MEM_IN_STRUCT_P (*paligned_mem) = MEM_IN_STRUCT_P (ref); - MEM_VOLATILE_P (*paligned_mem) = MEM_VOLATILE_P (ref); - RTX_UNCHANGING_P (*paligned_mem) = RTX_UNCHANGING_P (ref); + *paligned_mem = change_address (ref, SImode, + plus_constant (base, offset & ~3)); *pbitnum = GEN_INT ((offset & 3) * 8); } @@ -918,9 +922,9 @@ get_unaligned_address (ref, extra_offset) found in part of X. */ static void -alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p) +alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p, alias_set) rtx x; - int in_struct_p, volatile_p, unchanging_p; + int in_struct_p, volatile_p, unchanging_p, alias_set; { int i; @@ -930,25 +934,26 @@ alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p) case PARALLEL: for (i = XVECLEN (x, 0) - 1; i >= 0; i--) alpha_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p, - unchanging_p); + unchanging_p, alias_set); break; case INSN: alpha_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p, - unchanging_p); + unchanging_p, alias_set); break; case SET: alpha_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p, - unchanging_p); + unchanging_p, alias_set); alpha_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p, - unchanging_p); + unchanging_p, alias_set); break; case MEM: MEM_IN_STRUCT_P (x) = in_struct_p; MEM_VOLATILE_P (x) = volatile_p; RTX_UNCHANGING_P (x) = unchanging_p; + MEM_ALIAS_SET (x) = alias_set; break; default: @@ -967,17 +972,24 @@ alpha_set_memflags (insn, ref) rtx insn; rtx ref; { - /* Note that it is always safe to get these flags, though they won't - be what we think if REF is not a MEM. */ - int in_struct_p = MEM_IN_STRUCT_P (ref); - int volatile_p = MEM_VOLATILE_P (ref); - int unchanging_p = RTX_UNCHANGING_P (ref); + int in_struct_p, volatile_p, unchanging_p, alias_set; - if (GET_CODE (ref) != MEM - || (! in_struct_p && ! volatile_p && ! unchanging_p)) + if (GET_CODE (ref) != MEM) return; - alpha_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p); + in_struct_p = MEM_IN_STRUCT_P (ref); + volatile_p = MEM_VOLATILE_P (ref); + unchanging_p = RTX_UNCHANGING_P (ref); + alias_set = MEM_ALIAS_SET (ref); + + /* This is only called from alpha.md, after having had something + generated from one of the insn patterns. So if everything is + zero, the pattern is already up-to-date. */ + if (! in_struct_p && ! volatile_p && ! unchanging_p && ! alias_set) + return; + + alpha_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p, + alias_set); } /* Try to output insns to set TARGET equal to the constant C if it can be @@ -1979,7 +1991,7 @@ alpha_expand_block_move (operands) } src_done: - if (nregs > sizeof(data_regs)/sizeof(*data_regs)) + if (nregs > (int)(sizeof(data_regs)/sizeof(*data_regs))) abort(); /* @@ -2730,7 +2742,7 @@ print_operand (file, x, code) && CONST_DOUBLE_LOW (x) == -1) fprintf (file, "q"); #else - else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffffffffffff) + else if (GET_CODE (x) == CONST_INT && INTVAL (x) == -1) fprintf (file, "q"); else if (GET_CODE (x) == CONST_DOUBLE && CONST_DOUBLE_HIGH (x) == 0 @@ -3253,7 +3265,7 @@ alpha_expand_prologue () HOST_WIDE_INT frame_size; /* Offset from base reg to register save area. */ HOST_WIDE_INT reg_offset; - rtx sa_reg; + rtx sa_reg, mem; int i; sa_size = alpha_sa_size (); @@ -3367,16 +3379,17 @@ alpha_expand_prologue () /* Save regs in stack order. Beginning with VMS PV. */ if (TARGET_OPEN_VMS && vms_is_stack_procedure) { - FRP (emit_move_insn (gen_rtx_MEM (DImode, stack_pointer_rtx), - gen_rtx_REG (DImode, REG_PV))); + mem = gen_rtx_MEM (DImode, stack_pointer_rtx); + MEM_ALIAS_SET (mem) = alpha_sr_alias_set; + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV))); } /* Save register RA next. */ if (imask & (1L << REG_RA)) { - FRP (emit_move_insn (gen_rtx_MEM (DImode, - plus_constant (sa_reg, reg_offset)), - gen_rtx_REG (DImode, REG_RA))); + mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); + MEM_ALIAS_SET (mem) = alpha_sr_alias_set; + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA))); imask &= ~(1L << REG_RA); reg_offset += 8; } @@ -3385,18 +3398,18 @@ alpha_expand_prologue () for (i = 0; i < 32; i++) if (imask & (1L << i)) { - FRP (emit_move_insn (gen_rtx_MEM (DImode, - plus_constant (sa_reg, reg_offset)), - gen_rtx_REG (DImode, i))); + mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); + MEM_ALIAS_SET (mem) = alpha_sr_alias_set; + FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i))); reg_offset += 8; } for (i = 0; i < 32; i++) if (fmask & (1L << i)) { - FRP (emit_move_insn (gen_rtx_MEM (DFmode, - plus_constant (sa_reg, reg_offset)), - gen_rtx_REG (DFmode, i+32))); + mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset)); + MEM_ALIAS_SET (mem) = alpha_sr_alias_set; + FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32))); reg_offset += 8; } @@ -3675,7 +3688,7 @@ alpha_expand_epilogue () HOST_WIDE_INT reg_offset; int fp_is_frame_pointer, fp_offset; rtx sa_reg, sa_reg_exp = NULL; - rtx sp_adj1, sp_adj2; + rtx sp_adj1, sp_adj2, mem; int i; sa_size = alpha_sa_size (); @@ -3734,10 +3747,9 @@ alpha_expand_epilogue () if (! alpha_eh_epilogue_sp_ofs) { - FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), - gen_rtx_MEM (DImode, - plus_constant(sa_reg, - reg_offset)))); + mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset)); + MEM_ALIAS_SET (mem) = alpha_sr_alias_set; + FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem)); } reg_offset += 8; imask &= ~(1L << REG_RA); @@ -3749,10 +3761,9 @@ alpha_expand_epilogue () fp_offset = reg_offset; else { - FRP (emit_move_insn (gen_rtx_REG (DImode, i), - gen_rtx_MEM (DImode, - plus_constant(sa_reg, - reg_offset)))); + mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset)); + MEM_ALIAS_SET (mem) = alpha_sr_alias_set; + FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem)); } reg_offset += 8; } @@ -3760,10 +3771,9 @@ alpha_expand_epilogue () for (i = 0; i < 32; ++i) if (fmask & (1L << i)) { - FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), - gen_rtx_MEM (DFmode, - plus_constant(sa_reg, - reg_offset)))); + mem = gen_rtx_MEM (DFmode, plus_constant(sa_reg, reg_offset)); + MEM_ALIAS_SET (mem) = alpha_sr_alias_set; + FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem)); reg_offset += 8; } } @@ -3820,9 +3830,9 @@ alpha_expand_epilogue () if (fp_is_frame_pointer) { emit_insn (gen_blockage ()); - FRP (emit_move_insn (hard_frame_pointer_rtx, - gen_rtx_MEM (DImode, - plus_constant(sa_reg, fp_offset)))); + mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, fp_offset)); + MEM_ALIAS_SET (mem) = alpha_sr_alias_set; + FRP (emit_move_insn (hard_frame_pointer_rtx, mem)); } else if (TARGET_OPEN_VMS) { @@ -4281,6 +4291,13 @@ alpha_handle_trap_shadows (insns) /* Alpha can only issue instruction groups simultaneously if they are suitibly aligned. This is very processor-specific. */ +enum alphaev4_pipe { + EV4_STOP = 0, + EV4_IB0 = 1, + EV4_IB1 = 2, + EV4_IBX = 4 +}; + enum alphaev5_pipe { EV5_STOP = 0, EV5_NONE = 1, @@ -4292,6 +4309,58 @@ enum alphaev5_pipe { EV5_FM = 64 }; +static enum alphaev4_pipe alphaev4_insn_pipe PROTO((rtx)); +static enum alphaev5_pipe alphaev5_insn_pipe PROTO((rtx)); +static rtx alphaev4_next_group PROTO((rtx, int*, int*)); +static rtx alphaev5_next_group PROTO((rtx, int*, int*)); +static rtx alphaev4_next_nop PROTO((int*)); +static rtx alphaev5_next_nop PROTO((int*)); + +static void alpha_align_insns + PROTO((rtx, int, rtx (*)(rtx, int*, int*), rtx (*)(int*), int)); + +static enum alphaev4_pipe +alphaev4_insn_pipe (insn) + rtx insn; +{ + if (recog_memoized (insn) < 0) + return EV4_STOP; + if (get_attr_length (insn) != 4) + return EV4_STOP; + + switch (get_attr_type (insn)) + { + case TYPE_ILD: + case TYPE_FLD: + return EV4_IBX; + + case TYPE_LDSYM: + case TYPE_IADD: + case TYPE_ILOG: + case TYPE_ICMOV: + case TYPE_ICMP: + case TYPE_IST: + case TYPE_FST: + case TYPE_SHIFT: + case TYPE_IMUL: + case TYPE_FBR: + return EV4_IB0; + + case TYPE_MISC: + case TYPE_IBR: + case TYPE_JSR: + case TYPE_FCPYS: + case TYPE_FCMOV: + case TYPE_FADD: + case TYPE_FDIV: + case TYPE_FMUL: + return EV4_IB1; + + default: + abort(); + } +} + static enum alphaev5_pipe alphaev5_insn_pipe (insn) rtx insn; @@ -4341,10 +4410,109 @@ alphaev5_insn_pipe (insn) } } -/* IN_USE is a mask of the slots currently filled within the - insn group. The mask bits come from alphaev5_pipe above. - If EV5_E01 is set, then the insn in EV5_E0 can be swapp - by the hardware into EV5_E1. +/* IN_USE is a mask of the slots currently filled within the insn group. + The mask bits come from alphaev4_pipe above. If EV4_IBX is set, then + the insn in EV4_IB0 can be swapped by the hardware into EV4_IB1. + + LEN is, of course, the length of the group in bytes. */ + +static rtx +alphaev4_next_group (insn, pin_use, plen) + rtx insn; + int *pin_use, *plen; +{ + int len, in_use; + + len = in_use = 0; + + if (GET_RTX_CLASS (GET_CODE (insn)) != 'i' + || GET_CODE (PATTERN (insn)) == CLOBBER + || GET_CODE (PATTERN (insn)) == USE) + goto next_and_done; + + while (1) + { + enum alphaev4_pipe pipe; + + pipe = alphaev4_insn_pipe (insn); + switch (pipe) + { + case EV4_STOP: + /* Force complex instructions to start new groups. */ + if (in_use) + goto done; + + /* If this is a completely unrecognized insn, its an asm. + We don't know how long it is, so record length as -1 to + signal a needed realignment. */ + if (recog_memoized (insn) < 0) + len = -1; + else + len = get_attr_length (insn); + goto next_and_done; + + case EV4_IBX: + if (in_use & EV4_IB0) + { + if (in_use & EV4_IB1) + goto done; + in_use |= EV4_IB1; + } + else + in_use |= EV4_IB0 | EV4_IBX; + break; + + case EV4_IB0: + if (in_use & EV4_IB0) + { + if (!(in_use & EV4_IBX) || (in_use & EV4_IB1)) + goto done; + in_use |= EV4_IB1; + } + in_use |= EV4_IB0; + break; + + case EV4_IB1: + if (in_use & EV4_IB1) + goto done; + in_use |= EV4_IB1; + break; + + default: + abort(); + } + len += 4; + + /* Haifa doesn't do well scheduling branches. */ + if (GET_CODE (insn) == JUMP_INSN) + goto next_and_done; + + next: + insn = next_nonnote_insn (insn); + + if (!insn || GET_RTX_CLASS (GET_CODE (insn)) != 'i') + goto done; + + /* Let Haifa tell us where it thinks insn group boundaries are. */ + if (GET_MODE (insn) == TImode) + goto done; + + if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE) + goto next; + } + + next_and_done: + insn = next_nonnote_insn (insn); + + done: + *plen = len; + *pin_use = in_use; + return insn; +} + +/* IN_USE is a mask of the slots currently filled within the insn group. + The mask bits come from alphaev5_pipe above. If EV5_E01 is set, then + the insn in EV5_E0 can be swapped by the hardware into EV5_E1. LEN is, of course, the length of the group in bytes. */ @@ -4402,7 +4570,7 @@ alphaev5_next_group (insn, pin_use, plen) case EV5_E0: if (in_use & EV5_E0) { - if (!(in_use & EV5_E01) || in_use & EV5_E1) + if (!(in_use & EV5_E01) || (in_use & EV5_E1)) goto done; in_use |= EV5_E1; } @@ -4475,9 +4643,73 @@ alphaev5_next_group (insn, pin_use, plen) return insn; } +static rtx +alphaev4_next_nop (pin_use) + int *pin_use; +{ + int in_use = *pin_use; + rtx nop; + + if (!(in_use & EV4_IB0)) + { + in_use |= EV4_IB0; + nop = gen_nop (); + } + else if ((in_use & (EV4_IBX|EV4_IB1)) == EV4_IBX) + { + in_use |= EV4_IB1; + nop = gen_nop (); + } + else if (TARGET_FP && !(in_use & EV4_IB1)) + { + in_use |= EV4_IB1; + nop = gen_fnop (); + } + else + nop = gen_unop (); + + *pin_use = in_use; + return nop; +} + +static rtx +alphaev5_next_nop (pin_use) + int *pin_use; +{ + int in_use = *pin_use; + rtx nop; + + if (!(in_use & EV5_E1)) + { + in_use |= EV5_E1; + nop = gen_nop (); + } + else if (TARGET_FP && !(in_use & EV5_FA)) + { + in_use |= EV5_FA; + nop = gen_fnop (); + } + else if (TARGET_FP && !(in_use & EV5_FM)) + { + in_use |= EV5_FM; + nop = gen_fnop (); + } + else + nop = gen_unop (); + + *pin_use = in_use; + return nop; +} + +/* The instruction group alignment main loop. */ + static void -alphaev5_align_insns (insns) +alpha_align_insns (insns, max_align, next_group, next_nop, gp_in_use) rtx insns; + int max_align; + rtx (*next_group) PROTO((rtx, int*, int*)); + rtx (*next_nop) PROTO((int*)); + int gp_in_use; { /* ALIGN is the known alignment for the insn group. */ int align; @@ -4489,14 +4721,17 @@ alphaev5_align_insns (insns) /* Let shorten branches care for assigning alignments to code labels. */ shorten_branches (insns); + /* Account for the initial GP load, which happens before the scheduled + prologue we emitted as RTL. */ ofs = prev_in_use = 0; if (alpha_does_function_need_gp()) { ofs = 8; - prev_in_use = EV5_E01 | EV5_E0; + prev_in_use = gp_in_use; } - align = (FUNCTION_BOUNDARY/BITS_PER_UNIT < 16 - ? FUNCTION_BOUNDARY/BITS_PER_UNIT : 16); + + align = (FUNCTION_BOUNDARY/BITS_PER_UNIT < max_align + ? FUNCTION_BOUNDARY/BITS_PER_UNIT : max_align); i = insns; if (GET_CODE (i) == NOTE) @@ -4504,7 +4739,7 @@ alphaev5_align_insns (insns) while (i) { - next = alphaev5_next_group (i, &in_use, &len); + next = (*next_group)(i, &in_use, &len); /* When we see a label, resync alignment etc. */ if (GET_CODE (i) == CODE_LABEL) @@ -4512,7 +4747,7 @@ alphaev5_align_insns (insns) int new_align = 1 << label_to_alignment (i); if (new_align >= align) { - align = new_align < 16 ? new_align : 16; + align = new_align < max_align ? new_align : max_align; ofs = 0; } else if (ofs & (new_align-1)) @@ -4562,30 +4797,25 @@ alphaev5_align_insns (insns) int nop_count = (align - ofs) / 4; rtx where; + /* Insert nops before labels and branches to truely merge the + execution of the nops with the previous instruction group. */ where = prev_nonnote_insn (i); - if (!where || GET_CODE (where) != CODE_LABEL) + if (where) + { + if (GET_CODE (where) == CODE_LABEL) + { + rtx where2 = prev_nonnote_insn (where); + if (where2 && GET_CODE (where2) == JUMP_INSN) + where = where2; + } + else if (GET_CODE (where) != JUMP_INSN) + where = i; + } + else where = i; do - { - if (!(prev_in_use & EV5_E1)) - { - prev_in_use |= EV5_E1; - emit_insn_before (gen_nop(), where); - } - else if (TARGET_FP && !(prev_in_use & EV5_FA)) - { - prev_in_use |= EV5_FA; - emit_insn_before (gen_fnop(), where); - } - else if (TARGET_FP && !(prev_in_use & EV5_FM)) - { - prev_in_use |= EV5_FM; - emit_insn_before (gen_fnop(), where); - } - else - emit_insn_before (gen_unop(), where); - } + emit_insn_before ((*next_nop)(&prev_in_use), where); while (--nop_count); ofs = 0; } @@ -4614,8 +4844,12 @@ alpha_reorg (insns) && alpha_tp != ALPHA_TP_INSN && flag_schedule_insns_after_reload) { - if (alpha_cpu == PROCESSOR_EV5) - alphaev5_align_insns (insns); + if (alpha_cpu == PROCESSOR_EV4) + alpha_align_insns (insns, 8, alphaev4_next_group, + alphaev4_next_nop, EV4_IB0); + else if (alpha_cpu == PROCESSOR_EV5) + alpha_align_insns (insns, 16, alphaev5_next_group, + alphaev5_next_nop, EV5_E01 | EV5_E0); } #endif } diff --git a/gcc/output.h b/gcc/output.h index e2c9f4dcbf4..1d1a2afd8cd 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -88,6 +88,10 @@ extern void output_asm_insn PROTO((char *, rtx *)); Defined in final.c. */ extern int insn_current_reference_address PROTO((rtx)); +/* Find the alignment associated with a CODE_LABEL. + Defined in final.c. */ +extern int label_to_alignment PROTO((rtx)); + /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */ extern void output_asm_label PROTO((rtx));