ARM: Fix incorrect pack pattern for thumb2
authorJim Grosbach <grosbach@apple.com>
Tue, 9 Jul 2013 22:59:22 +0000 (22:59 +0000)
committerJim Grosbach <grosbach@apple.com>
Tue, 9 Jul 2013 22:59:22 +0000 (22:59 +0000)
Propagate the fix from r185712 to Thumb2 codegen as well. Original
commit message applies here as well:

A "pkhtb x, x, y asr #num" uses the lower 16 bits of "y asr #num" and
packs them in the bottom half of "x". An arithmetic and logic shift are
only equivalent in this context if the shift amount is 16. We would be
shifting in ones into the bottom 16bits instead of zeros if "y" is
negative.

rdar://14338767

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

lib/Target/ARM/ARMInstrThumb2.td
test/CodeGen/Thumb2/thumb2-pack.ll

index d71824e3c65be7b2916dfd2179237231cf1a1449..ee9eaaab31926b1063be9af6c8ca8c7ac36faf98 100644 (file)
@@ -2951,7 +2951,12 @@ def t2PKHTB : T2ThreeReg<
 
 // Alternate cases for PKHTB where identities eliminate some nodes.  Note that
 // a shift amount of 0 is *not legal* here, it is PKHBT instead.
-def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (srl rGPR:$src2, imm16_31:$sh)),
+// We also can not replace a srl (17..31) by an arithmetic shift we would use in
+// pkhtb src1, src2, asr (17..31).
+def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (srl rGPR:$src2, imm16:$sh)),
+            (t2PKHTB rGPR:$src1, rGPR:$src2, imm16:$sh)>,
+            Requires<[HasT2ExtractPack, IsThumb2]>;
+def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (sra rGPR:$src2, imm16_31:$sh)),
             (t2PKHTB rGPR:$src1, rGPR:$src2, imm16_31:$sh)>,
             Requires<[HasT2ExtractPack, IsThumb2]>;
 def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000),
index 2e8bb1d6093426aa3d222218cfa1f4bdd6227866..5deae1bf8f2ea4a2c2987968421e2b807cf43ea7 100644 (file)
@@ -88,10 +88,33 @@ define i32 @test7(i32 %X, i32 %Y) {
 }
 
 ; CHECK: test8
-; CHECK: pkhtb   r0, r0, r1, asr #22
+; CHECK-NOT: pkhtb   r0, r0, r1, asr #22
+;   pkhtb does an arithmetic shift, not a logical shift. Make sure we don't
+;   use it for problematic cases when whether sign bits would be shifted in
+;   would matter.
 define i32 @test8(i32 %X, i32 %Y) {
        %tmp1 = and i32 %X, -65536
        %tmp3 = lshr i32 %Y, 22
        %tmp57 = or i32 %tmp3, %tmp1
        ret i32 %tmp57
 }
+
+; CHECK: test9:
+; CHECK: pkhtb r0, r0, r1, asr #16
+define i32 @test9(i32 %src1, i32 %src2) {
+entry:
+    %tmp = and i32 %src1, -65536
+    %tmp2 = lshr i32 %src2, 16
+    %tmp3 = or i32 %tmp, %tmp2
+    ret i32 %tmp3
+}
+
+; CHECK: test10
+; CHECK: pkhtb   r0, r0, r1, asr #22
+define i32 @test10(i32 %X, i32 %Y) {
+       %tmp1 = and i32 %X, -65536
+       %tmp3 = ashr i32 %Y, 22
+       %tmp57 = or i32 %tmp3, %tmp1
+       ret i32 %tmp57
+}
+