Skip to content

Commit 36f0d8c

Browse files
authored
JIT: ARM64 SVE format encodings, SVE_ID_2A to SVE_JH_2A (#98015)
* Added SVE_IE_2A and SVE_JH_2A formats * Added SVE_ID_2A and SVE_JG_2A formats * Minor format change * Feedback * Formatting
1 parent b449152 commit 36f0d8c

File tree

4 files changed

+210
-18
lines changed

4 files changed

+210
-18
lines changed

src/coreclr/jit/codegenarm64test.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6956,6 +6956,48 @@ void CodeGen::genArm64EmitterUnitTestsSve()
69566956
// IF_SVE_JK_4B
69576957
theEmitter->emitIns_R_R_R_R(INS_sve_st1b, EA_SCALABLE, REG_V6, REG_P3, REG_R0, REG_V4,
69586958
INS_OPTS_SCALABLE_D); // ST1B {<Zt>.D }, <Pg>, [<Xn|SP>, <Zm>.D]
6959+
6960+
// IF_SVE_ID_2A
6961+
// LDR <Pt>, [<Xn|SP>{, #<imm>, MUL VL}]
6962+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, 0);
6963+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, 76);
6964+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, -25);
6965+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, -256);
6966+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, 255);
6967+
6968+
// IF_SVE_JG_2A
6969+
// STR <Pt>, [<Xn|SP>{, #<imm>, MUL VL}]
6970+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, 0);
6971+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, 221);
6972+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, -117);
6973+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, -256);
6974+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, 255);
6975+
6976+
// IF_SVE_IE_2A
6977+
// LDR <Zt>, [<Xn|SP>{, #<imm>, MUL VL}]
6978+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, 0, INS_OPTS_NONE,
6979+
INS_SCALABLE_OPTS_UNPREDICATED);
6980+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, 33, INS_OPTS_NONE,
6981+
INS_SCALABLE_OPTS_UNPREDICATED);
6982+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, -173, INS_OPTS_NONE,
6983+
INS_SCALABLE_OPTS_UNPREDICATED);
6984+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, -256, INS_OPTS_NONE,
6985+
INS_SCALABLE_OPTS_UNPREDICATED);
6986+
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, 255, INS_OPTS_NONE,
6987+
INS_SCALABLE_OPTS_UNPREDICATED);
6988+
6989+
// IF_SVE_JH_2A
6990+
// STR <Zt>, [<Xn|SP>{, #<imm>, MUL VL}]
6991+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, 0, INS_OPTS_NONE,
6992+
INS_SCALABLE_OPTS_UNPREDICATED);
6993+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, 71, INS_OPTS_NONE,
6994+
INS_SCALABLE_OPTS_UNPREDICATED);
6995+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, -165, INS_OPTS_NONE,
6996+
INS_SCALABLE_OPTS_UNPREDICATED);
6997+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, -256, INS_OPTS_NONE,
6998+
INS_SCALABLE_OPTS_UNPREDICATED);
6999+
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, 255, INS_OPTS_NONE,
7000+
INS_SCALABLE_OPTS_UNPREDICATED);
69597001
}
69607002

69617003
#endif // defined(TARGET_ARM64) && defined(DEBUG)

src/coreclr/jit/emitarm64.cpp

Lines changed: 156 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,28 @@ void emitter::emitInsSanityCheck(instrDesc* id)
20402040
assert(isScalableVectorSize(elemsize));
20412041
break;
20422042

2043+
case IF_SVE_ID_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE load predicate register
2044+
case IF_SVE_JG_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE store predicate register
2045+
elemsize = id->idOpSize();
2046+
assert(insOptsNone(id->idInsOpt()));
2047+
assert(isScalableVectorSize(elemsize));
2048+
assert(isPredicateRegister(id->idReg1())); // TTTT
2049+
assert(isGeneralRegister(id->idReg2())); // nnnnn
2050+
assert(isValidSimm9(emitGetInsSC(id))); // iii
2051+
// iiiiii
2052+
break;
2053+
2054+
case IF_SVE_IE_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE load vector register
2055+
case IF_SVE_JH_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE store vector register
2056+
elemsize = id->idOpSize();
2057+
assert(insOptsNone(id->idInsOpt()));
2058+
assert(isScalableVectorSize(elemsize));
2059+
assert(isVectorRegister(id->idReg1())); // ttttt
2060+
assert(isGeneralRegister(id->idReg2())); // nnnnn
2061+
assert(isValidSimm9(emitGetInsSC(id))); // iii
2062+
// iiiiii
2063+
break;
2064+
20432065
default:
20442066
printf("unexpected format %s\n", emitIfName(id->idInsFmt()));
20452067
assert(!"Unexpected format");
@@ -8768,6 +8790,46 @@ void emitter::emitIns_R_R_I(instruction ins,
87688790
}
87698791
break;
87708792

