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

Add Arm64 encodings for SVE IF_SVE_CX_4A_A to IF_SVE_HT_4A group #96214

Merged
merged 9 commits into from
Jan 12, 2024
52 changes: 52 additions & 0 deletions src/coreclr/jit/codegenarm64test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4772,6 +4772,28 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R_R(INS_sve_cmpne, EA_SCALABLE, REG_P3, REG_P1, REG_V15, REG_V20,
INS_OPTS_SCALABLE_H); // CMPNE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>

// IF_SVE_CX_4A_A
theEmitter->emitIns_R_R_R_R(INS_sve_cmpeq, EA_SCALABLE, REG_P15, REG_P7, REG_V31, REG_V3,
INS_OPTS_SCALABLE_WIDE_B); /* CMPEQ <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
SwapnilGaikwad marked this conversation as resolved.
Show resolved Hide resolved
theEmitter->emitIns_R_R_R_R(INS_sve_cmpge, EA_SCALABLE, REG_P14, REG_P6, REG_V21, REG_V13,
INS_OPTS_SCALABLE_WIDE_H); /* CMPGE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
theEmitter->emitIns_R_R_R_R(INS_sve_cmpgt, EA_SCALABLE, REG_P13, REG_P5, REG_V11, REG_V23,
INS_OPTS_SCALABLE_WIDE_S); /* CMPGT <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
theEmitter->emitIns_R_R_R_R(INS_sve_cmphi, EA_SCALABLE, REG_P12, REG_P4, REG_V1, REG_V31,
INS_OPTS_SCALABLE_WIDE_B); /* CMPHI <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
theEmitter->emitIns_R_R_R_R(INS_sve_cmphs, EA_SCALABLE, REG_P11, REG_P3, REG_V0, REG_V30,
INS_OPTS_SCALABLE_WIDE_H); /* CMPHS <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
theEmitter->emitIns_R_R_R_R(INS_sve_cmple, EA_SCALABLE, REG_P4, REG_P2, REG_V10, REG_V0,
INS_OPTS_SCALABLE_WIDE_S); /* CMPLE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
theEmitter->emitIns_R_R_R_R(INS_sve_cmplo, EA_SCALABLE, REG_P3, REG_P1, REG_V20, REG_V1,
INS_OPTS_SCALABLE_WIDE_B); /* CMPLO <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
theEmitter->emitIns_R_R_R_R(INS_sve_cmpls, EA_SCALABLE, REG_P2, REG_P0, REG_V30, REG_V2,
INS_OPTS_SCALABLE_WIDE_H); /* CMPLS <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
theEmitter->emitIns_R_R_R_R(INS_sve_cmplt, EA_SCALABLE, REG_P1, REG_P7, REG_V24, REG_V8,
INS_OPTS_SCALABLE_WIDE_S); /* CMPLT <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */
theEmitter->emitIns_R_R_R_R(INS_sve_cmpne, EA_SCALABLE, REG_P0, REG_P0, REG_V14, REG_V28,
INS_OPTS_SCALABLE_WIDE_B); /* CMPNE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */

// IF_SVE_EP_3A
theEmitter->emitIns_R_R_R(INS_sve_shadd, EA_SCALABLE, REG_V15, REG_P0, REG_V10,
INS_OPTS_SCALABLE_B); // SHADD <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
Expand Down Expand Up @@ -4846,6 +4868,12 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_urshlr, EA_SCALABLE, REG_V15, REG_P2, REG_V20,
INS_OPTS_SCALABLE_D); // URSHLR <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>

// IF_SVE_GE_4A
theEmitter->emitIns_R_R_R_R(INS_sve_match, EA_SCALABLE, REG_P15, REG_P0, REG_V21, REG_V0,
INS_OPTS_SCALABLE_B); // MATCH <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_nmatch, EA_SCALABLE, REG_P0, REG_P7, REG_V11, REG_V31,
INS_OPTS_SCALABLE_H); // NMATCH <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>

