Skip to content

Commit 91ddfb7

Browse files
committed
fixup! Use DAGToDAG approach
1 parent c44d2a7 commit 91ddfb7

File tree

8 files changed

+193
-138
lines changed

8 files changed

+193
-138
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9712,11 +9712,6 @@ Value *CodeGenFunction::EmitSVEMaskedStore(const CallExpr *E,
97129712
return Store;
97139713
}
97149714

9715-
Value *CodeGenFunction::EmitTileslice(Value *Offset, Value *Base) {
9716-
llvm::Value *CastOffset = Builder.CreateIntCast(Offset, Int64Ty, false);
9717-
return Builder.CreateAdd(Base, CastOffset, "tileslice");
9718-
}
9719-
97209715
Value *CodeGenFunction::EmitSMELd1St1(const SVETypeFlags &TypeFlags,
97219716
SmallVectorImpl<Value *> &Ops,
97229717
unsigned IntID) {
@@ -9772,34 +9767,10 @@ Value *CodeGenFunction::EmitSMEZero(const SVETypeFlags &TypeFlags,
97729767
Value *CodeGenFunction::EmitSMELdrStr(const SVETypeFlags &TypeFlags,
97739768
SmallVectorImpl<Value *> &Ops,
97749769
unsigned IntID) {
9775-
if (Ops.size() == 2) {
9776-
// Intrinsics without a vecnum also use this function, so just provide 0
9777-
Ops.push_back(Ops[1]);
9778-
Ops[1] = Builder.getInt32(0);
9779-
} else {
9780-
int Imm = -1;
9781-
if (ConstantInt* C = dyn_cast<ConstantInt>(Ops[2]))
9782-
if (C->getZExtValue() <= 15)
9783-
Imm = C->getZExtValue();
9784-
9785-
if (Imm != -1) {
9786-
Ops[2] = Ops[1];
9787-
Ops[1] = Builder.getInt32(Imm);
9788-
} else {
9789-
Function *Cntsb = CGM.getIntrinsic(Intrinsic::aarch64_sme_cntsb);
9790-
llvm::Value *CntsbCall = Builder.CreateCall(Cntsb, {}, "svlb");
9791-
9792-
llvm::Value *VecNum = Ops[2];
9793-
llvm::Value *MulVL = Builder.CreateMul(
9794-
CntsbCall,
9795-
VecNum,
9796-
"mulvl");
9797-
9798-
Ops[2] = Builder.CreateGEP(Int8Ty, Ops[1], MulVL);
9799-
Ops[1] = Builder.getInt32(0);
9800-
Ops[0] = Builder.CreateIntCast(EmitTileslice(Ops[0], VecNum), Int32Ty, false);
9801-
}
9802-
}
9770+
if (Ops.size() == 2)
9771+
Ops.push_back(Builder.getInt32(0));
9772+
else
9773+
Ops[2] = Builder.CreateIntCast(Ops[2], Int32Ty, true);
98039774
Function *F = CGM.getIntrinsic(IntID, {});
98049775
return Builder.CreateCall(F, Ops);
98059776
}

clang/test/CodeGen/aarch64-sme-intrinsics/acle_sme_ldr.c

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// CHECK-C-LABEL: @test_svldr_vnum_za(
1010
// CHECK-CXX-LABEL: @_Z18test_svldr_vnum_zajPKv(
1111
// CHECK-NEXT: entry:
12-
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[SLICE_BASE]], i32 0, ptr [[PTR]])
12+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 0)
1313
// CHECK-NEXT: ret void
1414
//
1515
void test_svldr_vnum_za(uint32_t slice_base, const void *ptr) {
@@ -19,60 +19,40 @@ void test_svldr_vnum_za(uint32_t slice_base, const void *ptr) {
1919
// CHECK-C-LABEL: @test_svldr_vnum_za_1(
2020
// CHECK-CXX-LABEL: @_Z20test_svldr_vnum_za_1jPKv(
2121
// CHECK-NEXT: entry:
22-
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[SLICE_BASE]], i32 15, ptr [[PTR]])
22+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 15)
2323
// CHECK-NEXT: ret void
2424
//
2525
void test_svldr_vnum_za_1(uint32_t slice_base, const void *ptr) {
2626
svldr_vnum_za(slice_base, ptr, 15);
2727
}
2828

