We have code in the backend to predicate instructions with long delays while scheduling, so that they can be placed in jump delay slots. For example,
[a1] b label nop 3 ldw *a2, a0 ;; this insn is from the basic block after the branch nop ;; branch occurs here is not safe even if A0 is not used at the branch target, since the load will place data into A0 after the branch occurs, and we don't know whether that conflicts with the code there. We can make this safe by changing it into [a1] b label nop 3 [!a1] ldw *a2, a0 nop ;; branch occurs here since we know we're scheduling extended basic blocks, so we control the code in the fallthru path. This all works except for certain floating point instructions, which not only store their destination after a given number of cycles, but which also reserve functional units for multiple cycles. In the testcase I have, it's a CMPLTDP instruction which can't be allowed to be placed in the last delay cycle of the branch, since it reserves its units for two cycles. Fixed with this patch. Committed. Bernd
* config/c6x/c6x.md (reserve_cycles): New attribute. * config/c6x/c6x.c (c6x_sched_reorder_1): Ensure insns we predicate don't reserve functional units after the branch occurs. Index: gcc/config/c6x/c6x.c =================================================================== --- gcc/config/c6x/c6x.c (revision 184237) +++ gcc/config/c6x/c6x.c (working copy) @@ -4196,13 +4196,14 @@ c6x_sched_reorder_1 (rtx *ready, int *pn bool is_asm = (icode < 0 && (GET_CODE (PATTERN (insn)) == ASM_INPUT || asm_noperands (PATTERN (insn)) >= 0)); - int this_cycles; + int this_cycles, rsrv_cycles; enum attr_type type; gcc_assert (!is_asm); if (icode < 0) continue; this_cycles = get_attr_cycles (insn); + rsrv_cycles = get_attr_reserve_cycles (insn); type = get_attr_type (insn); /* Treat branches specially; there is also a hazard if two jumps end at the same cycle. */ @@ -4211,6 +4212,7 @@ c6x_sched_reorder_1 (rtx *ready, int *pn if (clock_var + this_cycles <= first_cycle) continue; if ((first_jump > 0 && clock_var + this_cycles > second_cycle) + || clock_var + rsrv_cycles > first_cycle || !predicate_insn (insn, first_cond, false)) { memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx)); Index: gcc/config/c6x/c6x.md =================================================================== --- gcc/config/c6x/c6x.md (revision 184237) +++ gcc/config/c6x/c6x.md (working copy) @@ -201,6 +201,17 @@ (define_attr "cycles" "" (eq_attr "type" "mpysp2dp") (const_int 5)] (const_int 1))) +;; The number of cycles during which the instruction reserves functional +;; units. +(define_attr "reserve_cycles" "" + (cond [(eq_attr "type" "cmpdp") (const_int 2) + (eq_attr "type" "adddp") (const_int 2) + (eq_attr "type" "mpydp") (const_int 4) + (eq_attr "type" "mpyi") (const_int 4) + (eq_attr "type" "mpyid") (const_int 4) + (eq_attr "type" "mpyspdp") (const_int 2)] + (const_int 1))) + (define_attr "predicable" "no,yes" (const_string "yes"))