// IF_SVE_GR_3A
theEmitter->emitIns_R_R_R(INS_sve_faddp, EA_SCALABLE, REG_V16, REG_P3, REG_V19,
INS_OPTS_SCALABLE_H); // FADDP <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
Expand Down Expand Up @@ -4900,6 +4928,30 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_fsubr, EA_SCALABLE, REG_V6, REG_P4, REG_V29,
INS_OPTS_SCALABLE_D); // FSUBR <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>

// IF_SVE_HT_4A
theEmitter->emitIns_R_R_R_R(INS_sve_facge, EA_SCALABLE, REG_P0, REG_P0, REG_V10, REG_V31,
INS_OPTS_SCALABLE_H); // FACGE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_facgt, EA_SCALABLE, REG_P15, REG_P1, REG_V20, REG_V21,
INS_OPTS_SCALABLE_S); // FACGT <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_facle, EA_SCALABLE, REG_P1, REG_P2, REG_V0, REG_V11,
INS_OPTS_SCALABLE_D); // FACLE <Pd>.<T>, <Pg>/Z, <Zm>.<T>, <Zn>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_faclt, EA_SCALABLE, REG_P14, REG_P3, REG_V30, REG_V1,
INS_OPTS_SCALABLE_H); // FACLT <Pd>.<T>, <Pg>/Z, <Zm>.<T>, <Zn>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_fcmeq, EA_SCALABLE, REG_P2, REG_P4, REG_V28, REG_V8,
INS_OPTS_SCALABLE_S); // FCMEQ <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_fcmge, EA_SCALABLE, REG_P13, REG_P5, REG_V8, REG_V18,
INS_OPTS_SCALABLE_D); // FCMGE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_fcmgt, EA_SCALABLE, REG_P3, REG_P6, REG_V18, REG_V28,
INS_OPTS_SCALABLE_H); // FCMGT <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_fcmle, EA_SCALABLE, REG_P12, REG_P7, REG_V1, REG_V30,
INS_OPTS_SCALABLE_S); // FCMLE <Pd>.<T>, <Pg>/Z, <Zm>.<T>, <Zn>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_fcmlt, EA_SCALABLE, REG_P4, REG_P0, REG_V11, REG_V0,
INS_OPTS_SCALABLE_D); // FCMLT <Pd>.<T>, <Pg>/Z, <Zm>.<T>, <Zn>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_fcmne, EA_SCALABLE, REG_P11, REG_P1, REG_V21, REG_V10,
INS_OPTS_SCALABLE_H); // FCMNE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>
theEmitter->emitIns_R_R_R_R(INS_sve_fcmuo, EA_SCALABLE, REG_P5, REG_P2, REG_V31, REG_V20,
INS_OPTS_SCALABLE_S); // FCMUO <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>

// IF_SVE_AF_3A
theEmitter->emitIns_R_R_R(INS_sve_andv, EA_1BYTE, REG_V0, REG_P0, REG_V0,
INS_OPTS_SCALABLE_B_WITH_SIMD_SCALAR); // ANDV <V><d>, <Pg>, <Zn>.<T>
Expand Down
126 changes: 115 additions & 11 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1058,12 +1058,42 @@ void emitter::emitInsSanityCheck(instrDesc* id)
// Scalable, 4 regs, to predicate register.
case IF_SVE_CX_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
elemsize = id->idOpSize();
assert(isScalableVectorSize(elemsize));
assert(insOptsScalableSimple(id->idInsOpt())); // xx
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isLowPredicateRegister(id->idReg2())); // ggg
assert(isVectorRegister(id->idReg3())); // mmmmm
assert(isVectorRegister(id->idReg4())); // nnnnn
assert(isVectorRegister(id->idReg3())); // nnnnn
assert(isVectorRegister(id->idReg4())); // mmmmm
break;

case IF_SVE_CX_4A_A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
elemsize = id->idOpSize();
assert(isScalableVectorSize(elemsize));
assert(insOptsScalableWide(id->idInsOpt())); // xx
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isLowPredicateRegister(id->idReg2())); // ggg
assert(isVectorRegister(id->idReg3())); // nnnnn
assert(isVectorRegister(id->idReg4())); // mmmmm
break;