29-
// CHECK-C-LABEL: @test_svldr_vnum_za_var(
30-
// CHECK-CXX-LABEL: @_Z22test_svldr_vnum_za_varjPKvm(
31-
// CHECK-NEXT: entry:
32-
// CHECK-NEXT: [[SVLB:%.*]] = tail call i64 @llvm.aarch64.sme.cntsb()
33-
// CHECK-NEXT: [[MULVL:%.*]] = mul i64 [[SVLB]], [[VNUM]]
34-
// CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[MULVL]]
35-
// CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[VNUM]] to i32
36-
// CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], [[SLICE_BASE]]
37-
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[TMP2]], i32 0, ptr [[TMP0]])
38-
// CHECK-NEXT: ret void
39-
//
40-
void test_svldr_vnum_za_var(uint32_t slice_base, const void *ptr, uint64_t vnum) {
41-
svldr_vnum_za(slice_base, ptr, vnum);
42-
}
43-
4429
// CHECK-C-LABEL: @test_svldr_za(
4530
// CHECK-CXX-LABEL: @_Z13test_svldr_zajPKv(
4631
// CHECK-NEXT: entry:
47-
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[SLICE_BASE]], i32 0, ptr [[PTR]])
32+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 0)
4833
// CHECK-NEXT: ret void
4934
//
5035
void test_svldr_za(uint32_t slice_base, const void *ptr) {
5136
svldr_za(slice_base, ptr);
5237
}
5338

54-
// CHECK-C-LABEL: define dso_local void @test_svldr_vnum_za_var(
55-
// CHECK-C-SAME: i32 noundef [[SLICE_BASE:%.*]], ptr noundef [[PTR:%.*]], i64 noundef [[VNUM:%.*]]) local_unnamed_addr #[[ATTR0]] {
56-
// CHECK-C-NEXT: entry:
57-
// CHECK-C-NEXT: [[SVLB:%.*]] = tail call i64 @llvm.aarch64.sme.cntsb()
58-
// CHECK-C-NEXT: [[MULVL:%.*]] = mul i64 [[SVLB]], [[VNUM]]
59-
// CHECK-C-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[MULVL]]
60-
// CHECK-C-NEXT: [[TMP1:%.*]] = trunc i64 [[VNUM]] to i32
61-
// CHECK-C-NEXT: [[TILESLICE:%.*]] = add i32 [[TMP1]], [[SLICE_BASE]]
62-
// CHECK-C-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[TILESLICE]], ptr [[TMP0]])
63-
// CHECK-C-NEXT: ret void
64-
//
65-
// CHECK-CXX-LABEL: define dso_local void @_Z22test_svldr_vnum_za_varjPKvl(
66-
// CHECK-CXX-SAME: i32 noundef [[SLICE_BASE:%.*]], ptr noundef [[PTR:%.*]], i64 noundef [[VNUM:%.*]]) local_unnamed_addr #[[ATTR0]] {
67-
// CHECK-CXX-NEXT: entry:
68-
// CHECK-CXX-NEXT: [[SVLB:%.*]] = tail call i64 @llvm.aarch64.sme.cntsb()
69-
// CHECK-CXX-NEXT: [[MULVL:%.*]] = mul i64 [[SVLB]], [[VNUM]]
70-
// CHECK-CXX-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[MULVL]]
71-
// CHECK-CXX-NEXT: [[TMP1:%.*]] = trunc i64 [[VNUM]] to i32
72-
// CHECK-CXX-NEXT: [[TILESLICE:%.*]] = add i32 [[TMP1]], [[SLICE_BASE]]
73-
// CHECK-CXX-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[TILESLICE]], ptr [[TMP0]])
74-
// CHECK-CXX-NEXT: ret void
39+
// CHECK-C-LABEL: @test_svldr_vnum_za_var(
40+
// CHECK-CXX-LABEL: @_Z22test_svldr_vnum_za_varjPKvl(
41+
// CHECK-NEXT: entry:
42+
// CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[VNUM:%.*]] to i32
43+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 [[TMP0:%.*]])
44+
// CHECK-NEXT: ret void
7545
//
7646
void test_svldr_vnum_za_var(uint32_t slice_base, const void *ptr, int64_t vnum) {
7747
svldr_vnum_za(slice_base, ptr, vnum);
7848
}
49+
50+
// CHECK-C-LABEL: @test_svldr_vnum_za_2(
51+
// CHECK-CXX-LABEL: @_Z20test_svldr_vnum_za_2jPKv(
52+
// CHECK-NEXT: entry:
53+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.ldr(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 16)
54+
// CHECK-NEXT: ret void
55+
//
56+
void test_svldr_vnum_za_2(uint32_t slice_base, const void *ptr) {
57+
svldr_vnum_za(slice_base, ptr, 16);
58+
}

