Skip to content

Commit 7368558

Browse files
authored
[VP][RISCV] Add a vp.load.ff intrinsic for fault only first load. (#128593)
There's been some interest in supporting early-exit loops recently. https://discourse.llvm.org/t/rfc-supporting-more-early-exit-loops/84690 This patch was extracted from our downstream where we've been using it in our vectorizer.
1 parent 64eba6e commit 7368558

File tree

16 files changed

+1912
-0
lines changed

16 files changed

+1912
-0
lines changed

llvm/docs/LangRef.rst

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24243,6 +24243,92 @@ Examples:
2424324243
%also.r = call <8 x i8> @llvm.masked.load.v8i8.p0(ptr %ptr, i32 2, <8 x i1> %mask, <8 x i8> poison)
2424424244

2424524245

24246+
.. _int_vp_load_ff:
24247+
24248+
'``llvm.vp.load_ff``' Intrinsic
24249+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24250+
24251+
Syntax:
24252+
"""""""
24253+
This is an overloaded intrinsic.
24254+
24255+
::
24256+
24257+
declare {<4 x float>, i32} @llvm.vp.load.ff.v4f32.p0(ptr %ptr, <4 x i1> %mask, i32 %evl)
24258+
declare {<vscale x 2 x i16>, i32} @llvm.vp.load.ff.nxv2i16.p0(ptr %ptr, <vscale x 2 x i1> %mask, i32 %evl)
24259+
declare {<8 x float>, i32} @llvm.vp.load.ff.v8f32.p1(ptr addrspace(1) %ptr, <8 x i1> %mask, i32 %evl)
24260+
declare {<vscale x 1 x i64>, i32} @llvm.vp.load.ff.nxv1i64.p6(ptr addrspace(6) %ptr, <vscale x 1 x i1> %mask, i32 %evl)
24261+
24262+
Overview:
24263+
"""""""""
24264+
24265+
The '``llvm.vp.load.ff.*``' intrinsic is similar to
24266+
'``llvm.vp.load.*``', but will not trap if there are not ``evl`` readable
24267+
lanes at the pointer. '``ff``' stands for fault-first or fault-only-first.
24268+
24269+
Arguments:
24270+
""""""""""
24271+
24272+
The first argument is the base pointer for the load. The second argument is a
24273+
vector of boolean values with the same number of elements as the first return
24274+
type. The third is the explicit vector length of the operation. The first
24275+
return type and underlying type of the base pointer are the same vector types.
24276+
24277+
The :ref:`align <attr_align>` parameter attribute can be provided for the first
24278+
argument.
24279+
24280+
Semantics:
24281+
""""""""""
24282+
24283+
The '``llvm.vp.load.ff``' is designed for reading vector lanes in a single
24284+
IR operation where the number of lanes that can be read is not known and can
24285+
only be determined by looking at the data. This is useful for vectorizing
24286+
strcmp or strlen like loops where the data contains a null terminator. Some
24287+
targets have a fault-only-first load instruction that this intrinsic can be
24288+
lowered to. Other targets may support this intrinsic differently, for example by
24289+
lowering to a single scalar load guarded by ``evl!=0`` and ``mask[0]==1`` and
24290+
indicating only 1 lane could be read.
24291+
24292+
Like '``llvm.vp.load``', this intrinsic reads memory based on a ``mask`` and an
24293+
``evl``. If ``evl`` is non-zero and the first lane is masked-on, then the
24294+
first lane of the vector needs to be inbounds of an allocation. The remaining
24295+
masked-on lanes with index less than ``evl`` do not need to be inbounds of
24296+
an the same allocation or any allocation.
24297+
24298+
The second return value from the intrinsic indicates the index of the first
24299+
lane that could not be read for some reason or ``evl`` if all lanes could be
24300+
be read. Lanes at this index or higher in the first return value are
24301+
:ref:`poison value <poisonvalues>`. If ``evl`` is non-zero, the result in the
24302+
second return value must be at least 1, even if the first lane is masked-off.
24303+
24304+
The second result is usually less than ``evl`` when an exception would occur
24305+
for reading that lane, but it can be reduced for any reason. This facilitates
24306+
emulating this intrinsic when the hardware only supports narrower vector
24307+
types natively or when when hardware does not support fault-only-first loads.
24308+
24309+
Masked-on lanes that are not inbounds of the allocation that contains the first
24310+
lane are :ref:`poison value <poisonvalues>`. There should be a marker in the
24311+
allocation that indicates where valid data stops such as a null terminator. The
24312+
terminator should be checked for after calling this intrinsic to prevent using
24313+
any lanes past the terminator. Even if second return value is less than
24314+
``evl``, the terminator value may not have been read.
24315+
24316+
This intrinsic will typically be called in a loop until a terminator is
24317+
found. The second result should be used to indicates how many elements are
24318+
valid to look for the null terminator. If the terminator is not found, the
24319+
pointer should be advanced by the number of elements in the second result and
24320+
the intrinsic called again.
24321+
24322+
The default alignment is taken as the ABI alignment of the first return
24323+
type as specified by the :ref:`datalayout string<langref_datalayout>`.
24324+
24325+
Examples:
24326+
"""""""""
24327+
24328+
.. code-block:: text
24329+
24330+
%r = call {<8 x i8>, i32} @llvm.vp.load.ff.v8i8.p0(ptr align 2 %ptr, <8 x i1> %mask, i32 %evl)
24331+
2424624332
.. _int_vp_store:
2424724333

2424824334
'``llvm.vp.store``' Intrinsic

llvm/include/llvm/CodeGen/SelectionDAG.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,6 +1668,9 @@ class SelectionDAG {
16681668
ArrayRef<SDValue> Ops,
16691669
MachineMemOperand *MMO,
16701670
ISD::MemIndexType IndexType);
1671+
LLVM_ABI SDValue getLoadFFVP(EVT VT, const SDLoc &DL, SDValue Chain,
1672+
SDValue Ptr, SDValue Mask, SDValue EVL,
1673+
MachineMemOperand *MMO);
16711674

16721675
LLVM_ABI SDValue getGetFPEnv(SDValue Chain, const SDLoc &dl, SDValue Ptr,
16731676
EVT MemVT, MachineMemOperand *MMO);

llvm/include/llvm/CodeGen/SelectionDAGNodes.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3099,6 +3099,23 @@ class MaskedHistogramSDNode : public MaskedGatherScatterSDNode {
30993099
}
31003100
};
31013101

