[llvm] r318877 - [Hexagon] Implement buildVector32 and buildVector64 as utility functions
Krzysztof Parzyszek via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 22 12:56:23 PST 2017
Author: kparzysz
Date: Wed Nov 22 12:56:23 2017
New Revision: 318877
URL: http://llvm.org/viewvc/llvm-project?rev=318877&view=rev
Log:
[Hexagon] Implement buildVector32 and buildVector64 as utility functions
Change LowerBUILD_VECTOR to use those functions. This commit will tempora-
rily affect constant vector generation (it will generate constant-extended
values instead of non-extended combines), but the code for the general case
should be better. The constant selection part will be fixed later.
Modified:
llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.cpp
llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.h
llvm/trunk/test/CodeGen/Hexagon/constp-combine-neg.ll
llvm/trunk/test/CodeGen/Hexagon/vect/vect-cst-v4i32.ll
llvm/trunk/test/CodeGen/Hexagon/vect/vect-vsplatb.ll
Modified: llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.cpp?rev=318877&r1=318876&r2=318877&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.cpp Wed Nov 22 12:56:23 2017
@@ -2461,151 +2461,159 @@ HexagonTargetLowering::LowerVECTOR_SHIFT
}
SDValue
-HexagonTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
- BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Op.getNode());
- SDLoc dl(Op);
- EVT VT = Op.getValueType();
-
- unsigned Size = VT.getSizeInBits();
-
- // Only handle vectors of 64 bits or shorter.
- if (Size > 64)
- return SDValue();
-
- unsigned NElts = BVN->getNumOperands();
-
- // Try to generate a SPLAT instruction.
- if (VT == MVT::v4i8 || VT == MVT::v4i16 || VT == MVT::v2i32) {
- APInt APSplatBits, APSplatUndef;
- unsigned SplatBitSize;
- bool HasAnyUndefs;
- if (BVN->isConstantSplat(APSplatBits, APSplatUndef, SplatBitSize,
- HasAnyUndefs, 0, false)) {
- if (SplatBitSize == VT.getVectorElementType().getSizeInBits()) {
- unsigned ZV = APSplatBits.getZExtValue();
- assert(SplatBitSize <= 32 && "Can only handle up to i32");
- // Sign-extend the splat value from SplatBitSize to 32.
- int32_t SV = SplatBitSize < 32
- ? int32_t(ZV << (32-SplatBitSize)) >> (32-SplatBitSize)
- : int32_t(ZV);
- return DAG.getNode(HexagonISD::VSPLAT, dl, VT,
- DAG.getConstant(SV, dl, MVT::i32));
- }
- }
+HexagonTargetLowering::buildVector32(ArrayRef<SDValue> Elem, const SDLoc &dl,
+ MVT VecTy, SelectionDAG &DAG) const {
+ MVT ElemTy = VecTy.getVectorElementType();
+ assert(VecTy.getVectorNumElements() == Elem.size());
+
+ SmallVector<ConstantSDNode*,4> Consts;
+ bool AllConst = true;
+ for (SDValue V : Elem) {
+ if (V.getOpcode() == ISD::UNDEF)
+ V = DAG.getConstant(0, dl, ElemTy);
+ auto *C = dyn_cast<ConstantSDNode>(V.getNode());
+ Consts.push_back(C);
+ AllConst = AllConst && C != nullptr;
}
- // Try to generate COMBINE to build v2i32 vectors.
- if (VT.getSimpleVT() == MVT::v2i32) {
- SDValue V0 = BVN->getOperand(0);
- SDValue V1 = BVN->getOperand(1);
-
- if (V0.isUndef())
- V0 = DAG.getConstant(0, dl, MVT::i32);
- if (V1.isUndef())
- V1 = DAG.getConstant(0, dl, MVT::i32);
-
- ConstantSDNode *C0 = dyn_cast<ConstantSDNode>(V0);
- ConstantSDNode *C1 = dyn_cast<ConstantSDNode>(V1);
- // If the element isn't a constant, it is in a register:
- // generate a COMBINE Register Register instruction.
- if (!C0 || !C1)
- return DAG.getNode(HexagonISD::COMBINE, dl, VT, V1, V0);
-
- // If one of the operands is an 8 bit integer constant, generate
- // a COMBINE Immediate Immediate instruction.
- if (isInt<8>(C0->getSExtValue()) ||
- isInt<8>(C1->getSExtValue()))
- return DAG.getNode(HexagonISD::COMBINE, dl, VT, V1, V0);
- }
-
- // Try to generate a S2_packhl to build v2i16 vectors.
- if (VT.getSimpleVT() == MVT::v2i16) {
- for (unsigned i = 0, e = NElts; i != e; ++i) {
- if (BVN->getOperand(i).isUndef())
- continue;
- ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(BVN->getOperand(i));
- // If the element isn't a constant, it is in a register:
- // generate a S2_packhl instruction.
- if (!Cst) {
- SDValue pack = DAG.getNode(HexagonISD::PACKHL, dl, MVT::v4i16,
- BVN->getOperand(1), BVN->getOperand(0));
-
- return DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::v2i16,
- pack);
- }
+ unsigned First, Num = Elem.size();
+ for (First = 0; First != Num; ++First)
+ if (Elem[First].getOpcode() != ISD::UNDEF)
+ break;
+ if (First == Num)
+ return DAG.getUNDEF(VecTy);
+
+ if (ElemTy == MVT::i16) {
+ assert(Elem.size() == 2);
+ if (AllConst) {
+ uint32_t V = (Consts[0]->getZExtValue() & 0xFFFF) |
+ Consts[1]->getZExtValue() << 16;
+ return DAG.getBitcast(MVT::v2i16, DAG.getConstant(V, dl, MVT::i32));
}
+ SDNode *N = DAG.getMachineNode(Hexagon::A2_combine_ll, dl, MVT::i32,
+ { Elem[1], Elem[0] });
+ return DAG.getBitcast(MVT::v2i16, SDValue(N,0));
}
- // In the general case, generate a CONST32 or a CONST64 for constant vectors,
- // and insert_vector_elt for all the other cases.
- uint64_t Res = 0;
- unsigned EltSize = Size / NElts;
- SDValue ConstVal;
- uint64_t Mask = ~uint64_t(0ULL) >> (64 - EltSize);
- bool HasNonConstantElements = false;
-
- for (unsigned i = 0, e = NElts; i != e; ++i) {
- // LLVM's BUILD_VECTOR operands are in Little Endian mode, whereas Hexagon's
- // combine, const64, etc. are Big Endian.
- unsigned OpIdx = NElts - i - 1;
- SDValue Operand = BVN->getOperand(OpIdx);
- if (Operand.isUndef())
+ // First try generating a constant.
+ assert(ElemTy == MVT::i8 && Num == 4);
+ if (AllConst) {
+ int32_t V = (Consts[0]->getZExtValue() & 0xFF) |
+ (Consts[1]->getZExtValue() & 0xFF) << 8 |
+ (Consts[1]->getZExtValue() & 0xFF) << 16 |
+ Consts[2]->getZExtValue() << 24;
+ return DAG.getBitcast(MVT::v4i8, DAG.getConstant(V, dl, MVT::i32));
+ }
+
+ // Then try splat.
+ bool IsSplat = true;
+ for (unsigned i = 0; i != Num; ++i) {
+ if (i == First)
+ continue;
+ if (Elem[i] == Elem[First] || Elem[i].getOpcode() == ISD::UNDEF)
continue;
+ IsSplat = false;
+ break;
+ }
+ if (IsSplat)
+ return DAG.getNode(HexagonISD::VSPLAT, dl, VecTy, Elem[First]);
- int64_t Val = 0;
- if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Operand))
- Val = Cst->getSExtValue();
- else
- HasNonConstantElements = true;
-
- Val &= Mask;
- Res = (Res << EltSize) | Val;
- }
-
- if (Size > 64)
- return SDValue();
-
- if (Size == 64)
- ConstVal = DAG.getConstant(Res, dl, MVT::i64);
- else
- ConstVal = DAG.getConstant(Res, dl, MVT::i32);
-
- // When there are non constant operands, add them with INSERT_VECTOR_ELT to
- // ConstVal, the constant part of the vector.
- if (HasNonConstantElements) {
- EVT EltVT = VT.getVectorElementType();
- SDValue Width = DAG.getConstant(EltVT.getSizeInBits(), dl, MVT::i64);
- SDValue Shifted = DAG.getNode(ISD::SHL, dl, MVT::i64, Width,
- DAG.getConstant(32, dl, MVT::i64));
-
- for (unsigned i = 0, e = NElts; i != e; ++i) {
- // LLVM's BUILD_VECTOR operands are in Little Endian mode, whereas Hexagon
- // is Big Endian.
- unsigned OpIdx = NElts - i - 1;
- SDValue Operand = BVN->getOperand(OpIdx);
- if (isa<ConstantSDNode>(Operand))
- // This operand is already in ConstVal.
- continue;
+ // Generate
+ // (zxtb(Elem[0]) | (zxtb(Elem[1]) << 8)) |
+ // (zxtb(Elem[2]) | (zxtb(Elem[3]) << 8)) << 16
+ SDValue S8 = DAG.getConstant(8, dl, MVT::i32);
+ SDValue S16 = DAG.getConstant(16, dl, MVT::i32);
+ SDValue V0 = DAG.getZExtOrTrunc(Elem[0], dl, MVT::i32);
+ SDValue V1 = DAG.getZExtOrTrunc(Elem[2], dl, MVT::i32);
+ SDValue V2 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Elem[1], S8});
+ SDValue V3 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Elem[3], S8});
+ SDValue V4 = DAG.getNode(ISD::OR, dl, MVT::i32, {V0, V2});
+ SDValue V5 = DAG.getNode(ISD::OR, dl, MVT::i32, {V1, V3});
+ SDValue V6 = DAG.getNode(ISD::SHL, dl, MVT::i32, {V5, S16});
+ SDValue V7 = DAG.getNode(ISD::OR, dl, MVT::i32, {V4, V6});
+ return DAG.getBitcast(MVT::v4i8, V7);
+}
+
+SDValue
+HexagonTargetLowering::buildVector64(ArrayRef<SDValue> Elem, const SDLoc &dl,
+ MVT VecTy, SelectionDAG &DAG) const {
+ MVT ElemTy = VecTy.getVectorElementType();
+ assert(VecTy.getVectorNumElements() == Elem.size());
+
+ SmallVector<ConstantSDNode*,8> Consts;
+ bool AllConst = true;
+ for (SDValue V : Elem) {
+ if (V.getOpcode() == ISD::UNDEF)
+ V = DAG.getConstant(0, dl, ElemTy);
+ auto *C = dyn_cast<ConstantSDNode>(V.getNode());
+ Consts.push_back(C);
+ AllConst = AllConst && C != nullptr;
+ }
- if (VT.getSizeInBits() == 64 &&
- Operand.getValueSizeInBits() == 32) {
- SDValue C = DAG.getConstant(0, dl, MVT::i32);
- Operand = DAG.getNode(HexagonISD::COMBINE, dl, VT, C, Operand);
- }
-
- SDValue Idx = DAG.getConstant(OpIdx, dl, MVT::i64);
- SDValue Offset = DAG.getNode(ISD::MUL, dl, MVT::i64, Idx, Width);
- SDValue Combined = DAG.getNode(ISD::OR, dl, MVT::i64, Shifted, Offset);
- const SDValue Ops[] = {ConstVal, Operand, Combined};
-
- if (VT.getSizeInBits() == 32)
- ConstVal = DAG.getNode(HexagonISD::INSERTRP, dl, MVT::i32, Ops);
- else
- ConstVal = DAG.getNode(HexagonISD::INSERTRP, dl, MVT::i64, Ops);
+ unsigned First, Num = Elem.size();
+ for (First = 0; First != Num; ++First)
+ if (Elem[First].getOpcode() != ISD::UNDEF)
+ break;
+ if (First == Num)
+ return DAG.getUNDEF(VecTy);
+
+ // First try splat if possible.
+ if (ElemTy == MVT::i16) {
+ bool IsSplat = true;
+ for (unsigned i = 0; i != Num; ++i) {
+ if (i == First)
+ continue;
+ if (Elem[i] == Elem[First] || Elem[i].getOpcode() == ISD::UNDEF)
+ continue;
+ IsSplat = false;
+ break;
}
+ if (IsSplat)
+ return DAG.getNode(HexagonISD::VSPLAT, dl, VecTy, Elem[First]);
+ }
+
+ // Then try constant.
+ if (AllConst) {
+ uint64_t Val = 0;
+ unsigned W = ElemTy.getSizeInBits();
+ uint64_t Mask = (ElemTy == MVT::i8) ? 0xFFull
+ : (ElemTy == MVT::i16) ? 0xFFFFull : 0xFFFFFFFFull;
+ for (unsigned i = 0; i != Num; ++i)
+ Val = (Val << W) | (Consts[i]->getZExtValue() & Mask);
+ SDValue V0 = DAG.getConstant(Val, dl, MVT::i64);
+ return DAG.getBitcast(VecTy, V0);
+ }
+
+ // Build two 32-bit vectors and concatenate.
+ MVT HalfTy = MVT::getVectorVT(ElemTy, Num/2);
+ SDValue L = (ElemTy == MVT::i32)
+ ? Elem[0]
+ : buildVector32({Elem.data(), Num/2}, dl, HalfTy, DAG);
+ SDValue H = (ElemTy == MVT::i32)
+ ? Elem[1]
+ : buildVector32({Elem.data()+Num/2, Num/2}, dl, HalfTy, DAG);
+ unsigned Id = Hexagon::DoubleRegsRegClassID;
+ SDNode *N = DAG.getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VecTy,
+ { DAG.getTargetConstant(Id, dl, MVT::i32),
+ L, DAG.getTargetConstant(Hexagon::isub_lo, dl, MVT::i32),
+ H, DAG.getTargetConstant(Hexagon::isub_hi, dl, MVT::i32) });
+ return SDValue(N, 0);
+}
+
+SDValue
+HexagonTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
+ MVT VT = Op.getValueType().getSimpleVT();
+ unsigned BW = VT.getSizeInBits();
+ if (BW == 32 || BW == 64) {
+ SmallVector<SDValue,8> Ops;
+ for (unsigned i = 0, e = Op.getNumOperands(); i != e; ++i)
+ Ops.push_back(Op.getOperand(i));
+ if (BW == 32)
+ return buildVector32(Ops, SDLoc(Op), VT, DAG);
+ return buildVector64(Ops, SDLoc(Op), VT, DAG);
}
- return DAG.getNode(ISD::BITCAST, dl, VT, ConstVal);
+ return SDValue();
}
SDValue
Modified: llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.h?rev=318877&r1=318876&r2=318877&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.h (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.h Wed Nov 22 12:56:23 2017
@@ -270,6 +270,11 @@ namespace HexagonISD {
}
protected:
+ SDValue buildVector32(ArrayRef<SDValue> Elem, const SDLoc &dl, MVT VecTy,
+ SelectionDAG &DAG) const;
+ SDValue buildVector64(ArrayRef<SDValue> Elem, const SDLoc &dl, MVT VecTy,
+ SelectionDAG &DAG) const;
+
std::pair<const TargetRegisterClass*, uint8_t>
findRepresentativeClass(const TargetRegisterInfo *TRI, MVT VT)
const override;
Modified: llvm/trunk/test/CodeGen/Hexagon/constp-combine-neg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/constp-combine-neg.ll?rev=318877&r1=318876&r2=318877&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/Hexagon/constp-combine-neg.ll (original)
+++ llvm/trunk/test/CodeGen/Hexagon/constp-combine-neg.ll Wed Nov 22 12:56:23 2017
@@ -1,3 +1,6 @@
+; XFAIL: *
+; Implement generic selection of a constant.
+
; RUN: llc -O2 -march=hexagon < %s | FileCheck %s --check-prefix=CHECK-TEST1
; RUN: llc -O2 -march=hexagon < %s | FileCheck %s --check-prefix=CHECK-TEST2
; RUN: llc -O2 -march=hexagon < %s | FileCheck %s --check-prefix=CHECK-TEST3
Modified: llvm/trunk/test/CodeGen/Hexagon/vect/vect-cst-v4i32.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/vect/vect-cst-v4i32.ll?rev=318877&r1=318876&r2=318877&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/Hexagon/vect/vect-cst-v4i32.ll (original)
+++ llvm/trunk/test/CodeGen/Hexagon/vect/vect-cst-v4i32.ll Wed Nov 22 12:56:23 2017
@@ -1,3 +1,6 @@
+; XFAIL: *
+; Extract selecting of a constant into a generic utility function.
+;
; RUN: llc -march=hexagon -mcpu=hexagonv5 -disable-hsdr < %s | FileCheck %s
; This one should generate a combine with two immediates.
; CHECK: combine(#7,#7)
Modified: llvm/trunk/test/CodeGen/Hexagon/vect/vect-vsplatb.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/vect/vect-vsplatb.ll?rev=318877&r1=318876&r2=318877&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/Hexagon/vect/vect-vsplatb.ll (original)
+++ llvm/trunk/test/CodeGen/Hexagon/vect/vect-vsplatb.ll Wed Nov 22 12:56:23 2017
@@ -5,7 +5,7 @@
@A = common global [400 x i8] zeroinitializer, align 8
@C = common global [400 x i8] zeroinitializer, align 8
-define void @run() nounwind {
+define void @run(i8 %v) nounwind {
entry:
br label %polly.loop_body
@@ -19,7 +19,11 @@ polly.loop_body:
%p_arrayidx = getelementptr [400 x i8], [400 x i8]* @B, i32 0, i32 %polly.loopiv25
%vector_ptr = bitcast i8* %p_arrayidx to <4 x i8>*
%_p_vec_full = load <4 x i8>, <4 x i8>* %vector_ptr, align 8
- %mulp_vec = mul <4 x i8> %_p_vec_full, <i8 7, i8 7, i8 7, i8 7>
+ %vec0 = insertelement <4 x i8> undef, i8 %v, i32 0
+ %vec1 = insertelement <4 x i8> %vec0, i8 %v, i32 1
+ %vec2 = insertelement <4 x i8> %vec1, i8 %v, i32 2
+ %vec3 = insertelement <4 x i8> %vec2, i8 %v, i32 3
+ %mulp_vec = mul <4 x i8> %_p_vec_full, %vec3
%vector_ptr14 = bitcast i8* %p_arrayidx1 to <4 x i8>*
%_p_vec_full15 = load <4 x i8>, <4 x i8>* %vector_ptr14, align 8
%addp_vec = add <4 x i8> %_p_vec_full15, %mulp_vec
More information about the llvm-commits
mailing list