Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: Added SVE_GG_3A to SVG_GH_3A ARM64 encodings #95665

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10533,6 +10533,26 @@ void CodeGen::genArm64EmitterUnitTests()
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>

// IF_SVE_GG_3A
theEmitter->emitIns_R_R_R_I(INS_sve_luti2, EA_SCALABLE, REG_V0, REG_V0, REG_V0, 3,
INS_OPTS_SCALABLE_B); // LUTI2 <Zd>.B, {<Zn>.B }, <Zm>[<index>]

// IF_SVE_GH_3B
theEmitter->emitIns_R_R_R_I(INS_sve_luti4, EA_SCALABLE, REG_V0, REG_V0, REG_V0, 3,
INS_OPTS_SCALABLE_H); // LUTI4 <Zd>.H, {<Zn1>.H, <Zn2>.H }, <Zm>[<index>]

// IF_SVE_GH_3B_B
theEmitter->emitIns_R_R_R_I(INS_sve_luti4, EA_SCALABLE, REG_V0, REG_V0, REG_V0, 3,
INS_OPTS_SCALABLE_H); // LUTI4 <Zd>.H, {<Zn>.H }, <Zm>[<index>]

// IF_SVE_GG_3B
theEmitter->emitIns_R_R_R_I(INS_sve_luti2, EA_SCALABLE, REG_V0, REG_V0, REG_V0, 3,
INS_OPTS_SCALABLE_H); // LUTI2 <Zd>.H, {<Zn>.H }, <Zm>[<index>]

// IF_SVE_GH_3A
theEmitter->emitIns_R_R_R_I(INS_sve_luti4, EA_SCALABLE, REG_V0, REG_V0, REG_V0, 3,
INS_OPTS_SCALABLE_B); // LUTI4 <Zd>.B, {<Zn>.B }, <Zm>[<index>]

#endif // ALL_ARM64_EMITTER_UNIT_TESTS_SVE

#ifdef ALL_ARM64_EMITTER_UNIT_TESTS
Expand Down
211 changes: 211 additions & 0 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,56 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(id->idInsOpt() == INS_OPTS_SCALABLE_H);
break;

case IF_SVE_GG_3A: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 2-bit indices and 16-bit
// element size
assert(insOptsScalable(id->idInsOpt()));
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isVectorRegister(id->idReg2())); // nnnnn
assert(isVectorRegister(id->idReg3())); // mmmmm
assert(isValidImm2(emitGetInsSC(id))); // ii
assert(id->idInsOpt() == INS_OPTS_SCALABLE_B);
break;

case IF_SVE_GH_3B: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
assert(insOptsScalable(id->idInsOpt()));
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isVectorRegister(id->idReg2())); // nnnnn
assert(isVectorRegister(id->idReg3())); // mmmmm
assert(isValidImm2(emitGetInsSC(id))); // ii
assert(id->idInsOpt() == INS_OPTS_SCALABLE_H);
break;

case IF_SVE_GH_3B_B: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
assert(insOptsScalable(id->idInsOpt()));
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isVectorRegister(id->idReg2())); // nnnnn
assert(isVectorRegister(id->idReg3())); // mmmmm
assert(isValidImm2(emitGetInsSC(id))); // ii
assert(id->idInsOpt() == INS_OPTS_SCALABLE_H);
break;

case IF_SVE_GG_3B: // ........ii.mmmmm ...i..nnnnnddddd -- SVE2 lookup table with 2-bit indices and 16-bit
// element size
assert(insOptsScalable(id->idInsOpt()));
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isVectorRegister(id->idReg2())); // nnnnn
assert(isVectorRegister(id->idReg3())); // mmmmm
assert(isValidImm2(emitGetInsSC(id))); // ii
assert(id->idInsOpt() == INS_OPTS_SCALABLE_H);
break;

case IF_SVE_GH_3A: // ........i..mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
assert(insOptsScalable(id->idInsOpt()));
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isVectorRegister(id->idReg2())); // nnnnn
assert(isVectorRegister(id->idReg3())); // mmmmm
// TODO: Verify 'i'.
assert(id->idInsOpt() == INS_OPTS_SCALABLE_B);
break;

