Skip to content

Commit

Permalink
Add ARM64 encodings for groups IF_SVE_CE,CF (#98409)
Browse files Browse the repository at this point in the history
* Add ARM64 encodings for groups IF_SVE_CE,CF

* Move left-shifted integers into explicit types

* Address review comments

* Fix formatting errors

* Fix a typo with register ID and add a scalable option for moving to and
from predicate registers

* Add shortcut for pmov with zero index

* Fix formatting

---------

Co-authored-by: Kunal Pathak <[email protected]>
  • Loading branch information
snickolls-arm and kunalspathak authored Feb 29, 2024
1 parent 18b0816 commit 8dcca1c
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/coreclr/jit/codegenarm64test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4733,6 +4733,54 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_lsr, EA_SCALABLE, REG_V0, REG_P0, REG_V0, INS_OPTS_SCALABLE_S,
INS_SCALABLE_OPTS_WIDE); // LSR <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.D

// IF_SVE_CE_2A
theEmitter->emitIns_R_R(INS_sve_pmov, EA_SCALABLE, REG_P2, REG_V12, INS_OPTS_SCALABLE_B,
INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV <Pd>.B, <Zn>
theEmitter->emitIns_R_R(INS_sve_pmov, EA_SCALABLE, REG_P7, REG_V2, INS_OPTS_SCALABLE_H,
INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV <Pd>.H, <Zn>[0]

// IF_SVE_CE_2B
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P15, REG_V7, 7, INS_OPTS_SCALABLE_D,
INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV <Pd>.D, <Zn>[<imm>]
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P7, REG_V16, 0, INS_OPTS_SCALABLE_D,
INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV <Pd>.D, <Zn>[<imm>]

// IF_SVE_CE_2C
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P0, REG_V31, 1, INS_OPTS_SCALABLE_H,
INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV <Pd>.H, <Zn>[<imm>]
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V1, REG_P1, 0, INS_OPTS_SCALABLE_H,
INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV <Pd>.H, <Zn>[<imm>]

// IF_SVE_CE_2D
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P3, REG_V9, 3, INS_OPTS_SCALABLE_S,
INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV <Pd>.S, <Zn>[<imm>]
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P10, REG_V4, 0, INS_OPTS_SCALABLE_S,
INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV <Pd>.S, <Zn>[<imm>]

// IF_SVE_CF_2A
theEmitter->emitIns_R_R(INS_sve_pmov, EA_SCALABLE, REG_V11, REG_P12, INS_OPTS_SCALABLE_B,
INS_SCALABLE_OPTS_TO_VECTOR); // PMOV <Zd>, <Pn>.B
theEmitter->emitIns_R_R(INS_sve_pmov, EA_SCALABLE, REG_V2, REG_P7, INS_OPTS_SCALABLE_S,
INS_SCALABLE_OPTS_TO_VECTOR); // PMOV <Zd>[0], <Pn>.S

// IF_SVE_CF_2B
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V6, REG_P8, 7, INS_OPTS_SCALABLE_D,
INS_SCALABLE_OPTS_TO_VECTOR); // PMOV <Zd>[<imm>], <Pn>.D
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V9, REG_P7, 0, INS_OPTS_SCALABLE_D,
INS_SCALABLE_OPTS_TO_VECTOR); // PMOV <Zd>[<imm>], <Pn>.D

// IF_SVE_CF_2C
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V8, REG_P4, 1, INS_OPTS_SCALABLE_H,
INS_SCALABLE_OPTS_TO_VECTOR); // PMOV <Zd>[<imm>], <Pn>.H
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V5, REG_P9, 0, INS_OPTS_SCALABLE_H,
INS_SCALABLE_OPTS_TO_VECTOR); // PMOV <Zd>[<imm>], <Pn>.H

// IF_SVE_CF_2D
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V14, REG_P2, 3, INS_OPTS_SCALABLE_S,
INS_SCALABLE_OPTS_TO_VECTOR); // PMOV <Zd>[<imm>], <Pn>.S
theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V3, REG_P15, 0, INS_OPTS_SCALABLE_S,
INS_SCALABLE_OPTS_TO_VECTOR); // PMOV <Zd>[<imm>], <Pn>.S

