-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Changes from 2 commits
e7bda53
401ddd5
7ad452b
d30ed0e
c79d580
0e68a32
7e501ae
ae0235f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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())); | ||
|
@@ -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) | ||
|
@@ -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() | ||
{ | ||
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. | ||
|
@@ -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(); | ||
} | ||
|
@@ -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: | ||
|
@@ -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. | ||
|
@@ -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(); | ||
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: This makes is easy to group together the encoding groups with the same displays. Same for the other two groups (SetFFR would be |
||
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 | ||
|
@@ -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 | ||
|
@@ -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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have fixed this in #96082. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
||
|
@@ -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) | ||
{ | ||
|
@@ -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); | ||
|
There was a problem hiding this comment.
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.