Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 35a6730

Browse files
authored
ARM64-SVE: Add checks for MOVPRFX sequencing (#105514) (#106184)
1 parent 3eba702 commit 35a6730

File tree

5 files changed

+281
-16
lines changed

5 files changed

+281
-16
lines changed

src/coreclr/jit/codegen.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,8 +1012,12 @@ class CodeGen final : public CodeGenInterface
10121012
public:
10131013
HWIntrinsicImmOpHelper(CodeGen* codeGen, GenTree* immOp, GenTreeHWIntrinsic* intrin, int numInstrs = 1);
10141014

1015-
HWIntrinsicImmOpHelper(
1016-
CodeGen* codeGen, regNumber immReg, int immLowerBound, int immUpperBound, GenTreeHWIntrinsic* intrin);
1015+
HWIntrinsicImmOpHelper(CodeGen* codeGen,
1016+
regNumber immReg,
1017+
int immLowerBound,
1018+
int immUpperBound,
1019+
GenTreeHWIntrinsic* intrin,
1020+
int numInstrs = 1);
10171021

10181022
void EmitBegin();
10191023
void EmitCaseEnd();

src/coreclr/jit/emit.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7095,8 +7095,28 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
70957095
*instrCount = 0;
70967096
jitstd::list<RichIPMapping>::iterator nextMapping = emitComp->genRichIPmappings.begin();
70977097
#endif
7098+
#if defined(DEBUG) && defined(TARGET_ARM64)
7099+
instrDesc* prevId = nullptr;
7100+
#endif // defined(DEBUG) && defined(TARGET_ARM64)
7101+
70987102
for (insGroup* ig = emitIGlist; ig != nullptr; ig = ig->igNext)
70997103
{
7104+
7105+
#if defined(DEBUG) && defined(TARGET_ARM64)
7106+
instrDesc* currId = emitFirstInstrDesc(ig->igData);
7107+
for (unsigned cnt = ig->igInsCnt; cnt > 0; cnt--)
7108+
{
7109+
emitInsPairSanityCheck(prevId, currId);
7110+
prevId = currId;
7111+
emitAdvanceInstrDesc(&currId, emitSizeOfInsDsc(currId));
7112+
}
7113+
// Final instruction can't be a movprfx
7114+
if (ig->igNext == nullptr)
7115+
{
7116+
assert(prevId->idIns() != INS_sve_movprfx);
7117+
}
7118+
#endif // defined(DEBUG) && defined(TARGET_ARM64)
7119+
71007120
assert(!(ig->igFlags & IGF_PLACEHOLDER)); // There better not be any placeholder groups left
71017121

71027122
/* Is this the first cold block? */

src/coreclr/jit/emit.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3128,6 +3128,10 @@ class emitter
31283128
#ifndef TARGET_LOONGARCH64
31293129
void emitInsSanityCheck(instrDesc* id);
31303130
#endif // TARGET_LOONGARCH64
3131+
3132+
#ifdef TARGET_ARM64
3133+
void emitInsPairSanityCheck(instrDesc* prevId, instrDesc* id);
3134+
#endif
31313135
#endif // DEBUG
31323136

31333137
#ifdef TARGET_ARMARCH

src/coreclr/jit/emitarm64sve.cpp

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18432,4 +18432,212 @@ void emitter::getInsSveExecutionCharacteristics(instrDesc* id, insExecutionChara
1843218432
}
1843318433
#endif // defined(DEBUG) || defined(LATE_DISASM)
1843418434

18435+
#ifdef DEBUG
18436+
/*****************************************************************************
18437+
*
18438+
* Sanity check two instructions are valid when placed next to each other
18439+
*/
18440+
18441+
void emitter::emitInsPairSanityCheck(instrDesc* firstId, instrDesc* secondId)
18442+
{
18443+
if (firstId == nullptr || secondId == nullptr)
18444+
{
18445+
return;
18446+
}
18447+
18448+
// Currently only concerned with instructions that follow movprfx
18449+
if (firstId->idIns() != INS_sve_movprfx)
18450+
{
18451+
return;
18452+
}
18453+
18454+
bool movprefxIsPredicated = false;
18455+
if (firstId->idInsFmt() == IF_SVE_AH_3A)
18456+
{
18457+
movprefxIsPredicated = true;
18458+
}
18459+
else
18460+
{
18461+
// Unpredicated version
18462+
assert(firstId->idInsFmt() == IF_SVE_BI_2A);
18463+
}
18464+
18465+
// Quoted sections are taken from the Arm manual.
18466+
18467+
// "It is required that the prefixed instruction at PC+4 must be an SVE destructive binary or ternary
18468+
// instruction encoding, or a unary operation with merging predication, but excluding other MOVPRFX instructions."
18469+
// "The prefixed instruction must not use the destination register in any other operand position, even if
18470+
// they have different names but refer to the same architectural register state."
18471+
// "A predicated MOVPRFX cannot be used with an unpredicated instruction."
18472+
switch (secondId->idInsFmt())
18473+
{
18474+
case IF_SVE_BN_1A: // <Zdn>.D{, <pattern>{, MUL #<imm>}}
18475+
case IF_SVE_BP_1A: // <Zdn>.D{, <pattern>{, MUL #<imm>}}
18476+
case IF_SVE_CC_2A: // <Zdn>.<T>, <V><m>
18477+
case IF_SVE_CD_2A: // <Zdn>.<T>, <R><m>
18478+
case IF_SVE_DN_2A: // <Zdn>.<T>, <Pm>.<T>
18479+
case IF_SVE_DP_2A: // <Zdn>.<T>, <Pm>.<T>
18480+
// Tied registers
18481+
case IF_SVE_BS_1A: // <Zdn>.<T>, <Zdn>.<T>, #<const>
18482+
case IF_SVE_EC_1A: // <Zdn>.<T>, <Zdn>.<T>, #<imm>{, <shift>}
18483+
case IF_SVE_ED_1A: // <Zdn>.<T>, <Zdn>.<T>, #<imm>
18484+
case IF_SVE_EE_1A: // <Zdn>.<T>, <Zdn>.<T>, #<imm>
18485+
assert(!movprefxIsPredicated);
18486+
break;
18487+
18488+
case IF_SVE_BU_2A: // <Zd>.<T>, <Pg>/M, #<const>
18489+
case IF_SVE_BV_2A_A: // <Zd>.<T>, <Pg>/M, #<imm>{, <shift>}
18490+
case IF_SVE_BV_2A_J: // <Zd>.<T>, <Pg>/M, #<imm>{, <shift>}
18491+
case IF_SVE_BV_2B: // <Zd>.<T>, <Pg>/M, #0.0
18492+
case IF_SVE_CQ_3A: // <Zd>.<T>, <Pg>/M, <R><n|SP>
18493+
// Tied registers
18494+
case IF_SVE_AM_2A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, #<const>
18495+
case IF_SVE_HM_2A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <const>
18496+
break;
18497+
18498+
case IF_SVE_FU_2A: // <Zda>.<T>, <Zn>.<T>, #<const>
18499+
// Tied registers
18500+
case IF_SVE_AW_2A: // <Zdn>.<T>, <Zdn>.<T>, <Zm>.<T>, #<const>
18501+
case IF_SVE_BY_2A: // <Zdn>.B, <Zdn>.B, <Zm>.B, #<imm>
18502+
case IF_SVE_FV_2A: // <Zdn>.<T>, <Zdn>.<T>, <Zm>.<T>, <const>
18503+
case IF_SVE_HN_2A: // <Zdn>.<T>, <Zdn>.<T>, <Zm>.<T>, #<imm>
18504+
assert(!movprefxIsPredicated);
18505+
assert(secondId->idReg1() != secondId->idReg2());
18506+
break;
18507+
18508+
case IF_SVE_AP_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18509+
case IF_SVE_AQ_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18510+
case IF_SVE_CP_3A: // <Zd>.<T>, <Pg>/M, <V><n>
18511+
case IF_SVE_CT_3A: // <Zd>.Q, <Pg>/M, <Zn>.Q
18512+
case IF_SVE_CU_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18513+
case IF_SVE_ES_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18514+
case IF_SVE_EQ_3A: // <Zda>.<T>, <Pg>/M, <Zn>.<Tb>
18515+
case IF_SVE_HO_3A: // <Zd>.H, <Pg>/M, <Zn>.S
18516+
case IF_SVE_HO_3B: // <Zd>.D, <Pg>/M, <Zn>.S
18517+
case IF_SVE_HO_3C: // <Zd>.S, <Pg>/M, <Zn>.D
18518+
case IF_SVE_HP_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18519+
case IF_SVE_HQ_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18520+
case IF_SVE_HR_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18521+
case IF_SVE_HS_3A: // <Zd>.<H|S|D>, <Pg>/M, <Zn>.<H|S|D>
18522+
case IF_SVE_HP_3B: // <Zd>.<H|S|D>, <Pg>/M, <Zn>.<H|S|D>
18523+
// Tied registers
18524+
case IF_SVE_AA_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
18525+
case IF_SVE_AB_3B: // <Zdn>.D, <Pg>/M, <Zdn>.D, <Zm>.D
18526+
case IF_SVE_AC_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
18527+
case IF_SVE_AO_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.D
18528+
case IF_SVE_CM_3A: // <Zdn>.<T>, <Pg>, <Zdn>.<T>, <Zm>.<T>
18529+
case IF_SVE_GP_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>, <const>
18530+
case IF_SVE_GR_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
18531+
case IF_SVE_HL_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
18532+
case IF_SVE_HL_3B: // <Zdn>.H, <Pg>/M, <Zdn>.H, <Zm>.H
18533+
assert(secondId->idReg1() != secondId->idReg3());
18534+
break;
18535+
18536+
case IF_SVE_EF_3A: // <Zda>.S, <Zn>.H, <Zm>.H
18537+
case IF_SVE_EG_3A: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18538+
case IF_SVE_EH_3A: // <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb>
18539+
case IF_SVE_EI_3A: // <Zda>.S, <Zn>.B, <Zm>.B
18540+
case IF_SVE_EJ_3A: // <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb>, <const>
18541+
case IF_SVE_EK_3A: // <Zda>.<T>, <Zn>.<T>, <Zm>.<T>, <const>
18542+
case IF_SVE_EL_3A: // <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb>
18543+
case IF_SVE_EM_3A: // <Zda>.<T>, <Zn>.<T>, <Zm>.<T>
18544+
case IF_SVE_EW_3A: // <Zda>.D, <Zn>.D, <Zm>.D
18545+
case IF_SVE_EW_3B: // <Zdn>.D, <Zm>.D, <Za>.D
18546+
case IF_SVE_EY_3A: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>]
18547+
case IF_SVE_EY_3B: // <Zda>.D, <Zn>.H, <Zm>.H[<imm>]
18548+
case IF_SVE_EZ_3A: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>]
18549+
case IF_SVE_FA_3A: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>], <const>
18550+
case IF_SVE_FA_3B: // <Zda>.D, <Zn>.H, <Zm>.H[<imm>], <const>
18551+
case IF_SVE_FB_3A: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>], <const>
18552+
case IF_SVE_FB_3B: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>], <const>
18553+
case IF_SVE_FC_3A: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>], <const>
18554+
case IF_SVE_FC_3B: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>], <const>
18555+
case IF_SVE_FF_3A: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>]
18556+
case IF_SVE_FF_3B: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>]
18557+
case IF_SVE_FF_3C: // <Zda>.D, <Zn>.D, <Zm>.D[<imm>]
18558+
case IF_SVE_FG_3A: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18559+
case IF_SVE_FG_3B: // <Zda>.D, <Zn>.S, <Zm>.S[<imm>]
18560+
case IF_SVE_FJ_3A: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18561+
case IF_SVE_FJ_3B: // <Zda>.D, <Zn>.S, <Zm>.S[<imm>]
18562+
case IF_SVE_FK_3A: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>]
18563+
case IF_SVE_FK_3B: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>]
18564+
case IF_SVE_FK_3C: // <Zda>.D, <Zn>.D, <Zm>.D[<imm>]
18565+
case IF_SVE_FO_3A: // <Zda>.S, <Zn>.B, <Zm>.B
18566+
case IF_SVE_FW_3A: // <Zda>.<T>, <Zn>.<T>, <Zm>.<T>
18567+
case IF_SVE_FY_3A: // <Zda>.<T>, <Zn>.<T>, <Zm>.<T>
18568+
case IF_SVE_GM_3A: // <Zda>.H, <Zn>.B, <Zm>.B[<imm>]
18569+
case IF_SVE_GN_3A: // <Zda>.H, <Zn>.B, <Zm>.B
18570+
case IF_SVE_GO_3A: // <Zda>.S, <Zn>.B, <Zm>.B
18571+
case IF_SVE_GU_3A: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>]
18572+
case IF_SVE_GU_3B: // <Zda>.D, <Zn>.D, <Zm>.D[<imm>]
18573+
case IF_SVE_GU_3C: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>]
18574+
case IF_SVE_GV_3A: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>], <const>
18575+
case IF_SVE_GW_3B: // <Zd>.H, <Zn>.H, <Zm>.H
18576+
case IF_SVE_GY_3A: // <Zda>.H, <Zn>.B, <Zm>.B[<imm>]
18577+
case IF_SVE_GY_3B: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18578+
case IF_SVE_GY_3B_D: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>]
18579+
case IF_SVE_GZ_3A: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18580+
case IF_SVE_HA_3A: // <Zda>.S, <Zn>.H, <Zm>.H
18581+
case IF_SVE_HA_3A_E: // <Zda>.H, <Zn>.B, <Zm>.B
18582+
case IF_SVE_HA_3A_F: // <Zda>.S, <Zn>.B, <Zm>.B
18583+
case IF_SVE_HB_3A: // <Zda>.S, <Zn>.H, <Zm>.H
18584+
case IF_SVE_HC_3A: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>]
18585+
case IF_SVE_HD_3A: // <Zda>.S, <Zn>.H, <Zm>.H
18586+
case IF_SVE_HD_3A_A: // <Zda>.D, <Zn>.D, <Zm>.D
18587+
// Tied registers
18588+
case IF_SVE_AV_3A: // <Zdn>.D, <Zdn>.D, <Zm>.D, <Zk>.D
18589+
assert(!movprefxIsPredicated);
18590+
assert(secondId->idReg1() != secondId->idReg2());
18591+
assert(secondId->idReg1() != secondId->idReg3());
18592+
break;
18593+
18594+
case IF_SVE_AR_4A: // <Zda>.<T>, <Pg>/M, <Zn>.<T>, <Zm>.<T>
18595+
case IF_SVE_AS_4A: // <Zdn>.<T>, <Pg>/M, <Zm>.<T>, <Za>.<T>
18596+
case IF_SVE_GT_4A: // <Zda>.<T>, <Pg>/M, <Zn>.<T>, <Zm>.<T>, <const>
18597+
case IF_SVE_HU_4A: // <Zda>.<T>, <Pg>/M, <Zn>.<T>, <Zm>.<T>
18598+
case IF_SVE_HU_4B: // <Zda>.H, <Pg>/M, <Zn>.H, <Zm>.H
18599+
case IF_SVE_HV_4A: // <Zdn>.<T>, <Pg>/M, <Zm>.<T>, <Za>.<T>
18600+
assert(secondId->idReg1() != secondId->idReg3());
18601+
assert(secondId->idReg1() != secondId->idReg4());
18602+
break;
18603+
18604+
case IF_SVE_AT_3A: // <Zd>.<T>, <Zn>.<T>, <Zm>.<T>
18605+
// Only a subset of this group is valid
18606+
switch (secondId->idIns())
18607+
{
18608+
case INS_sve_sclamp:
18609+
case INS_sve_uclamp:
18610+
case INS_sve_eorbt:
18611+
case INS_sve_eortb:
18612+
case INS_sve_fclamp:
18613+
break;
18614+
default:
18615+
assert(!"Got unexpected instruction format within group after MOVPRFX");
18616+
}
18617+
assert(!movprefxIsPredicated);
18618+
assert(secondId->idReg1() != secondId->idReg2());
18619+
assert(secondId->idReg1() != secondId->idReg3());
18620+
break;
18621+
18622+
default:
18623+
assert(!"Got unexpected instruction format after MOVPRFX");
18624+
break;
18625+
}
18626+
18627+
// "The prefixed instruction must specify the same destination vector as the MOVPRFX instruction."
18628+
assert(firstId->idReg1() == secondId->idReg1());
18629+
18630+
if (movprefxIsPredicated)
18631+
{
18632+
// "The prefixed instruction must specify the same predicate register"
18633+
assert(isPredicateRegister(firstId->idReg2()));
18634+
assert(isPredicateRegister(secondId->idReg2()));
18635+
assert(firstId->idReg2() == secondId->idReg2());
18636+
18637+
// "predicated using the same governing predicate register and source element size as this instruction."
18638+
assert(firstId->idInsOpt() == secondId->idInsOpt());
18639+
}
18640+
}
18641+
#endif // DEBUG
18642+
1843518643
#endif // TARGET_ARM64

0 commit comments

Comments
 (0)