diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp index 162cf751c37deb..45afd2629a3682 100644 --- a/src/coreclr/jit/codegenarm64test.cpp +++ b/src/coreclr/jit/codegenarm64test.cpp @@ -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 ., /Z, ., .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 ., /Z, ., # */ + theEmitter->emitIns_R_R_R_I(INS_sve_cmpge, EA_SCALABLE, REG_P11, REG_P7, REG_V21, 1, + INS_OPTS_SCALABLE_H); /* CMPGE ., /Z, ., # */ + theEmitter->emitIns_R_R_R_I(INS_sve_cmpgt, EA_SCALABLE, REG_P10, REG_P1, REG_V18, 4, + INS_OPTS_SCALABLE_S); /* CMPGT ., /Z, ., # */ + theEmitter->emitIns_R_R_R_I(INS_sve_cmple, EA_SCALABLE, REG_P8, REG_P6, REG_V11, 15, + INS_OPTS_SCALABLE_D); /* CMPLE ., /Z, ., # */ + theEmitter->emitIns_R_R_R_I(INS_sve_cmplt, EA_SCALABLE, REG_P7, REG_P2, REG_V8, -16, + INS_OPTS_SCALABLE_B); /* CMPLT ., /Z, ., # */ + theEmitter->emitIns_R_R_R_I(INS_sve_cmpne, EA_SCALABLE, REG_P0, REG_P5, REG_V0, -14, + INS_OPTS_SCALABLE_H); /* CMPNE ., /Z, ., # */ + + // 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 ., /Z, ., # */ + theEmitter->emitIns_R_R_R_I(INS_sve_cmphs, EA_SCALABLE, REG_P11, REG_P1, REG_V0, 36, + INS_OPTS_SCALABLE_H); /* CMPHS ., /Z, ., # */ + theEmitter->emitIns_R_R_R_I(INS_sve_cmplo, EA_SCALABLE, REG_P8, REG_P5, REG_V21, 64, + INS_OPTS_SCALABLE_S); /* CMPLO ., /Z, ., # */ + theEmitter->emitIns_R_R_R_I(INS_sve_cmpls, EA_SCALABLE, REG_P0, REG_P3, REG_V9, 127, + INS_OPTS_SCALABLE_D); /* CMPLS ., /Z, ., # */ + // 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 ., /M, ., . diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index be18133b3d78c7..ce5a2820e0e43b 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -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 + 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 @@ -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: @@ -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 4/8-byte width specifier @@ -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); @@ -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; + + // ., /Z, ., # + 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 + emitDispSveReg(id->idReg3(), id->idInsOpt(), true); // nnnnn + emitDispImm(emitGetInsSC(id), false, (fmt == IF_SVE_CY_3B)); // iiiii break; // ., /M, . @@ -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; diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index ef77505f58d439..e76290a28a28bd 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -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); @@ -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) { @@ -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) {