Just knocking out another m68k issue since I've got my little aranym setup running.

This BZ is a quality of code regression relative to very old versions of GCC for two code sequences.

First, setting a bitfield to all ones. Right now we're doing this via moveq/bfins. It's a 6 byte sequence and uses a register. We can do better using or.b imm,<ea> which is a 4 byte sequence with no scratch register needed. The trick here is to detect that we're setting a field to all ones and rewriting the RTL to look like insv_bfset_reg during the insv expander. That in turn looks "nice" to combine which combines it with the memory references into the or.b insn.

The second sequence is turning a single bit on within a bitfield. At some point GCC stopped using a single or.[bw] and instead generated a movb imm,scr; or.l scr,<ea>, which is two bytes longer than the or.[bw] imm,<ea> and uses a scratch register. At some unknown point since the report was filed, we changed movb imm,scr into moveq imm,scr. That brought the code sequence back to parity WRT size. We still use an unnecessary scratch and I'm sure the two sequences run at different speeds depending on the cpu variant in use.

Further testing showed that xor of a single bit in a bitfield was generating poor code. Tweaking the constraints fixed it to behave like ior & and.

With that small xor issue fixed, the sequences we generate are the same size as direct manipulation via [or|eor|and].[bw]. Selecting between the same sized sequences based on target processor's characteristics probably isn't worth the effort and I'm not considering that part of this BZ.

Tested by building m68k-elf as a cross, then running the m68k.exp testsuite and by an ongoing bootstrap on m68k linux (into stage2 libraries right now, not expecting problems).

Installed on the trunk.

commit 2384fd2cc186c1de5b65db282ef8c67674e851df
Author: Jeff Law <l...@redhat.com>
Date:   Thu Jan 22 14:21:21 2015 -0700

        PR target/52076
        * config/m68k/m68k.md (xorsi3_internal): Twiddle constraints to
        improve code density for small immediate to memory case.
        (insv): Better handle bitfield assignments when the field is
        being set to all ones.
        * config/m68k/predicates.md (reg_or_pow2_m1_operand): New
        operand predicate.
    
        PR target/52076
        * gcc.target/m68k/pr52076-1.c: New test.
        * gcc.target/m68k/pr52076-2.c: New test.

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c166933..ae5e9a5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2015-01-22  Jeff Law  <l...@redhat.com>
+
+       PR target/52076
+       * config/m68k/m68k.md (xorsi3_internal): Twiddle constraints to
+       improve code density for small immediate to memory case.
+       (insv): Better handle bitfield assignments when the field is
+       being set to all ones.
+       * config/m68k/predicates.md (reg_or_pow2_m1_operand): New
+       operand predicate.
+
 2015-01-22  Rainer Orth  <r...@cebitec.uni-bielefeld.de>
            Jakub Jelinek  <ja...@redhat.com>
 
diff --git a/gcc/config/m68k/.m68k.md.swp b/gcc/config/m68k/.m68k.md.swp
new file mode 100755
index 0000000..36d7681
Binary files /dev/null and b/gcc/config/m68k/.m68k.md.swp differ
diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md
index d34ad1d..6bb296e 100644
--- a/gcc/config/m68k/m68k.md
+++ b/gcc/config/m68k/m68k.md
@@ -3838,9 +3838,9 @@
   "")
 
 (define_insn "xorsi3_internal"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=do,m")
-       (xor:SI (match_operand:SI 1 "general_operand" "%0,0")
-                (match_operand:SI 2 "general_operand" "di,dKT")))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,o,m")
+       (xor:SI (match_operand:SI 1 "general_operand" "%0, 0,0")
+                (match_operand:SI 2 "general_operand" "di,dK,dKT")))]
 
   "!TARGET_COLDFIRE"
 {
@@ -5583,9 +5583,20 @@
   [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "")
                         (match_operand:SI 1 "const_int_operand" "")
                         (match_operand:SI 2 "const_int_operand" ""))
