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 ARM64-SVE2: Add IF_SVE_DQ_0A, IF_SVE_DR_1A, IF_SVE_DS_2A #95996

Merged
merged 8 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
12 changes: 12 additions & 0 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10647,6 +10647,18 @@ 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_DQ_0A
theEmitter->emitInsSve_SetFFR(); // SETFFR

// IF_SVE_DR_1A
theEmitter->emitIns_R(INS_sve_wrffr, EA_SCALABLE, REG_P0); // WRFFR <Pn>.B

// IF_SVE_DS_2A
theEmitter->emitIns_R_R(INS_sve_ctermeq, EA_8BYTE, REG_R0, REG_R1, INS_OPTS_NONE); // CTERMEQ <R><n>, <R><m>
theEmitter->emitIns_R_R(INS_sve_ctermeq, EA_4BYTE, REG_R2, REG_R3, INS_OPTS_NONE); // CTERMEQ <R><n>, <R><m>
theEmitter->emitIns_R_R(INS_sve_ctermne, EA_8BYTE, REG_R4, REG_R5, INS_OPTS_NONE); // CTERMNE <R><n>, <R><m>
theEmitter->emitIns_R_R(INS_sve_ctermne, EA_4BYTE, REG_R6, REG_R7, INS_OPTS_NONE); // CTERMNE <R><n>, <R><m>

// IF_SVE_GD_2A
theEmitter->emitIns_R_R(INS_sve_sqxtnb, EA_SCALABLE, REG_V0, REG_V5, INS_OPTS_SCALABLE_B); // SQXTNB <Zd>.<T>,
// <Zn>.<Tb>
Expand Down
125 changes: 119 additions & 6 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,21 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(id->idInsOpt() == INS_OPTS_SCALABLE_H);
break;

case IF_SVE_DQ_0A: // ................ ................ -- SVE FFR initialise
break;

case IF_SVE_DR_1A: // ................ .......NNNN..... -- SVE FFR write from predicate
assert(id->idInsOpt() == INS_OPTS_SCALABLE_B);
assert(isPredicateRegister(id->idReg1())); // NNNN
break;

case IF_SVE_DS_2A: // .........x.mmmmm ......nnnnn..... -- SVE conditionally terminate scalars
assert(insOptsNone(id->idInsOpt()));
assert(isGeneralRegister(id->idReg1())); // nnnnn
assert(isGeneralRegister(id->idReg2())); // mmmmm
assert(isValidGeneralDatasize(id->idOpSize())); // x
break;

case IF_SVE_GD_2A: // .........x.xx... ......nnnnnddddd -- SVE2 saturating extract narrow
elemsize = id->idOpSize();
assert(insOptsScalableSimple(id->idInsOpt()));
Expand Down Expand Up @@ -1258,7 +1273,6 @@ bool emitter::emitInsMayWriteToGCReg(instrDesc* id)

case IF_DV_2B: // DV_2B .Q.........iiiii ......nnnnnddddd Rd Vn[] (umov - to general)
case IF_DV_2H: // DV_2H X........X...... ......nnnnnddddd Rd Vn (fmov - to general)

return true;

case IF_DV_2C: // DV_2C .Q.........iiiii ......nnnnnddddd Vd Rn (dup/ins - vector from general)
Expand Down Expand Up @@ -5579,6 +5593,21 @@ void emitter::emitIns(instruction ins)
appendToCurIG(id);
}

/*****************************************************************************
*
* Add a SETFFR instruction: initialize first-fault register to all true.
*/

void emitter::emitInsSve_SetFFR()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably reuse emitIns_I() for it. It encodes the instructions that don't take registers.

{
instrDesc* id = emitNewInstrSmall(EA_SCALABLE);
id->idIns(INS_sve_setffr);
id->idInsFmt(IF_SVE_DQ_0A);

dispIns(id);
appendToCurIG(id);
}

