Skip to content

Commit eaa6f01

Browse files
authored
JIT: ARM64 SVE format encodings, SVE_BX_2A and SVE_BY_2A (#99087)
* Added SVE_BX_2A and SVE_BY_2A formats * Formatting
1 parent 9863bf1 commit eaa6f01

File tree

3 files changed

+208
-0
lines changed

3 files changed

+208
-0
lines changed

src/coreclr/jit/codegenarm64test.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -8771,6 +8771,25 @@ void CodeGen::genArm64EmitterUnitTestsSve()
87718771
theEmitter->emitIns_R_R_I(INS_sve_usra, EA_SCALABLE, REG_V31, REG_V31, 64, INS_OPTS_SCALABLE_D);
87728772
theEmitter->emitIns_R_R_I(INS_sve_usra, EA_SCALABLE, REG_V0, REG_V31, 31, INS_OPTS_SCALABLE_D);
87738773
theEmitter->emitIns_R_R_I(INS_sve_usra, EA_SCALABLE, REG_V0, REG_V31, 32, INS_OPTS_SCALABLE_D);
8774+
8775+
// IF_SVE_BX_2A
8776+
// DUPQ <Zd>.<T>, <Zn>.<T>[<imm>]
8777+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V0, REG_V0, 0, INS_OPTS_SCALABLE_B);
8778+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V21, REG_V10, 10, INS_OPTS_SCALABLE_B);
8779+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V31, REG_V31, 15, INS_OPTS_SCALABLE_B);
8780+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V0, REG_V0, 0, INS_OPTS_SCALABLE_H);
8781+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V21, REG_V10, 5, INS_OPTS_SCALABLE_H);
8782+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V31, REG_V31, 7, INS_OPTS_SCALABLE_H);
8783+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V0, REG_V0, 0, INS_OPTS_SCALABLE_S);
8784+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V21, REG_V10, 2, INS_OPTS_SCALABLE_S);
8785+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V31, REG_V31, 3, INS_OPTS_SCALABLE_S);
8786+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V0, REG_V0, 0, INS_OPTS_SCALABLE_D);
8787+
theEmitter->emitIns_R_R_I(INS_sve_dupq, EA_SCALABLE, REG_V31, REG_V31, 1, INS_OPTS_SCALABLE_D);
8788+
8789+
// IF_SVE_BY_2A
8790+
// EXTQ <Zdn>.B, <Zdn>.B, <Zm>.B, #<imm>
8791+
theEmitter->emitIns_R_R_I(INS_sve_extq, EA_SCALABLE, REG_V0, REG_V0, 0, INS_OPTS_SCALABLE_B);
8792+
theEmitter->emitIns_R_R_I(INS_sve_extq, EA_SCALABLE, REG_V31, REG_V31, 15, INS_OPTS_SCALABLE_B);
87748793
}
87758794

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

src/coreclr/jit/emitarm64.cpp

+183
Original file line numberDiff line numberDiff line change
@@ -2722,6 +2722,48 @@ void emitter::emitInsSanityCheck(instrDesc* id)
27222722
assert(isScalableVectorSize(elemsize));
27232723
break;
27242724

