Skip to content

Commit

Permalink
JIT: Added ARM64 SVE_GA_2A encoding (dotnet#95435)
Browse files Browse the repository at this point in the history
* Initial work on SVE_GA_2A encoding

* Fixing the encoding, immediates are working

* Added times two encoding for register

* added missing break

* No need to check ureg for zero

* Tweak assert. Added throughput/latency placeholders

* Forgot a break

* Forgot a break

* Feedback

* Update emitarm64.cpp

* Formatting
  • Loading branch information
TIHan committed Dec 4, 2023
1 parent 2f5cf1c commit 0c513d9
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10513,6 +10513,25 @@ void CodeGen::genArm64EmitterUnitTests()
INS_OPTS_SCALABLE_D); /* REVH <Zd>.<T>, <Pg>/M, <Zn>.<T> */
theEmitter->emitIns_R_R_R(INS_sve_revw, EA_SCALABLE, REG_V25, REG_P4, REG_V16,
INS_OPTS_SCALABLE_D); /* REVW <Zd>.D, <Pg>/M, <Zn>.D */
// IF_SVE_GA_2A
theEmitter->emitIns_R_R_I(INS_sve_sqrshrn, EA_SCALABLE, REG_V0, REG_V0, 5,
INS_OPTS_SCALABLE_H); // SQRSHRN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>
theEmitter->emitIns_R_R_I(INS_sve_sqrshrun, EA_SCALABLE, REG_V0, REG_V0, 5,
INS_OPTS_SCALABLE_H); // SQRSHRUN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>
theEmitter->emitIns_R_R_I(INS_sve_uqrshrn, EA_SCALABLE, REG_V0, REG_V0, 5,
INS_OPTS_SCALABLE_H); // UQRSHRN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>
theEmitter->emitIns_R_R_I(INS_sve_sqrshrn, EA_SCALABLE, REG_V0, REG_V2, 16,
INS_OPTS_SCALABLE_H); // SQRSHRN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>
theEmitter->emitIns_R_R_I(INS_sve_sqrshrun, EA_SCALABLE, REG_V0, REG_V4, 7,
INS_OPTS_SCALABLE_H); // SQRSHRUN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>
theEmitter->emitIns_R_R_I(INS_sve_uqrshrn, EA_SCALABLE, REG_V0, REG_V6, 1,
INS_OPTS_SCALABLE_H); // UQRSHRN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>
theEmitter->emitIns_R_R_I(INS_sve_sqrshrn, EA_SCALABLE, REG_V30, REG_V16, 16,
INS_OPTS_SCALABLE_H); // SQRSHRN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>
theEmitter->emitIns_R_R_I(INS_sve_sqrshrun, EA_SCALABLE, REG_V16, REG_V8, 7,
INS_OPTS_SCALABLE_H); // SQRSHRUN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>
theEmitter->emitIns_R_R_I(INS_sve_uqrshrn, EA_SCALABLE, REG_V15, REG_V12, 1,
INS_OPTS_SCALABLE_H); // UQRSHRN <Zd>.H, {<Zn1>.S-<Zn2>.S }, #<const>

#endif // ALL_ARM64_EMITTER_UNIT_TESTS_SVE

Expand Down
115 changes: 115 additions & 0 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,13 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(isValidScalarDatasize(elemsize));
break;

case IF_SVE_GA_2A: // ............iiii ......nnnn.ddddd -- SME2 multi-vec shift narrow
elemsize = id->idOpSize();
assert(isVectorRegister(id->idReg1())); // nnnn
assert(isVectorRegister(id->idReg2())); // ddddd
assert(id->idInsOpt() == INS_OPTS_SCALABLE_H);
break;

default:
printf("unexpected format %s\n", emitIfName(id->idInsFmt()));
assert(!"Unexpected format");
Expand Down Expand Up @@ -1713,6 +1720,18 @@ emitter::insFormat emitter::emitInsFormat(instruction ins)
#define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) info,
#define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) info,
#include "instrs.h"
#define INST1(id, nm, info, fmt, e1 ) info,
#define INST2(id, nm, info, fmt, e1, e2 ) info,
#define INST3(id, nm, info, fmt, e1, e2, e3 ) info,
#define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) info,
#define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) info,
#define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) info,
#define INST7(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7 ) info,
#define INST8(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8 ) info,
#define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9 ) info,
#define INST11(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10,e11 ) info,
#define INST13(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13) info,
#include "instrsarm64sve.h"
};
// clang-format on