/*****************************************************************************
*
* Add an instruction with a single immediate value.
Expand Down Expand Up @@ -5623,43 +5652,46 @@ void emitter::emitIns_I(instruction ins, emitAttr attr, ssize_t imm)
void emitter::emitIns_R(instruction ins, emitAttr attr, regNumber reg)
{
insFormat fmt = IF_NONE;
instrDesc* id = nullptr;
instrDesc* id = emitNewInstrSmall(attr);

/* Figure out the encoding format of the instruction */
switch (ins)
{
case INS_br:
case INS_ret:
assert(isGeneralRegister(reg));
id = emitNewInstrSmall(attr);
id->idReg1(reg);
fmt = IF_BR_1A;
break;

case INS_dczva:
assert(isGeneralRegister(reg));
assert(attr == EA_8BYTE);
id = emitNewInstrSmall(attr);
id->idReg1(reg);
fmt = IF_SR_1A;
break;

case INS_mrs_tpid0:
id = emitNewInstrSmall(attr);
id->idReg1(reg);
fmt = IF_SR_1A;
break;

case INS_sve_aesmc:
case INS_sve_aesimc:
id = emitNewInstrSmall(attr);
id->idInsOpt(INS_OPTS_SCALABLE_B);
id->idReg1(reg);
assert(isVectorRegister(reg)); // ddddd
assert(isScalableVectorSize(attr));
fmt = IF_SVE_GL_1A;
break;

case INS_sve_wrffr:
id->idInsOpt(INS_OPTS_SCALABLE_B);
id->idReg1(reg);
assert(isPredicateRegister(reg)); // NNNN
fmt = IF_SVE_DR_1A;
break;

default:
unreached();
}
Expand Down Expand Up @@ -6850,6 +6882,15 @@ void emitter::emitIns_R_R(
}
break;

case INS_sve_ctermeq:
case INS_sve_ctermne:
assert(insOptsNone(opt));
assert(isGeneralRegister(reg1)); // nnnnn
assert(isGeneralRegister(reg2)); // mmmmm
assert(isValidGeneralDatasize(size)); // x
fmt = IF_SVE_DS_2A;
break;

case INS_sve_sqxtnb:
case INS_sve_sqxtnt:
case INS_sve_uqxtnb:
Expand Down Expand Up @@ -11613,6 +11654,19 @@ void emitter::emitIns_Call(EmitCallType callType,
return ureg << 17;
}

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

/*static*/ emitter::code_t emitter::insEncodeReg_R_20_to_16(regNumber reg)
{
assert(isIntegerRegister(reg));
emitter::code_t ureg = (emitter::code_t)reg;
assert((ureg >= 0) && (ureg <= 32));
return ureg << 16;
}

/*****************************************************************************
*
* Return an encoding for the specified 'R' register used in '9' thru '5' position.
Expand Down Expand Up @@ -12682,6 +12736,22 @@ void emitter::emitIns_Call(EmitCallType callType,
return encodedSize | imm3High | imm3Low;
}

/*****************************************************************************
*
* Returns the encoding to select the <R> 4/8-byte width specifier <R>
* at bit location 22 for an Arm64 Sve instruction.
*/
/*static*/ emitter::code_t emitter::insEncodeSveElemsize_R_22(emitAttr size)
{
if (size == EA_8BYTE)
{
return 0x400000; // set the bit at location 22
}

assert(size == EA_4BYTE);
return 0;
}