3102+
class VPLoadFFSDNode : public MemSDNode {
3103+
public:
3104+
friend class SelectionDAG;
3105+
3106+
VPLoadFFSDNode(unsigned Order, const DebugLoc &DL, SDVTList VTs, EVT MemVT,
3107+
MachineMemOperand *MMO)
3108+
: MemSDNode(ISD::VP_LOAD_FF, Order, DL, VTs, MemVT, MMO) {}
3109+
3110+
const SDValue &getBasePtr() const { return getOperand(1); }
3111+
const SDValue &getMask() const { return getOperand(2); }
3112+
const SDValue &getVectorLength() const { return getOperand(3); }
3113+
3114+
static bool classof(const SDNode *N) {
3115+
return N->getOpcode() == ISD::VP_LOAD_FF;
3116+
}
3117+
};
3118+
31023119
class FPStateAccessSDNode : public MemSDNode {
31033120
public:
31043121
friend class SelectionDAG;

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,12 @@ def int_vp_load : DefaultAttrsIntrinsic<[ llvm_anyvector_ty],
19321932
llvm_i32_ty],
19331933
[ NoCapture<ArgIndex<0>>, IntrReadMem, IntrArgMemOnly ]>;
19341934

1935+
def int_vp_load_ff : DefaultAttrsIntrinsic<[ llvm_anyvector_ty, llvm_i32_ty ],
1936+
[ llvm_anyptr_ty,
1937+
LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>,
1938+
llvm_i32_ty],
1939+
[ NoCapture<ArgIndex<0>>, IntrNoSync, IntrReadMem, IntrWillReturn, IntrArgMemOnly ]>;
1940+
19351941
def int_vp_gather: DefaultAttrsIntrinsic<[ llvm_anyvector_ty],
19361942
[ LLVMVectorOfAnyPointersToElt<0>,
19371943
LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>,

llvm/include/llvm/IR/VPIntrinsics.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,12 @@ VP_PROPERTY_FUNCTIONAL_OPC(Load)
587587
VP_PROPERTY_FUNCTIONAL_INTRINSIC(masked_load)
588588
END_REGISTER_VP(vp_load, VP_LOAD)
589589

590+
BEGIN_REGISTER_VP_INTRINSIC(vp_load_ff, 1, 2)
591+
// val,chain = VP_LOAD_FF chain,base,mask,evl
592+
BEGIN_REGISTER_VP_SDNODE(VP_LOAD_FF, -1, vp_load_ff, 2, 3)
593+
HELPER_MAP_VPID_TO_VPSD(vp_load_ff, VP_LOAD_FF)
594+
VP_PROPERTY_NO_FUNCTIONAL
595+
END_REGISTER_VP(vp_load_ff, VP_LOAD_FF)
590596
// llvm.experimental.vp.strided.load(ptr,stride,mask,vlen)
591597
BEGIN_REGISTER_VP_INTRINSIC(experimental_vp_strided_load, 2, 3)
592598
// chain = EXPERIMENTAL_VP_STRIDED_LOAD chain,base,offset,stride,mask,evl

llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
971971
void SplitVecRes_INSERT_VECTOR_ELT(SDNode *N, SDValue &Lo, SDValue &Hi);
972972
void SplitVecRes_LOAD(LoadSDNode *LD, SDValue &Lo, SDValue &Hi);
973973
void SplitVecRes_VP_LOAD(VPLoadSDNode *LD, SDValue &Lo, SDValue &Hi);
974+
void SplitVecRes_VP_LOAD_FF(VPLoadFFSDNode *LD, SDValue &Lo, SDValue &Hi);
974975
void SplitVecRes_VP_STRIDED_LOAD(VPStridedLoadSDNode *SLD, SDValue &Lo,
975976
SDValue &Hi);
976977
void SplitVecRes_MLOAD(MaskedLoadSDNode *MLD, SDValue &Lo, SDValue &Hi);
@@ -1075,6 +1076,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
10751076
SDValue WidenVecRes_INSERT_VECTOR_ELT(SDNode* N);
10761077
SDValue WidenVecRes_LOAD(SDNode* N);
10771078
SDValue WidenVecRes_VP_LOAD(VPLoadSDNode *N);
1079+
SDValue WidenVecRes_VP_LOAD_FF(VPLoadFFSDNode *N);
10781080
SDValue WidenVecRes_VP_STRIDED_LOAD(VPStridedLoadSDNode *N);
10791081
SDValue WidenVecRes_VECTOR_COMPRESS(SDNode *N);
10801082
SDValue WidenVecRes_MLOAD(MaskedLoadSDNode* N);

llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,9 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
11521152
case ISD::VP_LOAD:
11531153
SplitVecRes_VP_LOAD(cast<VPLoadSDNode>(N), Lo, Hi);
11541154
break;
1155+
case ISD::VP_LOAD_FF:
1156+
SplitVecRes_VP_LOAD_FF(cast<VPLoadFFSDNode>(N), Lo, Hi);
1157+
break;
11551158
case ISD::EXPERIMENTAL_VP_STRIDED_LOAD:
11561159
SplitVecRes_VP_STRIDED_LOAD(cast<VPStridedLoadSDNode>(N), Lo, Hi);
11571160
break;
@@ -2227,6 +2230,45 @@ void DAGTypeLegalizer::SplitVecRes_VP_LOAD(VPLoadSDNode *LD, SDValue &Lo,
22272230
ReplaceValueWith(SDValue(LD, 1), Ch);
22282231
}
22292232

2233+
void DAGTypeLegalizer::SplitVecRes_VP_LOAD_FF(VPLoadFFSDNode *LD, SDValue &Lo,
2234+
SDValue &Hi) {
2235+
SDLoc dl(LD);
2236+
auto [LoVT, HiVT] = DAG.GetSplitDestVTs(LD->getValueType(0));
2237+
2238+
SDValue Ch = LD->getChain();
2239+
SDValue Ptr = LD->getBasePtr();
2240+
Align Alignment = LD->getBaseAlign();
2241+
SDValue Mask = LD->getMask();
2242+
SDValue EVL = LD->getVectorLength();
2243+
2244+
// Split Mask operand
2245+
SDValue MaskLo, MaskHi;
2246+
if (Mask.getOpcode() == ISD::SETCC) {
2247+
SplitVecRes_SETCC(Mask.getNode(), MaskLo, MaskHi);
2248+
} else {
2249+
if (getTypeAction(Mask.getValueType()) == TargetLowering::TypeSplitVector)
2250+
GetSplitVector(Mask, MaskLo, MaskHi);
2251+
else
2252+
std::tie(MaskLo, MaskHi) = DAG.SplitVector(Mask, dl);
2253+
}
2254+
2255+
// Split EVL operand
2256+
auto [EVLLo, EVLHi] = DAG.SplitEVL(EVL, LD->getValueType(0), dl);
2257+
2258+
MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
2259+
LD->getPointerInfo(), MachineMemOperand::MOLoad,
2260+
LocationSize::beforeOrAfterPointer(), Alignment, LD->getAAInfo(),
2261+
LD->getRanges());
2262+
2263+
Lo = DAG.getLoadFFVP(LoVT, dl, Ch, Ptr, MaskLo, EVLLo, MMO);
2264+
2265+
// Fill the upper half with poison.
2266+
Hi = DAG.getUNDEF(HiVT);
2267+
2268+
ReplaceValueWith(SDValue(LD, 1), Lo.getValue(1));
2269+
ReplaceValueWith(SDValue(LD, 2), Lo.getValue(2));
2270+
}
2271+
22302272
void DAGTypeLegalizer::SplitVecRes_VP_STRIDED_LOAD(VPStridedLoadSDNode *SLD,
22312273
SDValue &Lo, SDValue &Hi) {
22322274
assert(SLD->isUnindexed() &&
@@ -4707,6 +4749,9 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
47074749
case ISD::VP_LOAD:
47084750
Res = WidenVecRes_VP_LOAD(cast<VPLoadSDNode>(N));
47094751
break;
4752+
case ISD::VP_LOAD_FF:
4753+
Res = WidenVecRes_VP_LOAD_FF(cast<VPLoadFFSDNode>(N));
4754+
break;
47104755
case ISD::EXPERIMENTAL_VP_STRIDED_LOAD:
47114756
Res = WidenVecRes_VP_STRIDED_LOAD(cast<VPStridedLoadSDNode>(N));
47124757
break;
@@ -6163,6 +6208,29 @@ SDValue DAGTypeLegalizer::WidenVecRes_VP_LOAD(VPLoadSDNode *N) {
61636208
return Res;
61646209
}
61656210

6211+
SDValue DAGTypeLegalizer::WidenVecRes_VP_LOAD_FF(VPLoadFFSDNode *N) {
6212+
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
6213+
SDValue Mask = N->getMask();
6214+
SDValue EVL = N->getVectorLength();
6215+
SDLoc dl(N);
6216+
6217+
// The mask should be widened as well
6218+
assert(getTypeAction(Mask.getValueType()) ==
6219+
TargetLowering::TypeWidenVector &&
6220+
"Unable to widen binary VP op");
6221+
Mask = GetWidenedVector(Mask);
6222+
assert(Mask.getValueType().getVectorElementCount() ==
6223+
TLI.getTypeToTransformTo(*DAG.getContext(), Mask.getValueType())
6224+
.getVectorElementCount() &&
6225+
"Unable to widen vector load");
6226+
6227+
SDValue Res = DAG.getLoadFFVP(WidenVT, dl, N->getChain(), N->getBasePtr(),
6228+
Mask, EVL, N->getMemOperand());
6229+
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
6230+
ReplaceValueWith(SDValue(N, 2), Res.getValue(2));
6231+
return Res;
6232+
}
6233+
61666234
SDValue DAGTypeLegalizer::WidenVecRes_VP_STRIDED_LOAD(VPStridedLoadSDNode *N) {
61676235
SDLoc DL(N);
61686236

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,14 @@ static void AddNodeIDCustom(FoldingSetNodeID &ID, const SDNode *N) {
837837
ID.AddInteger(ELD->getMemOperand()->getFlags());
838838
break;
839839
}
840+
case ISD::VP_LOAD_FF: {
841+
const auto *LD = cast<VPLoadFFSDNode>(N);
842+
ID.AddInteger(LD->getMemoryVT().getRawBits());
843+
ID.AddInteger(LD->getRawSubclassData());
844+
ID.AddInteger(LD->getPointerInfo().getAddrSpace());
845+
ID.AddInteger(LD->getMemOperand()->getFlags());
846+
break;
847+
}
840848
case ISD::VP_STORE: {
841849
const VPStoreSDNode *EST = cast<VPStoreSDNode>(N);
842850
ID.AddInteger(EST->getMemoryVT().getRawBits());
@@ -10433,6 +10441,34 @@ SDValue SelectionDAG::getMaskedHistogram(SDVTList VTs, EVT MemVT,
1043310441
return V;
1043410442
}
1043510443

10444+
SDValue SelectionDAG::getLoadFFVP(EVT VT, const SDLoc &DL, SDValue Chain,
10445+
SDValue Ptr, SDValue Mask, SDValue EVL,
10446+
MachineMemOperand *MMO) {
10447+
SDVTList VTs = getVTList(VT, EVL.getValueType(), MVT::Other);
10448+
SDValue Ops[] = {Chain, Ptr, Mask, EVL};
10449+
FoldingSetNodeID ID;
10450+
AddNodeIDNode(ID, ISD::VP_LOAD_FF, VTs, Ops);
10451+
ID.AddInteger(VT.getRawBits());
10452+
ID.AddInteger(getSyntheticNodeSubclassData<VPLoadFFSDNode>(DL.getIROrder(),
10453+
VTs, VT, MMO));
10454+
ID.AddInteger(MMO->getPointerInfo().getAddrSpace());
10455+
ID.AddInteger(MMO->getFlags());
10456+
void *IP = nullptr;
10457+
if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) {
10458+
cast<VPLoadFFSDNode>(E)->refineAlignment(MMO);
10459+
return SDValue(E, 0);
10460+
}
10461+
auto *N = newSDNode<VPLoadFFSDNode>(DL.getIROrder(), DL.getDebugLoc(), VTs,
10462+
VT, MMO);
10463+
createOperands(N, Ops);
10464+
10465+
CSEMap.InsertNode(N, IP);
10466+
InsertNode(N);
10467+
SDValue V(N, 0);
10468+
NewSDValueDbgMsg(V, "Creating new node: ", this);
10469+
return V;
10470+
}
10471+
1043610472
SDValue SelectionDAG::getGetFPEnv(SDValue Chain, const SDLoc &dl, SDValue Ptr,
1043710473
EVT MemVT, MachineMemOperand *MMO) {
1043810474
assert(Chain.getValueType() == MVT::Other && "Invalid chain type");

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8442,6 +8442,34 @@ void SelectionDAGBuilder::visitVPLoad(
84428442
setValue(&VPIntrin, LD);
84438443
}
84448444

8445+
void SelectionDAGBuilder::visitVPLoadFF(
8446+
const VPIntrinsic &VPIntrin, EVT VT, EVT EVLVT,
8447+
const SmallVectorImpl<SDValue> &OpValues) {
8448+
assert(OpValues.size() == 3 && "Unexpected number of operands");
8449+
SDLoc DL = getCurSDLoc();
8450+
Value *PtrOperand = VPIntrin.getArgOperand(0);
8451+
MaybeAlign Alignment = VPIntrin.getPointerAlignment();
8452+
AAMDNodes AAInfo = VPIntrin.getAAMetadata();
8453+
const MDNode *Ranges = VPIntrin.getMetadata(LLVMContext::MD_range);
8454+
SDValue LD;
8455+
// Do not serialize variable-length loads of constant memory with
8456+
// anything.
8457+
if (!Alignment)
8458+
Alignment = DAG.getEVTAlign(VT);
8459+
MemoryLocation ML = MemoryLocation::getAfter(PtrOperand, AAInfo);
8460+
bool AddToChain = !BatchAA || !BatchAA->pointsToConstantMemory(ML);
8461+
SDValue InChain = AddToChain ? DAG.getRoot() : DAG.getEntryNode();
8462+
MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
8463+
MachinePointerInfo(PtrOperand), MachineMemOperand::MOLoad,
8464+
LocationSize::beforeOrAfterPointer(), *Alignment, AAInfo, Ranges);
8465+
LD = DAG.getLoadFFVP(VT, DL, InChain, OpValues[0], OpValues[1], OpValues[2],
8466+
MMO);
8467+
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, EVLVT, LD.getValue(1));
8468+
if (AddToChain)
8469+
PendingLoads.push_back(LD.getValue(2));
8470+
setValue(&VPIntrin, DAG.getMergeValues({LD.getValue(0), Trunc}, DL));
8471+
}
8472+
84458473
void SelectionDAGBuilder::visitVPGather(
84468474
const VPIntrinsic &VPIntrin, EVT VT,
84478475
const SmallVectorImpl<SDValue> &OpValues) {
@@ -8675,6 +8703,9 @@ void SelectionDAGBuilder::visitVectorPredicationIntrinsic(
86758703
case ISD::VP_LOAD:
86768704
visitVPLoad(VPIntrin, ValueVTs[0], OpValues);
86778705
break;
8706+
case ISD::VP_LOAD_FF:
8707+
visitVPLoadFF(VPIntrin, ValueVTs[0], ValueVTs[1], OpValues);
8708+
break;
86788709
case ISD::VP_GATHER:
86798710
visitVPGather(VPIntrin, ValueVTs[0], OpValues);
86808711
break;

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,8 @@ class SelectionDAGBuilder {
631631
void visitVectorExtractLastActive(const CallInst &I, unsigned Intrinsic);
632632
void visitVPLoad(const VPIntrinsic &VPIntrin, EVT VT,
633633
const SmallVectorImpl<SDValue> &OpValues);
634+
void visitVPLoadFF(const VPIntrinsic &VPIntrin, EVT VT, EVT EVLVT,
635+
const SmallVectorImpl<SDValue> &OpValues);
634636
void visitVPStore(const VPIntrinsic &VPIntrin,
635637
const SmallVectorImpl<SDValue> &OpValues);
636638
void visitVPGather(const VPIntrinsic &VPIntrin, EVT VT,

0 commit comments

Comments
 (0)