-       (match_operand:SI 3 "register_operand" ""))]
+       (match_operand:SI 3 "reg_or_pow2_m1_operand" ""))]
   "TARGET_68020 && TARGET_BITFIELD"
-  "")
+  "
+{
+  /* Special case initializing a field to all ones. */
+  if (GET_CODE (operands[3]) == CONST_INT)
+    {
+      if (exact_log2 (INTVAL (operands[3]) + 1) != INTVAL (operands[1]))
+       operands[3] = force_reg (SImode, operands[3]);
+      else
+       operands[3] = constm1_rtx;
+
+    }
+}")
 
 (define_insn "*insv_bfins_mem"
   [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o")
diff --git a/gcc/config/m68k/predicates.md b/gcc/config/m68k/predicates.md
index a7b5c42..c652f10 100644
--- a/gcc/config/m68k/predicates.md
+++ b/gcc/config/m68k/predicates.md
@@ -244,3 +244,16 @@
                 || reload_in_progress
                 || reload_completed));
 })
+
+;; Used to detect when an operand is either a register
+;; or a constant that is all ones in its lower bits.
+;; Used by insv pattern to help detect when we're initializing
+;; a bitfield to all ones.
+
+(define_predicate "reg_or_pow2_m1_operand"
+  (match_code "reg,const_int")
+{
+  return (REG_P (op)
+         || (GET_CODE (op) == CONST_INT
+             && exact_log2 (INTVAL (op) + 1) >= 0));
+})
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8bebdac..1fc0241 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2015-01-22  Jeff Law  <l...@redhat.com>
+
+       PR target/52076
+       * gcc.target/m68k/pr52076-1.c: New test.
+       * gcc.target/m68k/pr52076-2.c: New test.
+
 2015-01-22  Richard Biener  <rguent...@suse.de>
 
        PR middle-end/64728
diff --git a/gcc/testsuite/gcc.target/m68k/pr52076-1.c 
b/gcc/testsuite/gcc.target/m68k/pr52076-1.c
new file mode 100644
index 0000000..86df0dc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/m68k/pr52076-1.c
@@ -0,0 +1,20 @@
+/* { dg-do assemble } /*
+/* { dg-options "-Os -fomit-frame-pointer -m68040" } */
+/* { dg-final { object-size text <= 72 } } */
+
+struct kobject {
+        unsigned int b7:1;
+        unsigned int :6;
+        unsigned int b0:1;
+        unsigned char x;
+        unsigned int f;
+};
+
+void ior(struct kobject *kobj) { kobj->f |= 4; }
+void ior_m(struct kobject *kobj) { kobj->f |= -4; }
+
+void xor(struct kobject *kobj) { kobj->f ^= 4; }
+void xor_m(struct kobject *kobj) { kobj->f ^= -4; }
+
+void and(struct kobject *kobj) { kobj->f &= 4; }
+void and_m(struct kobject *kobj) { kobj->f &= -4; }
diff --git a/gcc/testsuite/gcc.target/m68k/pr52076-2.c 
b/gcc/testsuite/gcc.target/m68k/pr52076-2.c
new file mode 100644
index 0000000..30c6991
--- /dev/null
+++ b/gcc/testsuite/gcc.target/m68k/pr52076-2.c
@@ -0,0 +1,27 @@
+/* { dg-do assemble } /*
+/* { dg-options "-Os -fomit-frame-pointer -m68040" } */
+/* { dg-final { object-size text <= 30 } } */
+
+struct kobject {
+        unsigned int b7:1;
+        unsigned int b56:2;
+        unsigned int b1234:4;
+        unsigned int b0:1;
+        unsigned char x;
+        unsigned int f;
+};
+
+void b7(struct kobject *kobj)
+{
+        kobj->b7 = 1;
+}
+
+void b56(struct kobject *kobj)
+{
+        kobj->b56 = 3;
+}
+
+void b1234(struct kobject *kobj)
+{
+        kobj->b1234 = 15;
+}

Reply via email to