These are various minor improvements to our C bit setcc handling.
First the mode of the operands being compared can be independent of the
mode of the destination. This allows us to pick up a few more cases.
Second, the result of an setcc can feed a negate insn. Producing -1,0
is actually cheaper for the C bit than 1,0, so clearly something we
should be supporting and it happens fairly regularly.
Third we can use bst, bist and rotxr to store the C bit into a variety
of bit positions in the destination which allows us to combine the setcc
with a subsequent left shift. I haven't really seen this with C, but I
have seen it semi-regularly with Z (shifting it to the sign bit in the
destination in particular). Regardless, the bits are in place to handle
it for C.
Overall it saves a few bytes & cycles here and there. Nothing near as
effective as the initial C support.
Tested without regressions.
Installed on the trunk,
Jeff
commit b27416a7a91b7e6b6b018411ac85cad556ff9903
Author: Jeff Law <jlaw@localhost.localdomain>
Date: Sun Sep 5 00:08:34 2021 -0400
Improve handling of C bit for setcc insns
gcc/
* config/h8300/h8300.md (QHSI2 mode iterator): New mode iterator.
* config/h8300/testcompare.md (store_c): Update name, use new
QHSI2 iterator.
(store_neg_c, store_shifted_c): New patterns.
diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md
index 89bfcf11126..e81e21b103e 100644
--- a/gcc/config/h8300/h8300.md
+++ b/gcc/config/h8300/h8300.md
@@ -223,6 +223,7 @@
(define_mode_iterator HSI [HI SI])
(define_mode_iterator QHSI [QI HI SI])
+(define_mode_iterator QHSI2 [QI HI SI])
(define_mode_iterator QHSIF [QI HI SI SF])
diff --git a/gcc/config/h8300/testcompare.md b/gcc/config/h8300/testcompare.md
index 9ff7a51077e..0ee3e360bea 100644
--- a/gcc/config/h8300/testcompare.md
+++ b/gcc/config/h8300/testcompare.md
@@ -212,11 +212,96 @@
}
[(set (attr "length") (symbol_ref "<MODE>mode == SImode ? 6 : 4"))])
+;; Similarly, but with a negated result
+(define_insn "*store_neg_c_<mode>"
+ [(set (match_operand:QHSI 0 "register_operand" "=r")
+ (neg:QHSI (ne:QHSI (reg:CCC CC_REG) (const_int 0))))]
+ "reload_completed"
+ {
+ if (<MODE>mode == QImode)
+ return "subx\t%X0,%X0";
+ else if (<MODE>mode == HImode)
+ return "subx\t%X0,%X0\;exts.w\t%T0";
+ else if (<MODE>mode == SImode)
+ return "subx\t%X0,%X0\;exts.w\t%T0\;exts.l\t%S0";
+ gcc_unreachable ();
+ }
+ [(set
+ (attr "length")
+ (symbol_ref "(<MODE>mode == SImode ? 6 : <MODE>mode == HImode ? 4 :
2)"))])
+
+;; Using b[i]st we can store the C bit into any of the low 16 bits of
+;; a destination. We can also rotate it up into the high bit of a 32 bit
+;; destination.
+(define_insn "*store_shifted_c<mode>"
+ [(set (match_operand:QHSI 0 "register_operand" "=r")
+ (ashift:QHSI (eqne:QHSI (reg:CCC CC_REG) (const_int 0))
+ (match_operand 1 "immediate_operand" "n")))]
+ "(reload_completed
+ && (INTVAL (operands[1]) == 31 || INTVAL (operands[1]) <= 15))"
+ {
+ if (<CODE> == NE)
+ {
+ if (<MODE>mode == QImode)
+ return "xor.b\t%X0,%X0\;bst\t%1,%X0";
+ else if (<MODE>mode == HImode && INTVAL (operands[1]) < 8)
+ return "xor.w\t%T0,%T0\;bst\t%1,%X0";
+ else if (<MODE>mode == HImode)
+ {
+ operands[1] = GEN_INT (INTVAL (operands[1]) - 8);
+ output_asm_insn ("xor.w\t%T0,%T0\;bst\t%1,%t0", operands);
+ return "";
+ }
+ else if (<MODE>mode == SImode && INTVAL (operands[1]) == 31)
+ return "xor.l\t%S0,%S0\;rotxr.l\t%S0";
+ else if (<MODE>mode == SImode && INTVAL (operands[1]) < 8)
+ return "xor.l\t%S0,%S0\;bst\t%1,%X0";
+ else if (<MODE>mode == SImode)
+ {
+ operands[1] = GEN_INT (INTVAL (operands[1]) - 8);
+ output_asm_insn ("xor.l\t%S0,%S0\;bst\t%1,%t0", operands);
+ return "";
+ }
+ gcc_unreachable ();
+ }
+ else if (<CODE> == EQ)
+ {
+ if (<MODE>mode == QImode)
+ return "xor.b\t%X0,%X0\;bist\t%1,%X0";
+ else if (<MODE>mode == HImode && INTVAL (operands[1]) < 8)
+ return "xor.w\t%T0,%T0\;bist\t%1,%X0";
+ else if (<MODE>mode == HImode)
+ {
+ operands[1] = GEN_INT (INTVAL (operands[1]) - 8);
+ output_asm_insn ("xor.w\t%T0,%T0\;bist\t%1,%t0", operands);
+ return "";
+ }
+ else if (<MODE>mode == SImode && INTVAL (operands[1]) == 31)
+ return "xor.l\t%S0,%S0\;bixor\t#0,%X0\;rotxr.l\t%S0";
+ else if (<MODE>mode == SImode && INTVAL (operands[1]) < 8)
+ return "xor.l\t%S0,%S0\;bist\t%1,%X0";
+ else if (<MODE>mode == SImode)
+ {
+ operands[1] = GEN_INT (INTVAL (operands[1]) - 8);
+ output_asm_insn ("xor.l\t%S0,%S0\;bist\t%1,%t0", operands);
+ return "";
+ }
+ gcc_unreachable ();
+ }
+ gcc_unreachable ();
+ }
+ [(set
+ (attr "length")
+ (symbol_ref "(<MODE>mode == QImode ? 4
+ : <MODE>mode == HImode ? 4
+ : <CODE> == NE ? 6
+ : INTVAL (operands[1]) == 31 ? 8 : 6)"))])
+
;; Recognize this scc and generate code we can match
-(define_insn_and_split "*store_c_i_<mode>"
+(define_insn_and_split "*store_c"
[(set (match_operand:QHSI 0 "register_operand" "=r")
- (geultu:QHSI (match_operand:QHSI 1 "register_operand" "r")
- (match_operand:QHSI 2 "register_operand" "r")))]
+ (geultu:QHSI (match_operand:QHSI2 1 "register_operand" "r")
+ (match_operand:QHSI2 2 "register_operand" "r")))]
""
"#"
"&& reload_completed"
@@ -224,3 +309,34 @@
(ltu:CCC (match_dup 1) (match_dup 2)))
(set (match_dup 0)
(<geultu_to_c>:QHSI (reg:CCC CC_REG) (const_int 0)))])
+
+;; We can fold in negation of the result and generate better code than
+;; what the generic bits would do when testing for C == 1
+(define_insn_and_split "*store_neg_c"
+ [(set (match_operand:QHSI 0 "register_operand" "=r")
+ (neg:QHSI
+ (ltu:QHSI (match_operand:QHSI2 1 "register_operand" "r")
+ (match_operand:QHSI2 2 "register_operand" "r"))))]
+ ""
+ "#"
+ "&& reload_completed"
+ [(set (reg:CCC CC_REG)
+ (ltu:CCC (match_dup 1) (match_dup 2)))
+ (set (match_dup 0)
+ (neg:QHSI (ne:QHSI (reg:CCC CC_REG) (const_int 0))))])
+
+;; We can use rotates and bst/bist to put the C bit into various places
+;; in the destination.
+(define_insn_and_split "*store_shifted_c"
+ [(set (match_operand:QHSI 0 "register_operand" "=r")
+ (ashift:QHSI (geultu:QHSI (match_operand:QHSI2 1 "register_operand" "r")
+ (match_operand:QHSI2 2 "register_operand"
"r"))
+ (match_operand 3 "immediate_operand" "n")))]
+ "INTVAL (operands[3]) == 31 || INTVAL (operands[3]) <= 15"
+ "#"
+ "&& reload_completed"
+ [(set (reg:CCC CC_REG) (ltu:CCC (match_dup 1) (match_dup 2)))
+ (set (match_dup 0)
+ (ashift:QHSI (<geultu_to_c>:QHSI (reg:CCC CC_REG) (const_int 0))
+ (match_dup 3)))])
+