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 IF_SVE_CY_3A and IF_SVE_CY_3B group #96992

Merged
merged 3 commits into from
Jan 17, 2024
Merged
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
24 changes: 24 additions & 0 deletions src/coreclr/jit/codegenarm64test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4794,6 +4794,30 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R_R(INS_sve_cmpne, EA_SCALABLE, REG_P0, REG_P0, REG_V14, REG_V28, INS_OPTS_SCALABLE_B,
INS_SCALABLE_OPTS_WIDE); /* CMPNE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, <Zm>.D */

// IF_SVE_CY_3A
theEmitter->emitIns_R_R_R_I(INS_sve_cmpeq, EA_SCALABLE, REG_P15, REG_P0, REG_V31, 8,
INS_OPTS_SCALABLE_B); /* CMPEQ <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */
theEmitter->emitIns_R_R_R_I(INS_sve_cmpge, EA_SCALABLE, REG_P11, REG_P7, REG_V21, 1,
INS_OPTS_SCALABLE_H); /* CMPGE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */
theEmitter->emitIns_R_R_R_I(INS_sve_cmpgt, EA_SCALABLE, REG_P10, REG_P1, REG_V18, 4,
INS_OPTS_SCALABLE_S); /* CMPGT <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */
theEmitter->emitIns_R_R_R_I(INS_sve_cmple, EA_SCALABLE, REG_P8, REG_P6, REG_V11, 15,
INS_OPTS_SCALABLE_D); /* CMPLE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */
theEmitter->emitIns_R_R_R_I(INS_sve_cmplt, EA_SCALABLE, REG_P7, REG_P2, REG_V8, -16,
INS_OPTS_SCALABLE_B); /* CMPLT <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */
theEmitter->emitIns_R_R_R_I(INS_sve_cmpne, EA_SCALABLE, REG_P0, REG_P5, REG_V0, -14,
INS_OPTS_SCALABLE_H); /* CMPNE <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */

// IF_SVE_CY_3B
theEmitter->emitIns_R_R_R_I(INS_sve_cmphi, EA_SCALABLE, REG_P15, REG_P7, REG_V19, 0,
INS_OPTS_SCALABLE_B); /* CMPHI <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */
theEmitter->emitIns_R_R_R_I(INS_sve_cmphs, EA_SCALABLE, REG_P11, REG_P1, REG_V0, 36,
INS_OPTS_SCALABLE_H); /* CMPHS <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */
theEmitter->emitIns_R_R_R_I(INS_sve_cmplo, EA_SCALABLE, REG_P8, REG_P5, REG_V21, 64,
INS_OPTS_SCALABLE_S); /* CMPLO <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */
theEmitter->emitIns_R_R_R_I(INS_sve_cmpls, EA_SCALABLE, REG_P0, REG_P3, REG_V9, 127,
INS_OPTS_SCALABLE_D); /* CMPLS <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm> */

// 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
117 changes: 113 additions & 4 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,8 +1072,28 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(insOptsScalableWide(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
Copy link
Member

Choose a reason for hiding this comment

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

good catch

assert(isVectorRegister(id->idReg4())); // mmmmm
break;

case IF_SVE_CY_3A: // ........xx.iiiii ...gggnnnnn.DDDD -- SVE integer compare with signed immediate
elemsize = id->idOpSize();
assert(isScalableVectorSize(elemsize));
assert(insOptsScalableStandard(id->idInsOpt()));
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isLowPredicateRegister(id->idReg2())); // ggg
assert(isVectorRegister(id->idReg3())); // nnnnn
assert(isValidSimm5(emitGetInsSC(id))); // iiiii
break;

case IF_SVE_CY_3B: // ........xx.iiiii ii.gggnnnnn.DDDD -- SVE integer compare with unsigned immediate
elemsize = id->idOpSize();
assert(isScalableVectorSize(elemsize));
assert(insOptsScalableStandard(id->idInsOpt()));
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isLowPredicateRegister(id->idReg2())); // ggg
assert(isVectorRegister(id->idReg3())); // nnnnn
assert(isValidUimm7(emitGetInsSC(id))); // iiiii
break;

case IF_SVE_GE_4A: // ........xx.mmmmm ...gggnnnnn.DDDD -- SVE2 character match
Expand Down Expand Up @@ -9639,6 +9659,32 @@ void emitter::emitIns_R_R_R_I(instruction ins,
}
break;

case INS_sve_cmpeq:
case INS_sve_cmpgt:
case INS_sve_cmpge:
case INS_sve_cmpne:
case INS_sve_cmple:
case INS_sve_cmplt:
assert(insOptsScalableStandard(opt));
assert(isPredicateRegister(reg1)); // DDDD
assert(isLowPredicateRegister(reg2)); // ggg
assert(isVectorRegister(reg3)); // nnnnn
assert(isValidSimm5(imm)); // iiiii
fmt = IF_SVE_CY_3A;
break;

case INS_sve_cmphi:
case INS_sve_cmphs:
case INS_sve_cmplo:
case INS_sve_cmpls:
assert(insOptsScalableStandard(opt));
assert(isPredicateRegister(reg1)); // DDDD
assert(isLowPredicateRegister(reg2)); // ggg
assert(isVectorRegister(reg3)); // nnnnn
assert(isValidUimm7(imm)); // iiiii
fmt = IF_SVE_CY_3B;
break;

case INS_fmul: // by element, imm[0..3] selects the element of reg3
case INS_fmla:
case INS_fmls:
Expand Down Expand Up @@ -14348,6 +14394,32 @@ void emitter::emitIns_Call(EmitCallType callType,
return insEncodeSimm4_19_to_16(imm / 32);
}

/*****************************************************************************
*
* Returns the encoding for the immediate value as 5-bits at bit locations '20-16'.
*/