// IF_SVE_CJ_2A
theEmitter->emitIns_R_R(INS_sve_rev, EA_SCALABLE, REG_P1, REG_P2,
INS_OPTS_SCALABLE_B); // REV <Pd>.<T>, <Pn>.<T>
Expand Down
254 changes: 254 additions & 0 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,52 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(isValidUimm4From1(emitGetInsSC(id)));
break;

case IF_SVE_CE_2A: // ................ ......nnnnn.DDDD -- SVE move predicate from vector
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isVectorRegister(id->idReg2())); // nnnnn
break;

case IF_SVE_CE_2B: // .........i...ii. ......nnnnn.DDDD -- SVE move predicate from vector
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isVectorRegister(id->idReg2())); // nnnnn
assert(isValidUimm<3>(emitGetInsSC(id)));
break;

case IF_SVE_CE_2C: // ..............i. ......nnnnn.DDDD -- SVE move predicate from vector
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isVectorRegister(id->idReg2())); // nnnnn
assert(isValidUimm<1>(emitGetInsSC(id))); // i
break;

case IF_SVE_CE_2D: // .............ii. ......nnnnn.DDDD -- SVE move predicate from vector
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isVectorRegister(id->idReg2())); // nnnnn
assert(isValidUimm<3>(emitGetInsSC(id))); // ii
break;

case IF_SVE_CF_2A: // ................ .......NNNNddddd -- SVE move predicate into vector
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isPredicateRegister(id->idReg2())); // NNNN
break;

case IF_SVE_CF_2B: // .........i...ii. .......NNNNddddd -- SVE move predicate into vector
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isPredicateRegister(id->idReg2())); // NNNN
assert(isValidUimm<3>(emitGetInsSC(id)));
break;

case IF_SVE_CF_2C: // ..............i. .......NNNNddddd -- SVE move predicate into vector
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isPredicateRegister(id->idReg2())); // NNNN
assert(isValidUimm<1>(emitGetInsSC(id))); // i
break;

case IF_SVE_CF_2D: // .............ii. .......NNNNddddd -- SVE move predicate into vector
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isPredicateRegister(id->idReg2())); // NNNN
assert(isValidUimm<2>(emitGetInsSC(id))); // ii
break;

case IF_SVE_CI_3A: // ........xx..MMMM .......NNNN.DDDD -- SVE permute predicate elements
elemsize = id->idOpSize();
assert(insOptsScalableStandard(id->idInsOpt()));
Expand Down Expand Up @@ -8775,6 +8821,30 @@ void emitter::emitIns_R_R(instruction ins,
}
break;

case INS_sve_pmov:
if (opt != INS_OPTS_SCALABLE_B)
{
assert(insOptsScalableStandard(opt));
return emitIns_R_R_I(INS_sve_pmov, attr, reg1, reg2, 0, opt, sopt);
}
if (sopt == INS_SCALABLE_OPTS_TO_PREDICATE)
{
assert(isPredicateRegister(reg1));
assert(isVectorRegister(reg2));
fmt = IF_SVE_CE_2A;
}
else if (sopt == INS_SCALABLE_OPTS_TO_VECTOR)
{
assert(isVectorRegister(reg1));
assert(isPredicateRegister(reg2));
fmt = IF_SVE_CF_2A;
}
else
{
assert(!"invalid instruction");
}
break;

