https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65166
Bug ID: 65166 Summary: [SH] use div1 to do R[n] = ((R[n] << 1) | T) - R[m] Product: gcc Version: 5.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: olegendo at gcc dot gnu.org Target: sh*-*-* The single-step division instruction 'div1 Rm,Rn' does R[n] = ((R[n] << 1) | T) - R[m] if M = 0 and Q = 0. Thus it could be utilized to do that calculation. I've added the following pattern ;; R[n] = ((R[n] << 1) | T) - R[m] (define_insn "*div1" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (minus:SI (mult:SI (match_operand:SI 1 "arith_reg_operand" "0") (const_int 2)) (match_operand:SI 2 "arith_reg_operand" "r"))) (clobber (reg:SI T_REG))] "TARGET_SH1" "div1 %1,%0" [(set_attr "type" "arith")]) and it seems it is hit a few times in CSiBE. The pattern above will produce wrong code, due to lack of M = Q = T = 0 setting before div1. To fix that a div1 has to be prefixed with a div0u, which eliminates the benefits over a regular 2 insn add,sub sequence. For this to make sense the div0u insn should be eliminated if possible. This is difficult to do, because div1 insn itself also does: Q = (0x80000000 & R[n]) ? (((R[n] << 1) | T) - R[m]) == 0 : (((R[n] << 1) | T) - R[m]) > R[n] So effectively, both div0u and div1s have to be used as a pair. If the T bit should be used as an input, the following patterns can be used (also lacking div0u here): ;; R[n] = ((R[n] << 1) | T) - R[m] (define_insn "div1" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (minus:SI (ior:SI (mult:SI (match_operand:SI 1 "arith_reg_operand" "0") (const_int 2)) (reg:SI T_REG)) (match_operand:SI 2 "arith_reg_operand" "r"))) (clobber (reg:SI T_REG))] "TARGET_SH1" "div1 %1,%0" [(set_attr "type" "arith")]) (define_insn_and_split "*div1" [(set (match_operand:SI 0 "arith_reg_dest") (minus:SI (ior:SI (mult:SI (match_operand:SI 1 "arith_reg_operand") (const_int 2)) (match_operand 2 "treg_set_expr")) (match_operand:SI 3 "arith_reg_operand"))) (clobber (reg:SI T_REG))] "TARGET_SH1 && can_create_pseudo_p ()" "#" "&& 1" [(const_int 0)] { sh_treg_insns ti = sh_split_treg_set_expr (operands[2], curr_insn); emit_insn (gen_div1 (operands[0], operands[1], operands[3])); DONE; })