2725+
case IF_SVE_BX_2A: // ...........ixxxx ......nnnnnddddd -- sve_int_perm_dupq_i
2726+
imm = emitGetInsSC(id);
2727+
elemsize = id->idOpSize();
2728+
assert(insOptsScalableStandard(id->idInsOpt()));
2729+
assert(isVectorRegister(id->idReg1()));
2730+
assert(isVectorRegister(id->idReg2()));
2731+
assert(isScalableVectorSize(elemsize));
2732+
#ifdef DEBUG
2733+
switch (id->idInsOpt())
2734+
{
2735+
case INS_OPTS_SCALABLE_B:
2736+
assert(isValidUimm4(imm));
2737+
break;
2738+
2739+
case INS_OPTS_SCALABLE_H:
2740+
assert(isValidUimm3(imm));
2741+
break;
2742+
2743+
case INS_OPTS_SCALABLE_S:
2744+
assert(isValidUimm2(imm));
2745+
break;
2746+
2747+
case INS_OPTS_SCALABLE_D:
2748+
assert(isValidImm1(imm));
2749+
break;
2750+
2751+
default:
2752+
break;
2753+
}
2754+
#endif // DEBUG
2755+
break;
2756+
2757+
case IF_SVE_BY_2A: // ............iiii ......mmmmmddddd -- sve_int_perm_extq
2758+
imm = emitGetInsSC(id);
2759+
elemsize = id->idOpSize();
2760+
assert(id->idInsOpt() == INS_OPTS_SCALABLE_B);
2761+
assert(isVectorRegister(id->idReg1()));
2762+
assert(isVectorRegister(id->idReg2()));
2763+
assert(isScalableVectorSize(elemsize));
2764+
assert(isValidUimm4(imm));
2765+
break;
2766+
27252767
default:
27262768
printf("unexpected format %s\n", emitIfName(id->idInsFmt()));
27272769
assert(!"Unexpected format");
@@ -10131,6 +10173,48 @@ void emitter::emitIns_R_R_I(instruction ins,
1013110173
fmt = IF_SVE_FU_2A;
1013210174
break;
1013310175

10176+
case INS_sve_dupq:
10177+
assert(insOptsScalableStandard(opt));
10178+
assert(insScalableOptsNone(sopt));
10179+
assert(isVectorRegister(reg1));
10180+
assert(isVectorRegister(reg2));
10181+
assert(isScalableVectorSize(size));
10182+
#ifdef DEBUG
10183+
switch (opt)
10184+
{
10185+
case INS_OPTS_SCALABLE_B:
10186+
assert(isValidUimm4(imm));
10187+
break;
10188+
10189+
case INS_OPTS_SCALABLE_H:
10190+
assert(isValidUimm3(imm));
10191+
break;
10192+
10193+
case INS_OPTS_SCALABLE_S:
10194+
assert(isValidUimm2(imm));
10195+
break;
10196+
10197+
case INS_OPTS_SCALABLE_D:
10198+
assert(isValidImm1(imm));
10199+
break;
10200+
10201+
default:
10202+
break;
10203+
}
10204+
#endif // DEBUG
10205+
fmt = IF_SVE_BX_2A;
10206+
break;
10207+
10208+
case INS_sve_extq:
10209+
assert(opt == INS_OPTS_SCALABLE_B);
10210+
assert(insScalableOptsNone(sopt));
10211+
assert(isVectorRegister(reg1));
10212+
assert(isVectorRegister(reg2));
10213+
assert(isScalableVectorSize(size));
10214+
assert(isValidUimm4(imm));
10215+
fmt = IF_SVE_BY_2A;
10216+
break;
10217+
1013410218
default:
1013510219
unreached();
1013610220
break;
@@ -19405,6 +19489,49 @@ void emitter::emitIns_Call(EmitCallType callType,
1940519489
return (encoding | (code_t)(imm << 16));
1940619490
}
1940719491

19492+
/*****************************************************************************
19493+
*
19494+
* Returns the encoding for the field 'i1:tsz' at bit locations '20:19-16'.
19495+
*/
19496+
19497+
/*static*/ emitter::code_t emitter::insEncodeSveElemsizeWithImmediate_i1_tsz(const insOpts opt, ssize_t imm)
19498+
{
19499+
code_t encoding = 0;
19500+
19501+
switch (opt)
19502+
{
19503+
case INS_OPTS_SCALABLE_B:
19504+
assert(isValidUimm4(imm));
19505+
encoding |= (1 << 16); // bit 16
19506+
encoding |= (imm << 17); // bits 20-17
19507+
break;
19508+
19509+
case INS_OPTS_SCALABLE_H:
19510+
assert(isValidUimm3(imm));
19511+
encoding |= (1 << 17); // bit 17
19512+
encoding |= (imm << 18); // bits 20-18
19513+
break;
19514+
19515+
case INS_OPTS_SCALABLE_S:
19516+
assert(isValidUimm2(imm));
19517+
encoding |= (1 << 18); // bit 18
19518+
encoding |= (imm << 19); // bits 20-19
19519+
break;
19520+
19521+
case INS_OPTS_SCALABLE_D:
19522+
assert(isValidImm1(imm));
19523+
encoding |= (1 << 19); // bit 19
19524+
encoding |= (imm << 20); // bit 20
19525+
break;
19526+
19527+
default:
19528+
assert(!"Invalid size for vector register");
19529+
break;
19530+
}
19531+
19532+
return encoding;
19533+
}
19534+
1940819535
/*****************************************************************************
1940919536
*
1941019537
* Returns the encoding to select the elemsize for an Arm64 SVE vector instruction plus an immediate.
@@ -21508,6 +21635,17 @@ void emitter::emitIns_Call(EmitCallType callType,
2150821635
return (code_t)imm << 14;
2150921636
}
2151021637

21638+
/*****************************************************************************
21639+
*
21640+
* Returns the encoding for the immediate value as 4-bits at bit locations '19-16'.
21641+
*/
21642+
21643+
/*static*/ emitter::code_t emitter::insEncodeUimm4_19_to_16(ssize_t imm)
21644+
{
21645+
assert(isValidUimm4(imm));
21646+
return (code_t)imm << 16;
21647+
}
21648+
2151121649
/*****************************************************************************
2151221650
*
2151321651
* Returns the encoding for the immediate value as 4-bits starting from 1, at bit locations '19-16'.
@@ -25433,6 +25571,24 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id)
2543325571
dst += emitOutput_Instr(dst, code);
2543425572
break;
2543525573

25574+
case IF_SVE_BX_2A: // ...........ixxxx ......nnnnnddddd -- sve_int_perm_dupq_i
25575+
imm = emitGetInsSC(id);
25576+
code = emitInsCodeSve(ins, fmt);
25577+
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
25578+
code |= insEncodeReg_V_9_to_5(id->idReg2()); // nnnnn
25579+
code |= insEncodeSveElemsizeWithImmediate_i1_tsz(id->idInsOpt(), imm); // ixxxx
25580+
dst += emitOutput_Instr(dst, code);
25581+
break;
25582+
25583+
case IF_SVE_BY_2A: // ............iiii ......mmmmmddddd -- sve_int_perm_extq
25584+
imm = emitGetInsSC(id);
25585+
code = emitInsCodeSve(ins, fmt);
25586+
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
25587+
code |= insEncodeReg_V_9_to_5(id->idReg2()); // mmmmm
25588+
code |= insEncodeUimm4_19_to_16(imm); // iiii
25589+
dst += emitOutput_Instr(dst, code);
25590+
break;
25591+
2543625592
default:
2543725593
assert(!"Unexpected format");
2543825594
break;
@@ -29489,6 +29645,23 @@ void emitter::emitDispInsHelp(
2948929645
emitDispImm(imm, false);
2949029646
break;
2949129647

29648+
// <Zd>.<T>, <Zn>.<T>[<imm>]
29649+
case IF_SVE_BX_2A: // ...........ixxxx ......nnnnnddddd -- sve_int_perm_dupq_i
29650+
imm = emitGetInsSC(id);
29651+
emitDispSveReg(id->idReg1(), id->idInsOpt(), true);
29652+
emitDispSveReg(id->idReg2(), id->idInsOpt(), false);
29653+
emitDispElementIndex(imm, false);
29654+
break;
29655+
29656+
// <Zdn>.B, <Zdn>.B, <Zm>.B, #<imm>
29657+
case IF_SVE_BY_2A: // ............iiii ......mmmmmddddd -- sve_int_perm_extq
29658+
imm = emitGetInsSC(id);
29659+
emitDispSveReg(id->idReg1(), id->idInsOpt(), true);
29660+
emitDispSveReg(id->idReg1(), id->idInsOpt(), true);
29661+
emitDispSveReg(id->idReg2(), id->idInsOpt(), true);
29662+
emitDispImm(imm, false);
29663+
break;
29664+
2949229665
default:
2949329666
printf("unexpected format %s", emitIfName(id->idInsFmt()));
2949429667
assert(!"unexpectedFormat");
@@ -33687,6 +33860,16 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
3368733860
result.insLatency = PERFSCORE_LATENCY_4C;
3368833861
break;
3368933862

33863+
case IF_SVE_BX_2A: // ...........ixxxx ......nnnnnddddd -- sve_int_perm_dupq_i
33864+
result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix
33865+
result.insLatency = PERFSCORE_LATENCY_1C; // need to fix
33866+
break;
33867+
33868+
case IF_SVE_BY_2A: // ............iiii ......mmmmmddddd -- sve_int_perm_extq
33869+
result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix
33870+
result.insLatency = PERFSCORE_LATENCY_1C; // need to fix
33871+
break;
33872+
3369033873
default:
3369133874
// all other instructions
3369233875
perfScoreUnhandledInstruction(id, &result);

src/coreclr/jit/emitarm64.h

+6
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,9 @@ static code_t insEncodeSveElemsize_tszh_tszl_and_imm(const insOpts opt, const ss
549549
// Returns the encoding for the field 'tszh:tszl:imm3' at bit locations '23-22:20-19:18-16'.
550550
static code_t insEncodeSveElemsizeWithShift_tszh_tszl_imm3(const insOpts opt, ssize_t imm, bool isRightShift);
551551

552+
// Returns the encoding for the field 'i1:tsz' at bit locations '20:19-16'.
553+
static code_t insEncodeSveElemsizeWithImmediate_i1_tsz(const insOpts opt, ssize_t imm);
554+
552555
// Returns the encoding to select the constant values 90 or 270 for an Arm64 SVE vector instruction
553556
// This specifically encode the field 'rot' at bit location '16'.
554557
static code_t insEncodeSveImm90_or_270_rot(ssize_t imm);
@@ -717,6 +720,9 @@ static code_t insEncodeImm1_22(ssize_t imm);
717720
// Returns the encoding for the immediate value as 7-bits at bit locations '20-14'.
718721
static code_t insEncodeUimm7_20_to_14(ssize_t imm);
719722

723+
// Returns the encoding for the immediate value as 4-bits at bit locations '19-16'.
724+
static code_t insEncodeUimm4_19_to_16(ssize_t imm);
725+
720726
// Returns the encoding for the immediate value as 4-bits starting from 1, at bit locations '19-16'.
721727
static code_t insEncodeUimm4From1_19_to_16(ssize_t imm);
722728

0 commit comments

Comments
 (0)