BYTE* emitter::emitOutputLoadLabel(BYTE* dst, BYTE* srcAddr, BYTE* dstAddr, instrDescJmp* id)
{
instruction ins = id->idIns();
Expand Down Expand Up @@ -14732,6 +14802,25 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_DQ_0A: // ................ ................ -- SVE FFR initialise
code = emitInsCodeSve(ins, fmt);
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_DR_1A: // ................ .......NNNN..... -- SVE FFR write from predicate
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_8_to_5(id->idReg1()); // NNNN
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_DS_2A: // .........x.mmmmm ......nnnnn..... -- SVE conditionally terminate scalars
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add the display encoding (just copy/paste from the codegen tests) above the case:
// <R><n>, <R><m>

This makes is easy to group together the encoding groups with the same displays.

Same for the other two groups (SetFFR would be // none or something similar)

code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_R_9_to_5(id->idReg1()); // nnnnn
code |= insEncodeReg_R_20_to_16(id->idReg2()); // mmmmm
code |= insEncodeSveElemsize_R_22(id->idOpSize()); // x
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_GD_2A: // .........x.xx... ......nnnnnddddd -- SVE2 saturating extract narrow
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
Expand Down Expand Up @@ -17130,6 +17219,19 @@ void emitter::emitDispInsHelp(
emitDispImm(emitGetInsSC(id), false); // iiii
break;

case IF_SVE_DQ_0A: // ................ ................ -- SVE FFR initialise
break;

case IF_SVE_DR_1A: // ................ .......NNNN..... -- SVE FFR write from predicate
emitDispPredicateReg(id->idReg1(), PREDICATE_NONE, false); // NNNN
emitDispArrangement(id->idInsOpt()); // .B
break;

case IF_SVE_DS_2A: // .........x.mmmmm ......nnnnn..... -- SVE conditionally terminate scalars
emitDispReg(id->idReg1(), id->idOpSize(), true); // nnnnn
emitDispReg(id->idReg2(), id->idOpSize(), false); // mmmmm
break;

// <Zd>.<T>, <Zn>.<Tb>
case IF_SVE_GD_2A: // .........x.xx... ......nnnnnddddd -- SVE2 saturating extract narrow
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
Expand Down Expand Up @@ -19637,6 +19739,17 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
}
break;

case IF_SVE_DQ_0A: // ................ ................ -- SVE FFR initialise
case IF_SVE_DR_1A: // ................ .......NNNN..... -- SVE FFR write from predicate
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
result.insLatency = PERFSCORE_LATENCY_2C;
break;

case IF_SVE_DS_2A: // .........x.mmmmm ......nnnnn..... -- SVE conditionally terminate scalars
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
result.insLatency = PERFSCORE_LATENCY_1C;
break;

// Not available in Arm Neoverse N2 Software Optimization Guide.
case IF_SVE_AG_3A: // ........xx...... ...gggnnnnnddddd -- SVE bitwise logical reduction (quadwords)
case IF_SVE_AJ_3A: // ........xx...... ...gggnnnnnddddd -- SVE integer add reduction (quadwords)
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/jit/emitarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,9 @@ static code_t insEncodeReg_V_21_to_17(regNumber reg);
// Return an encoding for the specified 'R' register used in '21' thru '17' position.
static code_t insEncodeReg_R_21_to_17(regNumber reg);

// Return an encoding for the specified 'R' register used in '20' thru '16' position.
static code_t insEncodeReg_R_20_to_16(regNumber reg);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have fixed this in #96082.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for letting me know. It looks like your PR will get merged in pretty soon, so I'll wait to merge your changes into mine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amanasifkhalid - do you mind addressing #96082 (comment) in your PR, since you will have another round of CI run anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing, I'll update the assert.


// Return an encoding for the specified 'R' register used in '9' thru '5' position.
static code_t insEncodeReg_R_9_to_5(regNumber reg);

Expand Down Expand Up @@ -485,6 +488,10 @@ static code_t insEncodeSveElemsize_tszh_22_tszl_20_to_19(emitAttr size);
// This specifically encodes the field 'tszh:tszl' at bit locations '23-22:9-8'.
static code_t insEncodeSveShift_23_to_22_9_to_0(emitAttr size, bool isRightShift, size_t imm);

// Returns the encoding to select the 4/8-byte width specifier <R> at bit location 22
// for an Arm64 Sve instruction.
static code_t insEncodeSveElemsize_R_22(emitAttr size);

// Returns true if 'reg' represents an integer register.
static bool isIntegerRegister(regNumber reg)
{
Expand Down Expand Up @@ -993,6 +1000,8 @@ void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0);
public:
void emitIns(instruction ins);

void emitInsSve_SetFFR();

void emitIns_I(instruction ins, emitAttr attr, ssize_t imm);

void emitIns_R(instruction ins, emitAttr attr, regNumber reg);
Expand Down