/*static*/ emitter::code_t emitter::insEncodeSimm5_20_to_16(ssize_t imm)
{
assert(isValidSimm5(imm));
if (imm < 0)
{
imm = (imm & 0x1F);
}
return (code_t)imm << 16;
}

/*****************************************************************************
*
* Returns the encoding for the immediate value as 7-bits at bit locations '20-14'.
*/

/*static*/ emitter::code_t emitter::insEncodeUimm7_20_to_14(ssize_t imm)
{
assert(isValidUimm7(imm));
return (code_t)imm << 14;
}

/*****************************************************************************
*
* Returns the encoding to select the <R> 4/8-byte width specifier <R>
Expand Down Expand Up @@ -16439,6 +16511,28 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CY_3A: // ........xx.iiiii ...gggnnnnn.DDDD -- SVE integer compare with signed immediate
imm = emitGetInsSC(id);
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()); // nnnnn
code |= insEncodeSimm5_20_to_16(imm); // iiiii
code |= insEncodeElemsize(optGetSveElemsize(id->idInsOpt())); // xx
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_CY_3B: // ........xx.iiiii ii.gggnnnnn.DDDD -- SVE integer compare with unsigned immediate
imm = emitGetInsSC(id);
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()); // nnnnn
code |= insEncodeUimm7_20_to_14(imm); // iiiii
code |= insEncodeElemsize(optGetSveElemsize(id->idInsOpt())); // xx
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);
Expand Down Expand Up @@ -19109,8 +19203,17 @@ void emitter::emitDispInsHelp(
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(), INS_OPTS_SCALABLE_D, false); // nnnnn
emitDispSveReg(id->idReg3(), id->idInsOpt(), true); // nnnnn
emitDispSveReg(id->idReg4(), INS_OPTS_SCALABLE_D, false); // mmmmm
break;

// <Pd>.<T>, <Pg>/Z, <Zn>.<T>, #<imm>
case IF_SVE_CY_3A: // ........xx.iiiii ...gggnnnnn.DDDD -- SVE integer compare with signed immediate
case IF_SVE_CY_3B: // ........xx.iiiii ii.gggnnnnn.DDDD -- SVE integer compare with unsigned immediate
emitDispPredicateReg(id->idReg1(), PREDICATE_SIZED, id->idInsOpt(), true); // DDDD
emitDispPredicateReg(id->idReg2(), PREDICATE_ZERO, id->idInsOpt(), true); // ggg
Copy link
Contributor

Choose a reason for hiding this comment

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

Here we should be using insGetPredicateType(fmt) instead of PREDICATE_ZERO.

But... on the previous line we would still need to do PREDICATE_SIZED.
We could extend insGetPredicateType() to have a an extra arg (reg position), which is ignored for most instructions.

Alternatively, we keep this PR as it is.

Copy link
Member

Choose a reason for hiding this comment

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

Alternatively, we keep this PR as it is.

I agree. But we should have a follow up PR that calls insGetPredicateType() instead of hard-coding even at other places.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree. But we should have a follow up PR that calls insGetPredicateType() instead of hard-coding even at other places.

Done: #97142

emitDispSveReg(id->idReg3(), id->idInsOpt(), true); // nnnnn
emitDispImm(emitGetInsSC(id), false, (fmt == IF_SVE_CY_3B)); // iiiii
break;

// <Zda>.<T>, <Pg>/M, <Zn>.<Tb>
Expand Down Expand Up @@ -21692,6 +21795,12 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
result.insThroughput = PERFSCORE_THROUGHPUT_1C;
break;

case IF_SVE_CY_3A: // ........xx.iiiii ...gggnnnnn.DDDD -- SVE integer compare with signed immediate
case IF_SVE_CY_3B: // ........xx.iiiii ii.gggnnnnn.DDDD -- SVE integer compare with unsigned immediate
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;
Expand Down
18 changes: 18 additions & 0 deletions src/coreclr/jit/emitarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,12 @@ static code_t insEncodeSimm4_MultipleOf16_19_to_16(ssize_t imm);
// Returns the encoding for the immediate value that is a multiple of 32 as 4-bits at bit locations '19-16'.
static code_t insEncodeSimm4_MultipleOf32_19_to_16(ssize_t imm);

// Returns the encoding for the immediate value as 5-bits at bit locations '20-16'.
static code_t insEncodeSimm5_20_to_16(ssize_t imm);

// Returns the encoding for the immediate value as 7-bits at bit locations '20-14'.
static code_t insEncodeUimm7_20_to_14(ssize_t imm);

// Returns the encoding to select the elemsize for an Arm64 SVE vector instruction plus an immediate.
// 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);
Expand Down Expand Up @@ -580,6 +586,12 @@ static bool isValidUimm5(ssize_t value)
return (0 <= value) && (value <= 0x1FLL);
};

// Returns true if 'value' is a legal unsigned immediate 7 bit encoding (such as for CMPLT, CMPNE).
static bool isValidUimm7(ssize_t value)
{
return (0 <= value) && (value <= 0x7FLL);
};

// Returns true if 'value' is a legal unsigned immediate 8 bit encoding (such as for FMOV).
static bool isValidUimm8(ssize_t value)
{
Expand Down Expand Up @@ -616,6 +628,12 @@ static bool isValidSimm14(ssize_t value)
return (-0x2000LL <= value) && (value <= 0x1FFFLL);
};

// Returns true if 'value' is a legal signed immediate 5 bit encoding (such as for CMPLO, CMPHI).
static bool isValidSimm5(ssize_t value)
{
return (-0x10LL <= value) && (value <= 0xFLL);
};

// Returns true if 'value' represents a valid 'bitmask immediate' encoding.
static bool isValidImmNRS(size_t value, emitAttr size)
{
Expand Down
Loading