Expand Down Expand Up @@ -7367,6 +7386,18 @@ void emitter::emitIns_R_R_I(
fmt = IF_LS_2E;
break;

case INS_sve_sqrshrn:
case INS_sve_sqrshrun:
case INS_sve_uqrshrn:
isRightShift = emitInsIsVectorRightShift(ins);
assert(isVectorRegister(reg1));
assert(isVectorRegister(reg2));
assert(opt == INS_OPTS_SCALABLE_H);
assert(isRightShift); // These are always right-shift.
assert(isValidVectorShiftAmount(imm, EA_4BYTE, isRightShift));
fmt = IF_SVE_GA_2A;
break;

default:
unreached();
break;
Expand Down Expand Up @@ -11454,6 +11485,22 @@ void emitter::emitIns_Call(EmitCallType callType,
return ureg << 6;
}

/*****************************************************************************
*
* Return an encoding for the specified 'V' register used in '9' thru '6' position with the times two encoding.
* This encoding requires that the register number be divisible by two.
*/

/*static*/ emitter::code_t emitter::insEncodeReg_V_9_to_6_Times_Two(regNumber reg)
{
assert(isVectorRegister(reg));
emitter::code_t ureg = (emitter::code_t)reg - (emitter::code_t)REG_V0;
assert(ureg % 2 == 0);
ureg /= 2u;
assert((ureg >= 0) && (ureg <= 32));
return ureg << 6;
}

/*****************************************************************************
*
* Returns an encoding for the specified condition code.
Expand Down Expand Up @@ -14296,6 +14343,18 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_GA_2A: // ............iiii ......nnnn.ddddd -- SME2 multi-vec shift narrow
imm = emitGetInsSC(id);
assert(id->idInsOpt() == INS_OPTS_SCALABLE_H);
assert(emitInsIsVectorRightShift(id->idIns()));
assert(isValidVectorShiftAmount(imm, EA_4BYTE, /* rightShift */ true));
code = emitInsCodeSve(ins, fmt);
code |= insEncodeVectorShift(EA_4BYTE, /* right-shift */ -imm); // iiii
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
code |= insEncodeReg_V_9_to_6_Times_Two(id->idReg2()); // nnnn
dst += emitOutput_Instr(dst, code);
break;

default:
assert(!"Unexpected format");
break;
Expand Down Expand Up @@ -14848,6 +14907,30 @@ void emitter::emitDispVectorElemList(
}
}

//------------------------------------------------------------------------
// emitDispSveRegList: Display a SVE vector register list
//
void emitter::emitDispSveRegList(regNumber firstReg, unsigned listSize, insOpts opt, bool addComma)
{
assert(isVectorRegister(firstReg));

regNumber currReg = firstReg;

printf("{ ");
for (unsigned i = 0; i < listSize; i++)
{
const bool notLastRegister = (i != listSize - 1);
emitDispSveReg(currReg, opt, notLastRegister);
currReg = (currReg == REG_V31) ? REG_V0 : REG_NEXT(currReg);
}
printf(" }");

if (addComma)
{
emitDispComma();
}
}

//------------------------------------------------------------------------
// emitDispPredicateReg: Display a predicate register name with with an arrangement suffix
//
Expand Down Expand Up @@ -16606,6 +16689,12 @@ void emitter::emitDispInsHelp(
emitDispReg(encodingZRtoSP(id->idReg3()), size, false); // mmmmm
break;

case IF_SVE_GA_2A: // ............iiii ......nnnn.ddddd -- SME2 multi-vec shift narrow
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
emitDispSveRegList(id->idReg2(), 2, INS_OPTS_SCALABLE_S, true); // nnnn
emitDispImm(emitGetInsSC(id), false); // iiii
break;

default:
printf("unexpected format %s", emitIfName(id->idInsFmt()));
assert(!"unexpectedFormat");
Expand Down Expand Up @@ -19006,6 +19095,32 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
result.insThroughput = PERFSCORE_THROUGHPUT_25C; // TODO-SVE: Placeholder
break;

// Not available in Arm Neoverse N2 Software Optimization Guide.
case IF_SVE_GA_2A: // ............iiii ......nnnn.ddddd -- SME2 multi-vec shift narrow
switch (ins)
{
case INS_sve_sqrshrn:
result.insThroughput = PERFSCORE_THROUGHPUT_25C; // TODO-SVE: Placeholder
result.insLatency = PERFSCORE_LATENCY_20C; // TODO-SVE: Placeholder
break;

case INS_sve_sqrshrun:
result.insThroughput = PERFSCORE_THROUGHPUT_25C; // TODO-SVE: Placeholder
result.insLatency = PERFSCORE_LATENCY_20C; // TODO-SVE: Placeholder
break;

case INS_sve_uqrshrn:
result.insThroughput = PERFSCORE_THROUGHPUT_25C; // TODO-SVE: Placeholder
result.insLatency = PERFSCORE_LATENCY_20C; // TODO-SVE: Placeholder
break;

default:
// all other instructions
perfScoreUnhandledInstruction(id, &result);
break;
}
break;

default:
// all other instructions
perfScoreUnhandledInstruction(id, &result);
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/emitarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ void emitDispVectorReg(regNumber reg, insOpts opt, bool addComma);
void emitDispVectorRegIndex(regNumber reg, emitAttr elemsize, ssize_t index, bool addComma);
void emitDispVectorRegList(regNumber firstReg, unsigned listSize, insOpts opt, bool addComma);
void emitDispVectorElemList(regNumber firstReg, unsigned listSize, emitAttr elemsize, unsigned index, bool addComma);
void emitDispSveRegList(regNumber firstReg, unsigned listSize, insOpts opt, bool addComma);
void emitDispPredicateReg(regNumber reg, PredicateType ptype, bool addComma);
void emitDispLowPredicateReg(regNumber reg, PredicateType ptype, bool addComma);
void emitDispArrangement(insOpts opt);
Expand Down Expand Up @@ -378,6 +379,10 @@ static code_t insEncodeReg_V_20_to_17(regNumber reg);
// Return an encoding for the specified 'V' register used in '9' thru '6' position.
static code_t insEncodeReg_V_9_to_6(regNumber reg);

// Return an encoding for the specified 'V' register used in '9' thru '6' position with the times two encoding.
// This encoding requires that the register number be divisible by two.
static code_t insEncodeReg_V_9_to_6_Times_Two(regNumber reg);

// Returns an encoding for the imm which represents the condition code.
static code_t insEncodeCond(insCond cond);

Expand Down

0 comments on commit 0c513d9

Please sign in to comment.