clang/test/CodeGen/aarch64-sme-intrinsics/acle_sme_str.c

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,50 @@
99
// CHECK-C-LABEL: @test_svstr_vnum_za(
1010
// CHECK-CXX-LABEL: @_Z18test_svstr_vnum_zajPv(
1111
// CHECK-NEXT: entry:
12-
// CHECK-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[SLICE_BASE]], i32 0, ptr [[PTR]])
12+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 0)
1313
// CHECK-NEXT: ret void
1414
//
1515
void test_svstr_vnum_za(uint32_t slice_base, void *ptr) {
1616
svstr_vnum_za(slice_base, ptr, 0);
1717
}
1818

19-
// CHECK-C-LABEL: define dso_local void @test_svstr_vnum_za_1(
20-
// CHECK-CXX-LABEL: define dso_local void @_Z20test_svstr_vnum_za_1jPv(
19+
// CHECK-C-LABEL: @test_svstr_vnum_za_1(
20+
// CHECK-CXX-LABEL: @_Z20test_svstr_vnum_za_1jPv(
2121
// CHECK-NEXT: entry:
22-
// CHECK-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[SLICE_BASE]], i32 15, ptr [[PTR]])
22+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 15)
2323
// CHECK-NEXT: ret void
2424
//
2525
void test_svstr_vnum_za_1(uint32_t slice_base, void *ptr) {
2626
svstr_vnum_za(slice_base, ptr, 15);
2727
}
2828

29-
// CHECK-C-LABEL: define dso_local void @test_svstr_za(
30-
// CHECK-CXX-LABEL: define dso_local void @_Z13test_svstr_zajPv(
31-
// CHECK-SAME: i32 noundef [[SLICE_BASE:%.*]], ptr noundef [[PTR:%.*]]) local_unnamed_addr #[[ATTR0]] {
29+
// CHECK-C-LABEL: @test_svstr_za(
30+
// CHECK-CXX-LABEL: @_Z13test_svstr_zajPv(
3231
// CHECK-NEXT: entry:
33-
// CHECK-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[SLICE_BASE]], i32 0, ptr [[PTR]])
32+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 0)
3433
// CHECK-NEXT: ret void
3534
//
3635
void test_svstr_za(uint32_t slice_base, void *ptr) {
3736
svstr_za(slice_base, ptr);
3837
}
3938

