Skip to content

Commit f297d0b

Browse files
authored
[AArch64][GlobalISel] More FCmp legalization. (#78734)
This fills out the fcmp handling to be more like the other instructions, adding better support for fp16 and some larger vectors. Select of f16 values is still not handled optimally in places as the select is only legal for s32 values, not s16. This would be correct for integer but not necessarily for fp. It is as if we need to do legalization -> regbankselect -> extra legaliation -> selection.
1 parent 916bd7d commit f297d0b

File tree

5 files changed

+526
-838
lines changed

5 files changed

+526
-838
lines changed

llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,6 +1556,15 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
15561556
MI.eraseFromParent();
15571557
return Legalized;
15581558
}
1559+
case TargetOpcode::G_FCMP:
1560+
if (TypeIdx != 0)
1561+
return UnableToLegalize;
1562+
1563+
Observer.changingInstr(MI);
1564+
narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1565+
Observer.changedInstr(MI);
1566+
return Legalized;
1567+
15591568
case TargetOpcode::G_SEXT_INREG: {
15601569
if (TypeIdx != 0)
15611570
return UnableToLegalize;
@@ -5317,14 +5326,18 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx,
53175326
Observer.changedInstr(MI);
53185327
return Legalized;
53195328
}
5320-
case TargetOpcode::G_ICMP: {
5321-
// TODO: the symmetric MoreTy works for targets like, e.g. NEON.
5322-
// For targets, like e.g. MVE, the result is a predicated vector (i1).
5323-
// This will need some refactoring.
5329+
case TargetOpcode::G_ICMP:
5330+
case TargetOpcode::G_FCMP: {
5331+
if (TypeIdx != 1)
5332+
return UnableToLegalize;
5333+
53245334
Observer.changingInstr(MI);
53255335
moreElementsVectorSrc(MI, MoreTy, 2);
53265336
moreElementsVectorSrc(MI, MoreTy, 3);
5327-
moreElementsVectorDst(MI, MoreTy, 0);
5337+
LLT CondTy = LLT::fixed_vector(
5338+
MoreTy.getNumElements(),
5339+
MRI.getType(MI.getOperand(0).getReg()).getElementType());
5340+
moreElementsVectorDst(MI, CondTy, 0);
53285341
Observer.changedInstr(MI);
53295342
return Legalized;
53305343
}

llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4600,8 +4600,7 @@ MachineInstr *AArch64InstructionSelector::emitFPCompare(
46004600
if (Ty.isVector())
46014601
return nullptr;
46024602
unsigned OpSize = Ty.getSizeInBits();
4603-
if (OpSize != 32 && OpSize != 64)
4604-
return nullptr;
4603+
assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
46054604

46064605
// If this is a compare against +0.0, then we don't have
46074606
// to explicitly materialize a constant.
@@ -4620,9 +4619,11 @@ MachineInstr *AArch64InstructionSelector::emitFPCompare(
46204619
std::swap(LHS, RHS);
46214620
}
46224621
}
4623-
unsigned CmpOpcTbl[2][2] = {{AArch64::FCMPSrr, AArch64::FCMPDrr},
4624-
{AArch64::FCMPSri, AArch64::FCMPDri}};
4625-
unsigned CmpOpc = CmpOpcTbl[ShouldUseImm][OpSize == 64];
4622+
unsigned CmpOpcTbl[2][3] = {
4623+
{AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4624+
{AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4625+
unsigned CmpOpc =
4626+
CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
46264627

46274628
// Partially build the compare. Decide if we need to add a use for the
46284629
// third operand based off whether or not we're comparing against 0.0.
@@ -4889,18 +4890,21 @@ MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
48894890
// TODO: emit CMN as an optimization.
48904891
auto &MRI = *MIB.getMRI();
48914892
LLT OpTy = MRI.getType(LHS);
4892-
assert(OpTy.getSizeInBits() == 32 || OpTy.getSizeInBits() == 64);
48934893
unsigned CCmpOpc;
48944894
std::optional<ValueAndVReg> C;
48954895
if (CmpInst::isIntPredicate(CC)) {
4896+
assert(OpTy.getSizeInBits() == 32 || OpTy.getSizeInBits() == 64);
48964897
C = getIConstantVRegValWithLookThrough(RHS, MRI);
48974898
if (C && C->Value.ult(32))
48984899
CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
48994900
else
49004901
CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
49014902
} else {
4903+
assert(OpTy.getSizeInBits() == 16 || OpTy.getSizeInBits() == 32 ||
4904+
OpTy.getSizeInBits() == 64);
49024905
switch (OpTy.getSizeInBits()) {
49034906
case 16:
4907+
assert(STI.hasFullFP16() && "Expected Full FP16 for fp16 comparisons");
49044908
CCmpOpc = AArch64::FCCMPHrr;
49054909
break;
49064910
case 32:

llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -527,39 +527,26 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
527527
.minScalarOrEltIf(
528528
[=](const LegalityQuery &Query) { return Query.Types[1] == v2p0; }, 0,
529529
s64)
530-
.moreElementsToNextPow2(0)
531-
.clampNumElements(0, v8s8, v16s8)
532-
.clampNumElements(0, v4s16, v8s16)
533-
.clampNumElements(0, v2s32, v4s32)
534-
.clampNumElements(0, v2s64, v2s64);
530+
.moreElementsToNextPow2(1)
531+
.clampNumElements(1, v8s8, v16s8)
532+
.clampNumElements(1, v4s16, v8s16)
533+
.clampNumElements(1, v2s32, v4s32)
534+
.clampNumElements(1, v2s64, v2s64);
535535

536536
getActionDefinitionsBuilder(G_FCMP)
537-
// If we don't have full FP16 support, then scalarize the elements of
538-
// vectors containing fp16 types.
539-
.fewerElementsIf(
540-
[=](const LegalityQuery &Query) {
541-
const auto &Ty = Query.Types[0];
542-
return Ty.isVector() && Ty.getElementType() == s16 && !HasFP16;
543-
},
544-
[=](const LegalityQuery &Query) { return std::make_pair(0, s16); })
545-
// If we don't have full FP16 support, then widen s16 to s32 if we
546-
// encounter it.
547-
.widenScalarIf(
548-
[=](const LegalityQuery &Query) {
549-
return Query.Types[0] == s16 && !HasFP16;
550-
},
551-
[=](const LegalityQuery &Query) { return std::make_pair(0, s32); })
552-
.legalFor({{s16, s16},
537+
.legalFor({{s32, MinFPScalar},
553538
{s32, s32},
554539
{s32, s64},
555540
{v4s32, v4s32},
556541
{v2s32, v2s32},
557-
{v2s64, v2s64},
558-
{v4s16, v4s16},
559-
{v8s16, v8s16}})
542+
{v2s64, v2s64}})
543+
.legalIf([=](const LegalityQuery &Query) {
544+
const auto &Ty = Query.Types[1];
545+
return (Ty == v8s16 || Ty == v4s16) && Ty == Query.Types[0] && HasFP16;
546+
})
560547
.widenScalarOrEltToNextPow2(1)
561-
.clampScalar(1, s32, s64)
562548
.clampScalar(0, s32, s32)
549+
.clampScalarOrElt(1, MinFPScalar, s64)
563550
.minScalarEltSameAsIf(
564551
[=](const LegalityQuery &Query) {
565552
const LLT &Ty = Query.Types[0];
@@ -568,8 +555,10 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
568555
Ty.getElementType() != SrcTy.getElementType();
569556
},
570557
0, 1)
571-
.clampNumElements(0, v2s32, v4s32)
572-
.clampMaxNumElements(1, s64, 2);
558+
.clampNumElements(1, v4s16, v8s16)
559+
.clampNumElements(1, v2s32, v4s32)
560+
.clampMaxNumElements(1, s64, 2)
561+
.moreElementsToNextPow2(1);
573562

574563
// Extensions
575564
auto ExtLegalFunc = [=](const LegalityQuery &Query) {

llvm/test/CodeGen/AArch64/GlobalISel/legalize-fcmp.mir

Lines changed: 22 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ body: |
66
bb.0.entry:
77
; CHECK-LABEL: name: test_icmp
88
; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
9-
; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY $x0
10-
; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64)
11-
; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64)
12-
; CHECK: [[FCMP:%[0-9]+]]:_(s32) = G_FCMP floatpred(oge), [[COPY]](s64), [[COPY1]]
13-
; CHECK: $w0 = COPY [[FCMP]](s32)
14-
; CHECK: [[FCMP1:%[0-9]+]]:_(s32) = G_FCMP floatpred(uno), [[TRUNC]](s32), [[TRUNC1]]
15-
; CHECK: $w0 = COPY [[FCMP1]](s32)
9+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x0
10+
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64)
11+
; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64)
12+
; CHECK-NEXT: [[FCMP:%[0-9]+]]:_(s32) = G_FCMP floatpred(oge), [[COPY]](s64), [[COPY1]]
13+
; CHECK-NEXT: $w0 = COPY [[FCMP]](s32)
14+
; CHECK-NEXT: [[FCMP1:%[0-9]+]]:_(s32) = G_FCMP floatpred(uno), [[TRUNC]](s32), [[TRUNC1]]
15+
; CHECK-NEXT: $w0 = COPY [[FCMP1]](s32)
1616
%0:_(s64) = COPY $x0
1717
%1:_(s64) = COPY $x0
1818
%2:_(s32) = G_TRUNC %0(s64)
@@ -36,41 +36,17 @@ body: |
3636
; CHECK-NEXT: {{ $}}
3737
; CHECK-NEXT: %lhs:_(<8 x s16>) = COPY $q0
3838
; CHECK-NEXT: %rhs:_(<8 x s16>) = COPY $q1
39-
; CHECK-NEXT: [[UV:%[0-9]+]]:_(s16), [[UV1:%[0-9]+]]:_(s16), [[UV2:%[0-9]+]]:_(s16), [[UV3:%[0-9]+]]:_(s16), [[UV4:%[0-9]+]]:_(s16), [[UV5:%[0-9]+]]:_(s16), [[UV6:%[0-9]+]]:_(s16), [[UV7:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES %lhs(<8 x s16>)
40-
; CHECK-NEXT: [[UV8:%[0-9]+]]:_(s16), [[UV9:%[0-9]+]]:_(s16), [[UV10:%[0-9]+]]:_(s16), [[UV11:%[0-9]+]]:_(s16), [[UV12:%[0-9]+]]:_(s16), [[UV13:%[0-9]+]]:_(s16), [[UV14:%[0-9]+]]:_(s16), [[UV15:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES %rhs(<8 x s16>)
41-
; CHECK-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = G_FPEXT [[UV]](s16)
42-
; CHECK-NEXT: [[FPEXT1:%[0-9]+]]:_(s32) = G_FPEXT [[UV8]](s16)
43-
; CHECK-NEXT: [[FCMP:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT]](s32), [[FPEXT1]]
44-
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP]](s32)
45-
; CHECK-NEXT: [[FPEXT2:%[0-9]+]]:_(s32) = G_FPEXT [[UV1]](s16)
46-
; CHECK-NEXT: [[FPEXT3:%[0-9]+]]:_(s32) = G_FPEXT [[UV9]](s16)
47-
; CHECK-NEXT: [[FCMP1:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT2]](s32), [[FPEXT3]]
48-
; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP1]](s32)
49-
; CHECK-NEXT: [[FPEXT4:%[0-9]+]]:_(s32) = G_FPEXT [[UV2]](s16)
50-
; CHECK-NEXT: [[FPEXT5:%[0-9]+]]:_(s32) = G_FPEXT [[UV10]](s16)
51-
; CHECK-NEXT: [[FCMP2:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT4]](s32), [[FPEXT5]]
52-
; CHECK-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP2]](s32)
53-
; CHECK-NEXT: [[FPEXT6:%[0-9]+]]:_(s32) = G_FPEXT [[UV3]](s16)
54-
; CHECK-NEXT: [[FPEXT7:%[0-9]+]]:_(s32) = G_FPEXT [[UV11]](s16)
55-
; CHECK-NEXT: [[FCMP3:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT6]](s32), [[FPEXT7]]
56-
; CHECK-NEXT: [[TRUNC3:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP3]](s32)
57-
; CHECK-NEXT: [[FPEXT8:%[0-9]+]]:_(s32) = G_FPEXT [[UV4]](s16)
58-
; CHECK-NEXT: [[FPEXT9:%[0-9]+]]:_(s32) = G_FPEXT [[UV12]](s16)
59-
; CHECK-NEXT: [[FCMP4:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT8]](s32), [[FPEXT9]]
60-
; CHECK-NEXT: [[TRUNC4:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP4]](s32)
61-
; CHECK-NEXT: [[FPEXT10:%[0-9]+]]:_(s32) = G_FPEXT [[UV5]](s16)
62-
; CHECK-NEXT: [[FPEXT11:%[0-9]+]]:_(s32) = G_FPEXT [[UV13]](s16)
63-
; CHECK-NEXT: [[FCMP5:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT10]](s32), [[FPEXT11]]
64-
; CHECK-NEXT: [[TRUNC5:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP5]](s32)
65-
; CHECK-NEXT: [[FPEXT12:%[0-9]+]]:_(s32) = G_FPEXT [[UV6]](s16)
66-
; CHECK-NEXT: [[FPEXT13:%[0-9]+]]:_(s32) = G_FPEXT [[UV14]](s16)
67-
; CHECK-NEXT: [[FCMP6:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT12]](s32), [[FPEXT13]]
68-
; CHECK-NEXT: [[TRUNC6:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP6]](s32)
69-
; CHECK-NEXT: [[FPEXT14:%[0-9]+]]:_(s32) = G_FPEXT [[UV7]](s16)
70-
; CHECK-NEXT: [[FPEXT15:%[0-9]+]]:_(s32) = G_FPEXT [[UV15]](s16)
71-
; CHECK-NEXT: [[FCMP7:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT14]](s32), [[FPEXT15]]
72-
; CHECK-NEXT: [[TRUNC7:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP7]](s32)
73-
; CHECK-NEXT: %fcmp:_(<8 x s16>) = G_BUILD_VECTOR [[TRUNC]](s16), [[TRUNC1]](s16), [[TRUNC2]](s16), [[TRUNC3]](s16), [[TRUNC4]](s16), [[TRUNC5]](s16), [[TRUNC6]](s16), [[TRUNC7]](s16)
39+
; CHECK-NEXT: [[UV:%[0-9]+]]:_(<4 x s16>), [[UV1:%[0-9]+]]:_(<4 x s16>) = G_UNMERGE_VALUES %lhs(<8 x s16>)
40+
; CHECK-NEXT: [[FPEXT:%[0-9]+]]:_(<4 x s32>) = G_FPEXT [[UV]](<4 x s16>)
41+
; CHECK-NEXT: [[FPEXT1:%[0-9]+]]:_(<4 x s32>) = G_FPEXT [[UV1]](<4 x s16>)
42+
; CHECK-NEXT: [[UV2:%[0-9]+]]:_(<4 x s16>), [[UV3:%[0-9]+]]:_(<4 x s16>) = G_UNMERGE_VALUES %rhs(<8 x s16>)
43+
; CHECK-NEXT: [[FPEXT2:%[0-9]+]]:_(<4 x s32>) = G_FPEXT [[UV2]](<4 x s16>)
44+
; CHECK-NEXT: [[FPEXT3:%[0-9]+]]:_(<4 x s32>) = G_FPEXT [[UV3]](<4 x s16>)
45+
; CHECK-NEXT: [[FCMP:%[0-9]+]]:_(<4 x s32>) = G_FCMP floatpred(oeq), [[FPEXT]](<4 x s32>), [[FPEXT2]]
46+
; CHECK-NEXT: [[FCMP1:%[0-9]+]]:_(<4 x s32>) = G_FCMP floatpred(oeq), [[FPEXT1]](<4 x s32>), [[FPEXT3]]
47+
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x s16>) = G_TRUNC [[FCMP]](<4 x s32>)
48+
; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(<4 x s16>) = G_TRUNC [[FCMP1]](<4 x s32>)
49+
; CHECK-NEXT: %fcmp:_(<8 x s16>) = G_CONCAT_VECTORS [[TRUNC]](<4 x s16>), [[TRUNC1]](<4 x s16>)
7450
; CHECK-NEXT: $q0 = COPY %fcmp(<8 x s16>)
7551
; CHECK-NEXT: RET_ReallyLR implicit $q0
7652
%lhs:_(<8 x s16>) = COPY $q0
@@ -93,25 +69,10 @@ body: |
9369
; CHECK-NEXT: {{ $}}
9470
; CHECK-NEXT: %lhs:_(<4 x s16>) = COPY $d0
9571
; CHECK-NEXT: %rhs:_(<4 x s16>) = COPY $d1
96-
; CHECK-NEXT: [[UV:%[0-9]+]]:_(s16), [[UV1:%[0-9]+]]:_(s16), [[UV2:%[0-9]+]]:_(s16), [[UV3:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES %lhs(<4 x s16>)
97-
; CHECK-NEXT: [[UV4:%[0-9]+]]:_(s16), [[UV5:%[0-9]+]]:_(s16), [[UV6:%[0-9]+]]:_(s16), [[UV7:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES %rhs(<4 x s16>)
98-
; CHECK-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = G_FPEXT [[UV]](s16)
99-
; CHECK-NEXT: [[FPEXT1:%[0-9]+]]:_(s32) = G_FPEXT [[UV4]](s16)
100-
; CHECK-NEXT: [[FCMP:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT]](s32), [[FPEXT1]]
101-
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP]](s32)
102-
; CHECK-NEXT: [[FPEXT2:%[0-9]+]]:_(s32) = G_FPEXT [[UV1]](s16)
103-
; CHECK-NEXT: [[FPEXT3:%[0-9]+]]:_(s32) = G_FPEXT [[UV5]](s16)
104-
; CHECK-NEXT: [[FCMP1:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT2]](s32), [[FPEXT3]]
105-
; CHECK-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP1]](s32)
106-
; CHECK-NEXT: [[FPEXT4:%[0-9]+]]:_(s32) = G_FPEXT [[UV2]](s16)
107-
; CHECK-NEXT: [[FPEXT5:%[0-9]+]]:_(s32) = G_FPEXT [[UV6]](s16)
108-
; CHECK-NEXT: [[FCMP2:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT4]](s32), [[FPEXT5]]
109-
; CHECK-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP2]](s32)
110-
; CHECK-NEXT: [[FPEXT6:%[0-9]+]]:_(s32) = G_FPEXT [[UV3]](s16)
111-
; CHECK-NEXT: [[FPEXT7:%[0-9]+]]:_(s32) = G_FPEXT [[UV7]](s16)
112-
; CHECK-NEXT: [[FCMP3:%[0-9]+]]:_(s32) = G_FCMP floatpred(oeq), [[FPEXT6]](s32), [[FPEXT7]]
113-
; CHECK-NEXT: [[TRUNC3:%[0-9]+]]:_(s16) = G_TRUNC [[FCMP3]](s32)
114-
; CHECK-NEXT: %fcmp:_(<4 x s16>) = G_BUILD_VECTOR [[TRUNC]](s16), [[TRUNC1]](s16), [[TRUNC2]](s16), [[TRUNC3]](s16)
72+
; CHECK-NEXT: [[FPEXT:%[0-9]+]]:_(<4 x s32>) = G_FPEXT %lhs(<4 x s16>)
73+
; CHECK-NEXT: [[FPEXT1:%[0-9]+]]:_(<4 x s32>) = G_FPEXT %rhs(<4 x s16>)
74+
; CHECK-NEXT: [[FCMP:%[0-9]+]]:_(<4 x s32>) = G_FCMP floatpred(oeq), [[FPEXT]](<4 x s32>), [[FPEXT1]]
75+
; CHECK-NEXT: %fcmp:_(<4 x s16>) = G_TRUNC [[FCMP]](<4 x s32>)
11576
; CHECK-NEXT: $d0 = COPY %fcmp(<4 x s16>)
11677
; CHECK-NEXT: RET_ReallyLR implicit $d0
11778
%lhs:_(<4 x s16>) = COPY $d0

0 commit comments

Comments
 (0)