Skip to content

Commit 5a1e16f

Browse files
mshockwavetopperc
andauthored
[IR][RISCV] Add llvm.vector.(de)interleave3/5/7 (#124825)
These three intrinsics are similar to llvm.vector.(de)interleave2 but work with 3/5/7 vector operands or results. For RISC-V, it's important to have them in order to support segmented load/store with factor of 2 to 8: factor of 2/4/8 can be synthesized from (de)interleave2; factor of 6 can be synthesized from factor of 2 and 3; factor 5 and 7 have their own intrinsics added by this patch. This patch only adds codegen support for these intrinsics, we still need to teach vectorizer to generate them as well as teaching InterleavedAccessPass to use them. --------- Co-authored-by: Craig Topper <[email protected]>
1 parent 1901f4a commit 5a1e16f

13 files changed

+4825
-202
lines changed

llvm/include/llvm/IR/DerivedTypes.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,15 @@ class VectorType : public Type {
536536
EltCnt.divideCoefficientBy(2));
537537
}
538538

539+
static VectorType *getOneNthElementsVectorType(VectorType *VTy,
540+
unsigned Denominator) {
541+
auto EltCnt = VTy->getElementCount();
542+
assert(EltCnt.isKnownMultipleOf(Denominator) &&
543+
"Cannot take one-nth of a vector");
544+
return VectorType::get(VTy->getScalarType(),
545+
EltCnt.divideCoefficientBy(Denominator));
546+
}
547+
539548
/// This static method returns a VectorType with twice as many elements as the
540549
/// input type and the same element type.
541550
static VectorType *getDoubleElementsVectorType(VectorType *VTy) {

llvm/include/llvm/IR/Intrinsics.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ namespace Intrinsic {
148148
ExtendArgument,
149149
TruncArgument,
150150
HalfVecArgument,
151+
OneThirdVecArgument,
152+
OneFifthVecArgument,
153+
OneSeventhVecArgument,
151154
SameVecWidthArgument,
152155
VecOfAnyPtrsToElt,
153156
VecElementArgument,
@@ -159,6 +162,9 @@ namespace Intrinsic {
159162
AArch64Svcount,
160163
} Kind;
161164

165+
// These three have to be contiguous.
166+
static_assert(OneFifthVecArgument == OneThirdVecArgument + 1 &&
167+
OneSeventhVecArgument == OneFifthVecArgument + 1);
162168
union {
163169
unsigned Integer_Width;
164170
unsigned Float_Width;
@@ -178,15 +184,17 @@ namespace Intrinsic {
178184
unsigned getArgumentNumber() const {
179185
assert(Kind == Argument || Kind == ExtendArgument ||
180186
Kind == TruncArgument || Kind == HalfVecArgument ||
181-
Kind == SameVecWidthArgument || Kind == VecElementArgument ||
182-
Kind == Subdivide2Argument || Kind == Subdivide4Argument ||
183-
Kind == VecOfBitcastsToInt);
187+
Kind == OneThirdVecArgument || Kind == OneFifthVecArgument ||
188+
Kind == OneSeventhVecArgument || Kind == SameVecWidthArgument ||
189+
Kind == VecElementArgument || Kind == Subdivide2Argument ||
190+
Kind == Subdivide4Argument || Kind == VecOfBitcastsToInt);
184191
return Argument_Info >> 3;
185192
}
186193
ArgKind getArgumentKind() const {
187194
assert(Kind == Argument || Kind == ExtendArgument ||
188195
Kind == TruncArgument || Kind == HalfVecArgument ||
189-
Kind == SameVecWidthArgument ||
196+
Kind == OneThirdVecArgument || Kind == OneFifthVecArgument ||
197+
Kind == OneSeventhVecArgument || Kind == SameVecWidthArgument ||
190198
Kind == VecElementArgument || Kind == Subdivide2Argument ||
191199
Kind == Subdivide4Argument || Kind == VecOfBitcastsToInt);
192200
return (ArgKind)(Argument_Info & 7);

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ def IIT_I4 : IIT_Int<4, 58>;
327327
def IIT_AARCH64_SVCOUNT : IIT_VT<aarch64svcount, 59>;
328328
def IIT_V6 : IIT_Vec<6, 60>;
329329
def IIT_V10 : IIT_Vec<10, 61>;
330+
def IIT_ONE_THIRD_VEC_ARG : IIT_Base<62>;
331+
def IIT_ONE_FIFTH_VEC_ARG : IIT_Base<63>;
332+
def IIT_ONE_SEVENTH_VEC_ARG : IIT_Base<64>;
330333
}
331334

332335
defvar IIT_all_FixedTypes = !filter(iit, IIT_all,
@@ -467,6 +470,15 @@ class LLVMVectorElementType<int num> : LLVMMatchType<num, IIT_VEC_ELEMENT>;
467470
class LLVMHalfElementsVectorType<int num>
468471
: LLVMMatchType<num, IIT_HALF_VEC_ARG>;
469472

473+
class LLVMOneThirdElementsVectorType<int num>
474+
: LLVMMatchType<num, IIT_ONE_THIRD_VEC_ARG>;
475+
476+
class LLVMOneFifthElementsVectorType<int num>
477+
: LLVMMatchType<num, IIT_ONE_FIFTH_VEC_ARG>;
478+
479+
class LLVMOneSeventhElementsVectorType<int num>
480+
: LLVMMatchType<num, IIT_ONE_SEVENTH_VEC_ARG>;
481+
470482
// Match the type of another intrinsic parameter that is expected to be a
471483
// vector type (i.e. <N x iM>) but with each element subdivided to
472484
// form a vector with more elements that are smaller than the original.
@@ -2728,6 +2740,54 @@ def int_vector_deinterleave2 : DefaultAttrsIntrinsic<[LLVMHalfElementsVectorType
27282740
[llvm_anyvector_ty],
27292741
[IntrNoMem]>;
27302742

2743+
def int_vector_interleave3 : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
2744+
[LLVMOneThirdElementsVectorType<0>,
2745+
LLVMOneThirdElementsVectorType<0>,
2746+
LLVMOneThirdElementsVectorType<0>],
2747+
[IntrNoMem]>;
2748+
2749+
def int_vector_deinterleave3 : DefaultAttrsIntrinsic<[LLVMOneThirdElementsVectorType<0>,
2750+
LLVMOneThirdElementsVectorType<0>,
2751+
LLVMOneThirdElementsVectorType<0>],
2752+
[llvm_anyvector_ty],
2753+
[IntrNoMem]>;
2754+
2755+
def int_vector_interleave5 : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
2756+
[LLVMOneFifthElementsVectorType<0>,
2757+
LLVMOneFifthElementsVectorType<0>,
2758+
LLVMOneFifthElementsVectorType<0>,
2759+
LLVMOneFifthElementsVectorType<0>,
2760+
LLVMOneFifthElementsVectorType<0>],
2761+
[IntrNoMem]>;
2762+
2763+
def int_vector_deinterleave5 : DefaultAttrsIntrinsic<[LLVMOneFifthElementsVectorType<0>,
2764+
LLVMOneFifthElementsVectorType<0>,
2765+
LLVMOneFifthElementsVectorType<0>,
2766+
LLVMOneFifthElementsVectorType<0>,
2767+
LLVMOneFifthElementsVectorType<0>],
2768+
[llvm_anyvector_ty],
2769+
[IntrNoMem]>;
2770+
2771+
def int_vector_interleave7 : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
2772+
[LLVMOneSeventhElementsVectorType<0>,
2773+
LLVMOneSeventhElementsVectorType<0>,
2774+
LLVMOneSeventhElementsVectorType<0>,
2775+
LLVMOneSeventhElementsVectorType<0>,
2776+
LLVMOneSeventhElementsVectorType<0>,
2777+
LLVMOneSeventhElementsVectorType<0>,
2778+
LLVMOneSeventhElementsVectorType<0>],
2779+
[IntrNoMem]>;
2780+
2781+
def int_vector_deinterleave7 : DefaultAttrsIntrinsic<[LLVMOneSeventhElementsVectorType<0>,
2782+
LLVMOneSeventhElementsVectorType<0>,
2783+
LLVMOneSeventhElementsVectorType<0>,
2784+
LLVMOneSeventhElementsVectorType<0>,
2785+
LLVMOneSeventhElementsVectorType<0>,
2786+
LLVMOneSeventhElementsVectorType<0>,
2787+
LLVMOneSeventhElementsVectorType<0>],
2788+
[llvm_anyvector_ty],
2789+
[IntrNoMem]>;
2790+
27312791
//===-------------- Intrinsics to perform partial reduction ---------------===//
27322792

27332793
def int_experimental_vector_partial_reduce_add : DefaultAttrsIntrinsic<[LLVMMatchType<0>],

llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5881,15 +5881,19 @@ SDValue DAGTypeLegalizer::PromoteIntRes_VECTOR_SPLICE(SDNode *N) {
58815881
}
58825882

58835883
SDValue DAGTypeLegalizer::PromoteIntRes_VECTOR_INTERLEAVE_DEINTERLEAVE(SDNode *N) {
5884-
SDLoc dl(N);
5884+
SDLoc DL(N);
5885+
unsigned Factor = N->getNumOperands();
5886+
5887+
SmallVector<SDValue, 8> Ops(Factor);
5888+
for (unsigned i = 0; i != Factor; i++)
5889+
Ops[i] = GetPromotedInteger(N->getOperand(i));
5890+
5891+
SmallVector<EVT, 8> ResVTs(Factor, Ops[0].getValueType());
5892+
SDValue Res = DAG.getNode(N->getOpcode(), DL, DAG.getVTList(ResVTs), Ops);
5893+
5894+
for (unsigned i = 0; i != Factor; i++)
5895+
SetPromotedInteger(SDValue(N, i), Res.getValue(i));
58855896

5886-
SDValue V0 = GetPromotedInteger(N->getOperand(0));
5887-
SDValue V1 = GetPromotedInteger(N->getOperand(1));
5888-
EVT ResVT = V0.getValueType();
5889-
SDValue Res = DAG.getNode(N->getOpcode(), dl,
5890-
DAG.getVTList(ResVT, ResVT), V0, V1);
5891-
SetPromotedInteger(SDValue(N, 0), Res.getValue(0));
5892-
SetPromotedInteger(SDValue(N, 1), Res.getValue(1));
58935897
return SDValue();
58945898
}
58955899

llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,6 +1668,15 @@ void DAGTypeLegalizer::SplitVecRes_INSERT_SUBVECTOR(SDNode *N, SDValue &Lo,
16681668
return;
16691669
}
16701670

1671+
if (getTypeAction(SubVecVT) == TargetLowering::TypeWidenVector &&
1672+
Vec.isUndef() && SubVecVT.getVectorElementType() == MVT::i1) {
1673+
SDValue WideSubVec = GetWidenedVector(SubVec);
1674+
if (WideSubVec.getValueType() == VecVT) {
1675+
std::tie(Lo, Hi) = DAG.SplitVector(WideSubVec, SDLoc(WideSubVec));
1676+
return;
1677+
}
1678+
}
1679+
16711680
// Spill the vector to the stack.
16721681
// In cases where the vector is illegal it will be broken down into parts
16731682
// and stored in parts - we should use the alignment for the smallest part.
@@ -3183,34 +3192,53 @@ void DAGTypeLegalizer::SplitVecRes_VP_REVERSE(SDNode *N, SDValue &Lo,
31833192
}
31843193

31853194
void DAGTypeLegalizer::SplitVecRes_VECTOR_DEINTERLEAVE(SDNode *N) {
3195+
unsigned Factor = N->getNumOperands();
3196+
3197+
SmallVector<SDValue, 8> Ops(Factor * 2);
3198+
for (unsigned i = 0; i != Factor; ++i) {
3199+
SDValue OpLo, OpHi;
3200+
GetSplitVector(N->getOperand(i), OpLo, OpHi);
3201+
Ops[i * 2] = OpLo;
3202+
Ops[i * 2 + 1] = OpHi;
3203+
}
3204+
3205+
SmallVector<EVT, 8> VTs(Factor, Ops[0].getValueType());
31863206

3187-
SDValue Op0Lo, Op0Hi, Op1Lo, Op1Hi;
3188-
GetSplitVector(N->getOperand(0), Op0Lo, Op0Hi);
3189-
GetSplitVector(N->getOperand(1), Op1Lo, Op1Hi);
3190-
EVT VT = Op0Lo.getValueType();
31913207
SDLoc DL(N);
3192-
SDValue ResLo = DAG.getNode(ISD::VECTOR_DEINTERLEAVE, DL,
3193-
DAG.getVTList(VT, VT), Op0Lo, Op0Hi);
3194-
SDValue ResHi = DAG.getNode(ISD::VECTOR_DEINTERLEAVE, DL,
3195-
DAG.getVTList(VT, VT), Op1Lo, Op1Hi);
3208+
SDValue ResLo = DAG.getNode(ISD::VECTOR_DEINTERLEAVE, DL, VTs,
3209+
ArrayRef(Ops).slice(0, Factor));
3210+
SDValue ResHi = DAG.getNode(ISD::VECTOR_DEINTERLEAVE, DL, VTs,
3211+
ArrayRef(Ops).slice(Factor, Factor));
31963212

3197-
SetSplitVector(SDValue(N, 0), ResLo.getValue(0), ResHi.getValue(0));
3198-
SetSplitVector(SDValue(N, 1), ResLo.getValue(1), ResHi.getValue(1));
3213+
for (unsigned i = 0; i != Factor; ++i)
3214+
SetSplitVector(SDValue(N, i), ResLo.getValue(i), ResHi.getValue(i));
31993215
}
32003216

32013217
void DAGTypeLegalizer::SplitVecRes_VECTOR_INTERLEAVE(SDNode *N) {
3202-
SDValue Op0Lo, Op0Hi, Op1Lo, Op1Hi;
3203-
GetSplitVector(N->getOperand(0), Op0Lo, Op0Hi);
3204-
GetSplitVector(N->getOperand(1), Op1Lo, Op1Hi);
3205-
EVT VT = Op0Lo.getValueType();
3218+
unsigned Factor = N->getNumOperands();
3219+
3220+
SmallVector<SDValue, 8> Ops(Factor * 2);
3221+
for (unsigned i = 0; i != Factor; ++i) {
3222+
SDValue OpLo, OpHi;
3223+
GetSplitVector(N->getOperand(i), OpLo, OpHi);
3224+
Ops[i] = OpLo;
3225+
Ops[i + Factor] = OpHi;
3226+
}
3227+
3228+
SmallVector<EVT, 8> VTs(Factor, Ops[0].getValueType());
3229+
32063230
SDLoc DL(N);
3207-
SDValue Res[] = {DAG.getNode(ISD::VECTOR_INTERLEAVE, DL,
3208-
DAG.getVTList(VT, VT), Op0Lo, Op1Lo),
3209-
DAG.getNode(ISD::VECTOR_INTERLEAVE, DL,
3210-
DAG.getVTList(VT, VT), Op0Hi, Op1Hi)};
3231+
SDValue Res[] = {DAG.getNode(ISD::VECTOR_INTERLEAVE, DL, VTs,
3232+
ArrayRef(Ops).slice(0, Factor)),
3233+
DAG.getNode(ISD::VECTOR_INTERLEAVE, DL, VTs,
3234+
ArrayRef(Ops).slice(Factor, Factor))};
32113235

3212-
SetSplitVector(SDValue(N, 0), Res[0].getValue(0), Res[0].getValue(1));
3213-
SetSplitVector(SDValue(N, 1), Res[1].getValue(0), Res[1].getValue(1));
3236+
for (unsigned i = 0; i != Factor; ++i) {
3237+
unsigned IdxLo = 2 * i;
3238+
unsigned IdxHi = 2 * i + 1;
3239+
SetSplitVector(SDValue(N, i), Res[IdxLo / Factor].getValue(IdxLo % Factor),
3240+
Res[IdxHi / Factor].getValue(IdxHi % Factor));
3241+
}
32143242
}
32153243

32163244
//===----------------------------------------------------------------------===//

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 62 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8251,10 +8251,28 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
82518251
visitCallBrLandingPad(I);
82528252
return;
82538253
case Intrinsic::vector_interleave2:
8254-
visitVectorInterleave(I);
8254+
visitVectorInterleave(I, 2);
8255+
return;
8256+
case Intrinsic::vector_interleave3:
8257+
visitVectorInterleave(I, 3);
8258+
return;
8259+
case Intrinsic::vector_interleave5:
8260+
visitVectorInterleave(I, 5);
8261+
return;
8262+
case Intrinsic::vector_interleave7:
8263+
visitVectorInterleave(I, 7);
82558264
return;
82568265
case Intrinsic::vector_deinterleave2:
8257-
visitVectorDeinterleave(I);
8266+
visitVectorDeinterleave(I, 2);
8267+
return;
8268+
case Intrinsic::vector_deinterleave3:
8269+
visitVectorDeinterleave(I, 3);
8270+
return;
8271+
case Intrinsic::vector_deinterleave5:
8272+
visitVectorDeinterleave(I, 5);
8273+
return;
8274+
case Intrinsic::vector_deinterleave7:
8275+
visitVectorDeinterleave(I, 7);
82588276
return;
82598277
case Intrinsic::experimental_vector_compress:
82608278
setValue(&I, DAG.getNode(ISD::VECTOR_COMPRESS, sdl,
@@ -12565,59 +12583,75 @@ void SelectionDAGBuilder::visitVectorReverse(const CallInst &I) {
1256512583
setValue(&I, DAG.getVectorShuffle(VT, DL, V, DAG.getUNDEF(VT), Mask));
1256612584
}
1256712585

12568-
void SelectionDAGBuilder::visitVectorDeinterleave(const CallInst &I) {
12586+
void SelectionDAGBuilder::visitVectorDeinterleave(const CallInst &I,
12587+
unsigned Factor) {
1256912588
auto DL = getCurSDLoc();
1257012589
SDValue InVec = getValue(I.getOperand(0));
12571-
EVT OutVT =
12572-
InVec.getValueType().getHalfNumVectorElementsVT(*DAG.getContext());
1257312590

12591+
SmallVector<EVT, 4> ValueVTs;
12592+
ComputeValueVTs(DAG.getTargetLoweringInfo(), DAG.getDataLayout(), I.getType(),
12593+
ValueVTs);
12594+
12595+
EVT OutVT = ValueVTs[0];
1257412596
unsigned OutNumElts = OutVT.getVectorMinNumElements();
1257512597

12576-
// ISD Node needs the input vectors split into two equal parts
12577-
SDValue Lo = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, OutVT, InVec,
12578-
DAG.getVectorIdxConstant(0, DL));
12579-
SDValue Hi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, OutVT, InVec,
12580-
DAG.getVectorIdxConstant(OutNumElts, DL));
12598+
SmallVector<SDValue, 4> SubVecs(Factor);
12599+
for (unsigned i = 0; i != Factor; ++i) {
12600+
assert(ValueVTs[i] == OutVT && "Expected VTs to be the same");
12601+
SubVecs[i] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, OutVT, InVec,
12602+
DAG.getVectorIdxConstant(OutNumElts * i, DL));
12603+
}
1258112604

12582-
// Use VECTOR_SHUFFLE for fixed-length vectors to benefit from existing
12583-
// legalisation and combines.
12584-
if (OutVT.isFixedLengthVector()) {
12585-
SDValue Even = DAG.getVectorShuffle(OutVT, DL, Lo, Hi,
12605+
// Use VECTOR_SHUFFLE for fixed-length vectors with factor of 2 to benefit
12606+
// from existing legalisation and combines.
12607+
if (OutVT.isFixedLengthVector() && Factor == 2) {
12608+
SDValue Even = DAG.getVectorShuffle(OutVT, DL, SubVecs[0], SubVecs[1],
1258612609
createStrideMask(0, 2, OutNumElts));
12587-
SDValue Odd = DAG.getVectorShuffle(OutVT, DL, Lo, Hi,
12610+
SDValue Odd = DAG.getVectorShuffle(OutVT, DL, SubVecs[0], SubVecs[1],
1258812611
createStrideMask(1, 2, OutNumElts));
1258912612
SDValue Res = DAG.getMergeValues({Even, Odd}, getCurSDLoc());
1259012613
setValue(&I, Res);
1259112614
return;
1259212615
}
1259312616

1259412617
SDValue Res = DAG.getNode(ISD::VECTOR_DEINTERLEAVE, DL,
12595-
DAG.getVTList(OutVT, OutVT), Lo, Hi);
12618+
DAG.getVTList(ValueVTs), SubVecs);
1259612619
setValue(&I, Res);
1259712620
}
1259812621

12599-
void SelectionDAGBuilder::visitVectorInterleave(const CallInst &I) {
12622+
void SelectionDAGBuilder::visitVectorInterleave(const CallInst &I,
12623+
unsigned Factor) {
1260012624
auto DL = getCurSDLoc();
12601-
EVT InVT = getValue(I.getOperand(0)).getValueType();
12602-
SDValue InVec0 = getValue(I.getOperand(0));
12603-
SDValue InVec1 = getValue(I.getOperand(1));
1260412625
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
12626+
EVT InVT = getValue(I.getOperand(0)).getValueType();
1260512627
EVT OutVT = TLI.getValueType(DAG.getDataLayout(), I.getType());
1260612628

12607-
// Use VECTOR_SHUFFLE for fixed-length vectors to benefit from existing
12608-
// legalisation and combines.
12609-
if (OutVT.isFixedLengthVector()) {
12629+
SmallVector<SDValue, 8> InVecs(Factor);
12630+
for (unsigned i = 0; i < Factor; ++i) {
12631+
InVecs[i] = getValue(I.getOperand(i));
12632+
assert(InVecs[i].getValueType() == InVecs[0].getValueType() &&
12633+
"Expected VTs to be the same");
12634+
}
12635+
12636+
// Use VECTOR_SHUFFLE for fixed-length vectors with factor of 2 to benefit
12637+
// from existing legalisation and combines.
12638+
if (OutVT.isFixedLengthVector() && Factor == 2) {
1261012639
unsigned NumElts = InVT.getVectorMinNumElements();
12611-
SDValue V = DAG.getNode(ISD::CONCAT_VECTORS, DL, OutVT, InVec0, InVec1);
12640+
SDValue V = DAG.getNode(ISD::CONCAT_VECTORS, DL, OutVT, InVecs);
1261212641
setValue(&I, DAG.getVectorShuffle(OutVT, DL, V, DAG.getUNDEF(OutVT),
1261312642
createInterleaveMask(NumElts, 2)));
1261412643
return;
1261512644
}
1261612645

12617-
SDValue Res = DAG.getNode(ISD::VECTOR_INTERLEAVE, DL,
12618-
DAG.getVTList(InVT, InVT), InVec0, InVec1);
12619-
Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, OutVT, Res.getValue(0),
12620-
Res.getValue(1));
12646+
SmallVector<EVT, 8> ValueVTs(Factor, InVT);
12647+
SDValue Res =
12648+
DAG.getNode(ISD::VECTOR_INTERLEAVE, DL, DAG.getVTList(ValueVTs), InVecs);
12649+
12650+
SmallVector<SDValue, 8> Results(Factor);
12651+
for (unsigned i = 0; i < Factor; ++i)
12652+
Results[i] = Res.getValue(i);
12653+
12654+
Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, OutVT, Results);
1262112655
setValue(&I, Res);
1262212656
}
1262312657

0 commit comments

Comments
 (0)