From 700337494e1b0d5ff608e1a3c77852381e264653 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Wed, 18 Nov 2020 21:01:06 -0700 Subject: [PATCH] Minor H8 shift code generation change in preparation for cc0 removal So I didn't stay up late to work from pago pago this year and beat the stage1 close, but I do want to flush out the removal of cc0 from the H8 port this cycle. Given these patches only affect the H8 and the H8 would be killed this cycle without the conversion, I think this is suitable even though we're past stage1 close. This patch addresses an initial codegen issue that would have resulted in regressions after removal of cc0. The compare/test eliminate pass is unable to handle multiple clobbers. So patterns that clobber a scratch and also clobber a condition code are never used to eliminate a compare/test. The H8 can shift 1 or 2 bits at a time depending on the precise model. Not surprisingly we have multiple strategies to implement shifts, some of which clobber scratch registers -- but we have a clobber on every shift insn and as a result they can not participate in compare/test removal once cc0 is removed from the port. This patch removes the clobber in the initial code generation in cases where it's obviously not needed allowing those shifts to participate in compare/test removal in a future patch. It has the advantage that is also generates slightly better code. By installing this now the removal of cc0 is a smaller patch, but more importantly, it allows for a more direct comparison of the generated code before/after cc0 removal. I've had my tester test before/after this patch with no regressions on the major H8 multilibs. I've also spot checked the generated code and as expected it's ever-so-slightly better after this patch. I'll be installing this on the trunk momentarily. More patches will follow, though probably not in rapid succession as my time to push this stuff is very limited. gcc/ * config/h8300/constraints.md (R constraint): Add argument to call to h8300_shift_needs_scratch_p. (S and T constraints): Similary. * config/h8300/h8300-protos.h: Update h8300_shift_needs_scratch_p prototype. * config/h8300/h8300.c (expand_a_shift): Emit a different pattern if the shift does not require a scratch register. (h8300_shift_needs_scratch_p): Refine to be more accurate. * config/h8300/shiftrotate.md (shiftqi_noscratch): New pattern. (shifthi_noscratch, shiftsi_noscratch): Similarly. --- gcc/config/h8300/constraints.md | 6 ++--- gcc/config/h8300/h8300-protos.h | 2 +- gcc/config/h8300/h8300.c | 44 ++++++++++++++++++++---------- gcc/config/h8300/shiftrotate.md | 48 +++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 18 deletions(-) diff --git a/gcc/config/h8300/constraints.md b/gcc/config/h8300/constraints.md index d24518225f8..1d80152ce41 100644 --- a/gcc/config/h8300/constraints.md +++ b/gcc/config/h8300/constraints.md @@ -152,7 +152,7 @@ (define_constraint "R" "@internal" (and (match_code "const_int") - (match_test "!h8300_shift_needs_scratch_p (ival, QImode)"))) + (match_test "!h8300_shift_needs_scratch_p (ival, QImode, CLOBBER)"))) (define_constraint "C" "@internal" @@ -161,12 +161,12 @@ (define_constraint "S" "@internal" (and (match_code "const_int") - (match_test "!h8300_shift_needs_scratch_p (ival, HImode)"))) + (match_test "!h8300_shift_needs_scratch_p (ival, HImode, CLOBBER)"))) (define_constraint "T" "@internal" (and (match_code "const_int") - (match_test "!h8300_shift_needs_scratch_p (ival, SImode)"))) + (match_test "!h8300_shift_needs_scratch_p (ival, SImode, CLOBBER)"))) (define_constraint "U" "An operand valid for a bset destination." diff --git a/gcc/config/h8300/h8300-protos.h b/gcc/config/h8300/h8300-protos.h index 2416741e76a..8a8ebf6f490 100644 --- a/gcc/config/h8300/h8300-protos.h +++ b/gcc/config/h8300/h8300-protos.h @@ -47,7 +47,7 @@ extern enum attr_cc compute_logical_op_cc (machine_mode, rtx *); extern void h8300_expand_branch (rtx[]); extern void h8300_expand_store (rtx[]); extern bool expand_a_shift (machine_mode, enum rtx_code, rtx[]); -extern int h8300_shift_needs_scratch_p (int, machine_mode); +extern int h8300_shift_needs_scratch_p (int, machine_mode, rtx_code); extern int expand_a_rotate (rtx[]); extern int fix_bit_operand (rtx *, enum rtx_code); extern int h8300_adjust_insn_length (rtx, int); diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index 6875cd9b81a..767ecda7979 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -3381,19 +3381,25 @@ expand_a_shift (machine_mode mode, enum rtx_code code, rtx operands[]) break; } - emit_move_insn (copy_rtx (operands[0]), operands[1]); - /* Need a loop to get all the bits we want - we generate the code at emit time, but need to allocate a scratch reg now. */ - - emit_insn (gen_rtx_PARALLEL - (VOIDmode, - gen_rtvec (2, - gen_rtx_SET (copy_rtx (operands[0]), - gen_rtx_fmt_ee (code, mode, - copy_rtx (operands[0]), operands[2])), - gen_rtx_CLOBBER (VOIDmode, - gen_rtx_SCRATCH (QImode))))); + emit_move_insn (copy_rtx (operands[0]), operands[1]); + if (operands[2] == CONST0_RTX (QImode)) + ; + else if (GET_CODE (operands[2]) == CONST_INT + && !h8300_shift_needs_scratch_p (INTVAL (operands[2]), mode, code)) + emit_insn (gen_rtx_SET (copy_rtx (operands[0]), + gen_rtx_fmt_ee (code, mode, + copy_rtx (operands[1]), operands[2]))); + else + emit_insn (gen_rtx_PARALLEL + (VOIDmode, + gen_rtvec (2, + gen_rtx_SET (copy_rtx (operands[0]), + gen_rtx_fmt_ee (code, mode, + copy_rtx (operands[0]), operands[2])), + gen_rtx_CLOBBER (VOIDmode, + gen_rtx_SCRATCH (QImode))))); return true; } @@ -3920,7 +3926,7 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, needed for some shift with COUNT and MODE. Return 0 otherwise. */ int -h8300_shift_needs_scratch_p (int count, machine_mode mode) +h8300_shift_needs_scratch_p (int count, machine_mode mode, enum rtx_code type) { enum h8_cpu cpu; int a, lr, ar; @@ -3960,8 +3966,18 @@ h8300_shift_needs_scratch_p (int count, machine_mode mode) } /* On H8/300H, count == 8 uses a scratch register. */ - return (a == SHIFT_LOOP || lr == SHIFT_LOOP || ar == SHIFT_LOOP - || (TARGET_H8300H && mode == SImode && count == 8)); + if (type == CLOBBER) + return (a == SHIFT_LOOP || lr == SHIFT_LOOP || ar == SHIFT_LOOP + || (TARGET_H8300H && mode == SImode && count == 8)); + else if (type == ASHIFT) + return (a == SHIFT_LOOP + || (TARGET_H8300H && mode == SImode && count == 8)); + else if (type == LSHIFTRT) + return (lr == SHIFT_LOOP + || (TARGET_H8300H && mode == SImode && count == 8)); + else if (type == ASHIFTRT) + return (ar == SHIFT_LOOP + || (TARGET_H8300H && mode == SImode && count == 8)); } /* Output the assembler code for doing shifts. */ diff --git a/gcc/config/h8300/shiftrotate.md b/gcc/config/h8300/shiftrotate.md index 75606d7c50b..5a85e1673fe 100644 --- a/gcc/config/h8300/shiftrotate.md +++ b/gcc/config/h8300/shiftrotate.md @@ -101,6 +101,22 @@ (set (attr "cc") (symbol_ref "compute_a_shift_cc (insn, operands)"))]) +(define_insn "*shiftqi_noscratch" + [(set (match_operand:QI 0 "register_operand" "=r,r") + (match_operator:QI 3 "nshift_operator" + [(match_operand:QI 1 "register_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "R,rn")]))] + "(GET_CODE (operands[2]) == CONST_INT + && !h8300_shift_needs_scratch_p (INTVAL (operands[2]), QImode, + GET_CODE (operands[3])))" +{ + return output_a_shift (operands); +} + [(set (attr "length") + (symbol_ref "compute_a_shift_length (insn, operands)")) + (set (attr "cc") + (symbol_ref "compute_a_shift_cc (insn, operands)"))]) + (define_insn "*shifthi" [(set (match_operand:HI 0 "register_operand" "=r,r") (match_operator:HI 3 "nshift_operator" @@ -116,6 +132,22 @@ (set (attr "cc") (symbol_ref "compute_a_shift_cc (insn, operands)"))]) +(define_insn "*shifthi_noscratch" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (match_operator:HI 3 "nshift_operator" + [(match_operand:HI 1 "register_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "S,rn")]))] + "(GET_CODE (operands[2]) == CONST_INT + && !h8300_shift_needs_scratch_p (INTVAL (operands[2]), HImode, + GET_CODE (operands[3])))" +{ + return output_a_shift (operands); +} + [(set (attr "length") + (symbol_ref "compute_a_shift_length (insn, operands)")) + (set (attr "cc") + (symbol_ref "compute_a_shift_cc (insn, operands)"))]) + (define_insn "*shiftsi" [(set (match_operand:SI 0 "register_operand" "=r,r") (match_operator:SI 3 "nshift_operator" @@ -131,6 +163,22 @@ (set (attr "cc") (symbol_ref "compute_a_shift_cc (insn, operands)"))]) +(define_insn "*shiftsi_noscratch" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (match_operator:SI 3 "nshift_operator" + [(match_operand:SI 1 "register_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "T,rn")]))] + "(GET_CODE (operands[2]) == CONST_INT + && !h8300_shift_needs_scratch_p (INTVAL (operands[2]), SImode, + GET_CODE (operands[3])))" +{ + return output_a_shift (operands); +} + [(set (attr "length") + (symbol_ref "compute_a_shift_length (insn, operands)")) + (set (attr "cc") + (symbol_ref "compute_a_shift_cc (insn, operands)"))]) + ;; Split a variable shift into a loop. If the register containing ;; the shift count dies, then we just use that register. -- 2.30.2