diff options
author | Benjamin Kramer <benny.kra@googlemail.com> | 2012-02-28 17:58:00 +0000 |
---|---|---|
committer | Benjamin Kramer <benny.kra@googlemail.com> | 2012-02-28 17:58:00 +0000 |
commit | 3bf15ced2b91661ac314911c1f28332da0e1c37c (patch) | |
tree | 73b480a3b1612372c3c122f9b17834e1141f18e2 | |
parent | 20bd5296cec8d8d597ab9db2aca7346a88e580c8 (diff) | |
download | external_llvm-3bf15ced2b91661ac314911c1f28332da0e1c37c.zip external_llvm-3bf15ced2b91661ac314911c1f28332da0e1c37c.tar.gz external_llvm-3bf15ced2b91661ac314911c1f28332da0e1c37c.tar.bz2 |
LegalizeIntegerTypes: Reenable the large shift with small amount optimization.
To avoid problems with zero shifts when getting the bits that move between words
we use a trick: first shift the by amount-1, then do another shift by one. When
amount is 0 (and size 32) we first shift by 31, then by one, instead of by 32.
Also fix a latent bug that emitted the low and high words in the wrong order
when shifting right.
Fixes PR12113.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151637 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp | 32 | ||||
-rw-r--r-- | test/CodeGen/X86/2008-12-16-BadShift.ll | 19 | ||||
-rw-r--r-- | test/CodeGen/X86/legalize-shift-64.ll | 56 |
3 files changed, 77 insertions, 30 deletions
diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index d18766a..38467c5 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1397,15 +1397,15 @@ ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) { } } -#if 0 - // FIXME: This code is broken for shifts with a zero amount! // If we know that all of the high bits of the shift amount are zero, then we // can do this as a couple of simple shifts. if ((KnownZero & HighBitMask) == HighBitMask) { - // Compute 32-amt. - SDValue Amt2 = DAG.getNode(ISD::SUB, ShTy, - DAG.getConstant(NVTBits, ShTy), - Amt); + // Calculate 31-x. 31 is used instead of 32 to avoid creating an undefined + // shift if x is zero. We can use XOR here because x is known to be smaller + // than 31. + SDValue Amt2 = DAG.getNode(ISD::XOR, dl, ShTy, Amt, + DAG.getConstant(NVTBits-1, ShTy)); + unsigned Op1, Op2; switch (N->getOpcode()) { default: llvm_unreachable("Unknown shift"); @@ -1414,13 +1414,23 @@ ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) { case ISD::SRA: Op1 = ISD::SRL; Op2 = ISD::SHL; break; } - Lo = DAG.getNode(N->getOpcode(), NVT, InL, Amt); - Hi = DAG.getNode(ISD::OR, NVT, - DAG.getNode(Op1, NVT, InH, Amt), - DAG.getNode(Op2, NVT, InL, Amt2)); + // When shifting right the arithmetic for Lo and Hi is swapped. + if (N->getOpcode() != ISD::SHL) + std::swap(InL, InH); + + // Use a little trick to get the bits that move from Lo to Hi. First + // calculate the shift with amount-1. + SDValue Sh1 = DAG.getNode(Op2, dl, NVT, InL, Amt2); + // Then shift one bit further to get the right result. + SDValue Sh2 = DAG.getNode(Op2, dl, NVT, Sh1, DAG.getConstant(1, ShTy)); + + Lo = DAG.getNode(N->getOpcode(), dl, NVT, InL, Amt); + Hi = DAG.getNode(ISD::OR, dl, NVT, DAG.getNode(Op1, dl, NVT, InH, Amt),Sh2); + + if (N->getOpcode() != ISD::SHL) + std::swap(Hi, Lo); return true; } -#endif return false; } diff --git a/test/CodeGen/X86/2008-12-16-BadShift.ll b/test/CodeGen/X86/2008-12-16-BadShift.ll deleted file mode 100644 index 6c70c5b..0000000 --- a/test/CodeGen/X86/2008-12-16-BadShift.ll +++ /dev/null @@ -1,19 +0,0 @@ -; RUN: llc < %s | not grep shrl -; Note: this test is really trying to make sure that the shift -; returns the right result; shrl is most likely wrong, -; but if CodeGen starts legitimately using an shrl here, -; please adjust the test appropriately. - -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32" -target triple = "i386-pc-linux-gnu" -@.str = internal constant [6 x i8] c"%lld\0A\00" ; <[6 x i8]*> [#uses=1] - -define i64 @mebbe_shift(i32 %xx, i32 %test) nounwind { -entry: - %conv = zext i32 %xx to i64 ; <i64> [#uses=1] - %tobool = icmp ne i32 %test, 0 ; <i1> [#uses=1] - %shl = select i1 %tobool, i64 3, i64 0 ; <i64> [#uses=1] - %x.0 = shl i64 %conv, %shl ; <i64> [#uses=1] - ret i64 %x.0 -} - diff --git a/test/CodeGen/X86/legalize-shift-64.ll b/test/CodeGen/X86/legalize-shift-64.ll new file mode 100644 index 0000000..66d9a6d --- /dev/null +++ b/test/CodeGen/X86/legalize-shift-64.ll @@ -0,0 +1,56 @@ +; RUN: llc -march=x86 < %s | FileCheck %s + +define i64 @test1(i32 %xx, i32 %test) nounwind { + %conv = zext i32 %xx to i64 + %and = and i32 %test, 7 + %sh_prom = zext i32 %and to i64 + %shl = shl i64 %conv, %sh_prom + ret i64 %shl +; CHECK: test1: +; CHECK: shll %cl, %eax +; CHECK: xorb $31 +; CHECK: shrl %cl, %edx +; CHECK: shrl %edx +} + +define i64 @test2(i64 %xx, i32 %test) nounwind { + %and = and i32 %test, 7 + %sh_prom = zext i32 %and to i64 + %shl = shl i64 %xx, %sh_prom + ret i64 %shl +; CHECK: test2: +; CHECK: shll %cl, %esi +; CHECK: xorb $31 +; CHECK: shrl %cl, %edx +; CHECK: shrl %edx +; CHECK: orl %esi, %edx +; CHECK: shll %cl, %eax +} + +define i64 @test3(i64 %xx, i32 %test) nounwind { + %and = and i32 %test, 7 + %sh_prom = zext i32 %and to i64 + %shr = lshr i64 %xx, %sh_prom + ret i64 %shr +; CHECK: test3: +; CHECK: shrl %cl, %esi +; CHECK: xorb $31, %cl +; CHECK: shll %cl, %eax +; CHECK: addl %eax, %eax +; CHECK: orl %esi, %eax +; CHECK: shrl %cl, %edx +} + +define i64 @test4(i64 %xx, i32 %test) nounwind { + %and = and i32 %test, 7 + %sh_prom = zext i32 %and to i64 + %shr = ashr i64 %xx, %sh_prom + ret i64 %shr +; CHECK: test4: +; CHECK: shrl %cl, %esi +; CHECK: xorb $31, %cl +; CHECK: shll %cl, %eax +; CHECK: addl %eax, %eax +; CHECK: orl %esi, %eax +; CHECK: sarl %cl, %edx +} |