diff options
author | Bill Schmidt <wschmidt@linux.vnet.ibm.com> | 2013-02-20 20:41:42 +0000 |
---|---|---|
committer | Bill Schmidt <wschmidt@linux.vnet.ibm.com> | 2013-02-20 20:41:42 +0000 |
commit | abc402886e407e21d845cccc15723cffd6e2dc20 (patch) | |
tree | fa874ad96d4341f8bed0efa315a1e52ad433756c /lib/Target/PowerPC/PPCISelDAGToDAG.cpp | |
parent | 8a3a1deed8e7b18b18dea73cb4245a8ef7c46a4f (diff) | |
download | external_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.cpp | 59 |
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)); + } } } |