case INS_sve_movs:
{
assert(opt == INS_OPTS_SCALABLE_B);
Expand Down Expand Up @@ -9817,6 +9887,57 @@ void emitter::emitIns_R_R_I(instruction ins,
fmt = IF_SVE_BB_2A;
break;

case INS_sve_pmov:
if (sopt == INS_SCALABLE_OPTS_TO_PREDICATE)
{
assert(isPredicateRegister(reg1));
assert(isVectorRegister(reg2));
switch (opt)
{
case INS_OPTS_SCALABLE_D:
assert(isValidUimm<3>(imm));
fmt = IF_SVE_CE_2B;
break;
case INS_OPTS_SCALABLE_S:
assert(isValidUimm<2>(imm));
fmt = IF_SVE_CE_2D;
break;
case INS_OPTS_SCALABLE_H:
assert(isValidUimm<1>(imm));
fmt = IF_SVE_CE_2C;
break;
default:
unreached();
}
}
else if (sopt == INS_SCALABLE_OPTS_TO_VECTOR)
{
assert(isVectorRegister(reg1));
assert(isPredicateRegister(reg2));
switch (opt)
{
case INS_OPTS_SCALABLE_D:
assert(isValidUimm<3>(imm));
fmt = IF_SVE_CF_2B;
break;
case INS_OPTS_SCALABLE_S:
assert(isValidUimm<2>(imm));
fmt = IF_SVE_CF_2D;
break;
case INS_OPTS_SCALABLE_H:
assert(isValidUimm<1>(imm));
fmt = IF_SVE_CF_2C;
break;
default:
unreached();
}
}
else
{
unreached();
}
break;

case INS_sve_sqrshrn:
case INS_sve_sqrshrun:
case INS_sve_uqrshrn:
Expand Down Expand Up @@ -19596,6 +19717,10 @@ void emitter::emitIns_Call(EmitCallType callType,

case IF_SVE_CZ_4A_A:
case IF_SVE_CZ_4A_L:
case IF_SVE_CE_2A:
case IF_SVE_CE_2B:
case IF_SVE_CE_2C:
case IF_SVE_CE_2D:
case IF_SVE_CF_2A:
case IF_SVE_CF_2B:
case IF_SVE_CF_2C:
Expand Down Expand Up @@ -23841,6 +23966,68 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id)
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CE_2A: // ................ ......nnnnn.DDDD -- SVE move predicate from vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD
code |= insEncodeReg_V_9_to_5(id->idReg2()); // nnnnn
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CE_2B: // .........i...ii. ......nnnnn.DDDD -- SVE move predicate from vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD
code |= insEncodeReg_V_9_to_5(id->idReg2()); // nnnnn
code |= insEncodeSplitUimm<22, 22, 18, 17>(emitGetInsSC(id)); // i...ii
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CE_2C: // ..............i. ......nnnnn.DDDD -- SVE move predicate from vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD
code |= insEncodeReg_V_9_to_5(id->idReg2()); // nnnnn
code |= insEncodeUimm<17, 17>(emitGetInsSC(id)); // i
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CE_2D: // .............ii. ......nnnnn.DDDD -- SVE move predicate from vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD
code |= insEncodeReg_V_9_to_5(id->idReg2()); // nnnnn
code |= insEncodeUimm<18, 17>(emitGetInsSC(id)); // ii
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CF_2A: // ................ .......NNNNddddd -- SVE move predicate into vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
code |= insEncodeReg_P_8_to_5(id->idReg2()); // NNNN
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CF_2B: // .........i...ii. .......NNNNddddd -- SVE move predicate into vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
code |= insEncodeReg_P_8_to_5(id->idReg2()); // NNNN
code |= insEncodeSplitUimm<22, 22, 18, 17>(emitGetInsSC(id)); // i...ii
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CF_2C: // ..............i. .......NNNNddddd -- SVE move predicate into vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
code |= insEncodeReg_P_8_to_5(id->idReg2()); // NNNN
code |= insEncodeUimm<17, 17>(emitGetInsSC(id)); // i
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CF_2D: // .............ii. .......NNNNddddd -- SVE move predicate into vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
code |= insEncodeReg_P_8_to_5(id->idReg2()); // NNNN
code |= insEncodeUimm<18, 17>(emitGetInsSC(id)); // ii
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CI_3A: // ........xx..MMMM .......NNNN.DDDD -- SVE permute predicate elements
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD
Expand Down Expand Up @@ -25733,6 +25920,18 @@ void emitter::emitDispReg(regNumber reg, emitAttr attr, bool addComma)
emitDispComma();
}

//------------------------------------------------------------------------
// emitDispSveReg: Display a scalable vector register name
//
void emitter::emitDispSveReg(regNumber reg, bool addComma)
{
assert(isVectorRegister(reg));
printf(emitSveRegName(reg));

if (addComma)
emitDispComma();
}

//------------------------------------------------------------------------
// emitDispSveReg: Display a scalable vector register name with an arrangement suffix
//
Expand All @@ -25751,6 +25950,16 @@ void emitter::emitDispSveReg(regNumber reg, insOpts opt, bool addComma)
emitDispComma();
}

//------------------------------------------------------------------------
// emitDispSveRegIndex: Display a scalable vector register with indexed element
//
void emitter::emitDispSveRegIndex(regNumber reg, ssize_t index, bool addComma)
{
assert(isVectorRegister(reg));
printf(emitSveRegName(reg));
emitDispElementIndex(index, addComma);
}