default:
printf("unexpected format %s\n", emitIfName(id->idInsFmt()));
assert(!"Unexpected format");
Expand Down Expand Up @@ -9119,6 +9169,22 @@ void emitter::emitIns_R_R_R_I(instruction ins,
fmt = IF_DV_3AI;
break;

case INS_sve_luti2:
assert(insOptsScalable(opt));
assert(isVectorRegister(reg1));
assert(isVectorRegister(reg2));
assert(isVectorRegister(reg3));
assert(imm >= 0 && imm < 4);
// TODO: Handle other formats: IF_SVE_GG_3B
fmt = IF_SVE_GG_3A;
break;

case INS_sve_luti4:
assert(!"not implemented");
// TODO: Handle other formats: IF_SVE_GH_3B_B, IF_SVE_GH_3A
fmt = IF_SVE_GH_3B;
break;

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

/*****************************************************************************
*
* Return an encoding for the specified 'V' register used in '20' thru '16' position.
*/

/*static*/ emitter::code_t emitter::insEncodeReg_V_20_to_16(regNumber reg)
{
assert(isVectorRegister(reg));
emitter::code_t ureg = (emitter::code_t)reg - (emitter::code_t)REG_V0;
assert((ureg >= 0) && (ureg <= 32));
return ureg << 16;
}

/*****************************************************************************
*
* Returns an encoding for the specified condition code.
Expand Down Expand Up @@ -11874,6 +11953,20 @@ void emitter::emitIns_Call(EmitCallType callType,
}
}

// insEncodeSveIndex_23_to_22: Returns the SVE encoding for a 2-bit index at bit locations '23-22'.
//
// Arguments:
// index - the value of the index, must be greater than or equal to 0 and less than 3.
//
// Returns:
// "i2" field of the instruction that contains encoded index.
//
/*static*/ emitter::code_t emitter::insEncodeSveIndex_23_to_22(ssize_t index)
{
assert(isValidImm2(index));
return (code_t)index << 22;
}

/*****************************************************************************
*
* Returns the encoding to select the 1/2/4/8 byte elemsize for an Arm64 vector instruction
Expand Down Expand Up @@ -14355,6 +14448,31 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_GG_3A: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 2-bit indices and 16-bit
// element size
case IF_SVE_GH_3B: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
case IF_SVE_GH_3B_B: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
imm = emitGetInsSC(id);
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
code |= insEncodeReg_V_9_to_5(id->idReg2()); // nnnnn
code |= insEncodeReg_V_20_to_16(id->idReg3()); // mmmmm
code |= insEncodeSveIndex_23_to_22(imm); // ii
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_GG_3B: // ........ii.mmmmm ...i..nnnnnddddd -- SVE2 lookup table with 2-bit indices and 16-bit
// element size
assert(!"not implemented");
break;

case IF_SVE_GH_3A: // ........i..mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
assert(!"not implemented");
break;

default:
assert(!"Unexpected format");
break;
Expand Down Expand Up @@ -14825,6 +14943,21 @@ void emitter::emitDispSveReg(regNumber reg, insOpts opt, bool addComma)
emitDispComma();
}

//------------------------------------------------------------------------
// emitDispSveReg: Display a scalable vector register name with an index suffix
//
void emitter::emitDispSveRegIndex(regNumber reg, ssize_t index, bool addComma)
{
assert(isVectorRegister(reg));
printf(emitSveRegName(reg));
printf("[");
emitDispImm(index, false);
printf("]");

if (addComma)
emitDispComma();
}

//------------------------------------------------------------------------
// emitDispVectorReg: Display a SIMD vector register name with an arrangement suffix
//
Expand Down Expand Up @@ -16695,6 +16828,54 @@ void emitter::emitDispInsHelp(
emitDispImm(emitGetInsSC(id), false); // iiii
break;

// <Zd>.B, { <Zn>.B }, <Zm>[<index>]
case IF_SVE_GG_3A: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 2-bit indices and 16-bit
// element size
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
emitDispSveRegList(id->idReg2(), 1, id->idInsOpt(), true); // nnnnn
emitDispSveRegIndex(id->idReg3(), emitGetInsSC(id), false); // mmmmm
// ii
break;

// <Zd>.H, { <Zn1>.H, <Zn2>.H }, <Zm>[<index>]
case IF_SVE_GH_3B: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
printf("{ ");
emitDispSveReg(id->idReg2(), id->idInsOpt(), true); // nnnnn
emitDispSveReg((regNumber)(((unsigned)id->idReg2() + 1) % 32), id->idInsOpt(), false);
printf(" }, ");
emitDispSveRegIndex(id->idReg3(), emitGetInsSC(id), false); // mmmmm
// ii
break;

// <Zd>.H, { <Zn>.H }, <Zm>[<index>]
case IF_SVE_GH_3B_B: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
emitDispSveRegList(id->idReg2(), 1, id->idInsOpt(), true); // nnnnn
emitDispSveRegIndex(id->idReg3(), emitGetInsSC(id), false); // mmmmm
// ii
break;

// <Zd>.H, { <Zn>.H }, <Zm>[<index>]
case IF_SVE_GG_3B: // ........ii.mmmmm ...i..nnnnnddddd -- SVE2 lookup table with 2-bit indices and 16-bit
// element size
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
emitDispSveRegList(id->idReg2(), 1, id->idInsOpt(), true); // nnnnn
emitDispSveRegIndex(id->idReg3(), emitGetInsSC(id), false); // mmmmm
// ii
break;

// <Zd>.B, { <Zn>.B }, <Zm>[<index>]
case IF_SVE_GH_3A: // ........i..mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
emitDispSveRegList(id->idReg2(), 1, id->idInsOpt(), true); // nnnnn
emitDispSveRegIndex(id->idReg3(), emitGetInsSC(id), false); // mmmmm
// ii
break;

default:
printf("unexpected format %s", emitIfName(id->idInsFmt()));
assert(!"unexpectedFormat");
Expand Down Expand Up @@ -19121,6 +19302,36 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
}
break;

case IF_SVE_GG_3A: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 2-bit indices and 16-bit
// element size
result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix
result.insLatency = PERFSCORE_LATENCY_1C; // need to fix
break;

case IF_SVE_GH_3B: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix
result.insLatency = PERFSCORE_LATENCY_1C; // need to fix
break;

case IF_SVE_GH_3B_B: // ........ii.mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix
result.insLatency = PERFSCORE_LATENCY_1C; // need to fix
break;

case IF_SVE_GG_3B: // ........ii.mmmmm ...i..nnnnnddddd -- SVE2 lookup table with 2-bit indices and 16-bit
// element size
result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix
result.insLatency = PERFSCORE_LATENCY_1C; // need to fix
break;

case IF_SVE_GH_3A: // ........i..mmmmm ......nnnnnddddd -- SVE2 lookup table with 4-bit indices and 16-bit
// element size
result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix
result.insLatency = PERFSCORE_LATENCY_1C; // need to fix
break;

default:
// all other instructions
perfScoreUnhandledInstruction(id, &result);
Expand Down
16 changes: 16 additions & 0 deletions src/coreclr/jit/emitarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void emitDispExtendOpts(insOpts opt);
void emitDispLSExtendOpts(insOpts opt);
void emitDispReg(regNumber reg, emitAttr attr, bool addComma);
void emitDispSveReg(regNumber reg, insOpts opt, bool addComma);
void emitDispSveRegIndex(regNumber reg, ssize_t index, bool addComma);
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);
Expand Down Expand Up @@ -383,6 +384,9 @@ static code_t insEncodeReg_V_9_to_6(regNumber reg);
// This encoding requires that the register number be divisible by two.
static code_t insEncodeReg_V_9_to_6_Times_Two(regNumber reg);

// Return an encoding for the specified 'V' register used in '20' thru '16' position.
static code_t insEncodeReg_V_20_to_16(regNumber reg);

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

Expand Down Expand Up @@ -426,6 +430,8 @@ static code_t insEncodeVectorIndexLMH(emitAttr elemsize, ssize_t index);
// Returns the encoding for ASIMD Shift instruction.
static code_t insEncodeVectorShift(emitAttr size, ssize_t shiftAmount);

static code_t insEncodeSveIndex_23_to_22(ssize_t index);

// Returns the encoding to select the 1/2/4/8 byte elemsize for an Arm64 vector instruction
static code_t insEncodeElemsize(emitAttr size);

Expand Down Expand Up @@ -468,6 +474,10 @@ static code_t insEncodeReg3Scale(bool isScaled);
// Returns the encoding to select the 1/2/4/8 byte elemsize for an Arm64 SVE vector instruction
static code_t insEncodeSveElemsize(insOpts opt);

// Returns the encoding to select the 1/2/4/8 byte elemsize for an Arm64 SVE vector instruction
// This specifically encodes the field 'tszh:tszl' at bit locations '22:20-19'.
static code_t insEncodeSveElemsize_tszh_22_tszl_20_to_19(insOpts opt);

// Returns true if 'reg' represents an integer register.
static bool isIntegerRegister(regNumber reg)
{
Expand Down Expand Up @@ -668,6 +678,12 @@ inline static unsigned isValidVectorShiftAmount(ssize_t shiftAmount, emitAttr si
((shiftAmount >= 0) && (shiftAmount < getBitWidth(size)));
}

// Returns true if the 'imm' represents a valid 2-bit integer.
inline static bool isValidImm2(ssize_t imm)
{
return (imm >= 0) && (imm < 4);
}

inline static bool isValidGeneralDatasize(emitAttr size)
{
return (size == EA_8BYTE) || (size == EA_4BYTE);
Expand Down
Loading