diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp index 7a102104ca773c..f5752a90166a82 100644 --- a/src/coreclr/jit/codegenarm64test.cpp +++ b/src/coreclr/jit/codegenarm64test.cpp @@ -5912,6 +5912,100 @@ void CodeGen::genArm64EmitterUnitTestsSve() theEmitter->emitIns_R_PATTERN_I(INS_sve_incw, EA_SCALABLE, REG_V5, SVE_PATTERN_VL6, 16, INS_OPTS_SCALABLE_S); // INCW .S{, {, MUL #}} + // IF_SVE_BO_1A + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqdecb, EA_4BYTE, REG_R0, SVE_PATTERN_POW2, + 1); // SQDECB , {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqdecd, EA_8BYTE, REG_R1, SVE_PATTERN_VL1, + 2); // SQDECD {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqdech, EA_4BYTE, REG_R2, SVE_PATTERN_VL2, + 3); // SQDECH , {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqdecw, EA_8BYTE, REG_R3, SVE_PATTERN_VL3, + 4); // SQDECW {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqincb, EA_4BYTE, REG_R4, SVE_PATTERN_VL4, + 5); // SQINCB , {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqincd, EA_8BYTE, REG_R5, SVE_PATTERN_VL5, + 6); // SQINCD {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqinch, EA_4BYTE, REG_R6, SVE_PATTERN_VL6, + 7); // SQINCH , {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqincw, EA_8BYTE, REG_R7, SVE_PATTERN_VL7, + 8); // SQINCW {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqdecb, EA_4BYTE, REG_R8, SVE_PATTERN_VL8, + 9); // UQDECB {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqdecd, EA_8BYTE, REG_R9, SVE_PATTERN_VL16, + 10); // UQDECD {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqdech, EA_4BYTE, REG_R10, SVE_PATTERN_VL32, + 11); // UQDECH {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqdecw, EA_8BYTE, REG_R11, SVE_PATTERN_VL64, + 12); // UQDECW {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqincb, EA_4BYTE, REG_R12, SVE_PATTERN_VL128, + 13); // UQINCB {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqincd, EA_8BYTE, REG_R13, SVE_PATTERN_VL256, + 14); // UQINCD {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqinch, EA_4BYTE, REG_R14, SVE_PATTERN_MUL4, + 15); // UQINCH {, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqincw, EA_8BYTE, REG_R15, SVE_PATTERN_ALL, + 16); // UQINCW {, {, MUL #}} + + // IF_SVE_BP_1A + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqdecd, EA_SCALABLE, REG_V0, SVE_PATTERN_VL1, 1, + INS_OPTS_SCALABLE_D); // SQDECD .D{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqdech, EA_SCALABLE, REG_V1, SVE_PATTERN_VL2, 2, + INS_OPTS_SCALABLE_H); // SQDECH .H{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqdecw, EA_SCALABLE, REG_V2, SVE_PATTERN_VL3, 3, + INS_OPTS_SCALABLE_S); // SQDECW .S{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqincd, EA_SCALABLE, REG_V3, SVE_PATTERN_VL4, 4, + INS_OPTS_SCALABLE_D); // SQINCD .D{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqinch, EA_SCALABLE, REG_V4, SVE_PATTERN_VL5, 5, + INS_OPTS_SCALABLE_H); // SQINCH .H{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_sqincw, EA_SCALABLE, REG_V5, SVE_PATTERN_VL6, 6, + INS_OPTS_SCALABLE_S); // SQINCW .S{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqdecd, EA_SCALABLE, REG_V6, SVE_PATTERN_VL7, 7, + INS_OPTS_SCALABLE_D); // UQDECD .D{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqdech, EA_SCALABLE, REG_V7, SVE_PATTERN_VL8, 8, + INS_OPTS_SCALABLE_H); // UQDECH .H{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqdecw, EA_SCALABLE, REG_V8, SVE_PATTERN_VL16, 9, + INS_OPTS_SCALABLE_S); // UQDECW .S{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqincd, EA_SCALABLE, REG_V9, SVE_PATTERN_VL32, 10, + INS_OPTS_SCALABLE_D); // UQINCD .D{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqinch, EA_SCALABLE, REG_V10, SVE_PATTERN_POW2, 11, + INS_OPTS_SCALABLE_H); // UQINCH .H{, {, MUL #}} + theEmitter->emitIns_R_PATTERN_I(INS_sve_uqincw, EA_SCALABLE, REG_V11, SVE_PATTERN_ALL, 16, + INS_OPTS_SCALABLE_S); // UQINCW .S{, {, MUL #}} + + // IF_SVE_BQ_2A + theEmitter->emitIns_R_R_I(INS_sve_ext, EA_SCALABLE, REG_V0, REG_V1, 0, INS_OPTS_SCALABLE_B, + INS_SCALABLE_OPTS_WITH_VECTOR_PAIR); // EXT .B, {.B, .B }, # + theEmitter->emitIns_R_R_I(INS_sve_ext, EA_SCALABLE, REG_V2, REG_V3, 5, INS_OPTS_SCALABLE_B, + INS_SCALABLE_OPTS_WITH_VECTOR_PAIR); // EXT .B, {.B, .B }, # + theEmitter->emitIns_R_R_I(INS_sve_ext, EA_SCALABLE, REG_V4, REG_V5, 128, INS_OPTS_SCALABLE_B, + INS_SCALABLE_OPTS_WITH_VECTOR_PAIR); // EXT .B, {.B, .B }, # + theEmitter->emitIns_R_R_I(INS_sve_ext, EA_SCALABLE, REG_V6, REG_FP_LAST, 255, INS_OPTS_SCALABLE_B, + INS_SCALABLE_OPTS_WITH_VECTOR_PAIR); // EXT .B, {.B, .B }, # + + // IF_SVE_BQ_2B + theEmitter->emitIns_R_R_I(INS_sve_ext, EA_SCALABLE, REG_V0, REG_V1, 0, + INS_OPTS_SCALABLE_B); // EXT .B, .B, .B, # + theEmitter->emitIns_R_R_I(INS_sve_ext, EA_SCALABLE, REG_V2, REG_V3, 31, + INS_OPTS_SCALABLE_B); // EXT .B, .B, .B, # + theEmitter->emitIns_R_R_I(INS_sve_ext, EA_SCALABLE, REG_V4, REG_V5, 64, + INS_OPTS_SCALABLE_B); // EXT .B, .B, .B, # + theEmitter->emitIns_R_R_I(INS_sve_ext, EA_SCALABLE, REG_V6, REG_V7, 255, + INS_OPTS_SCALABLE_B); // EXT .B, .B, .B, # + + // IF_SVE_BU_2A + theEmitter->emitIns_R_R_F(INS_sve_fcpy, EA_SCALABLE, REG_V0, REG_P1, 2.0, + INS_OPTS_SCALABLE_H); // FCPY ., /M, # + theEmitter->emitIns_R_R_F(INS_sve_fcpy, EA_SCALABLE, REG_V2, REG_P3, 1.0, + INS_OPTS_SCALABLE_S); // FCPY ., /M, # + theEmitter->emitIns_R_R_F(INS_sve_fcpy, EA_SCALABLE, REG_V4, REG_P5, -10.0, + INS_OPTS_SCALABLE_D); // FCPY ., /M, # + theEmitter->emitIns_R_R_F(INS_sve_fmov, EA_SCALABLE, REG_V6, REG_P7, -0.125, + INS_OPTS_SCALABLE_H); // FMOV ., /M, # + theEmitter->emitIns_R_R_F(INS_sve_fmov, EA_SCALABLE, REG_V8, REG_P9, 31.0, + INS_OPTS_SCALABLE_S); // FMOV ., /M, # + theEmitter->emitIns_R_R_F(INS_sve_fmov, EA_SCALABLE, REG_V10, REG_P11, 0.5, + INS_OPTS_SCALABLE_D); // FMOV ., /M, # + // IF_SVE_CI_3A theEmitter->emitIns_R_R_R(INS_sve_trn1, EA_SCALABLE, REG_P1, REG_P3, REG_P4, INS_OPTS_SCALABLE_B); // TRN1 ., ., . diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index f504f39e55b5d4..da8f4d55c66498 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -1146,13 +1146,43 @@ void emitter::emitInsSanityCheck(instrDesc* id) break; case IF_SVE_BN_1A: // ............iiii ......pppppddddd -- SVE inc/dec vector by element count + case IF_SVE_BP_1A: // ............iiii ......pppppddddd -- SVE saturating inc/dec vector by element count elemsize = id->idOpSize(); assert(insOptsScalableAtLeastHalf(id->idInsOpt())); assert(isVectorRegister(id->idReg1())); - assert(elemsize == EA_SCALABLE); + assert(isScalableVectorSize(elemsize)); + assert(isValidUimm4From1(emitGetInsSC(id))); + break; + + case IF_SVE_BO_1A: // ...........Xiiii ......pppppddddd -- SVE saturating inc/dec register by element count + elemsize = id->idOpSize(); + assert(id->idInsOpt() == INS_OPTS_NONE); + assert(isGeneralRegister(id->idReg1())); + assert(isValidGeneralDatasize(elemsize)); assert(isValidUimm4From1(emitGetInsSC(id))); break; + case IF_SVE_BQ_2A: // ...........iiiii ...iiinnnnnddddd -- SVE extract vector (immediate offset, destructive) + case IF_SVE_BQ_2B: // ...........iiiii ...iiimmmmmddddd -- SVE extract vector (immediate offset, destructive) + assert(id->idInsOpt() == INS_OPTS_SCALABLE_B); + assert(isVectorRegister(id->idReg1())); // ddddd + assert(isVectorRegister(id->idReg2())); // nnnnn + assert(isValidUimm8(emitGetInsSC(id))); // iiiii iii + break; + + case IF_SVE_BU_2A: // ........xx..gggg ...iiiiiiiiddddd -- SVE copy floating-point immediate (predicated) + { + imm = emitGetInsSC(id); + floatImm8 fpImm; + fpImm.immFPIVal = (unsigned)imm; + assert(insOptsScalableAtLeastHalf(id->idInsOpt())); + assert(isVectorRegister(id->idReg1())); // ddddd + assert(isValidSimm8((ssize_t)emitDecodeFloatImm8(fpImm))); // iiiiiiii + assert(isPredicateRegister(id->idReg2())); // gggg + assert(isValidVectorElemsize(optGetSveElemsize(id->idInsOpt()))); // xx + break; + } + case IF_SVE_BV_2A: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated) case IF_SVE_BV_2A_J: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated) assert(insOptsScalableStandard(id->idInsOpt())); // xx @@ -10341,6 +10371,23 @@ void emitter::emitIns_R_R_I(instruction ins, fmt = IF_SVE_FU_2A; break; + case INS_sve_ext: + assert(opt == INS_OPTS_SCALABLE_B); + assert(isVectorRegister(reg1)); // ddddd + assert(isVectorRegister(reg2)); // nnnnn + assert(isValidUimm8(imm)); // iiiii iii + + if (sopt == INS_SCALABLE_OPTS_WITH_VECTOR_PAIR) + { + fmt = IF_SVE_BQ_2A; + } + else + { + assert(insScalableOptsNone(sopt)); + fmt = IF_SVE_BQ_2B; + } + break; + case INS_sve_dupq: assert(insOptsScalableStandard(opt)); assert(insScalableOptsNone(sopt)); @@ -10575,6 +10622,22 @@ void emitter::emitIns_R_R_F( fmt = IF_SVE_HM_2A; break; + case INS_sve_fmov: + case INS_sve_fcpy: + assert(insOptsScalableAtLeastHalf(opt)); + assert(isVectorRegister(reg1)); // ddddd + assert(isPredicateRegister(reg2)); // gggg + assert(isValidVectorElemsize(optGetSveElemsize(opt))); // xx + floatImm8 fpi; + fpi.immFPIVal = 0; + canEncodeFloatImm8(immDbl, &fpi); + imm = fpi.immFPIVal; + fmt = IF_SVE_BU_2A; + + // FMOV is an alias for FCPY, and is always the preferred disassembly. + ins = INS_sve_fmov; + break; + default: unreached(); break; @@ -16532,8 +16595,7 @@ void emitter::emitIns_R_I_FLAGS_COND( void emitter::emitIns_R_PATTERN( instruction ins, emitAttr attr, regNumber reg1, insOpts opt, insSvePattern pattern /* = SVE_PATTERN_ALL*/) { - emitAttr elemsize = EA_UNKNOWN; - insFormat fmt = IF_NONE; + insFormat fmt = IF_NONE; /* Figure out the encoding format of the instruction */ switch (ins) @@ -16578,9 +16640,8 @@ void emitter::emitIns_R_PATTERN_I(instruction ins, ssize_t imm, insOpts opt /* = INS_OPTS_NONE */) { - emitAttr size = EA_SIZE(attr); - emitAttr elemsize = EA_UNKNOWN; - insFormat fmt = IF_NONE; + emitAttr size = EA_SIZE(attr); + insFormat fmt = IF_NONE; /* Figure out the encoding format of the instruction */ switch (ins) @@ -16626,6 +16687,46 @@ void emitter::emitIns_R_PATTERN_I(instruction ins, fmt = IF_SVE_BM_1A; break; + case INS_sve_sqincb: + case INS_sve_uqincb: + case INS_sve_sqdecb: + case INS_sve_uqdecb: + assert(insOptsNone(opt)); + assert(isGeneralRegister(reg1)); // ddddd + assert(isValidUimm4From1(imm)); // iiii + assert(isValidGeneralDatasize(size)); // X + fmt = IF_SVE_BO_1A; + break; + + case INS_sve_sqinch: + case INS_sve_uqinch: + case INS_sve_sqdech: + case INS_sve_uqdech: + case INS_sve_sqincw: + case INS_sve_uqincw: + case INS_sve_sqdecw: + case INS_sve_uqdecw: + case INS_sve_sqincd: + case INS_sve_uqincd: + case INS_sve_sqdecd: + case INS_sve_uqdecd: + assert(isValidUimm4From1(imm)); // iiii + + if (insOptsNone(opt)) + { + assert(isGeneralRegister(reg1)); // ddddd + assert(isValidGeneralDatasize(size)); // X + fmt = IF_SVE_BO_1A; + } + else + { + assert(insOptsScalableAtLeastHalf(opt)); + assert(isVectorRegister(reg1)); // ddddd + assert(isScalableVectorSize(size)); + fmt = IF_SVE_BP_1A; + } + break; + default: unreached(); break; @@ -16638,6 +16739,7 @@ void emitter::emitIns_R_PATTERN_I(instruction ins, id->idIns(ins); id->idInsFmt(fmt); id->idInsOpt(opt); + id->idOpSize(size); id->idReg1(reg1); id->idSvePattern(pattern); @@ -16660,9 +16762,8 @@ void emitter::emitIns_PRFOP_R_R_R(instruction ins, insOpts opt /* = INS_OPTS_NONE */, insScalableOpts sopt /* = INS_SCALABLE_OPTS_NONE */) { - emitAttr size = EA_SIZE(attr); - emitAttr elemsize = EA_UNKNOWN; - insFormat fmt = IF_NONE; + emitAttr size = EA_SIZE(attr); + insFormat fmt = IF_NONE; /* Figure out the encoding format of the instruction */ switch (ins) @@ -16771,9 +16872,8 @@ void emitter::emitIns_PRFOP_R_R_I(instruction ins, int imm, insOpts opt /* = INS_OPTS_NONE */) { - emitAttr size = EA_SIZE(attr); - emitAttr elemsize = EA_UNKNOWN; - insFormat fmt = IF_NONE; + emitAttr size = EA_SIZE(attr); + insFormat fmt = IF_NONE; /* Figure out the encoding format of the instruction */ switch (ins) @@ -19512,6 +19612,28 @@ void emitter::emitIns_Call(EmitCallType callType, return 0; } +/***************************************************************************** + * + * Returns the encoding to select the 4/8 byte elemsize for an Arm64 Sve vector instruction + * This specifically encodes the field 'sz' at bit location '20'. + */ + +/*static*/ emitter::code_t emitter::insEncodeSveElemsize_sz_20(emitAttr size) +{ + switch (size) + { + case EA_4BYTE: + return 0; + + case EA_8BYTE: + return (1 << 20); + + default: + assert(!"Invalid insOpt for vector register"); + } + return 0; +} + /***************************************************************************** * * Returns the encoding to select the 4/8 byte elemsize for an Arm64 Sve vector instruction @@ -21924,6 +22046,17 @@ void emitter::emitIns_Call(EmitCallType callType, return (code_t)((imm & 0xFF) << 5); } +/***************************************************************************** + * + * Returns the encoding for the unsigned immediate value as 3-bits at bit locations '12-10'. + */ + +/*static*/ emitter::code_t emitter::insEncodeUimm3_12_to_10(ssize_t imm) +{ + assert(isValidUimm3(imm)); + return (code_t)imm << 10; +} + /***************************************************************************** * * Returns the encoding for the unsigned immediate value as 3-bits at bit locations '18-16'. @@ -24406,7 +24539,29 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) dst += emitOutput_Instr(dst, code); break; + case IF_SVE_BO_1A: // ...........Xiiii ......pppppddddd -- SVE saturating inc/dec register by element count + imm = emitGetInsSC(id); + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_Rd(id->idReg1()); // ddddd + code |= insEncodeSvePattern(id->idSvePattern()); // ppppp + code |= insEncodeUimm4From1_19_to_16(imm); // iiii + code |= insEncodeSveElemsize_sz_20(id->idOpSize()); // X + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_BQ_2A: // ...........iiiii ...iiinnnnnddddd -- SVE extract vector (immediate offset, destructive) + case IF_SVE_BQ_2B: // ...........iiiii ...iiimmmmmddddd -- SVE extract vector (immediate offset, destructive) + imm = emitGetInsSC(id); + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeReg_V_9_to_5(id->idReg2()); // nnnnn/mmmmm + code |= insEncodeUimm3_12_to_10(imm & 0b111); // iii + code |= insEncodeUimm5_20_to_16(imm >> 3); // iiiii + dst += emitOutput_Instr(dst, code); + break; + case IF_SVE_BN_1A: // ............iiii ......pppppddddd -- SVE inc/dec vector by element count + case IF_SVE_BP_1A: // ............iiii ......pppppddddd -- SVE saturating inc/dec vector by element count imm = emitGetInsSC(id); code = emitInsCodeSve(ins, fmt); code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd @@ -24415,6 +24570,16 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) dst += emitOutput_Instr(dst, code); break; + case IF_SVE_BU_2A: // ........xx..gggg ...iiiiiiiiddddd -- SVE copy floating-point immediate (predicated) + imm = emitGetInsSC(id); + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeImm8_12_to_5(imm); // iiiiiiii + code |= insEncodeReg_P_19_to_16(id->idReg2()); // gggg + code |= insEncodeElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + case IF_SVE_BV_2A: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated) case IF_SVE_BV_2A_J: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated) imm = emitGetInsSC(id); @@ -24424,6 +24589,7 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) code |= insEncodeImm8_12_to_5(imm); // iiiiiiii code |= (id->idOptionalShift() ? 0x2000 : 0); // h code |= insEncodeElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); break; case IF_SVE_CE_2A: // ................ ......nnnnn.DDDD -- SVE move predicate from vector @@ -28609,8 +28775,8 @@ void emitter::emitDispInsHelp( break; // {, {, MUL #}} - // {, {, MUL #}} case IF_SVE_BL_1A: // ............iiii ......pppppddddd -- SVE element count + // {, {, MUL #}} case IF_SVE_BM_1A: // ............iiii ......pppppddddd -- SVE inc/dec register by element count imm = emitGetInsSC(id); emitDispReg(id->idReg1(), size, true); // ddddd @@ -28618,7 +28784,7 @@ void emitter::emitDispInsHelp( if (imm > 1) { printf("mul "); - emitDispImm(emitGetInsSC(id), false, false); // iiii + emitDispImm(imm, false, false); // iiii } break; @@ -28626,14 +28792,75 @@ void emitter::emitDispInsHelp( // .H{, {, MUL #}} // .S{, {, MUL #}} case IF_SVE_BN_1A: // ............iiii ......pppppddddd -- SVE inc/dec vector by element count + case IF_SVE_BP_1A: // ............iiii ......pppppddddd -- SVE saturating inc/dec vector by element count imm = emitGetInsSC(id); emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd emitDispSvePattern(id->idSvePattern(), (imm > 1)); // ppppp if (imm > 1) { printf("mul "); - emitDispImm(emitGetInsSC(id), false, false); // iiii + emitDispImm(imm, false, false); // iiii + } + break; + + // , {, {, MUL #}} + // {, {, MUL #}} + // {, {, MUL #}} + case IF_SVE_BO_1A: // ...........Xiiii ......pppppddddd -- SVE saturating inc/dec register by element count + switch (id->idIns()) + { + case INS_sve_sqincb: + case INS_sve_sqdecb: + case INS_sve_sqinch: + case INS_sve_sqdech: + case INS_sve_sqincw: + case INS_sve_sqdecw: + case INS_sve_sqincd: + case INS_sve_sqdecd: + emitDispReg(id->idReg1(), EA_8BYTE, true); // ddddd + + if (size == EA_4BYTE) + { + emitDispReg(id->idReg1(), EA_4BYTE, true); + } + break; + + default: + emitDispReg(id->idReg1(), size, true); // ddddd + break; } + + imm = emitGetInsSC(id); + emitDispSvePattern(id->idSvePattern(), (imm > 1)); // ppppp + if (imm > 1) + { + printf("mul "); + emitDispImm(imm, false, false); // iiii + } + break; + + // .B, {.B, .B }, # + case IF_SVE_BQ_2A: // ...........iiiii ...iiinnnnnddddd -- SVE extract vector (immediate offset, destructive) + imm = emitGetInsSC(id); + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd + emitDispVectorRegList(id->idReg2(), 2, id->idInsOpt(), true); // nnnnn + emitDispImm(imm, false); // iiiii iii + break; + + // .B, .B, .B, # + case IF_SVE_BQ_2B: // ...........iiiii ...iiimmmmmddddd -- SVE extract vector (immediate offset, destructive) + imm = emitGetInsSC(id); + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispSveReg(id->idReg2(), id->idInsOpt(), true); // mmmmm + emitDispImm(imm, false); // iiiii iii + break; + + // ., /M, # + case IF_SVE_BU_2A: // ........xx..gggg ...iiiiiiiiddddd -- SVE copy floating-point immediate (predicated) + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd + emitDispPredicateReg(id->idReg2(), insGetPredicateType(id->idInsFmt()), INS_OPTS_NONE, true); // gggg + emitDispFloatImm(emitGetInsSC(id)); // iiiiiiii break; // ., ., .D @@ -32606,6 +32833,11 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case IF_SVE_BL_1A: // ............iiii ......pppppddddd -- SVE element count case IF_SVE_BM_1A: // ............iiii ......pppppddddd -- SVE inc/dec register by element count case IF_SVE_BN_1A: // ............iiii ......pppppddddd -- SVE inc/dec vector by element count + case IF_SVE_BO_1A: // ...........Xiiii ......pppppddddd -- SVE saturating inc/dec register by element count + case IF_SVE_BP_1A: // ............iiii ......pppppddddd -- SVE saturating inc/dec vector by element count + case IF_SVE_BQ_2A: // ...........iiiii ...iiinnnnnddddd -- SVE extract vector (immediate offset, destructive) + case IF_SVE_BQ_2B: // ...........iiiii ...iiimmmmmddddd -- SVE extract vector (immediate offset, destructive) + case IF_SVE_BU_2A: // ........xx..gggg ...iiiiiiiiddddd -- SVE copy floating-point immediate (predicated) result.insThroughput = PERFSCORE_THROUGHPUT_2C; result.insLatency = PERFSCORE_LATENCY_2C; break; diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 114f7b678a6b79..d5e2d24577016f 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -530,6 +530,10 @@ static code_t insEncodeSveElemsize_22_to_21(emitAttr size); // This specifically encodes the size at bit locations '18-17'. static code_t insEncodeSveElemsize_18_to_17(emitAttr size); +// Returns the encoding to select the 4/8 byte elemsize for an Arm64 Sve vector instruction +// This specifically encodes the field 'sz' at bit location '20'. +static code_t insEncodeSveElemsize_sz_20(emitAttr size); + // Returns the encoding to select the 4/8 byte elemsize for an Arm64 Sve vector instruction // This specifically encodes the field 'sz' at bit location '21'. static code_t insEncodeSveElemsize_sz_21(emitAttr size); @@ -738,6 +742,9 @@ static code_t insEncodeUimm6_21_to_16(ssize_t imm); // Returns the encoding for the immediate value as 8-bits at bit locations '12-5'. static code_t insEncodeImm8_12_to_5(ssize_t imm); +// Returns the encoding for the unsigned immediate value as 3-bits at bit locations '12-10'. +static code_t insEncodeUimm3_12_to_10(ssize_t imm); + // Returns the encoding for the unsigned immediate value as 3-bits at bit locations '18-16'. static code_t insEncodeUimm3_18_to_16(ssize_t imm);