From d8af5cd93d0ed714805334ad50f961a8577336de Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Tue, 19 Dec 2023 15:23:12 -0500 Subject: [PATCH 01/10] Add IF_SVE_DT_3A/IF_SVE_DU_3A/IF_SVE_DX_3A/IF_SVE_DY_3A --- src/coreclr/jit/codegenarm64test.cpp | 104 ++++++++++++++ src/coreclr/jit/emitarm64.cpp | 201 ++++++++++++++++++++++++++- src/coreclr/jit/emitarm64.h | 27 +++- src/coreclr/jit/instr.h | 14 ++ 4 files changed, 340 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp index 7c0856775a7b6e..04a825e40f1a95 100644 --- a/src/coreclr/jit/codegenarm64test.cpp +++ b/src/coreclr/jit/codegenarm64test.cpp @@ -5360,6 +5360,110 @@ void CodeGen::genArm64EmitterUnitTestsSve() INS_OPTS_SCALABLE_H); /* FRECPX ., /M, . */ theEmitter->emitIns_R_R_R(INS_sve_fsqrt, EA_SCALABLE, REG_V6, REG_P6, REG_V6, INS_OPTS_SCALABLE_S); /* FSQRT ., /M, . */ + + // IF_SVE_DT_3A + theEmitter->emitIns_R_R_R(INS_sve_whilege, EA_4BYTE, REG_P0, REG_R0, REG_R1, + INS_OPTS_SCALABLE_B_WITH_SCALAR); // WHILEGE ., , + theEmitter->emitIns_R_R_R(INS_sve_whilege, EA_8BYTE, REG_P1, REG_R2, REG_R3, + INS_OPTS_SCALABLE_B_WITH_SCALAR); // WHILEGE ., , + theEmitter->emitIns_R_R_R(INS_sve_whilegt, EA_4BYTE, REG_P2, REG_R4, REG_R5, + INS_OPTS_SCALABLE_B_WITH_SCALAR); // WHILEGT ., , + theEmitter->emitIns_R_R_R(INS_sve_whilegt, EA_8BYTE, REG_P3, REG_R6, REG_R7, + INS_OPTS_SCALABLE_B_WITH_SCALAR); // WHILEGT ., , + theEmitter->emitIns_R_R_R(INS_sve_whilehi, EA_4BYTE, REG_P4, REG_R8, REG_R9, + INS_OPTS_SCALABLE_H_WITH_SCALAR); // WHILEHI ., , + theEmitter->emitIns_R_R_R(INS_sve_whilehi, EA_8BYTE, REG_P5, REG_R10, REG_R11, + INS_OPTS_SCALABLE_H_WITH_SCALAR); // WHILEHI ., , + theEmitter->emitIns_R_R_R(INS_sve_whilehs, EA_4BYTE, REG_P6, REG_R12, REG_R13, + INS_OPTS_SCALABLE_H_WITH_SCALAR); // WHILEHS ., , + theEmitter->emitIns_R_R_R(INS_sve_whilehs, EA_8BYTE, REG_P7, REG_R14, REG_R15, + INS_OPTS_SCALABLE_H_WITH_SCALAR); // WHILEHS ., , + theEmitter->emitIns_R_R_R(INS_sve_whilele, EA_4BYTE, REG_P8, REG_R0, REG_R1, + INS_OPTS_SCALABLE_S_WITH_SCALAR); // WHILELE ., , + theEmitter->emitIns_R_R_R(INS_sve_whilele, EA_8BYTE, REG_P9, REG_R2, REG_R3, + INS_OPTS_SCALABLE_S_WITH_SCALAR); // WHILELE ., , + theEmitter->emitIns_R_R_R(INS_sve_whilelo, EA_4BYTE, REG_P10, REG_R4, REG_R5, + INS_OPTS_SCALABLE_S_WITH_SCALAR); // WHILELO ., , + theEmitter->emitIns_R_R_R(INS_sve_whilelo, EA_8BYTE, REG_P11, REG_R6, REG_R7, + INS_OPTS_SCALABLE_S_WITH_SCALAR); // WHILELO ., , + theEmitter->emitIns_R_R_R(INS_sve_whilels, EA_4BYTE, REG_P12, REG_R8, REG_R9, + INS_OPTS_SCALABLE_D_WITH_SCALAR); // WHILELS ., , + theEmitter->emitIns_R_R_R(INS_sve_whilels, EA_8BYTE, REG_P13, REG_R10, REG_R11, + INS_OPTS_SCALABLE_D_WITH_SCALAR); // WHILELS ., , + theEmitter->emitIns_R_R_R(INS_sve_whilelt, EA_4BYTE, REG_P14, REG_R12, REG_R13, + INS_OPTS_SCALABLE_D_WITH_SCALAR); // WHILELT ., , + theEmitter->emitIns_R_R_R(INS_sve_whilelt, EA_8BYTE, REG_P15, REG_R14, REG_R15, + INS_OPTS_SCALABLE_D_WITH_SCALAR); // WHILELT ., , + + // IF_SVE_DU_3A + theEmitter->emitIns_R_R_R(INS_sve_whilerw, EA_8BYTE, REG_P0, REG_R0, REG_R1, + INS_OPTS_SCALABLE_B_WITH_SCALAR); // WHILERW ., , + theEmitter->emitIns_R_R_R(INS_sve_whilerw, EA_8BYTE, REG_P1, REG_R2, REG_R3, + INS_OPTS_SCALABLE_H_WITH_SCALAR); // WHILERW ., , + theEmitter->emitIns_R_R_R(INS_sve_whilerw, EA_8BYTE, REG_P2, REG_R4, REG_R5, + INS_OPTS_SCALABLE_S_WITH_SCALAR); // WHILERW ., , + theEmitter->emitIns_R_R_R(INS_sve_whilerw, EA_8BYTE, REG_P3, REG_R6, REG_R7, + INS_OPTS_SCALABLE_D_WITH_SCALAR); // WHILERW ., , + theEmitter->emitIns_R_R_R(INS_sve_whilewr, EA_8BYTE, REG_P4, REG_R8, REG_R9, + INS_OPTS_SCALABLE_B_WITH_SCALAR); // WHILEWR ., , + theEmitter->emitIns_R_R_R(INS_sve_whilewr, EA_8BYTE, REG_P5, REG_R10, REG_R11, + INS_OPTS_SCALABLE_H_WITH_SCALAR); // WHILEWR ., , + theEmitter->emitIns_R_R_R(INS_sve_whilewr, EA_8BYTE, REG_P6, REG_R12, REG_R13, + INS_OPTS_SCALABLE_S_WITH_SCALAR); // WHILEWR ., , + theEmitter->emitIns_R_R_R(INS_sve_whilewr, EA_8BYTE, REG_P7, REG_R14, REG_R15, + INS_OPTS_SCALABLE_D_WITH_SCALAR); // WHILEWR ., , + + // IF_SVE_DX_3A + theEmitter->emitIns_R_R_R(INS_sve_whilege, EA_8BYTE, REG_P0, REG_R0, REG_R1, + INS_OPTS_SCALABLE_B_WITH_PREDICATE_PAIR); // WHILEGE {., .}, , + theEmitter->emitIns_R_R_R(INS_sve_whilegt, EA_8BYTE, REG_P1, REG_R2, REG_R3, + INS_OPTS_SCALABLE_B_WITH_PREDICATE_PAIR); // WHILEGT {., .}, , + theEmitter->emitIns_R_R_R(INS_sve_whilehi, EA_8BYTE, REG_P2, REG_R4, REG_R5, + INS_OPTS_SCALABLE_H_WITH_PREDICATE_PAIR); // WHILEHI {., .}, , + theEmitter->emitIns_R_R_R(INS_sve_whilehs, EA_8BYTE, REG_P3, REG_R6, REG_R7, + INS_OPTS_SCALABLE_H_WITH_PREDICATE_PAIR); // WHILEHS {., .}, , + theEmitter->emitIns_R_R_R(INS_sve_whilele, EA_8BYTE, REG_P4, REG_R8, REG_R9, + INS_OPTS_SCALABLE_S_WITH_PREDICATE_PAIR); // WHILELE {., .}, , + theEmitter->emitIns_R_R_R(INS_sve_whilelo, EA_8BYTE, REG_P5, REG_R10, REG_R11, + INS_OPTS_SCALABLE_S_WITH_PREDICATE_PAIR); // WHILELO {., .}, , + theEmitter->emitIns_R_R_R(INS_sve_whilels, EA_8BYTE, REG_P6, REG_R12, REG_R13, + INS_OPTS_SCALABLE_D_WITH_PREDICATE_PAIR); // WHILELS {., .}, , + theEmitter->emitIns_R_R_R(INS_sve_whilelt, EA_8BYTE, REG_P7, REG_R14, REG_R15, + INS_OPTS_SCALABLE_D_WITH_PREDICATE_PAIR); // WHILELT {., .}, , + + // // IF_SVE_DY_3A + theEmitter->emitIns_R_R_R(INS_sve_whilege, EA_8BYTE, REG_P8, REG_R0, REG_R1, + INS_OPTS_SCALABLE_B_VL_2X); // WHILEGE ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilege, EA_8BYTE, REG_P9, REG_R2, REG_R3, + INS_OPTS_SCALABLE_B_VL_4X); // WHILEGE ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilegt, EA_8BYTE, REG_P10, REG_R4, REG_R5, + INS_OPTS_SCALABLE_H_VL_2X); // WHILEGT ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilegt, EA_8BYTE, REG_P11, REG_R6, REG_R7, + INS_OPTS_SCALABLE_H_VL_4X); // WHILEGT ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilehi, EA_8BYTE, REG_P12, REG_R8, REG_R9, + INS_OPTS_SCALABLE_S_VL_2X); // WHILEHI ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilehi, EA_8BYTE, REG_P13, REG_R10, REG_R11, + INS_OPTS_SCALABLE_S_VL_4X); // WHILEHI ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilehs, EA_8BYTE, REG_P14, REG_R12, REG_R13, + INS_OPTS_SCALABLE_D_VL_2X); // WHILEHS ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilehs, EA_8BYTE, REG_P15, REG_R14, REG_R15, + INS_OPTS_SCALABLE_D_VL_4X); // WHILEHS ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilele, EA_8BYTE, REG_P8, REG_R0, REG_R1, + INS_OPTS_SCALABLE_B_VL_2X); // WHILELE ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilele, EA_8BYTE, REG_P9, REG_R2, REG_R3, + INS_OPTS_SCALABLE_B_VL_4X); // WHILELE ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilelo, EA_8BYTE, REG_P10, REG_R4, REG_R5, + INS_OPTS_SCALABLE_H_VL_2X); // WHILELO ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilelo, EA_8BYTE, REG_P11, REG_R6, REG_R7, + INS_OPTS_SCALABLE_H_VL_4X); // WHILELO ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilels, EA_8BYTE, REG_P12, REG_R8, REG_R9, + INS_OPTS_SCALABLE_D_VL_2X); // WHILELS ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilels, EA_8BYTE, REG_P13, REG_R10, REG_R11, + INS_OPTS_SCALABLE_D_VL_4X); // WHILELS ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilelt, EA_8BYTE, REG_P14, REG_R12, REG_R13, + INS_OPTS_SCALABLE_B_VL_2X); // WHILELT ., , , + theEmitter->emitIns_R_R_R(INS_sve_whilelt, EA_8BYTE, REG_P15, REG_R14, REG_R15, + INS_OPTS_SCALABLE_B_VL_4X); // WHILELT ., , , } #endif // defined(TARGET_ARM64) && defined(DEBUG) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 594b9e67e69652..f85a552560aebb 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -1256,6 +1256,37 @@ void emitter::emitInsSanityCheck(instrDesc* id) assert(isScalableVectorSize(elemsize)); break; + case IF_SVE_DU_3A: // ........xx.mmmmm ......nnnnn.DDDD -- SVE pointer conflict compare + assert(id->idOpSize() == EA_8BYTE); + + FALLTHROUGH; + case IF_SVE_DT_3A: // ........xx.mmmmm ...X..nnnnn.DDDD -- SVE integer compare scalar count and limit + assert(insOptsScalableWithScalar(id->idInsOpt())); + assert(isPredicateRegister(id->idReg1())); // DDDD + assert(isGeneralRegister(id->idReg2())); // nnnnn + assert(isValidGeneralDatasize(id->idOpSize())); // X + assert(isGeneralRegister(id->idReg3())); // mmmmm + assert(isValidVectorElemsize(optGetSveElemsize(id->idInsOpt()))); // xx + break; + + case IF_SVE_DX_3A: // ........xx.mmmmm ......nnnnn.DDD. -- SVE integer compare scalar count and limit (predicate + // pair) + assert(insOptsScalableWithPredicatePair(id->idInsOpt())); + assert(isLowPredicateRegister(id->idReg1())); // DDD + assert(isGeneralRegister(id->idReg2())); // nnnnn + assert(isGeneralRegister(id->idReg3())); // mmmmm + assert(isValidVectorElemsize(optGetSveElemsize(id->idInsOpt()))); // xx + break; + + case IF_SVE_DY_3A: // ........xx.mmmmm ..l...nnnnn..DDD -- SVE integer compare scalar count and limit + // (predicate-as-counter) + assert(insOptsScalableWithVectorLength(id->idInsOpt())); // L + assert(isHighPredicateRegister(id->idReg1())); // DDD + assert(isGeneralRegister(id->idReg2())); // nnnnn + assert(isGeneralRegister(id->idReg3())); // mmmmm + assert(isValidVectorElemsize(optGetSveElemsize(id->idInsOpt()))); // xx + break; + default: printf("unexpected format %s\n", emitIfName(id->idInsFmt())); assert(!"Unexpected format"); @@ -5342,6 +5373,9 @@ emitter::code_t emitter::emitInsCodeSve(instruction ins, insFormat fmt) case INS_OPTS_SCALABLE_B_WITH_SIMD_VECTOR: case INS_OPTS_SCALABLE_B_WITH_SCALAR: case INS_OPTS_SCALABLE_B_WITH_PREDICATE_MERGE: + case INS_OPTS_SCALABLE_B_WITH_PREDICATE_PAIR: + case INS_OPTS_SCALABLE_B_VL_2X: + case INS_OPTS_SCALABLE_B_VL_4X: return EA_1BYTE; case INS_OPTS_SCALABLE_H: @@ -5350,6 +5384,9 @@ emitter::code_t emitter::emitInsCodeSve(instruction ins, insFormat fmt) case INS_OPTS_SCALABLE_H_WITH_SIMD_VECTOR: case INS_OPTS_SCALABLE_H_WITH_SCALAR: case INS_OPTS_SCALABLE_H_WITH_PREDICATE_MERGE: + case INS_OPTS_SCALABLE_H_WITH_PREDICATE_PAIR: + case INS_OPTS_SCALABLE_H_VL_2X: + case INS_OPTS_SCALABLE_H_VL_4X: return EA_2BYTE; case INS_OPTS_SCALABLE_S: @@ -5358,6 +5395,9 @@ emitter::code_t emitter::emitInsCodeSve(instruction ins, insFormat fmt) case INS_OPTS_SCALABLE_S_WITH_SIMD_VECTOR: case INS_OPTS_SCALABLE_S_WITH_SCALAR: case INS_OPTS_SCALABLE_S_WITH_PREDICATE_MERGE: + case INS_OPTS_SCALABLE_S_WITH_PREDICATE_PAIR: + case INS_OPTS_SCALABLE_S_VL_2X: + case INS_OPTS_SCALABLE_S_VL_4X: return EA_4BYTE; case INS_OPTS_SCALABLE_D: @@ -5365,6 +5405,9 @@ emitter::code_t emitter::emitInsCodeSve(instruction ins, insFormat fmt) case INS_OPTS_SCALABLE_D_WITH_SIMD_VECTOR: case INS_OPTS_SCALABLE_D_WITH_SCALAR: case INS_OPTS_SCALABLE_D_WITH_PREDICATE_MERGE: + case INS_OPTS_SCALABLE_D_WITH_PREDICATE_PAIR: + case INS_OPTS_SCALABLE_D_VL_2X: + case INS_OPTS_SCALABLE_D_VL_4X: return EA_8BYTE; default: @@ -9064,6 +9107,51 @@ void emitter::emitIns_R_R_R( fmt = IF_SVE_HR_3A; break; + case INS_sve_whilege: + case INS_sve_whilegt: + case INS_sve_whilelt: + case INS_sve_whilele: + case INS_sve_whilehs: + case INS_sve_whilehi: + case INS_sve_whilelo: + case INS_sve_whilels: + assert(isGeneralRegister(reg2)); // nnnnn + assert(isGeneralRegister(reg3)); // mmmmm + assert(isValidVectorElemsize(optGetSveElemsize(opt))); // xx + + if (insOptsScalableWithScalar(opt)) + { + assert(isPredicateRegister(reg1)); // DDDD + assert(isValidGeneralDatasize(size)); // X + fmt = IF_SVE_DT_3A; + } + else if (insOptsScalableWithPredicatePair(opt)) + { + assert(insOptsScalableWithPredicatePair(opt)); + assert(isLowPredicateRegister(reg1)); // DDD + assert(size == EA_8BYTE); + fmt = IF_SVE_DX_3A; + } + else + { + assert(insOptsScalableWithVectorLength(opt)); // l + assert(isHighPredicateRegister(reg1)); // DDD + assert(size == EA_8BYTE); + fmt = IF_SVE_DY_3A; + } + break; + + case INS_sve_whilewr: + case INS_sve_whilerw: + assert(insOptsScalableWithScalar(opt)); + assert(isPredicateRegister(reg1)); // DDDD + assert(isGeneralRegister(reg2)); // nnnnn + assert(size == EA_8BYTE); + assert(isGeneralRegister(reg3)); // mmmmm + assert(isValidVectorElemsize(optGetSveElemsize(opt))); // xx + fmt = IF_SVE_DU_3A; + break; + default: unreached(); break; @@ -12194,6 +12282,27 @@ void emitter::emitIns_Call(EmitCallType callType, } } +/***************************************************************************** + * + * Returns the encoding to set the vector length specifier (vl) for an Arm64 SVE instruction + */ + +/*static*/ emitter::code_t emitter::insEncodeVectorLengthSpecifier(insOpts opt) +{ + assert(insOptsScalableWithVectorLength(opt)); + + switch (opt) + { + case INS_OPTS_SCALABLE_B_VL_4X: + case INS_OPTS_SCALABLE_H_VL_4X: + case INS_OPTS_SCALABLE_S_VL_4X: + case INS_OPTS_SCALABLE_D_VL_4X: + return 0x2000; // set the bit at location 13 + default: + return 0; + } +} + /***************************************************************************** * * Returns the encoding to select 'index' for an Arm64 vector elem instruction @@ -14973,6 +15082,46 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) dst += emitOutput_Instr(dst, code); break; + case IF_SVE_DT_3A: // ........xx.mmmmm ...X..nnnnn.DDDD -- SVE integer compare scalar count and limit + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD + code |= insEncodeReg_R_9_to_5(id->idReg2()); // nnnnn + code |= (id->idOpSize() == EA_8BYTE) ? (1 << 12) : 0; // X + code |= insEncodeReg_R_20_to_16(id->idReg3()); // mmmmm + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_DX_3A: // ........xx.mmmmm ......nnnnn.DDD. -- SVE integer compare scalar count and limit (predicate + // pair) + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_P_3_to_1(id->idReg1()); // DDD + code |= insEncodeReg_R_9_to_5(id->idReg2()); // nnnnn + code |= insEncodeReg_R_20_to_16(id->idReg3()); // mmmmm + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_DY_3A: // ........xx.mmmmm ..l...nnnnn..DDD -- SVE integer compare scalar count and limit + // (predicate-as-counter) + code = emitInsCodeSve(ins, fmt); + code |= insEncodeVectorLengthSpecifier(id->idInsOpt()); // l + code |= insEncodeReg_P_2_to_0(id->idReg1()); // DDD + code |= insEncodeReg_R_9_to_5(id->idReg2()); // nnnnn + code |= insEncodeReg_R_20_to_16(id->idReg3()); // mmmmm + code |= insEncodeElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_DU_3A: // ........xx.mmmmm ......nnnnn.DDDD -- SVE pointer conflict compare + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD + code |= insEncodeReg_R_9_to_5(id->idReg2()); // nnnnn + code |= insEncodeReg_R_20_to_16(id->idReg3()); // mmmmm + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + default: assert(!"Unexpected format"); break; @@ -15584,6 +15733,21 @@ void emitter::emitDispLowPredicateReg(regNumber reg, PredicateType ptype, insOpt emitDispPredicateReg(reg, ptype, opt, addComma); } +//------------------------------------------------------------------------ +// emitDispLowPredicateRegPair: Display a pair of low predicate registers +// +void emitter::emitDispLowPredicateRegPair(regNumber reg, insOpts opt) +{ + assert(isLowPredicateRegister(reg)); + + printf("{ "); + const unsigned baseRegNum = ((unsigned)reg - REG_PREDICATE_FIRST) & 0x7; + const unsigned regNum = (baseRegNum * 2) + REG_PREDICATE_FIRST; + emitDispPredicateReg((regNumber)regNum, PREDICATE_SIZED, opt, true); + emitDispPredicateReg((regNumber)(regNum + 1), PREDICATE_SIZED, opt, false); + printf(" }, "); +} + //------------------------------------------------------------------------ // emitDispArrangement: Display a SIMD vector arrangement suffix // @@ -17433,6 +17597,31 @@ void emitter::emitDispInsHelp( emitDispSveReg(id->idReg1(), id->idInsOpt(), false); // ddddd break; + // ., , + case IF_SVE_DT_3A: // ........xx.mmmmm ...X..nnnnn.DDDD -- SVE integer compare scalar count and limit + // ., , + case IF_SVE_DU_3A: // ........xx.mmmmm ......nnnnn.DDDD -- SVE pointer conflict compare + emitDispPredicateReg(id->idReg1(), PREDICATE_SIZED, id->idInsOpt(), true); // DDDD + emitDispReg(id->idReg2(), id->idOpSize(), true); // nnnnn + emitDispReg(id->idReg3(), id->idOpSize(), false); // mmmmm + break; + + // {., .}, , + case IF_SVE_DX_3A: // ........xx.mmmmm ......nnnnn.DDD. -- SVE integer compare scalar count and limit (predicate + // pair) + emitDispLowPredicateRegPair(id->idReg1(), id->idInsOpt()); + emitDispReg(id->idReg2(), id->idOpSize(), true); // nnnnn + emitDispReg(id->idReg3(), id->idOpSize(), false); // mmmmm + break; + + // ., , , + case IF_SVE_DY_3A: // ........xx.mmmmm ..l...nnnnn..DDD -- SVE integer compare scalar count and limit + // (predicate-as-counter) + emitDispPredicateReg(id->idReg1(), PREDICATE_SIZED, id->idInsOpt(), true); // DDD + emitDispReg(id->idReg2(), id->idOpSize(), true); // nnnnn + emitDispReg(id->idReg3(), id->idOpSize(), true); // mmmmm + break; + default: printf("unexpected format %s", emitIfName(id->idInsFmt())); assert(!"unexpectedFormat"); @@ -19965,13 +20154,19 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins break; case IF_SVE_GK_2A: // ................ ......mmmmmddddd -- SVE2 crypto destructive binary operations + case IF_SVE_GL_1A: // ................ ...........ddddd -- SVE2 crypto unary operations result.insThroughput = PERFSCORE_THROUGHPUT_2C; result.insLatency = PERFSCORE_LATENCY_2C; break; - case IF_SVE_GL_1A: // ................ ...........ddddd -- SVE2 crypto unary operations - result.insThroughput = PERFSCORE_THROUGHPUT_2C; - result.insLatency = PERFSCORE_LATENCY_2C; + case IF_SVE_DT_3A: // ........xx.mmmmm ...X..nnnnn.DDDD -- SVE integer compare scalar count and limit + case IF_SVE_DX_3A: // ........xx.mmmmm ......nnnnn.DDD. -- SVE integer compare scalar count and limit (predicate + // pair) + case IF_SVE_DY_3A: // ........xx.mmmmm ..l...nnnnn..DDD -- SVE integer compare scalar count and limit + // (predicate-as-counter) + case IF_SVE_DU_3A: // ........xx.mmmmm ......nnnnn.DDDD -- SVE pointer conflict compare + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_3C; break; default: diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index b7a776c6691e43..f99da4172ed4b5 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -56,6 +56,7 @@ void emitDispVectorElemList(regNumber firstReg, unsigned listSize, emitAttr elem void emitDispSveRegList(regNumber firstReg, unsigned listSize, insOpts opt, bool addComma); void emitDispPredicateReg(regNumber reg, PredicateType ptype, insOpts opt, bool addComma); void emitDispLowPredicateReg(regNumber reg, PredicateType ptype, insOpts opt, bool addComma); +void emitDispLowPredicateRegPair(regNumber reg, insOpts opt); void emitDispArrangement(insOpts opt); void emitDispElemsize(emitAttr elemsize); void emitDispShiftedReg(regNumber reg, insOpts opt, ssize_t imm, emitAttr attr); @@ -418,6 +419,9 @@ static code_t insEncodeDatasizeBF(code_t code, emitAttr size); // Returns the encoding to select the vectorsize for SIMD Arm64 instructions static code_t insEncodeVectorsize(emitAttr size); +// Returns the encoding to set the vector length specifier (vl) for an Arm64 SVE instruction +static code_t insEncodeVectorLengthSpecifier(insOpts opt); + // Returns the encoding to select 'index' for an Arm64 vector elem instruction static code_t insEncodeVectorIndex(emitAttr elemsize, ssize_t index); @@ -789,12 +793,17 @@ inline static bool isFloatReg(regNumber reg) inline static bool isPredicateRegister(regNumber reg) { - return (reg >= REG_PREDICATE_FIRST && reg <= REG_PREDICATE_LAST); + return (reg >= REG_PREDICATE_FIRST) && (reg <= REG_PREDICATE_LAST); } inline static bool isLowPredicateRegister(regNumber reg) { - return (reg >= REG_PREDICATE_FIRST && reg <= REG_PREDICATE_LOW_LAST); + return (reg >= REG_PREDICATE_FIRST) && (reg <= REG_PREDICATE_LOW_LAST); +} + +inline static bool isHighPredicateRegister(regNumber reg) +{ + return (reg > REG_PREDICATE_LOW_LAST) && (reg <= REG_PREDICATE_LAST); } inline static bool insOptsNone(insOpts opt) @@ -898,7 +907,7 @@ inline static bool insOptsScalable(insOpts opt) // Opt is any of the scalable types. return ((insOptsScalableSimple(opt)) || (insOptsScalableWide(opt)) || (insOptsScalableWithSimdScalar(opt)) || (insOptsScalableWithScalar(opt)) || (insOptsScalableWithSimdVector(opt)) || - insOptsScalableWithPredicateMerge(opt)); + insOptsScalableWithPredicateMerge(opt) || insOptsScalableWithPredicatePair(opt)); } inline static bool insOptsScalableSimple(insOpts opt) @@ -975,6 +984,18 @@ inline static bool insOptsScalableWithPredicateMerge(insOpts opt) (opt == INS_OPTS_SCALABLE_S_WITH_PREDICATE_MERGE) || (opt == INS_OPTS_SCALABLE_D_WITH_PREDICATE_MERGE)); } +inline static bool insOptsScalableWithPredicatePair(insOpts opt) +{ + // `opt` is any of the scalable types that are valid for use with a predicate pair. + return ((opt >= INS_OPTS_SCALABLE_B_WITH_PREDICATE_PAIR) && (opt <= INS_OPTS_SCALABLE_D_WITH_PREDICATE_PAIR)); +} + +inline static bool insOptsScalableWithVectorLength(insOpts opt) +{ + // `opt` is any of the scalable types that are valid for use with instructions with a vector length specifier (vl). + return ((opt >= INS_OPTS_SCALABLE_B_VL_2X) && (opt <= INS_OPTS_SCALABLE_D_VL_4X)); +} + static bool isValidImmCond(ssize_t imm); static bool isValidImmCondFlags(ssize_t imm); static bool isValidImmCondFlagsImm5(ssize_t imm); diff --git a/src/coreclr/jit/instr.h b/src/coreclr/jit/instr.h index 0bf6cded9f3d60..c0aeed88199c27 100644 --- a/src/coreclr/jit/instr.h +++ b/src/coreclr/jit/instr.h @@ -299,6 +299,20 @@ enum insOpts : unsigned INS_OPTS_SCALABLE_S_WITH_PREDICATE_MERGE, INS_OPTS_SCALABLE_D_WITH_PREDICATE_MERGE, + INS_OPTS_SCALABLE_B_WITH_PREDICATE_PAIR, + INS_OPTS_SCALABLE_H_WITH_PREDICATE_PAIR, + INS_OPTS_SCALABLE_S_WITH_PREDICATE_PAIR, + INS_OPTS_SCALABLE_D_WITH_PREDICATE_PAIR, + + INS_OPTS_SCALABLE_B_VL_2X, + INS_OPTS_SCALABLE_B_VL_4X, + INS_OPTS_SCALABLE_H_VL_2X, + INS_OPTS_SCALABLE_H_VL_4X, + INS_OPTS_SCALABLE_S_VL_2X, + INS_OPTS_SCALABLE_S_VL_4X, + INS_OPTS_SCALABLE_D_VL_2X, + INS_OPTS_SCALABLE_D_VL_4X, + INS_OPTS_MSL, // Vector Immediate (shifting ones variant) INS_OPTS_S_TO_4BYTE, // Single to INT32 From acb2677d68d42aff4c4be64afe956691cc68e545 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Tue, 19 Dec 2023 15:47:16 -0500 Subject: [PATCH 02/10] Print vl --- src/coreclr/jit/emitarm64.cpp | 22 ++++++++++++++++++++++ src/coreclr/jit/emitarm64.h | 1 + 2 files changed, 23 insertions(+) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 2ebd2faa094638..22464754ea9693 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -15809,6 +15809,27 @@ void emitter::emitDispLowPredicateRegPair(regNumber reg, insOpts opt) printf(" }, "); } +//------------------------------------------------------------------------ +// emitDispVectorLengthSpecifier: Display the vector length specifier +// +void emitter::emitDispVectorLengthSpecifier(insOpts opt) +{ + assert(insOptsScalableWithVectorLength(opt)); + + switch (opt) + { + case INS_OPTS_SCALABLE_B_VL_2X: + case INS_OPTS_SCALABLE_H_VL_2X: + case INS_OPTS_SCALABLE_S_VL_2X: + case INS_OPTS_SCALABLE_D_VL_2X: + printf("vlx2"); + break; + default: + printf("vlx4"); + break; + } +} + //------------------------------------------------------------------------ // emitDispArrangement: Display a SIMD vector arrangement suffix // @@ -17693,6 +17714,7 @@ void emitter::emitDispInsHelp( emitDispPredicateReg(id->idReg1(), PREDICATE_SIZED, id->idInsOpt(), true); // DDD emitDispReg(id->idReg2(), id->idOpSize(), true); // nnnnn emitDispReg(id->idReg3(), id->idOpSize(), true); // mmmmm + emitDispVectorLengthSpecifier(id->idInsOpt()); break; default: diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index f99da4172ed4b5..73bb032ffe9a52 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -57,6 +57,7 @@ void emitDispSveRegList(regNumber firstReg, unsigned listSize, insOpts opt, bool void emitDispPredicateReg(regNumber reg, PredicateType ptype, insOpts opt, bool addComma); void emitDispLowPredicateReg(regNumber reg, PredicateType ptype, insOpts opt, bool addComma); void emitDispLowPredicateRegPair(regNumber reg, insOpts opt); +void emitDispVectorLengthSpecifier(insOpts opt); void emitDispArrangement(insOpts opt); void emitDispElemsize(emitAttr elemsize); void emitDispShiftedReg(regNumber reg, insOpts opt, ssize_t imm, emitAttr attr); From 2c00381146b10bdf675ce89184262d80692e6d22 Mon Sep 17 00:00:00 2001 From: Aman Khalid Date: Tue, 19 Dec 2023 16:34:35 -0500 Subject: [PATCH 03/10] Add insOptsScalableWithVectorLength to insOptsScalable --- src/coreclr/jit/emitarm64.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 73bb032ffe9a52..a82cab4cf09eb1 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -906,9 +906,10 @@ inline static bool insOptsConvertIntToFloat(insOpts opt) inline static bool insOptsScalable(insOpts opt) { // Opt is any of the scalable types. - return ((insOptsScalableSimple(opt)) || (insOptsScalableWide(opt)) || (insOptsScalableWithSimdScalar(opt)) || - (insOptsScalableWithScalar(opt)) || (insOptsScalableWithSimdVector(opt)) || - insOptsScalableWithPredicateMerge(opt) || insOptsScalableWithPredicatePair(opt)); + return insOptsScalableSimple(opt) || insOptsScalableWide(opt) || insOptsScalableWithSimdScalar(opt) || + insOptsScalableWithScalar(opt) || insOptsScalableWithSimdVector(opt) || + insOptsScalableWithPredicateMerge(opt) || insOptsScalableWithPredicatePair(opt) || + insOptsScalableWithVectorLength(opt); } inline static bool insOptsScalableSimple(insOpts opt) From a8bcb13d82c73e7d5052517e48620702a5b9b69e Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Tue, 19 Dec 2023 16:40:35 -0500 Subject: [PATCH 04/10] Style --- src/coreclr/jit/emitarm64.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index a82cab4cf09eb1..d0f7ff8ac863c0 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -907,9 +907,9 @@ inline static bool insOptsScalable(insOpts opt) { // Opt is any of the scalable types. return insOptsScalableSimple(opt) || insOptsScalableWide(opt) || insOptsScalableWithSimdScalar(opt) || - insOptsScalableWithScalar(opt) || insOptsScalableWithSimdVector(opt) || - insOptsScalableWithPredicateMerge(opt) || insOptsScalableWithPredicatePair(opt) || - insOptsScalableWithVectorLength(opt); + insOptsScalableWithScalar(opt) || insOptsScalableWithSimdVector(opt) || + insOptsScalableWithPredicateMerge(opt) || insOptsScalableWithPredicatePair(opt) || + insOptsScalableWithVectorLength(opt); } inline static bool insOptsScalableSimple(insOpts opt) From d809682dac31fbb9176136f3d4df0822c2bbbf6a Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Wed, 20 Dec 2023 11:13:51 -0500 Subject: [PATCH 05/10] Fix insEncodeReg_P_2_to_0 --- src/coreclr/jit/emitarm64.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 22464754ea9693..69b52de0f2d8c5 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -12012,8 +12012,8 @@ void emitter::emitIns_Call(EmitCallType callType, { assert(isPredicateRegister(reg)); emitter::code_t ureg = (emitter::code_t)reg - (emitter::code_t)REG_P0; - assert((ureg >= 0) && (ureg <= 15)); - return ureg << 0; + assert((ureg >= 8) && (ureg <= 15)); + return (ureg - 8) << 0; } /***************************************************************************** From dc66c6e112c239e4c1cfcb37288b912ab09889b3 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Wed, 20 Dec 2023 15:07:24 -0500 Subject: [PATCH 06/10] Reset insOpts enum value for SVE formats --- src/coreclr/jit/emitarm64.cpp | 55 ++++++++++++++++++++++++++--------- src/coreclr/jit/emitarm64.h | 1 + src/coreclr/jit/instr.h | 4 ++- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 69b52de0f2d8c5..bf2597639591a9 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -15647,7 +15647,7 @@ void emitter::emitDispSveReg(regNumber reg, insOpts opt, bool addComma) assert(insOptsScalable(opt)); assert(isVectorRegister(reg)); printf(emitSveRegName(reg)); - emitDispArrangement(opt); + emitDispSveArrangement(opt); if (addComma) emitDispComma(); @@ -15835,6 +15835,7 @@ void emitter::emitDispVectorLengthSpecifier(insOpts opt) // void emitter::emitDispArrangement(insOpts opt) { + assert(!insOptsScalable(opt)); const char* str = "???"; switch (opt) @@ -15843,6 +15844,44 @@ void emitter::emitDispArrangement(insOpts opt) str = "8b"; break; case INS_OPTS_16B: + str = "16b"; + break; + case INS_OPTS_4H: + str = "4h"; + break; + case INS_OPTS_8H: + str = "8h"; + break; + case INS_OPTS_2S: + str = "2s"; + break; + case INS_OPTS_4S: + str = "4s"; + break; + case INS_OPTS_1D: + str = "1d"; + break; + case INS_OPTS_2D: + str = "2d"; + break; + + default: + assert(!"Invalid insOpt for vector register"); + } + printf("."); + printf(str); +} + +//------------------------------------------------------------------------ +// emitDispSveArrangement: Display a SVE register arrangement suffix +// +void emitter::emitDispSveArrangement(insOpts opt) +{ + assert(insOptsScalable(opt)); + const char* str = "???"; + + switch (opt) + { case INS_OPTS_SCALABLE_B_WITH_SIMD_VECTOR: str = "16b"; break; @@ -15853,10 +15892,6 @@ void emitter::emitDispArrangement(insOpts opt) case INS_OPTS_SCALABLE_B_WITH_PREDICATE_MERGE: str = "b"; break; - case INS_OPTS_4H: - str = "4h"; - break; - case INS_OPTS_8H: case INS_OPTS_SCALABLE_H_WITH_SIMD_VECTOR: str = "8h"; break; @@ -15867,10 +15902,6 @@ void emitter::emitDispArrangement(insOpts opt) case INS_OPTS_SCALABLE_H_WITH_PREDICATE_MERGE: str = "h"; break; - case INS_OPTS_2S: - str = "2s"; - break; - case INS_OPTS_4S: case INS_OPTS_SCALABLE_S_WITH_SIMD_VECTOR: str = "4s"; break; @@ -15881,10 +15912,6 @@ void emitter::emitDispArrangement(insOpts opt) case INS_OPTS_SCALABLE_S_WITH_PREDICATE_MERGE: str = "s"; break; - case INS_OPTS_1D: - str = "1d"; - break; - case INS_OPTS_2D: case INS_OPTS_SCALABLE_D_WITH_SIMD_VECTOR: str = "2d"; break; @@ -15896,7 +15923,7 @@ void emitter::emitDispArrangement(insOpts opt) break; default: - assert(!"Invalid insOpt for vector register"); + assert(!"Invalid SVE insOpt"); } printf("."); printf(str); diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index d0f7ff8ac863c0..8bdc6321cfa97c 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -59,6 +59,7 @@ void emitDispLowPredicateReg(regNumber reg, PredicateType ptype, insOpts opt, bo void emitDispLowPredicateRegPair(regNumber reg, insOpts opt); void emitDispVectorLengthSpecifier(insOpts opt); void emitDispArrangement(insOpts opt); +void emitDispSveArrangement(insOpts opt); void emitDispElemsize(emitAttr elemsize); void emitDispShiftedReg(regNumber reg, insOpts opt, ssize_t imm, emitAttr attr); void emitDispExtendReg(regNumber reg, insOpts opt, ssize_t imm); diff --git a/src/coreclr/jit/instr.h b/src/coreclr/jit/instr.h index c0aeed88199c27..b2fea238e9810c 100644 --- a/src/coreclr/jit/instr.h +++ b/src/coreclr/jit/instr.h @@ -270,7 +270,9 @@ enum insOpts : unsigned INS_OPTS_1D, INS_OPTS_2D, - INS_OPTS_SCALABLE_B, + // There should be no overlap between non-SVE and SVE values, + // so reset value to 1 here + INS_OPTS_SCALABLE_B = 1, INS_OPTS_SCALABLE_H, INS_OPTS_SCALABLE_S, INS_OPTS_SCALABLE_D, From d259e773b73dd329a37840291dabd50b63917434 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Thu, 21 Dec 2023 11:28:46 -0500 Subject: [PATCH 07/10] Feedback --- src/coreclr/jit/codegenarm64test.cpp | 2 +- src/coreclr/jit/emitarm64.h | 2 +- src/coreclr/jit/instr.h | 54 ++++++++++++++-------------- src/coreclr/jit/targetarm64.h | 4 +++ 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp index 2fd77cbec0f9ba..ec2631bdfc2a35 100644 --- a/src/coreclr/jit/codegenarm64test.cpp +++ b/src/coreclr/jit/codegenarm64test.cpp @@ -5371,7 +5371,7 @@ void CodeGen::genArm64EmitterUnitTestsSve() theEmitter->emitIns_R_R_R(INS_sve_frecpx, EA_SCALABLE, REG_V5, REG_P5, REG_V5, INS_OPTS_SCALABLE_H); // FRECPX ., /M, . theEmitter->emitIns_R_R_R(INS_sve_fsqrt, EA_SCALABLE, REG_V6, REG_P6, REG_V6, - INS_OPTS_SCALABLE_S); /* FSQRT ., /M, . */ + INS_OPTS_SCALABLE_S); // FSQRT ., /M, . // IF_SVE_DT_3A theEmitter->emitIns_R_R_R(INS_sve_whilege, EA_4BYTE, REG_P0, REG_R0, REG_R1, diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 8bdc6321cfa97c..ea6b4ef3b5f080 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -805,7 +805,7 @@ inline static bool isLowPredicateRegister(regNumber reg) inline static bool isHighPredicateRegister(regNumber reg) { - return (reg > REG_PREDICATE_LOW_LAST) && (reg <= REG_PREDICATE_LAST); + return (reg >= REG_PREDICATE_HIGH_FIRST) && (reg <= REG_PREDICATE_HIGH_LAST); } inline static bool insOptsNone(insOpts opt) diff --git a/src/coreclr/jit/instr.h b/src/coreclr/jit/instr.h index b2fea238e9810c..a03f1245a2d7b7 100644 --- a/src/coreclr/jit/instr.h +++ b/src/coreclr/jit/instr.h @@ -270,6 +270,33 @@ enum insOpts : unsigned INS_OPTS_1D, INS_OPTS_2D, + INS_OPTS_MSL, // Vector Immediate (shifting ones variant) + + INS_OPTS_S_TO_4BYTE, // Single to INT32 + INS_OPTS_D_TO_4BYTE, // Double to INT32 + + INS_OPTS_S_TO_8BYTE, // Single to INT64 + INS_OPTS_D_TO_8BYTE, // Double to INT64 + + INS_OPTS_4BYTE_TO_S, // INT32 to Single + INS_OPTS_4BYTE_TO_D, // INT32 to Double + + INS_OPTS_8BYTE_TO_S, // INT64 to Single + INS_OPTS_8BYTE_TO_D, // INT64 to Double + + INS_OPTS_S_TO_D, // Single to Double + INS_OPTS_D_TO_S, // Double to Single + + INS_OPTS_H_TO_S, // Half to Single + INS_OPTS_H_TO_D, // Half to Double + + INS_OPTS_S_TO_H, // Single to Half + INS_OPTS_D_TO_H, // Double to Half + +#if FEATURE_LOOP_ALIGN + INS_OPTS_ALIGN, // Align instruction +#endif + // There should be no overlap between non-SVE and SVE values, // so reset value to 1 here INS_OPTS_SCALABLE_B = 1, @@ -314,33 +341,6 @@ enum insOpts : unsigned INS_OPTS_SCALABLE_S_VL_4X, INS_OPTS_SCALABLE_D_VL_2X, INS_OPTS_SCALABLE_D_VL_4X, - - INS_OPTS_MSL, // Vector Immediate (shifting ones variant) - - INS_OPTS_S_TO_4BYTE, // Single to INT32 - INS_OPTS_D_TO_4BYTE, // Double to INT32 - - INS_OPTS_S_TO_8BYTE, // Single to INT64 - INS_OPTS_D_TO_8BYTE, // Double to INT64 - - INS_OPTS_4BYTE_TO_S, // INT32 to Single - INS_OPTS_4BYTE_TO_D, // INT32 to Double - - INS_OPTS_8BYTE_TO_S, // INT64 to Single - INS_OPTS_8BYTE_TO_D, // INT64 to Double - - INS_OPTS_S_TO_D, // Single to Double - INS_OPTS_D_TO_S, // Double to Single - - INS_OPTS_H_TO_S, // Half to Single - INS_OPTS_H_TO_D, // Half to Double - - INS_OPTS_S_TO_H, // Single to Half - INS_OPTS_D_TO_H // Double to Half - -#if FEATURE_LOOP_ALIGN - , INS_OPTS_ALIGN // Align instruction -#endif }; enum insCond : unsigned diff --git a/src/coreclr/jit/targetarm64.h b/src/coreclr/jit/targetarm64.h index 961862e5184d7e..3646ecb4407bf7 100644 --- a/src/coreclr/jit/targetarm64.h +++ b/src/coreclr/jit/targetarm64.h @@ -53,6 +53,10 @@ #define REG_PREDICATE_FIRST REG_P0 #define REG_PREDICATE_LAST REG_P15 #define REG_PREDICATE_LOW_LAST REG_P7 // Some instructions can only use the first half of the predicate registers. + #define REG_PREDICATE_HIGH_FIRST REG_P8 // Similarly, some instructions can only use the second half of the predicate registers. + #define REG_PREDICATE_HIGH_LAST REG_P15 + + static_assert_no_msg(REG_PREDICATE_HIGH_LAST == REG_PREDICATE_LAST); #define REGNUM_BITS 6 // number of bits in a REG_* #define REGSIZE_BYTES 8 // number of bytes in one general purpose register From 0202549348d9feb553ea0b1915894cfe565097c6 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Fri, 22 Dec 2023 11:58:45 -0500 Subject: [PATCH 08/10] Remove asserts --- src/coreclr/jit/emitarm64.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index bf2597639591a9..f68493e6674129 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -15835,7 +15835,6 @@ void emitter::emitDispVectorLengthSpecifier(insOpts opt) // void emitter::emitDispArrangement(insOpts opt) { - assert(!insOptsScalable(opt)); const char* str = "???"; switch (opt) @@ -15877,7 +15876,6 @@ void emitter::emitDispArrangement(insOpts opt) // void emitter::emitDispSveArrangement(insOpts opt) { - assert(insOptsScalable(opt)); const char* str = "???"; switch (opt) From f5d0fa0f825af37617eb9dc9f4daed89cfbba69e Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Fri, 12 Jan 2024 18:57:04 -0500 Subject: [PATCH 09/10] Fix typo --- src/coreclr/jit/emitarm64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index f0781d9f999b2c..749b5f63948341 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -1030,7 +1030,7 @@ inline static bool insScalableOptsWithPredicatePair(insScalableOpts sopt) inline static bool insScalableOptsWithVectorLength(insScalableOpts sopt) { // `sopt` is any of the scalable types that are valid for use with instructions with a vector length specifier (vl). - return ((sopt == INS_SCALABLE_OPTS_VL_2X) || (sopt <= INS_SCALABLE_OPTS_VL_4X)); + return ((sopt == INS_SCALABLE_OPTS_VL_2X) || (sopt == INS_SCALABLE_OPTS_VL_4X)); } static bool isValidImmCond(ssize_t imm); From 37715305353c0a0a2be42cd6219c10b07334aaf3 Mon Sep 17 00:00:00 2001 From: "Aman Khalid (from Dev Box)" Date: Mon, 15 Jan 2024 12:00:15 -0500 Subject: [PATCH 10/10] Feedback --- src/coreclr/jit/emitarm64.cpp | 1 + src/coreclr/jit/emitarm64.h | 2 ++ src/coreclr/jit/instr.h | 16 +++++++--------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index e649cbb4ccb248..feb0ddc39d31eb 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -16499,6 +16499,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) { code = insEncodeSveElemsize_dtype(ins, optGetSveElemsize(id->idInsOpt()), code); } + dst += emitOutput_Instr(dst, code); break; diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 749b5f63948341..de7b53805e2865 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -1019,11 +1019,13 @@ inline static bool insOptsScalableWide(insOpts opt) inline static bool insScalableOptsNone(insScalableOpts sopt) { + // `sopt` is used for instructions with no extra encoding variants. return sopt == INS_SCALABLE_OPTS_NONE; } inline static bool insScalableOptsWithPredicatePair(insScalableOpts sopt) { + // `sopt` denotes the instruction's predicate register should be encoded as a {., .} pair. return sopt == INS_SCALABLE_OPTS_WITH_PREDICATE_PAIR; } diff --git a/src/coreclr/jit/instr.h b/src/coreclr/jit/instr.h index 1c6797f7273fb2..a906ce2a5e440f 100644 --- a/src/coreclr/jit/instr.h +++ b/src/coreclr/jit/instr.h @@ -270,6 +270,12 @@ enum insOpts : unsigned INS_OPTS_1D, INS_OPTS_2D, + INS_OPTS_SCALABLE_B, + INS_OPTS_SCALABLE_H, + INS_OPTS_SCALABLE_S, + INS_OPTS_SCALABLE_D, + INS_OPTS_SCALABLE_Q, + INS_OPTS_MSL, // Vector Immediate (shifting ones variant) INS_OPTS_S_TO_4BYTE, // Single to INT32 @@ -294,16 +300,8 @@ enum insOpts : unsigned INS_OPTS_D_TO_H, // Double to Half #if FEATURE_LOOP_ALIGN - INS_OPTS_ALIGN, // Align instruction + INS_OPTS_ALIGN // Align instruction #endif - - // There should be no overlap between non-SVE and SVE values, - // so reset value to 1 here - INS_OPTS_SCALABLE_B = 1, - INS_OPTS_SCALABLE_H, - INS_OPTS_SCALABLE_S, - INS_OPTS_SCALABLE_D, - INS_OPTS_SCALABLE_Q, }; // When a single instruction has different encodings variants, this is used