40-
// CHECK-C-LABEL: define dso_local void @test_svstr_vnum_za_var(
41-
// CHECK-C-SAME: i32 noundef [[SLICE_BASE:%.*]], ptr noundef [[PTR:%.*]], i64 noundef [[VNUM:%.*]]) local_unnamed_addr #[[ATTR0]] {
42-
// CHECK-C-NEXT: entry:
43-
// CHECK-C-NEXT: [[SVLB:%.*]] = tail call i64 @llvm.aarch64.sme.cntsb()
44-
// CHECK-C-NEXT: [[MULVL:%.*]] = mul i64 [[SVLB]], [[VNUM]]
45-
// CHECK-C-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[MULVL]]
46-
// CHECK-C-NEXT: [[TMP1:%.*]] = trunc i64 [[VNUM]] to i32
47-
// CHECK-C-NEXT: [[TILESLICE:%.*]] = add i32 [[TMP1]], [[SLICE_BASE]]
48-
// CHECK-C-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[TILESLICE]], ptr [[TMP0]])
49-
// CHECK-C-NEXT: ret void
50-
//
51-
// CHECK-CXX-LABEL: define dso_local void @_Z22test_svstr_vnum_za_varjPvl(
52-
// CHECK-CXX-SAME: i32 noundef [[SLICE_BASE:%.*]], ptr noundef [[PTR:%.*]], i64 noundef [[VNUM:%.*]]) local_unnamed_addr #[[ATTR0]] {
53-
// CHECK-CXX-NEXT: entry:
54-
// CHECK-CXX-NEXT: [[SVLB:%.*]] = tail call i64 @llvm.aarch64.sme.cntsb()
55-
// CHECK-CXX-NEXT: [[MULVL:%.*]] = mul i64 [[SVLB]], [[VNUM]]
56-
// CHECK-CXX-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[MULVL]]
57-
// CHECK-CXX-NEXT: [[TMP1:%.*]] = trunc i64 [[VNUM]] to i32
58-
// CHECK-CXX-NEXT: [[TILESLICE:%.*]] = add i32 [[TMP1]], [[SLICE_BASE]]
59-
// CHECK-CXX-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[TILESLICE]], ptr [[TMP0]])
60-
// CHECK-CXX-NEXT: ret void
39+
// CHECK-C-LABEL: @test_svstr_vnum_za_var(
40+
// CHECK-CXX-LABEL: @_Z22test_svstr_vnum_za_varjPvl(
41+
// CHECK-NEXT: entry:
42+
// CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[VNUM:%.*]] to i32
43+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 [[TMP0:%.*]])
44+
// CHECK-NEXT: ret void
6145
//
6246
void test_svstr_vnum_za_var(uint32_t slice_base, void *ptr, int64_t vnum) {
6347
svstr_vnum_za(slice_base, ptr, vnum);
6448
}
49+
50+
// CHECK-C-LABEL: @test_svstr_vnum_za_2(
51+
// CHECK-CXX-LABEL: @_Z20test_svstr_vnum_za_2jPv(
52+
// CHECK-NEXT: entry:
53+
// CHECK-NEXT: tail call void @llvm.aarch64.sme.str(i32 [[SLICE_BASE:%.*]], ptr [[PTR:%.*]], i32 16)
54+
// CHECK-NEXT: ret void
55+
//
56+
void test_svstr_vnum_za_2(uint32_t slice_base, void *ptr) {
57+
svstr_vnum_za(slice_base, ptr, 16);
58+
}

