Mon Mar 3 19:47:26 2003 J"orn Rennecke * sh.h (OVERRIDE_OPTIONS): Set default values for align_loops and align_jumps if not set. Force align_jumps to be at least 2. When relaxing, force align_functions to be at least the maximum of align_loops, align_jumps and 4. * sh.c (find_barrier, barrier_align): Honour align_jumps_log. (sh_loop_align): Honour align_loops_log. * sh.md (length attribute): Use prev_nonnote_insn instead of PREV_INSN to check for indirect_jump_scratch. (indirect_jump_scratch): Add second set. * sh.c (output_far_jump): Use prev_nonnote_insn instead of PREV_INSN when looking for indirect_jump_scratch. Extract scratch register taking new structure of indirect_jump_scratch into account. (gen_block_redirect): Set INSN_SCOPE for indirect_jump_scratch. Index: config/sh/sh.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.c,v retrieving revision 1.200 diff -p -r1.200 sh.c *** config/sh/sh.c 24 Feb 2003 02:44:01 -0000 1.200 --- config/sh/sh.c 3 Mar 2003 19:25:05 -0000 *************** output_far_jump (insn, op) *** 1048,1053 **** --- 1048,1054 ---- const char *jump; int far; int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn)); + rtx prev; this.lab = gen_label_rtx (); *************** output_far_jump (insn, op) *** 1072,1081 **** jump = "mov.l %O0,%1; jmp @%1"; } /* If we have a scratch register available, use it. */ ! if (GET_CODE (PREV_INSN (insn)) == INSN ! && INSN_CODE (PREV_INSN (insn)) == CODE_FOR_indirect_jump_scratch) { ! this.reg = SET_DEST (PATTERN (PREV_INSN (insn))); if (REGNO (this.reg) == R0_REG && flag_pic && ! TARGET_SH2) jump = "mov.l r1,@-r15; mova %O0,r0; mov.l @r0,r1; add r1,r0; mov.l @r15+,r1; jmp @%1"; output_asm_insn (jump, &this.lab); --- 1073,1082 ---- jump = "mov.l %O0,%1; jmp @%1"; } /* If we have a scratch register available, use it. */ ! if (GET_CODE ((prev = prev_nonnote_insn (insn))) == INSN ! && INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch) { ! this.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0)); if (REGNO (this.reg) == R0_REG && flag_pic && ! TARGET_SH2) jump = "mov.l r1,@-r15; mova %O0,r0; mov.l @r0,r1; add r1,r0; mov.l @r15+,r1; jmp @%1"; output_asm_insn (jump, &this.lab); *************** find_barrier (num_mova, mova, from) *** 3016,3022 **** { if (num_mova) num_mova--; ! if (barrier_align (next_real_insn (from)) == CACHE_LOG) { /* We have just passed the barrier in front of the ADDR_DIFF_VEC, which is stored in found_barrier. Since --- 3017,3023 ---- { if (num_mova) num_mova--; ! if (barrier_align (next_real_insn (from)) == align_jumps_log) { /* We have just passed the barrier in front of the ADDR_DIFF_VEC, which is stored in found_barrier. Since *************** gen_block_redirect (jump, addr, need_blo *** 3454,3459 **** --- 3455,3467 ---- rtx insn = emit_insn_before (gen_indirect_jump_scratch (reg, GEN_INT (INSN_UID (JUMP_LABEL (jump)))) , jump); + /* ??? We would like this to have the scope of the jump, but that + scope will change when a delay slot insn of an inner scope is added. + Hence, after delay slot scheduling, we'll have to expect + NOTE_INSN_BLOCK_END notes between the indirect_jump_scratch and + the jump. */ + + INSN_SCOPE (insn) = INSN_SCOPE (jump); INSN_CODE (insn) = CODE_FOR_indirect_jump_scratch; return insn; } *************** barrier_align (barrier_or_label) *** 3596,3609 **** return ((TARGET_SMALLCODE || ((unsigned) XVECLEN (pat, 1) * GET_MODE_SIZE (GET_MODE (pat)) <= (unsigned)1 << (CACHE_LOG - 2))) ! ? 1 << TARGET_SHMEDIA : CACHE_LOG); } if (TARGET_SMALLCODE) return 0; if (! TARGET_SH2 || ! optimize) ! return CACHE_LOG; /* When fixing up pcloads, a constant table might be inserted just before the basic block that ends with the barrier. Thus, we can't trust the --- 3604,3617 ---- return ((TARGET_SMALLCODE || ((unsigned) XVECLEN (pat, 1) * GET_MODE_SIZE (GET_MODE (pat)) <= (unsigned)1 << (CACHE_LOG - 2))) ! ? 1 << TARGET_SHMEDIA : align_jumps_log); } if (TARGET_SMALLCODE) return 0; if (! TARGET_SH2 || ! optimize) ! return align_jumps_log; /* When fixing up pcloads, a constant table might be inserted just before the basic block that ends with the barrier. Thus, we can't trust the *************** barrier_align (barrier_or_label) *** 3679,3685 **** } } ! return CACHE_LOG; } /* If we are inside a phony loop, almost any kind of label can turn up as the --- 3687,3693 ---- } } ! return align_jumps_log; } /* If we are inside a phony loop, almost any kind of label can turn up as the *************** sh_loop_align (label) *** 3704,3713 **** || recog_memoized (next) == CODE_FOR_consttable_2) return 0; ! if (TARGET_SH5) ! return 3; ! ! return 2; } /* Exported to toplev.c. --- 3712,3718 ---- || recog_memoized (next) == CODE_FOR_consttable_2) return 0; ! return align_loops_log; } /* Exported to toplev.c. *************** split_branches (first) *** 4417,4425 **** If relaxing, output the label and pseudo-ops used to link together calls and the instruction which set the registers. */ - - /* ??? This is unnecessary, and probably should be deleted. This makes - the insn_addresses declaration above unnecessary. */ /* ??? The addresses printed by this routine for insns are nonsense for insns which are inside of a sequence where none of the inner insns have --- 4422,4427 ---- Index: config/sh/sh.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.h,v retrieving revision 1.191 diff -p -r1.191 sh.h *** config/sh/sh.h 24 Feb 2003 02:44:01 -0000 1.191 --- config/sh/sh.h 3 Mar 2003 19:25:05 -0000 *************** do { \ *** 489,494 **** --- 489,501 ---- flag_schedule_insns = 0; \ } \ \ + if (align_loops == 0) \ + align_loops = 1 << (TARGET_SH5 ? 3 : 2); \ + if (align_jumps == 0) \ + align_jumps = 1 << CACHE_LOG; \ + else if (align_jumps <= 1) \ + align_jumps = 2; \ + \ /* Allocation boundary (in *bytes*) for the code of a function. \ SH1: 32 bit alignment is faster, because instructions are always \ fetched as a pair from a longword boundary. \ *************** do { \ *** 496,501 **** --- 503,522 ---- if (align_functions == 0) \ align_functions \ = TARGET_SMALLCODE ? FUNCTION_BOUNDARY/8 : (1 << CACHE_LOG); \ + /* The linker relaxation code breaks when a function contains \ + alignments that are larger than that at the start of a \ + compilation unit. */ \ + if (TARGET_RELAX) \ + { \ + int min_align \ + = align_loops > align_jumps ? align_loops : align_jumps; \ + \ + /* Also take possible .long constants / mova tables int account. */\ + if (min_align < 4) \ + min_align = 4; \ + if (align_functions < min_align) \ + align_functions = min_align; \ + } \ } while (0) /* Target machine storage layout. */ Index: config/sh/sh.md =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.md,v retrieving revision 1.140 diff -p -r1.140 sh.md *** config/sh/sh.md 24 Feb 2003 02:44:02 -0000 1.140 --- config/sh/sh.md 3 Mar 2003 19:25:05 -0000 *************** *** 391,399 **** (eq_attr "type" "jump") (cond [(eq_attr "med_branch_p" "yes") (const_int 2) ! (and (eq (symbol_ref "GET_CODE (PREV_INSN (insn))") (symbol_ref "INSN")) ! (eq (symbol_ref "INSN_CODE (PREV_INSN (insn))") (symbol_ref "code_for_indirect_jump_scratch"))) (if_then_else (eq_attr "braf_branch_p" "yes") (const_int 6) --- 391,399 ---- (eq_attr "type" "jump") (cond [(eq_attr "med_branch_p" "yes") (const_int 2) ! (and (eq (symbol_ref "GET_CODE (prev_nonnote_insn (insn))") (symbol_ref "INSN")) ! (eq (symbol_ref "INSN_CODE (prev_nonnote_insn (insn))") (symbol_ref "code_for_indirect_jump_scratch"))) (if_then_else (eq_attr "braf_branch_p" "yes") (const_int 6) *************** *** 5035,5043 **** ;; This one has the additional purpose to record a possible scratch register ;; for the following branch. (define_insn "indirect_jump_scratch" [(set (match_operand:SI 0 "register_operand" "=r") ! (unspec:SI [(match_operand 1 "const_int_operand" "")] UNSPEC_BBR))] "TARGET_SH1" "" [(set_attr "length" "0")]) --- 5035,5048 ---- ;; This one has the additional purpose to record a possible scratch register ;; for the following branch. + ;; ??? Unfortunately, just setting the scratch register is not good enough, + ;; because the insn then might be deemed dead and deleted. And we can't + ;; make the use in the jump insn explicit because that would disable + ;; delay slot scheduling from the target. (define_insn "indirect_jump_scratch" [(set (match_operand:SI 0 "register_operand" "=r") ! (unspec:SI [(match_operand 1 "const_int_operand" "")] UNSPEC_BBR)) ! (set (pc) (unspec [(const_int 0)] UNSPEC_BBR))] "TARGET_SH1" "" [(set_attr "length" "0")]) *************** *** 5474,5479 **** --- 5479,5497 ---- }" [(set_attr "type" "jump") (set_attr "needs_delay_slot" "yes")]) + + ;; ??? It would be much saner to explicitly use the scratch register + ;; in the jump insn, and have indirect_jump_scratch only set it, + ;; but fill_simple_delay_slots would refuse to do delay slot filling + ;; from the target then, as it uses simplejump_p. + ;;(define_insn "jump_compact_far" + ;; [(set (pc) + ;; (label_ref (match_operand 0 "" ""))) + ;; (use (match_operand 1 "register_operand" "r")] + ;; "TARGET_SH1" + ;; "* return output_far_jump(insn, operands[0], operands[1]);" + ;; [(set_attr "type" "jump") + ;; (set_attr "needs_delay_slot" "yes")]) (define_insn "jump_media" [(set (pc)