8793+
case INS_sve_ldr:
8794+
assert(insOptsNone(opt));
8795+
assert(isScalableVectorSize(size));
8796+
assert(isGeneralRegister(reg2)); // nnnnn
8797+
assert(isValidSimm9(imm)); // iii
8798+
// iiiiii
8799+
8800+
if (sopt == INS_SCALABLE_OPTS_UNPREDICATED)
8801+
{
8802+
assert(isVectorRegister(reg1));
8803+
fmt = IF_SVE_IE_2A;
8804+
}
8805+
else
8806+
{
8807+
assert(insScalableOptsNone(sopt));
8808+
assert(isPredicateRegister(reg1));
8809+
fmt = IF_SVE_ID_2A;
8810+
}
8811+
break;
8812+
8813+
case INS_sve_str:
8814+
assert(insOptsNone(opt));
8815+
assert(isScalableVectorSize(size));
8816+
assert(isGeneralRegister(reg2)); // nnnnn
8817+
assert(isValidSimm9(imm)); // iii
8818+
// iiiiii
8819+
8820+
if (sopt == INS_SCALABLE_OPTS_UNPREDICATED)
8821+
{
8822+
assert(isVectorRegister(reg1));
8823+
fmt = IF_SVE_JH_2A;
8824+
}
8825+
else
8826+
{
8827+
assert(insScalableOptsNone(sopt));
8828+
assert(isPredicateRegister(reg1));
8829+
fmt = IF_SVE_JG_2A;
8830+
}
8831+
break;
8832+
87718833
default:
87728834
unreached();
87738835
break;
@@ -16432,6 +16494,10 @@ void emitter::emitIns_Call(EmitCallType callType,
1643216494
assert((regpos == 2) || (regpos == 3));
1643316495
return ((regpos == 2) ? PREDICATE_NONE : PREDICATE_SIZED);
1643416496

16497+
case IF_SVE_ID_2A:
16498+
case IF_SVE_JG_2A:
16499+
return PREDICATE_NONE;
16500+
1643516501
default:
1643616502
break;
1643716503
}
@@ -17578,6 +17644,26 @@ void emitter::emitIns_Call(EmitCallType callType,
1757817644
return (code_t)imm << 16;
1757917645
}
1758017646

