@@ -486,22 +486,108 @@ (define_expand "extend<EQS0:mode><EQDHIDI:mode>2"
})
;; Bit extraction
-;; We define it solely to allow combine to choose SImode
+;; One reason to define it is to allow combine to choose SImode
;; for word mode when trying to match our cbranch_qbbx_* insn.
;;
;; Check how combine.cc:make_extraction() uses
;; get_best_reg_extraction_insn() to select the op size.
-(define_insn "extzv<mode>"
- [(set (match_operand:QISI 0 "register_operand" "=r")
+(define_expand "extzv<mode>"
+ [(set (match_operand:QISI 0 "register_operand")
(zero_extract:QISI
- (match_operand:QISI 1 "register_operand" "r")
- (match_operand:QISI 2 "const_int_operand" "i")
- (match_operand:QISI 3 "const_int_operand" "i")))]
+ (match_operand:QISI 1 "register_operand")
+ (match_operand:QISI 2 "const_int_operand")
+ (match_operand:QISI 3 "const_int_operand")))]
""
- "lsl\\t%0, %1, (%S0 * 8 - %2 - %3)\;lsr\\t%0, %0, (%S0 * 8 - %2)"
- [(set_attr "type" "complex")
- (set_attr "length" "8")])
+{
+ const int nbits = INTVAL (operands[2]);
+ const int bitpos = INTVAL (operands[3]);
+ const int trailing_bits = GET_MODE_BITSIZE (<MODE>mode) - nbits - bitpos;
+
+ if (bitpos == 0 && nbits <= 7)
+ {
+ emit_insn (gen_and<mode>3 (operands[0],
+ operands[1],
+ gen_int_mode ((HOST_WIDE_INT_1U << nbits) - 1,
+ <MODE>mode)));
+ DONE;
+ }
+
+ rtx src = operands[1];
+ if (trailing_bits != 0)
+ {
+ emit_insn (gen_ashl<mode>3 (operands[0],
+ operands[1],
+ GEN_INT (trailing_bits)));
+ src = operands[0];
+ }
+ emit_insn (gen_lshr<mode>3 (operands[0],
+ src,
+ GEN_INT (trailing_bits + bitpos)));
+ DONE;
+})
+
+;; Bit-field insert.
+(define_expand "insv<mode>"
+ [(set (zero_extract:QISI
+ (match_operand:QISI 0 "register_operand")
+ (match_operand:QISI 1 "const_int_operand")
+ (match_operand:QISI 2 "const_int_operand"))
+ (match_operand:QISI 3 "reg_or_ubyte_operand"))]
+ ""
+{
+ const int nbits = INTVAL (operands[1]);
+ const int bitpos = INTVAL (operands[2]);
+ if (nbits == 1)
+ {
+ rtx j;
+ rtx src = gen_reg_rtx (<MODE>mode);
+ rtx dst = operands[0];
+
+ emit_move_insn (src, operands[3]);
+
+ emit_insn (gen_and<mode>3 (dst,
+ dst,
+ gen_int_mode (~(HOST_WIDE_INT_1U << bitpos),
+ <MODE>mode)));
+
+ rtx_code_label *skip_set_label = gen_label_rtx ();
+ j = emit_jump_insn (gen_cbranch_qbbx_eq<mode><mode><mode>4 (
+ src,
+ GEN_INT (0),
+ skip_set_label));
+ JUMP_LABEL (j) = skip_set_label;
+ LABEL_NUSES (skip_set_label)++;
+
+ emit_insn (gen_ior<mode>3 (dst,
+ dst,
+ gen_int_mode (HOST_WIDE_INT_1U << bitpos,
+ <MODE>mode)));
+ emit_label (skip_set_label);
+
+ DONE;
+ }
+
+ /* Explicitly expand in order to avoid using word_mode for PRU, and instead
+ use SI and HI modes as applicable. */
+ rtx dst = operands[0];
+ rtx src = gen_reg_rtx (<MODE>mode);
+ emit_insn (gen_and<mode>3 (src,
+ force_reg (<MODE>mode, operands[3]),
+ gen_int_mode ((HOST_WIDE_INT_1U << nbits) - 1,
+ <MODE>mode)));
+ if (bitpos > 0)
+ emit_insn (gen_ashl<mode>3 (src, src, gen_int_mode (bitpos, <MODE>mode)));
+
+ HOST_WIDE_INT vmask = ~(((HOST_WIDE_INT_1U << nbits) - 1) << bitpos);
+ emit_insn (gen_and<mode>3 (dst,
+ dst,
+ gen_int_mode (vmask, <MODE>mode)));
+
+ emit_insn (gen_ior<mode>3 (dst, dst, src));
+
+ DONE;
+})
;; Arithmetic Operations
@@ -8,6 +8,6 @@ extern void func2(unsigned char);
void test(unsigned char v)
{
- /* { dg-final { scan-assembler "lsl\tr14.b0, r14.b0, .\+\n\tlsr\tr14.b0, r14.b0" } } */
+ /* { dg-final { scan-assembler "lsr\tr14(.b0)?, r14.b0, .\+\n\tand\tr14.b0, r14.b0" } } */
func2((v & 2) ? 1 : 0);
}
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 12 } } */
+
+struct S {
+ unsigned int a : 5;
+ unsigned int b : 1;
+ unsigned int c : 1;
+};
+
+unsigned int test(struct S s)
+{
+ return s.a;
+}
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 12 } } */
+
+struct S {
+ unsigned int a : 5;
+ unsigned int b : 1;
+ unsigned int c : 24;
+ unsigned int d : 2;
+};
+
+unsigned int test(struct S s)
+{
+ return s.d;
+}
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 16 } } */
+
+struct S {
+ unsigned int a : 9;
+ unsigned int b : 4;
+};
+
+unsigned int test(struct S s)
+{
+ return s.b;
+}
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 16 } } */
+
+struct S {
+ unsigned int a : 5;
+ unsigned int b : 1;
+ unsigned int c : 1;
+};
+
+void test(struct S *s)
+{
+ s->b = 1;
+}
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 16 } } */
+
+struct S {
+ unsigned int a : 5;
+ unsigned int b : 1;
+ unsigned int c : 1;
+};
+
+void test(struct S *s)
+{
+ s->b = 0;
+}
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 24 } } */
+
+struct S {
+ unsigned int a : 5;
+ unsigned int b : 1;
+ unsigned int c : 1;
+};
+
+void test(struct S *s, unsigned int val)
+{
+ s->b = val;
+}
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 28 } } */
+
+struct S {
+ unsigned int a : 3;
+ unsigned int b : 3;
+ unsigned int c : 3;
+};
+
+void test(struct S *s, unsigned int val)
+{
+ s->b = val;
+}
Optimize the generated code for the bit-field extract and insert patterns: - Use bit-set and bit-clear instructions for 1-bit fields. - Expand to SImode operations instead of relying on the default expansion to word (QI) mode. gcc/ChangeLog: * config/pru/pru.md (extzv<mode>): Make it an expand pattern, handle efficiently zero-positioned bit-fields. (insv<mode>): New expand pattern. gcc/testsuite/ChangeLog: * gcc.target/pru/ashiftrt.c: Minor update due to new (but equivalent) generated code sequence. * gcc.target/pru/extzv-1.c: New test. * gcc.target/pru/extzv-2.c: New test. * gcc.target/pru/extzv-3.c: New test. * gcc.target/pru/insv-1.c: New test. * gcc.target/pru/insv-2.c: New test. * gcc.target/pru/insv-3.c: New test. * gcc.target/pru/insv-4.c: New test. Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu> --- gcc/config/pru/pru.md | 104 ++++++++++++++++++++++-- gcc/testsuite/gcc.target/pru/ashiftrt.c | 2 +- gcc/testsuite/gcc.target/pru/extzv-1.c | 14 ++++ gcc/testsuite/gcc.target/pru/extzv-2.c | 15 ++++ gcc/testsuite/gcc.target/pru/extzv-3.c | 13 +++ gcc/testsuite/gcc.target/pru/insv-1.c | 14 ++++ gcc/testsuite/gcc.target/pru/insv-2.c | 14 ++++ gcc/testsuite/gcc.target/pru/insv-3.c | 14 ++++ gcc/testsuite/gcc.target/pru/insv-4.c | 14 ++++ 9 files changed, 194 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.target/pru/extzv-1.c create mode 100644 gcc/testsuite/gcc.target/pru/extzv-2.c create mode 100644 gcc/testsuite/gcc.target/pru/extzv-3.c create mode 100644 gcc/testsuite/gcc.target/pru/insv-1.c create mode 100644 gcc/testsuite/gcc.target/pru/insv-2.c create mode 100644 gcc/testsuite/gcc.target/pru/insv-3.c create mode 100644 gcc/testsuite/gcc.target/pru/insv-4.c