-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[AArch64] Remove copy in SVE/SME predicate spill and fill #81716
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 16 commits
c0c0609
929b111
514b9b5
264a844
53a3177
6a4502c
808ddbb
ed8519e
6a55451
a229c76
8c5b567
a64ca22
9e59c45
1a398e1
2f6d418
f06c0ce
23b051b
a53aeb4
03aabd2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4813,24 +4813,22 @@ void AArch64InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, | |||||||||||||||||||||||||||||||||||||||||||||
case 2: | ||||||||||||||||||||||||||||||||||||||||||||||
if (AArch64::FPR16RegClass.hasSubClassEq(RC)) | ||||||||||||||||||||||||||||||||||||||||||||||
Opc = AArch64::STRHui; | ||||||||||||||||||||||||||||||||||||||||||||||
else if (AArch64::PPRRegClass.hasSubClassEq(RC)) { | ||||||||||||||||||||||||||||||||||||||||||||||
assert(Subtarget.hasSVEorSME() && | ||||||||||||||||||||||||||||||||||||||||||||||
"Unexpected register store without SVE store instructions"); | ||||||||||||||||||||||||||||||||||||||||||||||
Opc = AArch64::STR_PXI; | ||||||||||||||||||||||||||||||||||||||||||||||
StackID = TargetStackID::ScalableVector; | ||||||||||||||||||||||||||||||||||||||||||||||
} else if (AArch64::PNRRegClass.hasSubClassEq(RC)) { | ||||||||||||||||||||||||||||||||||||||||||||||
assert((Subtarget.hasSVE2p1() || Subtarget.hasSME2()) && | ||||||||||||||||||||||||||||||||||||||||||||||
"Unexpected register store without SVE2p1 or SME2"); | ||||||||||||||||||||||||||||||||||||||||||||||
if (SrcReg.isVirtual()) { | ||||||||||||||||||||||||||||||||||||||||||||||
auto NewSrcReg = | ||||||||||||||||||||||||||||||||||||||||||||||
MF.getRegInfo().createVirtualRegister(&AArch64::PPRRegClass); | ||||||||||||||||||||||||||||||||||||||||||||||
BuildMI(MBB, MBBI, DebugLoc(), get(TargetOpcode::COPY), NewSrcReg) | ||||||||||||||||||||||||||||||||||||||||||||||
.addReg(SrcReg); | ||||||||||||||||||||||||||||||||||||||||||||||
SrcReg = NewSrcReg; | ||||||||||||||||||||||||||||||||||||||||||||||
} else | ||||||||||||||||||||||||||||||||||||||||||||||
SrcReg = (SrcReg - AArch64::PN0) + AArch64::P0; | ||||||||||||||||||||||||||||||||||||||||||||||
Opc = AArch64::STR_PXI; | ||||||||||||||||||||||||||||||||||||||||||||||
StackID = TargetStackID::ScalableVector; | ||||||||||||||||||||||||||||||||||||||||||||||
else { | ||||||||||||||||||||||||||||||||||||||||||||||
bool IsPPR = AArch64::PPRRegClass.hasSubClassEq(RC); | ||||||||||||||||||||||||||||||||||||||||||||||
bool IsPNR = AArch64::PNRRegClass.hasSubClassEq(RC); | ||||||||||||||||||||||||||||||||||||||||||||||
if (IsPPR || IsPNR) { | ||||||||||||||||||||||||||||||||||||||||||||||
assert((!IsPPR || Subtarget.hasSVEorSME()) && | ||||||||||||||||||||||||||||||||||||||||||||||
"Unexpected register store without SVE store instructions"); | ||||||||||||||||||||||||||||||||||||||||||||||
assert((!IsPNR || Subtarget.hasSVE2p1() || Subtarget.hasSME2()) && | ||||||||||||||||||||||||||||||||||||||||||||||
"Unexpected register store without SVE2p1 or SME2"); | ||||||||||||||||||||||||||||||||||||||||||||||
Opc = AArch64::STR_PXI; | ||||||||||||||||||||||||||||||||||||||||||||||
StackID = TargetStackID::ScalableVector; | ||||||||||||||||||||||||||||||||||||||||||||||
if (SrcReg.isVirtual()) | ||||||||||||||||||||||||||||||||||||||||||||||
MF.getRegInfo().constrainRegClass(SrcReg, &AArch64::PPRRegClass); | ||||||||||||||||||||||||||||||||||||||||||||||
else if (IsPNR) | ||||||||||||||||||||||||||||||||||||||||||||||
// Normalise to PPR | ||||||||||||||||||||||||||||||||||||||||||||||
SrcReg = (SrcReg - AArch64::PN0) + AArch64::P0; | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that the LDR and STR instructions accept a predicate-as-counter register, we can remove this trick to change the register class and simplify this code to:
Suggested change
same for the other case in loadRegFromStackSlot There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right! Thanks. I've kept the |
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||
case 4: | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -4996,21 +4994,27 @@ void AArch64InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, | |||||||||||||||||||||||||||||||||||||||||||||
case 2: | ||||||||||||||||||||||||||||||||||||||||||||||
if (AArch64::FPR16RegClass.hasSubClassEq(RC)) | ||||||||||||||||||||||||||||||||||||||||||||||
Opc = AArch64::LDRHui; | ||||||||||||||||||||||||||||||||||||||||||||||
else if (AArch64::PPRRegClass.hasSubClassEq(RC)) { | ||||||||||||||||||||||||||||||||||||||||||||||
assert(Subtarget.hasSVEorSME() && | ||||||||||||||||||||||||||||||||||||||||||||||
"Unexpected register load without SVE load instructions"); | ||||||||||||||||||||||||||||||||||||||||||||||
Opc = AArch64::LDR_PXI; | ||||||||||||||||||||||||||||||||||||||||||||||
StackID = TargetStackID::ScalableVector; | ||||||||||||||||||||||||||||||||||||||||||||||
} else if (AArch64::PNRRegClass.hasSubClassEq(RC)) { | ||||||||||||||||||||||||||||||||||||||||||||||
assert((Subtarget.hasSVE2p1() || Subtarget.hasSME2()) && | ||||||||||||||||||||||||||||||||||||||||||||||
"Unexpected register load without SVE2p1 or SME2"); | ||||||||||||||||||||||||||||||||||||||||||||||
PNRReg = DestReg; | ||||||||||||||||||||||||||||||||||||||||||||||
if (DestReg.isVirtual()) | ||||||||||||||||||||||||||||||||||||||||||||||
DestReg = MF.getRegInfo().createVirtualRegister(&AArch64::PPRRegClass); | ||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||
DestReg = (DestReg - AArch64::PN0) + AArch64::P0; | ||||||||||||||||||||||||||||||||||||||||||||||
Opc = AArch64::LDR_PXI; | ||||||||||||||||||||||||||||||||||||||||||||||
StackID = TargetStackID::ScalableVector; | ||||||||||||||||||||||||||||||||||||||||||||||
else { | ||||||||||||||||||||||||||||||||||||||||||||||
bool IsPPR = AArch64::PPRRegClass.hasSubClassEq(RC); | ||||||||||||||||||||||||||||||||||||||||||||||
bool IsPNR = AArch64::PNRRegClass.hasSubClassEq(RC); | ||||||||||||||||||||||||||||||||||||||||||||||
if (IsPPR || IsPNR) { | ||||||||||||||||||||||||||||||||||||||||||||||
assert((!IsPPR || Subtarget.hasSVEorSME()) && | ||||||||||||||||||||||||||||||||||||||||||||||
"Unexpected register load without SVE load instructions"); | ||||||||||||||||||||||||||||||||||||||||||||||
assert((!IsPNR || Subtarget.hasSVE2p1() || Subtarget.hasSME2()) && | ||||||||||||||||||||||||||||||||||||||||||||||
"Unexpected register load without SVE2p1 or SME2"); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
if (IsPNR) | ||||||||||||||||||||||||||||||||||||||||||||||
PNRReg = DestReg; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
if (DestReg.isVirtual()) | ||||||||||||||||||||||||||||||||||||||||||||||
MF.getRegInfo().constrainRegClass(DestReg, &AArch64::PPRRegClass); | ||||||||||||||||||||||||||||||||||||||||||||||
else if (IsPNR) | ||||||||||||||||||||||||||||||||||||||||||||||
// Normalise to PPR | ||||||||||||||||||||||||||||||||||||||||||||||
DestReg = (DestReg - AArch64::PN0) + AArch64::P0; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
Opc = AArch64::LDR_PXI; | ||||||||||||||||||||||||||||||||||||||||||||||
StackID = TargetStackID::ScalableVector; | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||||||||||||||
case 4: | ||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -276,6 +276,8 @@ class AArch64AsmParser : public MCTargetAsmParser { | |||||
ParseStatus tryParseSVEDataVector(OperandVector &Operands); | ||||||
template <RegKind RK> | ||||||
ParseStatus tryParseSVEPredicateVector(OperandVector &Operands); | ||||||
ParseStatus | ||||||
tryParseSVEPredicateOrPredicateAsCounterVector(OperandVector &Operands); | ||||||
template <RegKind VectorKind> | ||||||
ParseStatus tryParseVectorList(OperandVector &Operands, | ||||||
bool ExpectMatch = false); | ||||||
|
@@ -1241,6 +1243,7 @@ class AArch64Operand : public MCParsedAsmOperand { | |||||
case AArch64::PPR_p8to15RegClassID: | ||||||
case AArch64::PNRRegClassID: | ||||||
case AArch64::PNR_p8to15RegClassID: | ||||||
case AArch64::PPRorPNRRegClassID: | ||||||
RK = RegKind::SVEPredicateAsCounter; | ||||||
break; | ||||||
default: | ||||||
|
@@ -1264,6 +1267,7 @@ class AArch64Operand : public MCParsedAsmOperand { | |||||
case AArch64::PPR_p8to15RegClassID: | ||||||
case AArch64::PNRRegClassID: | ||||||
case AArch64::PNR_p8to15RegClassID: | ||||||
case AArch64::PPRorPNRRegClassID: | ||||||
RK = RegKind::SVEPredicateVector; | ||||||
break; | ||||||
default: | ||||||
|
@@ -1290,6 +1294,20 @@ class AArch64Operand : public MCParsedAsmOperand { | |||||
return DiagnosticPredicateTy::NearMatch; | ||||||
} | ||||||
|
||||||
template <int ElementWidth, unsigned Class> | ||||||
DiagnosticPredicate isSVEPredicateOrPredicateAsCounterRegOfWidth() const { | ||||||
if (Kind != k_Register || (Reg.Kind != RegKind::SVEPredicateAsCounter && | ||||||
Reg.Kind != RegKind::SVEPredicateVector)) | ||||||
return DiagnosticPredicateTy::NoMatch; | ||||||
|
||||||
if ((isSVEPredicateAsCounterReg<Class>() || | ||||||
isSVEPredicateVectorRegOfWidth<ElementWidth, Class>()) && | ||||||
(Reg.ElementWidth == ElementWidth)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: no parenthesis needed in:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||||||
return DiagnosticPredicateTy::Match; | ||||||
|
||||||
return DiagnosticPredicateTy::NearMatch; | ||||||
} | ||||||
|
||||||
template <int ElementWidth, unsigned Class> | ||||||
DiagnosticPredicate isSVEPredicateAsCounterRegOfWidth() const { | ||||||
if (Kind != k_Register || Reg.Kind != RegKind::SVEPredicateAsCounter) | ||||||
|
@@ -1770,6 +1788,15 @@ class AArch64Operand : public MCParsedAsmOperand { | |||||
Inst.addOperand(MCOperand::createReg(AArch64::Z0 + getReg() - Base)); | ||||||
} | ||||||
|
||||||
void addPPRorPNRRegOperands(MCInst &Inst, unsigned N) const { | ||||||
assert(N == 1 && "Invalid number of operands!"); | ||||||
unsigned Reg = getReg(); | ||||||
// Normalise to PPR | ||||||
if (Reg >= AArch64::PN0 && Reg <= AArch64::PN15) | ||||||
Reg = Reg - AArch64::PN0 + AArch64::P0; | ||||||
Inst.addOperand(MCOperand::createReg(Reg)); | ||||||
} | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
void addPNRasPPRRegOperands(MCInst &Inst, unsigned N) const { | ||||||
assert(N == 1 && "Invalid number of operands!"); | ||||||
Inst.addOperand( | ||||||
|
@@ -4167,6 +4194,15 @@ ParseStatus AArch64AsmParser::tryParseVectorRegister(MCRegister &Reg, | |||||
return ParseStatus::NoMatch; | ||||||
} | ||||||
|
||||||
ParseStatus AArch64AsmParser::tryParseSVEPredicateOrPredicateAsCounterVector( | ||||||
OperandVector &Operands) { | ||||||
ParseStatus Status = | ||||||
tryParseSVEPredicateVector<RegKind::SVEPredicateAsCounter>(Operands); | ||||||
if (!Status.isSuccess()) | ||||||
Status = tryParseSVEPredicateVector<RegKind::SVEPredicateVector>(Operands); | ||||||
return Status; | ||||||
} | ||||||
|
||||||
/// tryParseSVEPredicateVector - Parse a SVE predicate register operand. | ||||||
template <RegKind RK> | ||||||
ParseStatus | ||||||
|
@@ -6019,6 +6055,8 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode, | |||||
return Error(Loc, "Invalid restricted vector register, expected z0.d..z15.d"); | ||||||
case Match_InvalidSVEPattern: | ||||||
return Error(Loc, "invalid predicate pattern"); | ||||||
case Match_InvalidSVEPPRorPNRAnyReg: | ||||||
case Match_InvalidSVEPPRorPNRBReg: | ||||||
case Match_InvalidSVEPredicateAnyReg: | ||||||
case Match_InvalidSVEPredicateBReg: | ||||||
case Match_InvalidSVEPredicateHReg: | ||||||
|
@@ -6131,9 +6169,6 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode, | |||||
case Match_AddSubLSLImm3ShiftLarge: | ||||||
return Error(Loc, | ||||||
"expected 'lsl' with optional integer in range [0, 7]"); | ||||||
case Match_InvalidSVEPNRasPPRPredicateBReg: | ||||||
return Error(Loc, | ||||||
"Expected predicate-as-counter register name with .B suffix"); | ||||||
default: | ||||||
llvm_unreachable("unexpected error code!"); | ||||||
} | ||||||
|
@@ -6653,6 +6688,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, | |||||
case Match_InvalidZPR_4b16: | ||||||
case Match_InvalidZPR_4b32: | ||||||
case Match_InvalidZPR_4b64: | ||||||
case Match_InvalidSVEPPRorPNRAnyReg: | ||||||
case Match_InvalidSVEPredicateAnyReg: | ||||||
case Match_InvalidSVEPattern: | ||||||
case Match_InvalidSVEVecLenSpecifier: | ||||||
|
@@ -6714,7 +6750,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, | |||||
case Match_InvalidSVEVectorListStrided4x16: | ||||||
case Match_InvalidSVEVectorListStrided4x32: | ||||||
case Match_InvalidSVEVectorListStrided4x64: | ||||||
case Match_InvalidSVEPNRasPPRPredicateBReg: | ||||||
case Match_InvalidSVEPPRorPNRBReg: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: should this be together with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we keep it here we retain the same error messages as the older reg class. I can move it up but it will require updating quite a few tests. |
||||||
case Match_MSR: | ||||||
case Match_MRS: { | ||||||
if (ErrorInfo >= Operands.size()) | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -143,6 +143,9 @@ DecodeMatrixTileListRegisterClass(MCInst &Inst, unsigned RegMask, | |
static DecodeStatus DecodePPRRegisterClass(MCInst &Inst, unsigned RegNo, | ||
uint64_t Address, | ||
const MCDisassembler *Decoder); | ||
static DecodeStatus DecodePPRorPNRRegisterClass(MCInst &Inst, unsigned RegNo, | ||
uint64_t Addr, | ||
const MCDisassembler *Decoder); | ||
static DecodeStatus DecodePNRRegisterClass(MCInst &Inst, unsigned RegNo, | ||
uint64_t Address, | ||
const MCDisassembler *Decoder); | ||
|
@@ -741,6 +744,18 @@ static DecodeStatus DecodeMatrixTile(MCInst &Inst, unsigned RegNo, | |
return Success; | ||
} | ||
|
||
static DecodeStatus DecodePPRorPNRRegisterClass(MCInst &Inst, unsigned RegNo, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cleanup suggestion for a separate patch: All these decoder classes looks rather identical, it would be nice to clean this up with something like this:
And then remove the other functions and just specify e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That sounds good to me. We can do it in a separate patch. |
||
uint64_t Addr, | ||
const MCDisassembler *Decoder) { | ||
if (RegNo > 15) | ||
return Fail; | ||
|
||
unsigned Register = | ||
AArch64MCRegisterClasses[AArch64::PPRorPNRRegClassID].getRegister(RegNo); | ||
Inst.addOperand(MCOperand::createReg(Register)); | ||
return Success; | ||
} | ||
|
||
static DecodeStatus DecodePPRRegisterClass(MCInst &Inst, unsigned RegNo, | ||
uint64_t Addr, | ||
const MCDisassembler *Decoder) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -740,7 +740,7 @@ let hasNoSchedulingInfo = 1 in { | |
//===----------------------------------------------------------------------===// | ||
|
||
class sve_int_pfalse<bits<6> opc, string asm> | ||
: I<(outs PPR8:$Pd), (ins), | ||
: I<(outs PPRorPNR8:$Pd), (ins), | ||
asm, "\t$Pd", | ||
"", | ||
[]>, Sched<[]> { | ||
|
@@ -1848,7 +1848,7 @@ multiclass sve_int_sel_vvv<string asm, SDPatternOperator op> { | |
//===----------------------------------------------------------------------===// | ||
|
||
class sve_int_pred_log<bits<4> opc, string asm> | ||
: I<(outs PPR8:$Pd), (ins PPRAny:$Pg, PPR8:$Pn, PPR8:$Pm), | ||
: I<(outs PPRorPNR8:$Pd), (ins PPRorPNRAny:$Pg, PPRorPNR8:$Pn, PPRorPNR8:$Pm), | ||
asm, "\t$Pd, $Pg/z, $Pn, $Pm", | ||
"", | ||
[]>, Sched<[]> { | ||
|
@@ -6689,7 +6689,7 @@ multiclass sve_mem_z_spill<string asm> { | |
} | ||
|
||
class sve_mem_p_spill<string asm> | ||
: I<(outs), (ins PPRAny:$Pt, GPR64sp:$Rn, simm9:$imm9), | ||
: I<(outs), (ins PPRorPNRAny:$Pt, GPR64sp:$Rn, simm9:$imm9), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This removes the need for having the following InstAliases in AArch64SVEInstrInfo.td:
Can you remove them? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
asm, "\t$Pt, [$Rn, $imm9, mul vl]", | ||
"", | ||
[]>, Sched<[]> { | ||
|
@@ -6712,7 +6712,7 @@ multiclass sve_mem_p_spill<string asm> { | |
def NAME : sve_mem_p_spill<asm>; | ||
|
||
def : InstAlias<asm # "\t$Pt, [$Rn]", | ||
(!cast<Instruction>(NAME) PPRAny:$Pt, GPR64sp:$Rn, 0), 1>; | ||
(!cast<Instruction>(NAME) PPRorPNRAny:$Pt, GPR64sp:$Rn, 0), 1>; | ||
} | ||
|
||
//===----------------------------------------------------------------------===// | ||
|
@@ -7858,7 +7858,7 @@ multiclass sve_mem_z_fill<string asm> { | |
} | ||
|
||
class sve_mem_p_fill<string asm> | ||
: I<(outs PPRAny:$Pt), (ins GPR64sp:$Rn, simm9:$imm9), | ||
: I<(outs PPRorPNRAny:$Pt), (ins GPR64sp:$Rn, simm9:$imm9), | ||
asm, "\t$Pt, [$Rn, $imm9, mul vl]", | ||
"", | ||
[]>, Sched<[]> { | ||
|
@@ -7881,7 +7881,7 @@ multiclass sve_mem_p_fill<string asm> { | |
def NAME : sve_mem_p_fill<asm>; | ||
|
||
def : InstAlias<asm # "\t$Pt, [$Rn]", | ||
(!cast<Instruction>(NAME) PPRAny:$Pt, GPR64sp:$Rn, 0), 1>; | ||
(!cast<Instruction>(NAME) PPRorPNRAny:$Pt, GPR64sp:$Rn, 0), 1>; | ||
} | ||
|
||
class sve2_mem_gldnt_vs_base<bits<5> opc, dag iops, string asm, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this can be
because both PPR and PNR require at least either SME or SVE. (same for the assert on line 4996)