17647+
/*****************************************************************************
17648+
*
17649+
* Returns the encoding for the immediate value as 9-bits at bit locations '21-16' for high and '12-10' for low.
17650+
*/
17651+
17652+
/*static*/ emitter::code_t emitter::insEncodeSimm9h9l_21_to_16_and_12_to_10(ssize_t imm)
17653+
{
17654+
assert(isValidSimm9(imm));
17655+
17656+
if (imm < 0)
17657+
{
17658+
imm = (imm & 0x1FF);
17659+
}
17660+
17661+
code_t h = (code_t)(imm & 0x1F8) << 13; // encode high 6-bits at locations '21-16'
17662+
code_t l = (code_t)((imm & ~0x1F8) & 0x7) << 10; // encode low 3-bits at locations '12-10'
17663+
17664+
return (h | l);
17665+
}
17666+
1758117667
/*****************************************************************************
1758217668
*
1758317669
* Returns the encoding for the immediate value that is a multiple of 2 as 4-bits at bit locations '19-16'.
@@ -20820,6 +20906,28 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id)
2082020906
dst += emitOutput_Instr(dst, code);
2082120907
break;
2082220908

20909+
case IF_SVE_ID_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE load predicate register
20910+
case IF_SVE_JG_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE store predicate register
20911+
imm = emitGetInsSC(id);
20912+
code = emitInsCodeSve(ins, fmt);
20913+
code |= insEncodeReg_P_3_to_0(id->idReg1()); // TTTT
20914+
code |= insEncodeReg_R_9_to_5(id->idReg2()); // nnnnn
20915+
code |= insEncodeSimm9h9l_21_to_16_and_12_to_10(imm); // iii
20916+
// iiiiii
20917+
dst += emitOutput_Instr(dst, code);
20918+
break;
20919+
20920+
case IF_SVE_IE_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE load vector register
20921+
case IF_SVE_JH_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE store vector register
20922+
imm = emitGetInsSC(id);
20923+
code = emitInsCodeSve(ins, fmt);
20924+
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ttttt
20925+
code |= insEncodeReg_R_9_to_5(id->idReg2()); // nnnnn
20926+
code |= insEncodeSimm9h9l_21_to_16_and_12_to_10(imm); // iii
20927+
// iiiiii
20928+
dst += emitOutput_Instr(dst, code);
20929+
break;
20930+
2082320931
default:
2082420932
assert(!"Unexpected format");
2082520933
break;
@@ -21205,6 +21313,22 @@ void emitter::emitDispSveModAddr(instruction ins, regNumber reg1, regNumber reg2
2120521313
printf("]");
2120621314
}
2120721315

21316+
/*****************************************************************************
21317+
*
21318+
* Prints the encoding for format [<Xn|SP>{, #<imm>, MUL VL}]
21319+
*/
21320+
void emitter::emitDispSveImmMulVl(regNumber reg1, ssize_t imm)
21321+
{
21322+
printf("[");
21323+
emitDispReg(reg1, EA_8BYTE, imm != 0);
21324+
if (imm != 0)
21325+
{
21326+
emitDispImm(imm, true);
21327+
printf("mul vl");
21328+
}
21329+
printf("]");
21330+
}
21331+
2120821332
/*****************************************************************************
2120921333
*
2121021334
* Prints the encoding for the Extend Type encoding in loads/stores
@@ -24016,29 +24140,33 @@ void emitter::emitDispInsHelp(
2401624140
imm = emitGetInsSC(id);
2401724141
emitDispSveConsecutiveRegList(id->idReg1(), insGetSveReg1ListSize(ins), id->idInsOpt(), true); // ttttt
2401824142
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); // ggg
24019-
printf("[");
24020-
emitDispReg(id->idReg3(), EA_8BYTE, imm != 0); // nnnnn
24021-
if (imm != 0)
24022-
{
24023-
emitDispImm(emitGetInsSC(id), true); // iiii
24024-
printf("mul vl");
24025-
}
24026-
printf("]");
24143+
emitDispSveImmMulVl(id->idReg3(), imm);
2402724144
break;
2402824145

2402924146
// {<Zt>.<T>}, <Pg>, [<Xn|SP>{, #<imm>, MUL VL}]
2403024147
case IF_SVE_JN_3B: // ..........x.iiii ...gggnnnnnttttt -- SVE contiguous store (scalar plus immediate)
2403124148
imm = emitGetInsSC(id);
2403224149
emitDispSveConsecutiveRegList(id->idReg1(), insGetSveReg1ListSize(ins), id->idInsOpt(), true); // ttttt
2403324150
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); // ggg
24034-
printf("[");
24035-
emitDispReg(id->idReg3(), EA_8BYTE, imm != 0); // nnnnn
24036-
if (imm != 0)
24037-
{
24038-
emitDispImm(emitGetInsSC(id), true); // iiii
24039-
printf("mul vl");
24040-
}
24041-
printf("]");
24151+
emitDispSveImmMulVl(id->idReg3(), imm);
24152+
break;
24153+
24154+
// <Pt>, [<Xn|SP>{, #<imm>, MUL VL}]
24155+
case IF_SVE_ID_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE load predicate register
24156+
// <Pt>, [<Xn|SP>{, #<imm>, MUL VL}]
24157+
case IF_SVE_JG_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE store predicate register
24158+
imm = emitGetInsSC(id);
24159+
emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt), id->idInsOpt(), true); // TTTT
24160+
emitDispSveImmMulVl(id->idReg2(), imm);
24161+
break;
24162+
24163+
// <Zt>, [<Xn|SP>{, #<imm>, MUL VL}]
24164+
case IF_SVE_IE_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE load vector register
24165+
// <Zt>, [<Xn|SP>{, #<imm>, MUL VL}]
24166+
case IF_SVE_JH_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE store vector register
24167+
imm = emitGetInsSC(id);
24168+
emitDispReg(id->idReg1(), EA_SCALABLE, true); // ttttt
24169+
emitDispSveImmMulVl(id->idReg2(), imm);
2404224170
break;
2404324171

2404424172
default:
@@ -27458,6 +27586,18 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
2745827586
result.insLatency = PERFSCORE_LATENCY_2C;
2745927587
break;
2746027588

27589+
case IF_SVE_ID_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE load predicate register
27590+
case IF_SVE_IE_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE load vector register
27591+
result.insThroughput = PERFSCORE_THROUGHPUT_3C;
27592+
result.insLatency = PERFSCORE_LATENCY_6C;
27593+
break;
27594+
27595+
case IF_SVE_JG_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE store predicate register
27596+
case IF_SVE_JH_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE store vector register
27597+
result.insThroughput = PERFSCORE_THROUGHPUT_2C;
27598+
result.insLatency = PERFSCORE_LATENCY_2C;
27599+
break;
27600+
2746127601
default:
2746227602
// all other instructions
2746327603
perfScoreUnhandledInstruction(id, &result);

src/coreclr/jit/emitarm64.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void emitDispExtendOpts(insOpts opt);
5252
void emitDispSveExtendOpts(insOpts opt);
5353
void emitDispSveExtendOptsModN(insOpts opt, int n);
5454
void emitDispSveModAddr(instruction ins, regNumber reg1, regNumber reg2, insOpts opt, insFormat fmt);
55+
void emitDispSveImmMulVl(regNumber reg1, ssize_t imm);
5556
void emitDispLSExtendOpts(insOpts opt);
5657
void emitDispReg(regNumber reg, emitAttr attr, bool addComma);
5758
void emitDispSveReg(regNumber reg, insOpts opt, bool addComma);
@@ -543,6 +544,9 @@ static code_t insEncodeSveElemsize_dtype_ld1w(instruction ins, insFormat fmt, em
543544
// Returns the encoding for the immediate value as 4-bits at bit locations '19-16'.
544545
static code_t insEncodeSimm4_19_to_16(ssize_t imm);
545546

547+
// Returns the encoding for the immediate value as 9-bits at bit locations '21-16' for high and '12-10' for low.
548+
static code_t insEncodeSimm9h9l_21_to_16_and_12_to_10(ssize_t imm);
549+
546550
// Returns the encoding for the immediate value that is a multiple of 2 as 4-bits at bit locations '19-16'.
547551
static code_t insEncodeSimm4_MultipleOf2_19_to_16(ssize_t imm);
548552

@@ -611,6 +615,12 @@ static bool isValidSimm4(ssize_t value)
611615
return (-8 <= value) && (value <= 7);
612616
};
613617

618+
// Returns true if 'value' is a legal signed immediate 9 bit encoding (such as for LDR).
619+
static bool isValidSimm9(ssize_t value)
620+
{
621+
return (-256 <= value) && (value <= 255);
622+
};
623+
614624
// Returns true if 'value' is a legal signed multiple of 2 immediate 4 bit encoding (such as for LD2Q).
615625
static bool isValidSimm4_MultipleOf2(ssize_t value)
616626
{

src/coreclr/jit/instrsarm64sve.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -942,13 +942,13 @@ INST3(stnt1d, "stnt1d", 0, IF_SV
942942

943943

944944
// enum name info SVE_ID_2A SVE_IE_2A
945-
INST2(ldr, "ldr", LD, IF_SVE_2AA, 0x85800000, 0x85804000 )
945+
INST2(ldr, "ldr", 0, IF_SVE_2AA, 0x85800000, 0x85804000 )
946946
// LDR <Pt>, [<Xn|SP>{, #<imm>, MUL VL}] SVE_ID_2A 1000010110iiiiii 000iiinnnnn0TTTT 8580 0000
947947
// LDR <Zt>, [<Xn|SP>{, #<imm>, MUL VL}] SVE_IE_2A 1000010110iiiiii 010iiinnnnnttttt 8580 4000
948948

949949

950950
// enum name info SVE_JG_2A SVE_JH_2A
951-
INST2(str, "str", ST, IF_SVE_2AB, 0xE5800000, 0xE5804000 )
951+
INST2(str, "str", 0, IF_SVE_2AB, 0xE5800000, 0xE5804000 )
952952
// STR <Pt>, [<Xn|SP>{, #<imm>, MUL VL}] SVE_JG_2A 1110010110iiiiii 000iiinnnnn0TTTT E580 0000
953953
// STR <Zt>, [<Xn|SP>{, #<imm>, MUL VL}] SVE_JH_2A 1110010110iiiiii 010iiinnnnnttttt E580 4000
954954

0 commit comments

Comments
 (0)