//------------------------------------------------------------------------
// emitDispVectorReg: Display a SIMD vector register name with an arrangement suffix
//
Expand Down Expand Up @@ -27947,6 +28156,39 @@ void emitter::emitDispInsHelp(
emitDispSveReg(id->idReg3(), id->idInsOpt(), false); // mmmmm
break;

case IF_SVE_CE_2A: // ................ ......nnnnn.DDDD -- SVE move predicate from vector
emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt), INS_OPTS_SCALABLE_B, true); // DDDD
emitDispSveReg(id->idReg2(), false); // nnnnn
break;
case IF_SVE_CE_2B: // .........i...ii. ......nnnnn.DDDD -- SVE move predicate from vector
emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt), INS_OPTS_SCALABLE_D, true); // DDDD
emitDispSveRegIndex(id->idReg2(), emitGetInsSC(id), false); // nnnnn
break;
case IF_SVE_CE_2C: // ..............i. ......nnnnn.DDDD -- SVE move predicate from vector
emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt), INS_OPTS_SCALABLE_H, true); // DDDD
emitDispSveRegIndex(id->idReg2(), emitGetInsSC(id), false); // nnnnn
break;
case IF_SVE_CE_2D: // .............ii. ......nnnnn.DDDD -- SVE move predicate from vector
emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt), INS_OPTS_SCALABLE_S, true); // DDDD
emitDispSveRegIndex(id->idReg2(), emitGetInsSC(id), false); // nnnnn
break;
case IF_SVE_CF_2A: // ................ .......NNNNddddd -- SVE move predicate into vector
emitDispSveReg(id->idReg1(), true); // ddddd
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), INS_OPTS_SCALABLE_B, false); // NNNN
break;
case IF_SVE_CF_2B: // .........i...ii. .......NNNNddddd -- SVE move predicate into vector
emitDispSveRegIndex(id->idReg1(), emitGetInsSC(id), true); // ddddd
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), INS_OPTS_SCALABLE_D, false); // NNNN
break;
case IF_SVE_CF_2C: // ..............i. .......NNNNddddd -- SVE move predicate into vector
emitDispSveRegIndex(id->idReg1(), emitGetInsSC(id), true); // ddddd
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), INS_OPTS_SCALABLE_H, false); // NNNN
break;
case IF_SVE_CF_2D: // .............ii. .......NNNNddddd -- SVE move predicate into vector
emitDispSveRegIndex(id->idReg1(), emitGetInsSC(id), true); // ddddd
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), INS_OPTS_SCALABLE_S, false); // NNNN
break;

// <Pd>.<T>, <Pn>.<T>, <Pm>.<T>
case IF_SVE_CI_3A: // ........xx..MMMM .......NNNN.DDDD -- SVE permute predicate elements
emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt, 1), id->idInsOpt(), true); // DDDD
Expand Down Expand Up @@ -31763,6 +32005,18 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
result.insLatency = PERFSCORE_LATENCY_2C;
break;

case IF_SVE_CE_2A: // ................ ......nnnnn.DDDD -- SVE move predicate from vector
case IF_SVE_CE_2B: // .........i...ii. ......nnnnn.DDDD -- SVE move predicate from vector
case IF_SVE_CE_2C: // ..............i. ......nnnnn.DDDD -- SVE move predicate from vector
case IF_SVE_CE_2D: // .............ii. ......nnnnn.DDDD -- SVE move predicate from vector
case IF_SVE_CF_2A: // ................ .......NNNNddddd -- SVE move predicate into vector
case IF_SVE_CF_2B: // .........i...ii. .......NNNNddddd -- SVE move predicate into vector
case IF_SVE_CF_2C: // ..............i. .......NNNNddddd -- SVE move predicate into vector
case IF_SVE_CF_2D: // .............ii. .......NNNNddddd -- SVE move predicate into vector
result.insThroughput = PERFSCORE_THROUGHPUT_140C; // @ToDo currently undocumented
result.insLatency = PERFSCORE_LATENCY_140C;
break;

case IF_SVE_CI_3A: // ........xx..MMMM .......NNNN.DDDD -- SVE permute predicate elements
case IF_SVE_CJ_2A: // ........xx...... .......NNNN.DDDD -- SVE reverse predicate elements
case IF_SVE_CK_2A: // ................ .......NNNN.DDDD -- SVE unpack predicate elements
Expand Down
Loading

0 comments on commit 8dcca1c

Please sign in to comment.