aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
diff options
context:
space:
mode:
authorBill Schmidt <wschmidt@linux.vnet.ibm.com>2013-02-20 20:41:42 +0000
committerBill Schmidt <wschmidt@linux.vnet.ibm.com>2013-02-20 20:41:42 +0000
commitabc402886e407e21d845cccc15723cffd6e2dc20 (patch)
treefa874ad96d4341f8bed0efa315a1e52ad433756c /lib/Target/PowerPC/PPCISelDAGToDAG.cpp
parent8a3a1deed8e7b18b18dea73cb4245a8ef7c46a4f (diff)
downloadexternal_llvm-abc402886e407e21d845cccc15723cffd6e2dc20.zip
external_llvm-abc402886e407e21d845cccc15723cffd6e2dc20.tar.gz
external_llvm-abc402886e407e21d845cccc15723cffd6e2dc20.tar.bz2
Additional fixes for bug 15155.
This handles the cases where the 6-bit splat element is odd, converting to a three-instruction sequence to add or subtract two splats. With this fix, the XFAIL in test/CodeGen/PowerPC/vec_constants.ll is removed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175663 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/PowerPC/PPCISelDAGToDAG.cpp')
-rw-r--r--lib/Target/PowerPC/PPCISelDAGToDAG.cpp59
1 files changed, 50 insertions, 9 deletions
diff --git a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 01d731a..1453506 100644
--- a/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -1323,34 +1323,75 @@ SDNode *PPCDAGToDAGISel::Select(SDNode *N) {
SDValue(Tmp, 0), GA);
}
case PPCISD::VADD_SPLAT: {
- // Convert: VADD_SPLAT elt, size
- // Into: tmp = VSPLTIS[BHW] elt
- // VADDU[BHW]M tmp, tmp
- // Where: [BHW] = B for size = 1, H for size = 2, W for size = 4
+ // This expands into one of three sequences, depending on whether
+ // the first operand is odd or even, positive or negative.
assert(isa<ConstantSDNode>(N->getOperand(0)) &&
isa<ConstantSDNode>(N->getOperand(1)) &&
"Invalid operand on VADD_SPLAT!");
+
+ int Elt = N->getConstantOperandVal(0);
int EltSize = N->getConstantOperandVal(1);
- unsigned Opc1, Opc2;
+ unsigned Opc1, Opc2, Opc3;
EVT VT;
+
if (EltSize == 1) {
Opc1 = PPC::VSPLTISB;
Opc2 = PPC::VADDUBM;
+ Opc3 = PPC::VSUBUBM;
VT = MVT::v16i8;
} else if (EltSize == 2) {
Opc1 = PPC::VSPLTISH;
Opc2 = PPC::VADDUHM;
+ Opc3 = PPC::VSUBUHM;
VT = MVT::v8i16;
} else {
assert(EltSize == 4 && "Invalid element size on VADD_SPLAT!");
Opc1 = PPC::VSPLTISW;
Opc2 = PPC::VADDUWM;
+ Opc3 = PPC::VSUBUWM;
VT = MVT::v4i32;
}
- SDValue Elt = getI32Imm(N->getConstantOperandVal(0));
- SDNode *Tmp = CurDAG->getMachineNode(Opc1, dl, VT, Elt);
- SDValue TmpVal = SDValue(Tmp, 0);
- return CurDAG->getMachineNode(Opc2, dl, VT, TmpVal, TmpVal);
+
+ if ((Elt & 1) == 0) {
+ // Elt is even, in the range [-32,-18] + [16,30].
+ //
+ // Convert: VADD_SPLAT elt, size
+ // Into: tmp = VSPLTIS[BHW] elt
+ // VADDU[BHW]M tmp, tmp
+ // Where: [BHW] = B for size = 1, H for size = 2, W for size = 4
+ SDValue EltVal = getI32Imm(Elt >> 1);
+ SDNode *Tmp = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
+ SDValue TmpVal = SDValue(Tmp, 0);
+ return CurDAG->getMachineNode(Opc2, dl, VT, TmpVal, TmpVal);
+
+ } else if (Elt > 0) {
+ // Elt is odd and positive, in the range [17,31].
+ //
+ // Convert: VADD_SPLAT elt, size
+ // Into: tmp1 = VSPLTIS[BHW] elt-16
+ // tmp2 = VSPLTIS[BHW] -16
+ // VSUBU[BHW]M tmp1, tmp2
+ SDValue EltVal = getI32Imm(Elt - 16);
+ SDNode *Tmp1 = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
+ EltVal = getI32Imm(-16);
+ SDNode *Tmp2 = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
+ return CurDAG->getMachineNode(Opc3, dl, VT, SDValue(Tmp1, 0),
+ SDValue(Tmp2, 0));
+
+ } else {
+ // Elt is odd and negative, in the range [-31,-17].
+ //
+ // Convert: VADD_SPLAT elt, size
+ // Into: tmp1 = VSPLTIS[BHW] elt+16
+ // tmp2 = VSPLTIS[BHW] -16
+ // VADDU[BHW]M tmp1, tmp2
+ SDValue EltVal = getI32Imm(Elt + 16);
+ SDNode *Tmp1 = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
+ EltVal = getI32Imm(-16);
+ SDNode *Tmp2 = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
+ return CurDAG->getMachineNode(Opc2, dl, VT, SDValue(Tmp1, 0),
+ SDValue(Tmp2, 0));
+ }
}
}