case IF_SVE_GE_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE2 character match
elemsize = id->idOpSize();
assert(isScalableVectorSize(elemsize));
assert(insOptsScalableAtMaxHalf(id->idInsOpt()));
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isLowPredicateRegister(id->idReg2())); // ggg
assert(isVectorRegister(id->idReg3())); // nnnnn
assert(isVectorRegister(id->idReg4())); // mmmmm
break;

case IF_SVE_HT_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE floating-point compare vectors
elemsize = id->idOpSize();
assert(isScalableVectorSize(elemsize));
assert(insOptsScalableFloat(id->idInsOpt()));
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isLowPredicateRegister(id->idReg2())); // ggg
assert(isVectorRegister(id->idReg3())); // nnnnn
assert(isVectorRegister(id->idReg4())); // mmmmm
break;

// Scalable FP.
Expand Down Expand Up @@ -9988,13 +10018,51 @@ void emitter::emitIns_R_R_R_R(instruction ins,
case INS_sve_cmplo:
case INS_sve_cmpls:
case INS_sve_cmplt:
assert(insOptsScalableSimple(opt));
assert(isPredicateRegister(reg1)); // DDDD
assert(isLowPredicateRegister(reg2)); // ggg
assert(isVectorRegister(reg3)); // mmmmm
assert(isVectorRegister(reg4)); // nnnnn
assert(isVectorRegister(reg3)); // nnnnn
assert(isVectorRegister(reg4)); // mmmmm
assert(isScalableVectorSize(attr)); // xx
fmt = IF_SVE_CX_4A;
if (insOptsScalableSimple(opt))
{
fmt = IF_SVE_CX_4A;
}
else
{
assert(insOptsScalableWide(opt));
fmt = IF_SVE_CX_4A_A;
}
break;

case INS_sve_fcmeq:
case INS_sve_fcmge:
case INS_sve_facge:
case INS_sve_fcmgt:
case INS_sve_facgt:
case INS_sve_fcmlt:
case INS_sve_fcmle:
case INS_sve_fcmne:
case INS_sve_fcmuo:
case INS_sve_facle:
case INS_sve_faclt:
assert(insOptsScalableFloat(opt));
assert(isVectorRegister(reg3)); // nnnnn
assert(isVectorRegister(reg4)); // mmmmm
assert(isPredicateRegister(reg1)); // DDDD
assert(isLowPredicateRegister(reg2)); // ggg
assert(isScalableVectorSize(attr)); // xx
fmt = IF_SVE_HT_4A;
break;

case INS_sve_match:
case INS_sve_nmatch:
assert(insOptsScalableAtMaxHalf(opt));
assert(isPredicateRegister(reg1)); // DDDD
assert(isLowPredicateRegister(reg2)); // ggg
assert(isVectorRegister(reg3)); // nnnnn
assert(isVectorRegister(reg4)); // mmmmm
assert(isScalableVectorSize(attr)); // xx
fmt = IF_SVE_GE_4A;
break;

case INS_sve_mla:
Expand Down Expand Up @@ -10044,6 +10112,22 @@ void emitter::emitIns_R_R_R_R(instruction ins,
std::swap(reg3, reg4);
ins = INS_sve_cmpgt;
break;
case INS_sve_facle:
std::swap(reg3, reg4);
ins = INS_sve_facge;
break;
case INS_sve_faclt:
std::swap(reg3, reg4);
ins = INS_sve_facgt;
break;
case INS_sve_fcmle:
std::swap(reg3, reg4);
ins = INS_sve_fcmge;
break;
case INS_sve_fcmlt:
std::swap(reg3, reg4);
ins = INS_sve_fcmgt;
break;
default:
break;
}
Expand Down Expand Up @@ -14945,12 +15029,15 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CX_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
case IF_SVE_CX_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
case IF_SVE_CX_4A_A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
case IF_SVE_GE_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE2 character match
case IF_SVE_HT_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE floating-point compare vectors
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD
code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg
code |= insEncodeReg_V_9_to_5(id->idReg3()); // mmmmm
code |= insEncodeReg_V_20_to_16(id->idReg4()); // nnnnn
code |= insEncodeReg_V_9_to_5(id->idReg3()); // nnnnn
code |= insEncodeReg_V_20_to_16(id->idReg4()); // mmmmm
code |= insEncodeElemsize(optGetSveElemsize(id->idInsOpt())); // xx
dst += emitOutput_Instr(dst, code);
break;
Expand Down Expand Up @@ -17414,10 +17501,20 @@ void emitter::emitDispInsHelp(

// <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.<T>
case IF_SVE_CX_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
case IF_SVE_GE_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE2 character match
case IF_SVE_HT_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE floating-point compare vectors
emitDispPredicateReg(id->idReg1(), PREDICATE_SIZED, id->idInsOpt(), true); // DDDD
emitDispPredicateReg(id->idReg2(), PREDICATE_ZERO, id->idInsOpt(), true); // ggg
emitDispSveReg(id->idReg3(), id->idInsOpt(), true); // nnnnn
emitDispSveReg(id->idReg4(), id->idInsOpt(), false); // mmmmm
break;

// <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D
case IF_SVE_CX_4A_A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
emitDispPredicateReg(id->idReg1(), PREDICATE_SIZED, id->idInsOpt(), true); // DDDD
emitDispPredicateReg(id->idReg2(), PREDICATE_ZERO, id->idInsOpt(), true); // ggg
emitDispSveReg(id->idReg3(), id->idInsOpt(), true); // mmmmm
emitDispSveReg(id->idReg4(), id->idInsOpt(), false); // nnnnn
emitDispSveReg(id->idReg4(), INS_OPTS_SCALABLE_D, false); // nnnnn
Copy link
Member

Choose a reason for hiding this comment

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

While passing INS_OPTS_SCALABLE_D looks fine for this instruction format, I was checking other formats where we directly pass the INS_OPTS and seems like for IF_SVE_EQ_3A, we should have a method that is reverse of optWidenSveElemsizeArrangement(), which will basically lower H->B, S->H and D->S instead of manipulating the idOpts() this way.

case IF_SVE_EQ_3A: // ........xx...... ...gggnnnnnddddd -- SVE2 integer pairwise add and accumulate long
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
emitDispLowPredicateReg(id->idReg2(), PREDICATE_MERGE, id->idInsOpt(), true); // ggg
emitDispSveReg(id->idReg3(), (insOpts)((unsigned)id->idInsOpt() - 1), false); // mmmmm

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, makes sense. I will piggyback this change on my next patch 👍

break;

// <Zda>.<T>, <Pg>/M, <Zn>.<Tb>
Expand Down Expand Up @@ -19838,11 +19935,18 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
break;

case IF_SVE_CX_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
case IF_SVE_CX_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
case IF_SVE_CX_4A_A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE integer compare vectors
result.insLatency = PERFSCORE_LATENCY_4C;
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
break;

case IF_SVE_GE_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE2 character match
case IF_SVE_HT_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE floating-point compare vectors
result.insLatency = PERFSCORE_LATENCY_2C;
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
break;

// Extract/insert operation, SIMD and FP scalar form
case IF_SVE_CR_3A: // ........xx...... ...gggnnnnnddddd -- SVE extract element to SIMD&FP scalar register
result.insLatency = PERFSCORE_LATENCY_3C;
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/emitarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,12 @@ inline static bool insOptsScalableAtLeastHalf(insOpts opt)
return ((opt == INS_OPTS_SCALABLE_H) || (opt == INS_OPTS_SCALABLE_S) || (opt == INS_OPTS_SCALABLE_D));
}

inline static bool insOptsScalableAtMaxHalf(insOpts opt)
{
// `opt` is any of the standard half and below scalable types.
return ((opt == INS_OPTS_SCALABLE_B) || (opt == INS_OPTS_SCALABLE_H));
}

inline static bool insOptsScalableFloat(insOpts opt)
{
// `opt` is any of the standard scalable types that are valid for FP.
Expand Down
Loading