llvm/include/llvm/IR/IntrinsicsAArch64.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,9 +2680,9 @@ let TargetPrefix = "aarch64" in {
26802680

26812681
// Spill + fill
26822682
def int_aarch64_sme_ldr : DefaultAttrsIntrinsic<
2683-
[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], [ImmArg<ArgIndex<1>>]>;
2683+
[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty]>;
26842684
def int_aarch64_sme_str : DefaultAttrsIntrinsic<
2685-
[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], [ImmArg<ArgIndex<1>>]>;
2685+
[], [llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty]>;
26862686

26872687
class SME_TileToVector_Intrinsic
26882688
: DefaultAttrsIntrinsic<[llvm_anyvector_ty],

llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ class AArch64DAGToDAGISel : public SelectionDAGISel {
379379
void SelectPExtPair(SDNode *N, unsigned Opc);
380380
void SelectWhilePair(SDNode *N, unsigned Opc);
381381
void SelectCVTIntrinsic(SDNode *N, unsigned NumVecs, unsigned Opcode);
382+
void SelectSMELdrStrZA(SDNode *N, bool IsLoad);
382383
void SelectClamp(SDNode *N, unsigned NumVecs, unsigned Opcode);
383384
void SelectUnaryMultiIntrinsic(SDNode *N, unsigned NumOutVecs,
384385
bool IsTupleInput, unsigned Opc);
@@ -1741,6 +1742,54 @@ void AArch64DAGToDAGISel::SelectCVTIntrinsic(SDNode *N, unsigned NumVecs,
17411742
CurDAG->RemoveDeadNode(N);
17421743
}
17431744

1745+
void AArch64DAGToDAGISel::SelectSMELdrStrZA(SDNode *N, bool IsLoad) {
1746+
// Lower an SME LDR/STR ZA intrinsic to LDR_ZA_PSEUDO or STR_ZA.
1747+
// If the vector select parameter is an immediate in the range 0-15 then we
1748+
// can emit it directly into the instruction as it's a legal operand.
1749+
// Otherwise we must emit 0 as the vector select operand and modify the base
1750+
// register instead.
1751+
SDLoc DL(N);
1752+
1753+
SDValue VecNum = N->getOperand(4), Base = N->getOperand(3),
1754+
TileSlice = N->getOperand(2);
1755+
int Imm = -1;
1756+
if (auto ImmNode = dyn_cast<ConstantSDNode>(VecNum))
1757+
Imm = ImmNode->getZExtValue();
1758+
1759+
if (Imm >= 0 && Imm <= 15) {
1760+
// 0-15 is a legal immediate so just pass it directly as a TargetConstant
1761+
VecNum = CurDAG->getTargetConstant(Imm, DL, MVT::i32);
1762+
} else {
1763+
// Get the vector length that will be multiplied by vnum
1764+
auto SVL = SDValue(
1765+
CurDAG->getMachineNode(AArch64::RDSVLI_XI, DL, MVT::i64,
1766+
CurDAG->getTargetConstant(1, DL, MVT::i32)),
1767+
0);
1768+
1769+
// Multiply SVL and vnum then add it to the base register
1770+
if (VecNum.getValueType() == MVT::i32)
1771+
VecNum = Widen(CurDAG, VecNum);
1772+
SDValue AddOps[] = {SVL, VecNum, Base};
1773+
auto Add = SDValue(
1774+
CurDAG->getMachineNode(AArch64::MADDXrrr, DL, MVT::i64, AddOps), 0);
1775+
1776+
// The base register has been modified to take vnum into account so just
1777+
// pass 0
1778+
VecNum = CurDAG->getTargetConstant(0, DL, MVT::i32);
1779+
Base = Add;
1780+
}
1781+
1782+
SmallVector<SDValue, 6> Ops = {TileSlice, VecNum, Base};
1783+
if (!IsLoad) {
1784+
Ops.insert(Ops.begin(), CurDAG->getRegister(AArch64::ZA, MVT::Other));
1785+
Ops.push_back(VecNum);
1786+
}
1787+
auto LdrStr =
1788+
CurDAG->getMachineNode(IsLoad ? AArch64::LDR_ZA_PSEUDO : AArch64::STR_ZA,
1789+
DL, N->getValueType(0), Ops);
1790+
ReplaceNode(N, LdrStr);
1791+
}
1792+
17441793
void AArch64DAGToDAGISel::SelectDestructiveMultiIntrinsic(SDNode *N,
17451794
unsigned NumVecs,
17461795
bool IsZmMulti,
@@ -5663,6 +5712,11 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
56635712
switch (IntNo) {
56645713
default:
56655714
break;
5715+
case Intrinsic::aarch64_sme_str:
5716+
case Intrinsic::aarch64_sme_ldr: {
5717+
SelectSMELdrStrZA(Node, IntNo == Intrinsic::aarch64_sme_ldr);
5718+
return;
5719+
}
56665720
case Intrinsic::aarch64_neon_st1x2: {
56675721
if (VT == MVT::v8i8) {
56685722
SelectStore(Node, 2, AArch64::ST1Twov8b);

llvm/lib/Target/AArch64/SMEInstrFormats.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ multiclass sme_spill<string opcodestr> {
794794
(!cast<Instruction>(NAME) MatrixOp:$ZAt,
795795
MatrixIndexGPR32Op12_15:$Rv, sme_elm_idx0_15:$imm4, GPR64sp:$Rn, 0), 1>;
796796
// base
797-
def : Pat<(int_aarch64_sme_str MatrixIndexGPR32Op12_15:$idx, sme_elm_idx0_15:$imm, GPR64sp:$base),
797+
def : Pat<(int_aarch64_sme_str MatrixIndexGPR32Op12_15:$idx, GPR64sp:$base, sme_elm_idx0_15:$imm),
798798
(!cast<Instruction>(NAME) ZA, $idx, $imm, $base, 0)>;
799799
}
800800

@@ -813,7 +813,7 @@ multiclass sme_fill<string opcodestr> {
813813
let mayLoad = 1;
814814
}
815815
// base
816-
def : Pat<(int_aarch64_sme_ldr MatrixIndexGPR32Op12_15:$idx, sme_elm_idx0_15:$imm, GPR64sp:$base),
816+
def : Pat<(int_aarch64_sme_ldr MatrixIndexGPR32Op12_15:$idx, GPR64sp:$base, sme_elm_idx0_15:$imm),
817817
(!cast<Instruction>(NAME # _PSEUDO) $idx, $imm, $base)>;
818818
}
819819

0 commit comments

Comments
 (0)