[clang] 331dcc4 - [PowerPC] Implemented Vector Load with Zero and Signed Extend Builtins
Albion Fung via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 28 09:29:13 PDT 2020
Author: Albion Fung
Date: 2020-08-28T11:28:58-05:00
New Revision: 331dcc43eac28b8e659f928fd1f1ce7fd091e1e3
URL: https://github.com/llvm/llvm-project/commit/331dcc43eac28b8e659f928fd1f1ce7fd091e1e3
DIFF: https://github.com/llvm/llvm-project/commit/331dcc43eac28b8e659f928fd1f1ce7fd091e1e3.diff
LOG: [PowerPC] Implemented Vector Load with Zero and Signed Extend Builtins
This patch implements the builtins for Vector Load with Zero and Signed Extend Builtins (lxvr_x for b, h, w, d), and adds the appropriate test cases for these builtins. The builtins utilize the vector load instructions itnroduced with ISA 3.1.
Differential Revision: https://reviews.llvm.org/D82502#inline-797941
Added:
Modified:
clang/lib/Headers/altivec.h
clang/test/CodeGen/builtins-ppc-p10vector.c
llvm/lib/Target/PowerPC/PPCISelLowering.cpp
llvm/lib/Target/PowerPC/PPCISelLowering.h
llvm/lib/Target/PowerPC/PPCInstrPrefix.td
llvm/test/CodeGen/PowerPC/builtins-ppc-p10vsx.ll
Removed:
################################################################################
diff --git a/clang/lib/Headers/altivec.h b/clang/lib/Headers/altivec.h
index 6583b0f22a16..5bc0e23792d4 100644
--- a/clang/lib/Headers/altivec.h
+++ b/clang/lib/Headers/altivec.h
@@ -16557,6 +16557,54 @@ vec_xl_be(signed long long __offset, unsigned __int128 *__ptr) {
#define vec_xl_be vec_xl
#endif
+#if defined(__POWER10_VECTOR__) && defined(__VSX__)
+
+/* vect_xl_sext */
+
+static __inline__ vector unsigned __int128 __ATTRS_o_ai
+vec_xl_sext(signed long long __offset, signed char *__pointer) {
+ return (vector unsigned __int128)*(__pointer + __offset);
+}
+
+static __inline__ vector unsigned __int128 __ATTRS_o_ai
+vec_xl_sext(signed long long __offset, signed short *__pointer) {
+ return (vector unsigned __int128)*(__pointer + __offset);
+}
+
+static __inline__ vector unsigned __int128 __ATTRS_o_ai
+vec_xl_sext(signed long long __offset, signed int *__pointer) {
+ return (vector unsigned __int128)*(__pointer + __offset);
+}
+
+static __inline__ vector unsigned __int128 __ATTRS_o_ai
+vec_xl_sext(signed long long __offset, signed long long *__pointer) {
+ return (vector unsigned __int128)*(__pointer + __offset);
+}
+
+/* vec_xl_zext */
+
+static __inline__ vector unsigned __int128 __ATTRS_o_ai
+vec_xl_zext(signed long long __offset, unsigned char *__pointer) {
+ return (vector unsigned __int128)*(__pointer + __offset);
+}
+
+static __inline__ vector unsigned __int128 __ATTRS_o_ai
+vec_xl_zext(signed long long __offset, unsigned short *__pointer) {
+ return (vector unsigned __int128)*(__pointer + __offset);
+}
+
+static __inline__ vector unsigned __int128 __ATTRS_o_ai
+vec_xl_zext(signed long long __offset, unsigned int *__pointer) {
+ return (vector unsigned __int128)*(__pointer + __offset);
+}
+
+static __inline__ vector unsigned __int128 __ATTRS_o_ai
+vec_xl_zext(signed long long __offset, unsigned long long *__pointer) {
+ return (vector unsigned __int128)*(__pointer + __offset);
+}
+
+#endif
+
/* vec_xst */
static inline __ATTRS_o_ai void vec_xst(vector signed char __vec,
diff --git a/clang/test/CodeGen/builtins-ppc-p10vector.c b/clang/test/CodeGen/builtins-ppc-p10vector.c
index 16e468b62318..09477891bb06 100644
--- a/clang/test/CodeGen/builtins-ppc-p10vector.c
+++ b/clang/test/CodeGen/builtins-ppc-p10vector.c
@@ -20,10 +20,14 @@ vector unsigned long long vulla, vullb, vullc;
vector unsigned __int128 vui128a, vui128b, vui128c;
vector float vfa, vfb;
vector double vda, vdb;
-unsigned int uia, uib;
-unsigned char uca;
-unsigned short usa;
-unsigned long long ulla;
+signed int *iap;
+unsigned int uia, uib, *uiap;
+signed char *cap;
+unsigned char uca, *ucap;
+signed short *sap;
+unsigned short usa, *usap;
+signed long long *llap, llb;
+unsigned long long ulla, *ullap;
vector signed long long test_vec_mul_sll(void) {
// CHECK: mul <2 x i64>
@@ -911,3 +915,59 @@ int test_vec_test_lsbb_all_zeros(void) {
// CHECK-NEXT: ret i32
return vec_test_lsbb_all_zeros(vuca);
}
+
+vector signed __int128 test_vec_xl_sext_i8(void) {
+ // CHECK: load i8
+ // CHECK: sext i8
+ // CHECK: ret <1 x i128>
+ return vec_xl_sext(llb, cap);
+}
+
+vector signed __int128 test_vec_xl_sext_i16(void) {
+ // CHECK: load i16
+ // CHECK: sext i16
+ // CHECK: ret <1 x i128>
+ return vec_xl_sext(llb, sap);
+}
+
+vector signed __int128 test_vec_xl_sext_i32(void) {
+ // CHECK: load i32
+ // CHECK: sext i32
+ // CHECK: ret <1 x i128>
+ return vec_xl_sext(llb, iap);
+}
+
+vector signed __int128 test_vec_xl_sext_i64(void) {
+ // CHECK: load i64
+ // CHECK: sext i64
+ // CHECK: ret <1 x i128>
+ return vec_xl_sext(llb, llap);
+}
+
+vector unsigned __int128 test_vec_xl_zext_i8(void) {
+ // CHECK: load i8
+ // CHECK: zext i8
+ // CHECK: ret <1 x i128>
+ return vec_xl_zext(llb, ucap);
+}
+
+vector unsigned __int128 test_vec_xl_zext_i16(void) {
+ // CHECK: load i16
+ // CHECK: zext i16
+ // CHECK: ret <1 x i128>
+ return vec_xl_zext(llb, usap);
+}
+
+vector unsigned __int128 test_vec_xl_zext_i32(void) {
+ // CHECK: load i32
+ // CHECK: zext i32
+ // CHECK: ret <1 x i128>
+ return vec_xl_zext(llb, uiap);
+}
+
+vector unsigned __int128 test_vec_xl_zext_i64(void) {
+ // CHECK: load i64
+ // CHECK: zext i64
+ // CHECK: ret <1 x i128>
+ return vec_xl_zext(llb, ullap);
+}
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 2c0de9a90b8f..4ffb35dda4fa 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -1527,6 +1527,7 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const {
return "PPCISD::STRICT_FCFIDS";
case PPCISD::STRICT_FCFIDUS:
return "PPCISD::STRICT_FCFIDUS";
+ case PPCISD::LXVRZX: return "PPCISD::LXVRZX";
}
return nullptr;
}
@@ -13639,6 +13640,46 @@ static SDValue combineBVOfVecSExt(SDNode *N, SelectionDAG &DAG) {
return SDValue();
}
+// Look for the pattern of a load from a narrow width to i128, feeding
+// into a BUILD_VECTOR of v1i128. Replace this sequence with a PPCISD node
+// (LXVRZX). This node represents a zero extending load that will be matched
+// to the Load VSX Vector Rightmost instructions.
+static SDValue combineBVZEXTLOAD(SDNode *N, SelectionDAG &DAG) {
+ SDLoc DL(N);
+
+ // This combine is only eligible for a BUILD_VECTOR of v1i128.
+ if (N->getValueType(0) != MVT::v1i128)
+ return SDValue();
+
+ SDValue Operand = N->getOperand(0);
+ // Proceed with the transformation if the operand to the BUILD_VECTOR
+ // is a load instruction.
+ if (Operand.getOpcode() != ISD::LOAD)
+ return SDValue();
+
+ LoadSDNode *LD = dyn_cast<LoadSDNode>(Operand);
+ EVT MemoryType = LD->getMemoryVT();
+
+ // This transformation is only valid if the we are loading either a byte,
+ // halfword, word, or doubleword.
+ bool ValidLDType = MemoryType == MVT::i8 || MemoryType == MVT::i16 ||
+ MemoryType == MVT::i32 || MemoryType == MVT::i64;
+
+ // Ensure that the load from the narrow width is being zero extended to i128.
+ if (!ValidLDType ||
+ (LD->getExtensionType() != ISD::ZEXTLOAD &&
+ LD->getExtensionType() != ISD::EXTLOAD))
+ return SDValue();
+
+ SDValue LoadOps[] = {
+ LD->getChain(), LD->getBasePtr(),
+ DAG.getIntPtrConstant(MemoryType.getScalarSizeInBits(), DL)};
+
+ return DAG.getMemIntrinsicNode(PPCISD::LXVRZX, DL,
+ DAG.getVTList(MVT::v1i128, MVT::Other),
+ LoadOps, MemoryType, LD->getMemOperand());
+}
+
SDValue PPCTargetLowering::DAGCombineBuildVector(SDNode *N,
DAGCombinerInfo &DCI) const {
assert(N->getOpcode() == ISD::BUILD_VECTOR &&
@@ -13676,6 +13717,14 @@ SDValue PPCTargetLowering::DAGCombineBuildVector(SDNode *N,
return Reduced;
}
+ // On Power10, the Load VSX Vector Rightmost instructions can be utilized
+ // if this is a BUILD_VECTOR of v1i128, and if the operand to the BUILD_VECTOR
+ // is a load from <valid narrow width> to i128.
+ if (Subtarget.isISA3_1()) {
+ SDValue BVOfZLoad = combineBVZEXTLOAD(N, DAG);
+ if (BVOfZLoad)
+ return BVOfZLoad;
+ }
if (N->getValueType(0) != MVT::v2f64)
return SDValue();
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index 8ee243017e7f..f51cd2823fcd 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -494,6 +494,12 @@ namespace llvm {
/// an xxswapd.
LXVD2X,
+ /// LXVRZX - Load VSX Vector Rightmost and Zero Extend
+ /// This node represents v1i128 BUILD_VECTOR of a zero extending load
+ /// instruction from <byte, halfword, word, or doubleword> to i128.
+ /// Allows utilization of the Load VSX Vector Rightmost Instructions.
+ LXVRZX,
+
/// VSRC, CHAIN = LOAD_VEC_BE CHAIN, Ptr - Occurs only for little endian.
/// Maps directly to one of lxvd2x/lxvw4x/lxvh8x/lxvb16x depending on
/// the vector type to load vector in big-endian element order.
diff --git a/llvm/lib/Target/PowerPC/PPCInstrPrefix.td b/llvm/lib/Target/PowerPC/PPCInstrPrefix.td
index 491d969861e1..f5176850836e 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrPrefix.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrPrefix.td
@@ -18,6 +18,15 @@ def PPCxxsplti32dx : SDNode<"PPCISD::XXSPLTI32DX", SDT_PPCSplat32, []>;
// address computations).
class isPCRel { bit PCRel = 1; }
+// PowerPC specific type constraints.
+def SDT_PPCLXVRZX : SDTypeProfile<1, 2, [
+ SDTCisVT<0, v1i128>, SDTCisPtrTy<1>, SDTCisPtrTy<2>
+]>;
+
+// PPC Specific DAG Nodes.
+def PPClxvrzx : SDNode<"PPCISD::LXVRZX", SDT_PPCLXVRZX,
+ [SDNPHasChain, SDNPMayLoad]>;
+
// Top-level class for prefixed instructions.
class PI<bits<6> pref, bits<6> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin> : Instruction {
@@ -1326,6 +1335,15 @@ let Predicates = [IsISA3_1] in {
(v1i128 (VSRAQ v1i128:$VRA, v1i128:$VRB))>;
def : Pat<(v1i128 (PPCsra v1i128:$VRA, v1i128:$VRB)),
(v1i128 (VSRAQ v1i128:$VRA, v1i128:$VRB))>;
+
+ def : Pat <(v1i128 (PPClxvrzx xoaddr:$src, 8)),
+ (v1i128 (COPY_TO_REGCLASS (LXVRBX xoaddr:$src), VRRC))>;
+ def : Pat <(v1i128 (PPClxvrzx xoaddr:$src, 16)),
+ (v1i128 (COPY_TO_REGCLASS (LXVRHX xoaddr:$src), VRRC))>;
+ def : Pat <(v1i128 (PPClxvrzx xoaddr:$src, 32)),
+ (v1i128 (COPY_TO_REGCLASS (LXVRWX xoaddr:$src), VRRC))>;
+ def : Pat <(v1i128 (PPClxvrzx xoaddr:$src, 64)),
+ (v1i128 (COPY_TO_REGCLASS (LXVRDX xoaddr:$src), VRRC))>;
}
let AddedComplexity = 400, Predicates = [IsISA3_1] in {
diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-p10vsx.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-p10vsx.ll
index faddb5b4cc7f..ca25afa458aa 100644
--- a/llvm/test/CodeGen/PowerPC/builtins-ppc-p10vsx.ll
+++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-p10vsx.ll
@@ -239,3 +239,181 @@ entry:
store i64 %conv, i64* %add.ptr, align 8
ret void
}
+
+define dso_local <1 x i128> @vec_xl_zext(i64 %__offset, i8* nocapture readonly %__pointer) {
+; CHECK-LABEL: vec_xl_zext:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lxvrbx v2, r4, r3
+; CHECK-NEXT: blr
+;
+; CHECK-O0-LABEL: vec_xl_zext:
+; CHECK-O0: # %bb.0: # %entry
+; CHECK-O0-NEXT: lxvrbx vs0, r4, r3
+; CHECK-O0-NEXT: xxlor v2, vs0, vs0
+; CHECK-O0-NEXT: blr
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %__pointer, i64 %__offset
+ %0 = load i8, i8* %add.ptr, align 1
+ %conv = zext i8 %0 to i128
+ %splat.splatinsert = insertelement <1 x i128> undef, i128 %conv, i32 0
+ ret <1 x i128> %splat.splatinsert
+}
+
+define dso_local <1 x i128> @vec_xl_zext_short(i64 %__offset, i16* nocapture readonly %__pointer) {
+; CHECK-LABEL: vec_xl_zext_short:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sldi r3, r3, 1
+; CHECK-NEXT: lxvrhx v2, r4, r3
+; CHECK-NEXT: blr
+;
+; CHECK-O0-LABEL: vec_xl_zext_short:
+; CHECK-O0: # %bb.0: # %entry
+; CHECK-O0-NEXT: sldi r3, r3, 1
+; CHECK-O0-NEXT: lxvrhx vs0, r4, r3
+; CHECK-O0-NEXT: xxlor v2, vs0, vs0
+; CHECK-O0-NEXT: blr
+entry:
+ %add.ptr = getelementptr inbounds i16, i16* %__pointer, i64 %__offset
+ %0 = load i16, i16* %add.ptr, align 2
+ %conv = zext i16 %0 to i128
+ %splat.splatinsert = insertelement <1 x i128> undef, i128 %conv, i32 0
+ ret <1 x i128> %splat.splatinsert
+}
+
+define dso_local <1 x i128> @vec_xl_zext_word(i64 %__offset, i32* nocapture readonly %__pointer) {
+; CHECK-LABEL: vec_xl_zext_word:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sldi r3, r3, 2
+; CHECK-NEXT: lxvrwx v2, r4, r3
+; CHECK-NEXT: blr
+;
+; CHECK-O0-LABEL: vec_xl_zext_word:
+; CHECK-O0: # %bb.0: # %entry
+; CHECK-O0-NEXT: sldi r3, r3, 2
+; CHECK-O0-NEXT: lxvrwx vs0, r4, r3
+; CHECK-O0-NEXT: xxlor v2, vs0, vs0
+; CHECK-O0-NEXT: blr
+entry:
+ %add.ptr = getelementptr inbounds i32, i32* %__pointer, i64 %__offset
+ %0 = load i32, i32* %add.ptr, align 4
+ %conv = zext i32 %0 to i128
+ %splat.splatinsert = insertelement <1 x i128> undef, i128 %conv, i32 0
+ ret <1 x i128> %splat.splatinsert
+}
+
+define dso_local <1 x i128> @vec_xl_zext_dw(i64 %__offset, i64* nocapture readonly %__pointer) {
+; CHECK-LABEL: vec_xl_zext_dw:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sldi r3, r3, 3
+; CHECK-NEXT: lxvrdx v2, r4, r3
+; CHECK-NEXT: blr
+;
+; CHECK-O0-LABEL: vec_xl_zext_dw:
+; CHECK-O0: # %bb.0: # %entry
+; CHECK-O0-NEXT: sldi r3, r3, 3
+; CHECK-O0-NEXT: lxvrdx vs0, r4, r3
+; CHECK-O0-NEXT: xxlor v2, vs0, vs0
+; CHECK-O0-NEXT: blr
+entry:
+ %add.ptr = getelementptr inbounds i64, i64* %__pointer, i64 %__offset
+ %0 = load i64, i64* %add.ptr, align 8
+ %conv = zext i64 %0 to i128
+ %splat.splatinsert = insertelement <1 x i128> undef, i128 %conv, i32 0
+ ret <1 x i128> %splat.splatinsert
+}
+
+define dso_local <1 x i128> @vec_xl_sext_b(i64 %offset, i8* %p) {
+; CHECK-LABEL: vec_xl_sext_b:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lbzx r3, r4, r3
+; CHECK-NEXT: extsb r3, r3
+; CHECK-NEXT: sradi r4, r3, 63
+; CHECK-NEXT: mtvsrdd v2, r4, r3
+; CHECK-NEXT: blr
+;
+; CHECK-O0-LABEL: vec_xl_sext_b:
+; CHECK-O0: # %bb.0: # %entry
+; CHECK-O0-NEXT: lbzx r3, r4, r3
+; CHECK-O0-NEXT: extsb r3, r3
+; CHECK-O0-NEXT: sradi r4, r3, 63
+; CHECK-O0-NEXT: mtvsrdd v2, r4, r3
+; CHECK-O0-NEXT: blr
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i64 %offset
+ %0 = load i8, i8* %add.ptr, align 1
+ %conv = sext i8 %0 to i128
+ %splat.splatinsert = insertelement <1 x i128> undef, i128 %conv, i32 0
+ ret <1 x i128> %splat.splatinsert
+}
+
+define dso_local <1 x i128> @vec_xl_sext_h(i64 %offset, i16* %p) {
+; CHECK-LABEL: vec_xl_sext_h:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sldi r3, r3, 1
+; CHECK-NEXT: lhax r3, r4, r3
+; CHECK-NEXT: sradi r4, r3, 63
+; CHECK-NEXT: mtvsrdd v2, r4, r3
+; CHECK-NEXT: blr
+;
+; CHECK-O0-LABEL: vec_xl_sext_h:
+; CHECK-O0: # %bb.0: # %entry
+; CHECK-O0-NEXT: sldi r3, r3, 1
+; CHECK-O0-NEXT: lhax r3, r4, r3
+; CHECK-O0-NEXT: sradi r4, r3, 63
+; CHECK-O0-NEXT: mtvsrdd v2, r4, r3
+; CHECK-O0-NEXT: blr
+entry:
+ %add.ptr = getelementptr inbounds i16, i16* %p, i64 %offset
+ %0 = load i16, i16* %add.ptr, align 2
+ %conv = sext i16 %0 to i128
+ %splat.splatinsert = insertelement <1 x i128> undef, i128 %conv, i32 0
+ ret <1 x i128> %splat.splatinsert
+}
+
+define dso_local <1 x i128> @vec_xl_sext_w(i64 %offset, i32* %p) {
+; CHECK-LABEL: vec_xl_sext_w:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sldi r3, r3, 2
+; CHECK-NEXT: lwax r3, r4, r3
+; CHECK-NEXT: sradi r4, r3, 63
+; CHECK-NEXT: mtvsrdd v2, r4, r3
+; CHECK-NEXT: blr
+;
+; CHECK-O0-LABEL: vec_xl_sext_w:
+; CHECK-O0: # %bb.0: # %entry
+; CHECK-O0-NEXT: sldi r3, r3, 2
+; CHECK-O0-NEXT: lwax r3, r4, r3
+; CHECK-O0-NEXT: sradi r4, r3, 63
+; CHECK-O0-NEXT: mtvsrdd v2, r4, r3
+; CHECK-O0-NEXT: blr
+entry:
+ %add.ptr = getelementptr inbounds i32, i32* %p, i64 %offset
+ %0 = load i32, i32* %add.ptr, align 4
+ %conv = sext i32 %0 to i128
+ %splat.splatinsert = insertelement <1 x i128> undef, i128 %conv, i32 0
+ ret <1 x i128> %splat.splatinsert
+}
+
+define dso_local <1 x i128> @vec_xl_sext_d(i64 %offset, i64* %p) {
+; CHECK-LABEL: vec_xl_sext_d:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sldi r3, r3, 3
+; CHECK-NEXT: ldx r3, r4, r3
+; CHECK-NEXT: sradi r4, r3, 63
+; CHECK-NEXT: mtvsrdd v2, r4, r3
+; CHECK-NEXT: blr
+;
+; CHECK-O0-LABEL: vec_xl_sext_d:
+; CHECK-O0: # %bb.0: # %entry
+; CHECK-O0-NEXT: sldi r3, r3, 3
+; CHECK-O0-NEXT: ldx r3, r4, r3
+; CHECK-O0-NEXT: sradi r4, r3, 63
+; CHECK-O0-NEXT: mtvsrdd v2, r4, r3
+; CHECK-O0-NEXT: blr
+entry:
+ %add.ptr = getelementptr inbounds i64, i64* %p, i64 %offset
+ %0 = load i64, i64* %add.ptr, align 8
+ %conv = sext i64 %0 to i128
+ %splat.splatinsert = insertelement <1 x i128> undef, i128 %conv, i32 0
+ ret <1 x i128> %splat.splatinsert
+}
More information about the cfe-commits
mailing list