Don't fold and's into test instructions if they have multiple uses.
authorChris Lattner <sabre@nondot.org>
Tue, 19 Feb 2008 17:37:35 +0000 (17:37 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 19 Feb 2008 17:37:35 +0000 (17:37 +0000)
This compiles test-nofold.ll into:

_test:
movl $15, %ecx
andl 4(%esp), %ecx
testl %ecx, %ecx
movl $42, %eax
cmove %ecx, %eax
ret

instead of:
_test:
movl 4(%esp), %eax
movl %eax, %ecx
andl $15, %ecx
testl $15, %eax
movl $42, %eax
cmove %ecx, %eax
ret

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47330 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/X86InstrInfo.td
test/CodeGen/X86/test-nofold.ll [new file with mode: 0644]

index f40847f1e47ca1a4da3136e179af6612f5bde450..4482da7d4b11d0f518947045cb5fbb2522138748 100644 (file)
@@ -245,6 +245,12 @@ def extloadi16i8   : PatFrag<(ops node:$ptr), (i16 (extloadi8 node:$ptr))>;
 def extloadi32i8   : PatFrag<(ops node:$ptr), (i32 (extloadi8 node:$ptr))>;
 def extloadi32i16  : PatFrag<(ops node:$ptr), (i32 (extloadi16 node:$ptr))>;
 
+
+// An 'and' node with a single use.
+def and_su : PatFrag<(ops node:$lhs, node:$rhs), (and node:$lhs, node:$rhs), [{
+  return N->hasOneUse();
+}]>;
+
 //===----------------------------------------------------------------------===//
 // Instruction list...
 //
@@ -2078,16 +2084,16 @@ let Defs = [EFLAGS] in {
 let isCommutable = 1 in {   // TEST X, Y   --> TEST Y, X
 def TEST8rr  : I<0x84, MRMDestReg, (outs),  (ins GR8:$src1, GR8:$src2),
                      "test{b}\t{$src2, $src1|$src1, $src2}",
-                     [(X86cmp (and GR8:$src1, GR8:$src2), 0),
+                     [(X86cmp (and_su GR8:$src1, GR8:$src2), 0),
                       (implicit EFLAGS)]>;
 def TEST16rr : I<0x85, MRMDestReg, (outs),  (ins GR16:$src1, GR16:$src2),
                      "test{w}\t{$src2, $src1|$src1, $src2}",
-                     [(X86cmp (and GR16:$src1, GR16:$src2), 0),
+                     [(X86cmp (and_su GR16:$src1, GR16:$src2), 0),
                       (implicit EFLAGS)]>,
                  OpSize;
 def TEST32rr : I<0x85, MRMDestReg, (outs),  (ins GR32:$src1, GR32:$src2),
                      "test{l}\t{$src2, $src1|$src1, $src2}",
-                     [(X86cmp (and GR32:$src1, GR32:$src2), 0),
+                     [(X86cmp (and_su GR32:$src1, GR32:$src2), 0),
                       (implicit EFLAGS)]>;
 }
 
@@ -2107,17 +2113,17 @@ def TEST32rm : I<0x85, MRMSrcMem, (outs),  (ins GR32:$src1, i32mem:$src2),
 def TEST8ri  : Ii8 <0xF6, MRM0r,                     // flags = GR8  & imm8
                     (outs),  (ins GR8:$src1, i8imm:$src2),
                     "test{b}\t{$src2, $src1|$src1, $src2}",
-                    [(X86cmp (and GR8:$src1, imm:$src2), 0),
+                    [(X86cmp (and_su GR8:$src1, imm:$src2), 0),
                      (implicit EFLAGS)]>;
 def TEST16ri : Ii16<0xF7, MRM0r,                     // flags = GR16 & imm16
                     (outs),  (ins GR16:$src1, i16imm:$src2),
                     "test{w}\t{$src2, $src1|$src1, $src2}",
-                    [(X86cmp (and GR16:$src1, imm:$src2), 0),
+                    [(X86cmp (and_su GR16:$src1, imm:$src2), 0),
                      (implicit EFLAGS)]>, OpSize;
 def TEST32ri : Ii32<0xF7, MRM0r,                     // flags = GR32 & imm32
                     (outs),  (ins GR32:$src1, i32imm:$src2),
                     "test{l}\t{$src2, $src1|$src1, $src2}",
-                    [(X86cmp (and GR32:$src1, imm:$src2), 0),
+                    [(X86cmp (and_su GR32:$src1, imm:$src2), 0),
                      (implicit EFLAGS)]>;
 
 def TEST8mi  : Ii8 <0xF6, MRM0m,                   // flags = [mem8]  & imm8
diff --git a/test/CodeGen/X86/test-nofold.ll b/test/CodeGen/X86/test-nofold.ll
new file mode 100644 (file)
index 0000000..a24a9a0
--- /dev/null
@@ -0,0 +1,29 @@
+; RUN: llvm-as < %s | llc -march=x86 -mcpu=yonah | grep {testl.*%e.x.*%e.x}
+; rdar://5752025
+
+; We don't want to fold the and into the test, because the and clobbers its
+; input forcing a copy.  We want:
+;      movl    $15, %ecx
+;      andl    4(%esp), %ecx
+;      testl   %ecx, %ecx
+;      movl    $42, %eax
+;      cmove   %ecx, %eax
+;      ret
+;
+; Not:
+;      movl    4(%esp), %eax
+;      movl    %eax, %ecx
+;      andl    $15, %ecx
+;      testl   $15, %eax
+;      movl    $42, %eax
+;      cmove   %ecx, %eax
+;      ret
+
+define i32 @t1(i32 %X) nounwind  {
+entry:
+       %tmp2 = and i32 %X, 15          ; <i32> [#uses=2]
+       %tmp4 = icmp eq i32 %tmp2, 0            ; <i1> [#uses=1]
+       %retval = select i1 %tmp4, i32 %tmp2, i32 42            ; <i32> [#uses=1]
+       ret i32 %retval
+}
+