From a299d6056264a1d7b4ae8bf5685a2f57f4a4e9ea Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 6 Feb 2024 20:21:25 -0800 Subject: [PATCH 1/6] Added SVE_GP_3A, SVE_GT_4A, SVE_HI_3A, SVE_HM_2A formats --- src/coreclr/jit/codegenarm64test.cpp | 92 +++++ src/coreclr/jit/emitarm64.cpp | 544 ++++++++++++++++++++++++++- src/coreclr/jit/emitarm64.h | 24 ++ 3 files changed, 659 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp index ce46e75992096f..12ab5f777e77c4 100644 --- a/src/coreclr/jit/codegenarm64test.cpp +++ b/src/coreclr/jit/codegenarm64test.cpp @@ -6946,6 +6946,98 @@ void CodeGen::genArm64EmitterUnitTestsSve() // IF_SVE_JK_4B theEmitter->emitIns_R_R_R_R(INS_sve_st1b, EA_SCALABLE, REG_V6, REG_P3, REG_R0, REG_V4, INS_OPTS_SCALABLE_D); // ST1B {.D }, , [, .D] + + // IF_SVE_GP_3A + theEmitter->emitIns_R_R_R_I(INS_sve_fcadd, EA_SCALABLE, REG_V0, REG_P1, REG_V2, 90, + INS_OPTS_SCALABLE_H); // FCADD ., /M, ., ., + theEmitter->emitIns_R_R_R_I(INS_sve_fcadd, EA_SCALABLE, REG_V0, REG_P1, REG_V2, 270, + INS_OPTS_SCALABLE_H); // FCADD ., /M, ., ., + theEmitter->emitIns_R_R_R_I(INS_sve_fcadd, EA_SCALABLE, REG_V0, REG_P1, REG_V2, 270, + INS_OPTS_SCALABLE_S); // FCADD ., /M, ., ., + theEmitter->emitIns_R_R_R_I(INS_sve_fcadd, EA_SCALABLE, REG_V0, REG_P1, REG_V2, 270, + INS_OPTS_SCALABLE_D); // FCADD ., /M, ., ., + + // IF_SVE_GT_4A + theEmitter->emitIns_R_R_R_R_I(INS_sve_fcmla, EA_SCALABLE, REG_V2, REG_P1, REG_V3, REG_V4, 0, + INS_OPTS_SCALABLE_H); // FCMLA ., /M, ., ., + theEmitter->emitIns_R_R_R_R_I(INS_sve_fcmla, EA_SCALABLE, REG_V0, REG_P2, REG_V1, REG_V5, 90, + INS_OPTS_SCALABLE_S); // FCMLA ., /M, ., ., + theEmitter->emitIns_R_R_R_R_I(INS_sve_fcmla, EA_SCALABLE, REG_V2, REG_P3, REG_V0, REG_V6, 180, + INS_OPTS_SCALABLE_D); // FCMLA ., /M, ., ., + theEmitter->emitIns_R_R_R_R_I(INS_sve_fcmla, EA_SCALABLE, REG_V2, REG_P3, REG_V0, REG_V6, 270, + INS_OPTS_SCALABLE_D); // FCMLA ., /M, ., ., + + // IF_SVE_HI_3A + theEmitter->emitIns_R_R_R(INS_sve_fcmeq, EA_SCALABLE, REG_P2, REG_P3, REG_V4, + INS_OPTS_SCALABLE_H); // FCMEQ ., /Z, ., #0.0 + theEmitter->emitIns_R_R_R(INS_sve_fcmge, EA_SCALABLE, REG_P1, REG_P2, REG_V3, + INS_OPTS_SCALABLE_S); // FCMGE ., /Z, ., #0.0 + theEmitter->emitIns_R_R_R(INS_sve_fcmgt, EA_SCALABLE, REG_P11, REG_P5, REG_V2, + INS_OPTS_SCALABLE_D); // FCMGT ., /Z, ., #0.0 + theEmitter->emitIns_R_R_R(INS_sve_fcmle, EA_SCALABLE, REG_P2, REG_P7, REG_V1, + INS_OPTS_SCALABLE_H); // FCMLE ., /Z, ., #0.0 + theEmitter->emitIns_R_R_R(INS_sve_fcmlt, EA_SCALABLE, REG_P3, REG_P1, REG_V0, + INS_OPTS_SCALABLE_S); // FCMLT ., /Z, ., #0.0 + theEmitter->emitIns_R_R_R(INS_sve_fcmne, EA_SCALABLE, REG_P1, REG_P0, REG_V5, + INS_OPTS_SCALABLE_D); // FCMNE ., /Z, ., #0.0 + + // IF_SVE_HM_2A + theEmitter->emitIns_R_R_F(INS_sve_fadd, EA_SCALABLE, REG_V0, REG_P1, 0.5, + INS_OPTS_SCALABLE_H); // FADD ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fadd, EA_SCALABLE, REG_V0, REG_P1, 1.0, + INS_OPTS_SCALABLE_H); // FADD ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fmax, EA_SCALABLE, REG_V1, REG_P0, 0.0, + INS_OPTS_SCALABLE_S); // FMAX ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fmax, EA_SCALABLE, REG_V1, REG_P0, 1.0, + INS_OPTS_SCALABLE_S); // FMAX ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fmaxnm, EA_SCALABLE, REG_V3, REG_P4, 0.0, + INS_OPTS_SCALABLE_D); // FMAXNM ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fmaxnm, EA_SCALABLE, REG_V3, REG_P4, 1.0, + INS_OPTS_SCALABLE_D); // FMAXNM ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fmin, EA_SCALABLE, REG_V6, REG_P5, 0.0, + INS_OPTS_SCALABLE_H); // FMIN ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fmin, EA_SCALABLE, REG_V6, REG_P5, 1.0, + INS_OPTS_SCALABLE_H); // FMIN ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fminnm, EA_SCALABLE, REG_V2, REG_P4, 0.0, + INS_OPTS_SCALABLE_S); // FMINNM ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fminnm, EA_SCALABLE, REG_V2, REG_P4, 1.0, + INS_OPTS_SCALABLE_S); // FMINNM ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fmul, EA_SCALABLE, REG_V5, REG_P1, 0.5, + INS_OPTS_SCALABLE_D); // FMUL ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fmul, EA_SCALABLE, REG_V5, REG_P1, 2.0, + INS_OPTS_SCALABLE_D); // FMUL ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fsub, EA_SCALABLE, REG_V7, REG_P2, 0.5, + INS_OPTS_SCALABLE_H); // FSUB ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fsub, EA_SCALABLE, REG_V7, REG_P2, 1.0, + INS_OPTS_SCALABLE_H); // FSUB ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fsubr, EA_SCALABLE, REG_V6, REG_P3, 0.5, + INS_OPTS_SCALABLE_S); // FSUBR ., /M, ., + theEmitter->emitIns_R_R_F(INS_sve_fsubr, EA_SCALABLE, REG_V6, REG_P3, 1.0, + INS_OPTS_SCALABLE_S); // FSUBR ., /M, ., + + //// IF_SVE_HN_2A + //theEmitter->emitIns_R_R_I(INS_sve_ftmad, EA_SCALABLE, REG_V0, REG_V0, 5, + // INS_OPTS_SCALABLE_B); // FTMAD ., ., ., # + + //// IF_SVE_HP_3A + //theEmitter->emitIns_R_R_R(INS_sve_flogb, EA_SCALABLE, REG_V0, REG_P0, REG_V0, + // INS_OPTS_SCALABLE_B); // FLOGB ., /M, . + + //// IF_SVE_HU_4B + //theEmitter->emitIns_R_R_R_R(INS_sve_bfmla, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, + // INS_OPTS_SCALABLE_B); // BFMLA .H, /M, .H, .H + //theEmitter->emitIns_R_R_R_R(INS_sve_bfmls, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, + // INS_OPTS_SCALABLE_B); // BFMLS .H, /M, .H, .H + + //// IF_SVE_HV_4A + //theEmitter->emitIns_R_R_R_R(INS_sve_fmad, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, + // INS_OPTS_SCALABLE_B); // FMAD ., /M, ., . + //theEmitter->emitIns_R_R_R_R(INS_sve_fmsb, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, + // INS_OPTS_SCALABLE_B); // FMSB ., /M, ., . + //theEmitter->emitIns_R_R_R_R(INS_sve_fnmad, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, + // INS_OPTS_SCALABLE_B); // FNMAD ., /M, ., . + //theEmitter->emitIns_R_R_R_R(INS_sve_fnmsb, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, + // INS_OPTS_SCALABLE_B); // FNMSB ., /M, ., . } #endif // defined(TARGET_ARM64) && defined(DEBUG) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 2391e52e5b2004..77c3bffa9d8381 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -2032,6 +2032,84 @@ void emitter::emitInsSanityCheck(instrDesc* id) assert(isScalableVectorSize(elemsize)); break; + case IF_SVE_GP_3A: // ........xx.....r ...gggmmmmmddddd -- SVE floating-point complex add (predicated) + imm = emitGetInsSC(id); + elemsize = id->idOpSize(); + assert(insOptsScalableAtLeastHalf(id->idInsOpt())); + assert(isVectorRegister(id->idReg1())); + assert(isLowPredicateRegister(id->idReg2())); + assert(isVectorRegister(id->idReg3())); + assert((imm == 90) || (imm == 270)); + assert(isScalableVectorSize(elemsize)); + break; + + case IF_SVE_GT_4A: // ........xx.mmmmm .rrgggnnnnnddddd -- SVE floating-point complex multiply-add (predicated) + imm = emitGetInsSC(id); + elemsize = id->idOpSize(); + assert(insOptsScalableAtLeastHalf(id->idInsOpt())); + assert(isVectorRegister(id->idReg1())); + assert(isLowPredicateRegister(id->idReg2())); + assert(isVectorRegister(id->idReg3())); + assert(isVectorRegister(id->idReg4())); + assert((imm == 0) || (imm == 90) || (imm == 180) || (imm == 270)); + assert(isScalableVectorSize(elemsize)); + break; + + case IF_SVE_HI_3A: // ........xx...... ...gggnnnnn.DDDD -- SVE floating-point compare with zero + elemsize = id->idOpSize(); + assert(insOptsScalableAtLeastHalf(id->idInsOpt())); + assert(isPredicateRegister(id->idReg1())); + assert(isLowPredicateRegister(id->idReg2())); + assert(isVectorRegister(id->idReg3())); + assert(isScalableVectorSize(elemsize)); + break; + + case IF_SVE_HM_2A: // ........xx...... ...ggg....iddddd -- SVE floating-point arithmetic with immediate + // (predicated) + elemsize = id->idOpSize(); + assert(insOptsScalableAtLeastHalf(id->idInsOpt())); + assert(isVectorRegister(id->idReg1())); + assert(isLowPredicateRegister(id->idReg2())); + assert(isScalableVectorSize(elemsize)); + break; + + //case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient + // elemsize = id->idOpSize(); + // assert(insOptsScalable(id->idInsOpt())); + // assert(isVectorRegister(id->idReg10())); // mmmmm + // assert(isVectorRegister(id->idReg20())); // ddddd + // assert(isValidImm()); // iii + // assert(isValidVectorElemsize(id->idInsOpt())); // xx + // break; + + //case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer + // elemsize = id->idOpSize(); + // assert(insOptsScalable(id->idInsOpt())); + // assert(isVectorRegister(id->idReg10())); // nnnnn + // assert(isPredicateRegister(id->idReg20())); // ggg + // assert(isVectorRegister(id->idReg30())); // ddddd + // assert(isValidVectorElemsize(id->idInsOpt())); // xx + // break; + + //case IF_SVE_HU_4B: // ...........mmmmm ...gggnnnnnddddd -- SVE floating-point multiply-accumulate writing addend + // assert(insOptsScalable(id->idInsOpt())); + // assert(isVectorRegister(id->idReg10())); // mmmmm + // assert(isVectorRegister(id->idReg20())); // nnnnn + // assert(isPredicateRegister(id->idReg30())); // ggg + // assert(isVectorRegister(id->idReg40())); // ddddd + // break; + + //case IF_SVE_HV_4A: // ........xx.aaaaa ...gggmmmmmddddd -- SVE floating-point multiply-accumulate writing + // // multiplicand + // elemsize = id->idOpSize(); + // assert(insOptsScalable(id->idInsOpt())); + // assert(isVectorRegister(id->idReg10())); // aaaaa + // assert(isVectorRegister(id->idReg20())); // mmmmm + // assert(isPredicateRegister(id->idReg30())); // ggg + // assert(isVectorRegister(id->idReg40())); // ddddd + // assert(isValidVectorElemsize(id->idInsOpt())); // xx + // break; + default: printf("unexpected format %s\n", emitIfName(id->idInsFmt())); assert(!"Unexpected format"); @@ -8899,6 +8977,99 @@ void emitter::emitIns_R_R_I(instruction ins, appendToCurIG(id); } +/***************************************************************************** + * + * Add an instruction referencing two registers and a floating point constant. + */ + +void emitter::emitIns_R_R_F( + instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, double immDbl, insOpts opt /* = INS_OPTS_NONE */) +{ + ssize_t imm = 0; + emitAttr size = EA_SIZE(attr); + insFormat fmt = IF_NONE; + + bool canEncode = false; + floatImm8 fpi; + + /* Figure out the encoding format of the instruction */ + switch (ins) + { + case INS_sve_fmul: + case INS_sve_fmaxnm: + case INS_sve_fadd: + case INS_sve_fmax: + case INS_sve_fminnm: + case INS_sve_fsub: + case INS_sve_fmin: + case INS_sve_fsubr: +#ifdef DEBUG + switch (ins) + { + case INS_sve_fadd: + case INS_sve_fsub: + case INS_sve_fsubr: + assert((immDbl == 0.5) || (immDbl == 1.0)); + break; + + case INS_sve_fmax: + case INS_sve_fmaxnm: + case INS_sve_fmin: + case INS_sve_fminnm: + assert((immDbl == 0) || (immDbl == 1.0)); + break; + + case INS_sve_fmul: + assert((immDbl == 0.5) || (immDbl == 2.0)); + break; + + default: + assert(!"Invalid instruction"); + break; + } +#endif // DEBUG + + assert(insOptsScalableAtLeastHalf(opt)); + assert(isVectorRegister(reg1)); + assert(isLowPredicateRegister(reg2)); + assert(isScalableVectorSize(size)); + + if (immDbl != 0.0) + { + fpi.immFPIVal = 0; + canEncode = canEncodeFloatImm8(immDbl, &fpi); + imm = fpi.immFPIVal; + } + else + { + canEncode = true; + imm = 0; + } + fmt = IF_SVE_HM_2A; + break; + + default: + unreached(); + break; + + } // end switch (ins) + + assert(canEncode); + assert(fmt != IF_NONE); + + instrDesc* id = emitNewInstrSC(attr, imm); + + id->idIns(ins); + id->idInsFmt(fmt); + id->idInsOpt(opt); + + id->idReg1(reg1); + id->idReg2(reg2); + + dispIns(id); + appendToCurIG(id); +} + /***************************************************************************** * * Add an instruction referencing two registers and a constant. @@ -10377,6 +10548,20 @@ void emitter::emitIns_R_R_R(instruction ins, fmt = IF_SVE_CZ_4A; break; + case INS_sve_fcmeq: + case INS_sve_fcmge: + case INS_sve_fcmgt: + case INS_sve_fcmlt: + case INS_sve_fcmle: + case INS_sve_fcmne: + assert(insOptsScalableAtLeastHalf(opt)); + assert(isPredicateRegister(reg1)); + assert(isLowPredicateRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isScalableVectorSize(size)); + fmt = IF_SVE_HI_3A; + break; + default: unreached(); break; @@ -11510,6 +11695,16 @@ void emitter::emitIns_R_R_R_I(instruction ins, fmt = IF_SVE_JN_3A; break; + case INS_sve_fcadd: + assert(insOptsScalableAtLeastHalf(opt)); + assert(isVectorRegister(reg1)); + assert(isLowPredicateRegister(reg2)); + assert(isVectorRegister(reg3)); + assert((imm == 90) || (imm == 270)); + assert(isScalableVectorSize(size)); + fmt = IF_SVE_GP_3A; + break; + default: unreached(); break; @@ -13074,6 +13269,58 @@ void emitter::emitInsSve_R_R_R_R(instruction ins, appendToCurIG(id); } +/***************************************************************************** + * + * Add an instruction referencing four registers and a constant. + */ + +void emitter::emitIns_R_R_R_R_I(instruction ins, + emitAttr attr, + regNumber reg1, + regNumber reg2, + regNumber reg3, + regNumber reg4, + ssize_t imm, + insOpts opt /* = INS_OPT_NONE*/) +{ + emitAttr size = EA_SIZE(attr); + insFormat fmt = IF_NONE; + + /* Figure out the encoding format of the instruction */ + switch (ins) + { + case INS_sve_fcmla: + assert(insOptsScalableAtLeastHalf(opt)); + assert(isVectorRegister(reg1)); + assert(isLowPredicateRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isVectorRegister(reg4)); + assert((imm == 0) || (imm == 90) || (imm == 180) || (imm == 270)); + assert(isScalableVectorSize(size)); + fmt = IF_SVE_GT_4A; + break; + + default: + unreached(); + break; + } + assert(fmt != IF_NONE); + + instrDesc* id = emitNewInstrCns(attr, imm); + + id->idIns(ins); + id->idInsFmt(fmt); + id->idInsOpt(opt); + + id->idReg1(reg1); + id->idReg2(reg2); + id->idReg3(reg3); + id->idReg4(reg4); + + dispIns(id); + appendToCurIG(id); +} + /***************************************************************************** * * Add an instruction referencing a register and a condition code @@ -16050,6 +16297,77 @@ void emitter::emitIns_Call(EmitCallType callType, return encodedSize | imm3High | imm3Low; } +/***************************************************************************** + * + * Returns the encoding to select the constant values 90 or 270 for an Arm64 SVE vector instruction + * This specifically encode the field 'rot' at bit location '16'. + */ + +/*static*/ emitter::code_t emitter::insEncodeSveImm90_or_270_rot(ssize_t imm) +{ + switch (imm) + { + case 90: + return 0; + + case 270: + return (1 << 16); + + default: + break; + } + + assert("Invalid immediate rotation value"); + return 0; +} + +/***************************************************************************** + * + * Returns the encoding to select the constant values 0, 90, 180 or 270 for an Arm64 SVE vector instruction + * This specifically encode the field 'rot' at bit locations '14-13'. + */ + +/*static*/ emitter::code_t emitter::insEncodeSveImm0_or_90_or_180_or_270_rot(ssize_t imm) +{ + switch (imm) + { + case 0: + return 0; + + case 90: + return (1 << 13); + + case 180: + return (1 << 14); + + case 270: + return (1 << 14) | (1 << 13); + + default: + break; + } + + assert("Invalid immediate rotation value"); + return 0; +} + +/***************************************************************************** + * + * Returns the encoding to select the constant float values 0, 0.5, 1.0 or 2.0 for an Arm64 SVE vector instruction + * This specifically encode the field 'i1' at bit location '5'. + */ + +/*static*/ emitter::code_t emitter::insEncodeSveFloatImmZero_to_Two(double immDbl) +{ + assert((immDbl == 0.0) || (immDbl == 0.5) || (immDbl == 1.0) || (immDbl == 2.0)); + + if (immDbl < 1.0) + { + return 0; + } + return (1 << 5); +} + /***************************************************************************** * * Returns the register list size for the given SVE instruction. @@ -16215,7 +16533,6 @@ void emitter::emitIns_Call(EmitCallType callType, case IF_SVE_IM_3A: case IF_SVE_IN_4A: case IF_SVE_IX_4A: - case IF_SVE_HI_3A: case IF_SVE_IO_3A: case IF_SVE_IP_4A: case IF_SVE_IQ_3A: @@ -16416,6 +16733,10 @@ void emitter::emitIns_Call(EmitCallType callType, assert((regpos == 2) || (regpos == 3)); return ((regpos == 2) ? PREDICATE_NONE : PREDICATE_SIZED); + case IF_SVE_HI_3A: + assert((regpos == 1) || (regpos == 2)); + return ((regpos == 2) ? PREDICATE_ZERO : PREDICATE_SIZED); + default: break; } @@ -20796,6 +21117,99 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) dst += emitOutput_Instr(dst, code); break; + case IF_SVE_GP_3A: // ........xx.....r ...gggmmmmmddddd -- SVE floating-point complex add (predicated) + imm = emitGetInsSC(id); + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg + code |= insEncodeReg_V_9_to_5(id->idReg3()); // mmmmm + code |= insEncodeSveImm90_or_270_rot(imm); // r + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_GT_4A: // ........xx.mmmmm .rrgggnnnnnddddd -- SVE floating-point complex multiply-add (predicated) + imm = emitGetInsSC(id); + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg + code |= insEncodeReg_V_9_to_5(id->idReg3()); // nnnnn + code |= insEncodeReg_V_20_to_16(id->idReg4()); // mmmmm + code |= insEncodeSveImm0_or_90_or_180_or_270_rot(imm); // rr + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_HI_3A: // ........xx...... ...gggnnnnn.DDDD -- SVE floating-point compare with zero + 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 |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_HM_2A: // ........xx...... ...ggg....iddddd -- SVE floating-point arithmetic with immediate + // (predicated) + { + double immDbl = 0.0; + + imm = emitGetInsSC(id); + + if (imm != 0) + { + floatImm8 fpImm; + fpImm.immFPIVal = (unsigned)imm; + immDbl = emitDecodeFloatImm8(fpImm); + } + + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg + code |= insEncodeSveFloatImmZero_to_Two(immDbl); // i + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + } + break; + + //case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient + // code = emitInsCodeSve(ins, fmt); + // code |= insEncodeReg_V_9_to_5(id->idReg10()); // mmmmm + // code |= insEncodeReg_V_4_to_0(id->idReg20()); // ddddd + // code |= insEncodeImm(); // iii + // code |= insEncodeElemsize(id->idInsOpt()); // xx + // dst += emitOutput_Instr(dst, code); + // break; + + //case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer + // code = emitInsCodeSve(ins, fmt); + // code |= insEncodeReg_V_9_to_5(id->idReg10()); // nnnnn + // code |= insEncodeReg_P_12_to_10(id->idReg20()); // ggg + // code |= insEncodeReg_V_4_to_0(id->idReg30()); // ddddd + // code |= insEncodeElemsize(id->idInsOpt()); // xx + // dst += emitOutput_Instr(dst, code); + // break; + + //case IF_SVE_HU_4B: // ...........mmmmm ...gggnnnnnddddd -- SVE floating-point multiply-accumulate writing addend + // code = emitInsCodeSve(ins, fmt); + // code |= insEncodeReg_V_21_to_17(id->idReg10()); // mmmmm + // code |= insEncodeReg_V_9_to_5(id->idReg20()); // nnnnn + // code |= insEncodeReg_P_12_to_10(id->idReg30()); // ggg + // code |= insEncodeReg_V_4_to_0(id->idReg40()); // ddddd + // dst += emitOutput_Instr(dst, code); + // break; + + //case IF_SVE_HV_4A: // ........xx.aaaaa ...gggmmmmmddddd -- SVE floating-point multiply-accumulate writing + // // multiplicand + // code = emitInsCodeSve(ins, fmt); + // code |= insEncodeReg_V_21_to_17(id->idReg10()); // aaaaa + // code |= insEncodeReg_V_9_to_5(id->idReg20()); // mmmmm + // code |= insEncodeReg_P_12_to_10(id->idReg30()); // ggg + // code |= insEncodeReg_V_4_to_0(id->idReg40()); // ddddd + // code |= insEncodeElemsize(id->idInsOpt()); // xx + // dst += emitOutput_Instr(dst, code); + // break; + default: assert(!"Unexpected format"); break; @@ -24011,6 +24425,67 @@ void emitter::emitDispInsHelp( printf("]"); break; + // ., /M, ., ., + case IF_SVE_GP_3A: // ........xx.....r ...gggmmmmmddddd -- SVE floating-point complex add (predicated) + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispSveReg(id->idReg3(), id->idInsOpt(), true); + emitDispImm(emitGetInsSC(id), false); + break; + + // ., /M, ., ., + case IF_SVE_GT_4A: // ........xx.mmmmm .rrgggnnnnnddddd -- SVE floating-point complex multiply-add (predicated) + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); + emitDispSveReg(id->idReg3(), id->idInsOpt(), true); + emitDispSveReg(id->idReg4(), id->idInsOpt(), true); + emitDispImm(emitGetInsSC(id), false); + break; + + // ., /Z, ., #0.0 + case IF_SVE_HI_3A: // ........xx...... ...gggnnnnn.DDDD -- SVE floating-point compare with zero + emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt, 1), id->idInsOpt(), true); + emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt, 2), id->idInsOpt(), true); + emitDispSveReg(id->idReg3(), id->idInsOpt(), true); + emitDispFloatZero(); + break; + + // ., /M, ., + case IF_SVE_HM_2A: // ........xx...... ...ggg....iddddd -- SVE floating-point arithmetic with immediate + // (predicated) + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispFloatImm(emitGetInsSC(id)); + break; + + // ., ., ., # + case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispSveReg(id->idReg2(), id->idInsOpt(), true); + emitDispImm(emitGetInsSC(id), false); + break; + + // ., /M, . + case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); + emitDispSveReg(id->idReg3(), id->idInsOpt(), false); + break; + + // .H, /M, .H, .H + case IF_SVE_HU_4B: // ...........mmmmm ...gggnnnnnddddd -- SVE floating-point multiply-accumulate writing addend + // ., /M, ., . + case IF_SVE_HV_4A: // ........xx.aaaaa ...gggmmmmmddddd -- SVE floating-point multiply-accumulate writing + // multiplicand + emitDispSveReg(id->idReg1(), id->idInsOpt(), true); + emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); + emitDispSveReg(id->idReg3(), id->idInsOpt(), true); + emitDispSveReg(id->idReg4(), id->idInsOpt(), false); + break; + default: printf("unexpected format %s", emitIfName(id->idInsFmt())); assert(!"unexpectedFormat"); @@ -27431,6 +27906,73 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insLatency = PERFSCORE_LATENCY_2C; break; + case IF_SVE_GP_3A: // ........xx.....r ...gggmmmmmddddd -- SVE floating-point complex add (predicated) + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_3C; + break; + + case IF_SVE_GT_4A: // ........xx.mmmmm .rrgggnnnnnddddd -- SVE floating-point complex multiply-add (predicated) + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_5C; + break; + + case IF_SVE_HI_3A: // ........xx...... ...gggnnnnn.DDDD -- SVE floating-point compare with zero + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_2C; + break; + + case IF_SVE_HM_2A: // ........xx...... ...ggg....iddddd -- SVE floating-point arithmetic with immediate + // (predicated) + switch (ins) + { + case INS_sve_fmul: + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_3C; + break; + + default: + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_2C; + break; + } + break; + + case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + + case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_3C; + break; + + case IF_SVE_HU_4B: // ...........mmmmm ...gggnnnnnddddd -- SVE floating-point multiply-accumulate writing addend + switch (ins) + { + case INS_sve_bfmla: + result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix + result.insLatency = PERFSCORE_LATENCY_1C; // need to fix + break; + + case INS_sve_bfmls: + result.insThroughput = PERFSCORE_THROUGHPUT_1C; // need to fix + result.insLatency = PERFSCORE_LATENCY_1C; // need to fix + break; + + default: + // all other instructions + perfScoreUnhandledInstruction(id, &result); + break; + } + break; + + case IF_SVE_HV_4A: // ........xx.aaaaa ...gggmmmmmddddd -- SVE floating-point multiply-accumulate writing + // multiplicand + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + default: // all other instructions perfScoreUnhandledInstruction(id, &result); diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 6d40ce8116fb3e..3be2e1c6d2df83 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -509,6 +509,18 @@ static code_t insEncodeSveElemsize_sz_21(emitAttr size); // This specifically encodes the field 'tszh:tszl' at bit locations '22:20-19'. static code_t insEncodeSveElemsize_tszh_22_tszl_20_to_19(emitAttr size); +// Returns the encoding to select the constant values 90 or 270 for an Arm64 SVE vector instruction +// This specifically encode the field 'rot' at bit location '16'. +static code_t insEncodeSveImm90_or_270_rot(ssize_t imm); + +// Returns the encoding to select the constant values 0, 90, 180 or 270 for an Arm64 SVE vector instruction +// This specifically encode the field 'rot' at bit locations '14-13'. +static code_t insEncodeSveImm0_or_90_or_180_or_270_rot(ssize_t imm); + +// Returns the encoding to select the constant float values 0, 0.5, 1.0 or 2.0 for an Arm64 SVE vector instruction +// This specifically encode the field 'i1' at bit location '5'. +static code_t insEncodeSveFloatImmZero_to_Two(double immDbl); + // Returns the first register list size for the given SVE instruction. static int insGetSveReg1ListSize(instruction ins); @@ -1245,6 +1257,9 @@ void emitIns_R_R_I(instruction ins, insOpts opt = INS_OPTS_NONE, insScalableOpts sopt = INS_SCALABLE_OPTS_NONE); +void emitIns_R_R_F( + instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, double immDbl, insOpts opt = INS_OPTS_NONE); + // Checks for a large immediate that needs a second instruction void emitIns_R_R_Imm(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm); @@ -1303,6 +1318,15 @@ void emitInsSve_R_R_R_R(instruction ins, insOpts opt = INS_OPTS_NONE, insScalableOpts sopt = INS_SCALABLE_OPTS_NONE); +void emitIns_R_R_R_R_I(instruction ins, + emitAttr attr, + regNumber reg1, + regNumber reg2, + regNumber reg3, + regNumber reg4, + ssize_t imm, + insOpts opt = INS_OPTS_NONE); + void emitIns_R_COND(instruction ins, emitAttr attr, regNumber reg, insCond cond); void emitIns_R_R_COND(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insCond cond); From 40ec09423ec4dc3419a98312bbc36285fbcc513f Mon Sep 17 00:00:00 2001 From: TIHan Date: Tue, 6 Feb 2024 20:30:34 -0800 Subject: [PATCH 2/6] Minor fix for display --- src/coreclr/jit/emitarm64.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 77c3bffa9d8381..7381e7c7cadd94 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -24454,10 +24454,18 @@ void emitter::emitDispInsHelp( // ., /M, ., case IF_SVE_HM_2A: // ........xx...... ...ggg....iddddd -- SVE floating-point arithmetic with immediate // (predicated) + imm = emitGetInsSC(id); emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); emitDispSveReg(id->idReg1(), id->idInsOpt(), true); - emitDispFloatImm(emitGetInsSC(id)); + if (imm != 0) + { + emitDispFloatImm(imm); + } + else + { + emitDispFloatZero(); + } break; // ., ., ., # From 5968609a90ee578166def5bbe65a1b86181995f0 Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 7 Feb 2024 17:20:51 -0800 Subject: [PATCH 3/6] Added more formats --- src/coreclr/jit/codegenarm64test.cpp | 50 +++--- src/coreclr/jit/emitarm64.cpp | 235 ++++++++++++++++++--------- src/coreclr/jit/emitarm64.h | 7 + 3 files changed, 196 insertions(+), 96 deletions(-) diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp index 12ab5f777e77c4..7e428f0262b7b3 100644 --- a/src/coreclr/jit/codegenarm64test.cpp +++ b/src/coreclr/jit/codegenarm64test.cpp @@ -7015,29 +7015,33 @@ void CodeGen::genArm64EmitterUnitTestsSve() theEmitter->emitIns_R_R_F(INS_sve_fsubr, EA_SCALABLE, REG_V6, REG_P3, 1.0, INS_OPTS_SCALABLE_S); // FSUBR ., /M, ., - //// IF_SVE_HN_2A - //theEmitter->emitIns_R_R_I(INS_sve_ftmad, EA_SCALABLE, REG_V0, REG_V0, 5, - // INS_OPTS_SCALABLE_B); // FTMAD ., ., ., # - - //// IF_SVE_HP_3A - //theEmitter->emitIns_R_R_R(INS_sve_flogb, EA_SCALABLE, REG_V0, REG_P0, REG_V0, - // INS_OPTS_SCALABLE_B); // FLOGB ., /M, . - - //// IF_SVE_HU_4B - //theEmitter->emitIns_R_R_R_R(INS_sve_bfmla, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, - // INS_OPTS_SCALABLE_B); // BFMLA .H, /M, .H, .H - //theEmitter->emitIns_R_R_R_R(INS_sve_bfmls, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, - // INS_OPTS_SCALABLE_B); // BFMLS .H, /M, .H, .H - - //// IF_SVE_HV_4A - //theEmitter->emitIns_R_R_R_R(INS_sve_fmad, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, - // INS_OPTS_SCALABLE_B); // FMAD ., /M, ., . - //theEmitter->emitIns_R_R_R_R(INS_sve_fmsb, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, - // INS_OPTS_SCALABLE_B); // FMSB ., /M, ., . - //theEmitter->emitIns_R_R_R_R(INS_sve_fnmad, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, - // INS_OPTS_SCALABLE_B); // FNMAD ., /M, ., . - //theEmitter->emitIns_R_R_R_R(INS_sve_fnmsb, EA_SCALABLE, REG_V0, REG_V0, REG_P0, REG_V0, - // INS_OPTS_SCALABLE_B); // FNMSB ., /M, ., . + // IF_SVE_HN_2A + // FTMAD ., ., ., # + theEmitter->emitIns_R_R_I(INS_sve_ftmad, EA_SCALABLE, REG_V0, REG_V2, 0, INS_OPTS_SCALABLE_H); + theEmitter->emitIns_R_R_I(INS_sve_ftmad, EA_SCALABLE, REG_V3, REG_V5, 1, INS_OPTS_SCALABLE_S); + theEmitter->emitIns_R_R_I(INS_sve_ftmad, EA_SCALABLE, REG_V4, REG_V2, 7, INS_OPTS_SCALABLE_D); + + // IF_SVE_HP_3A + // FLOGB ., /M, . + theEmitter->emitIns_R_R_R(INS_sve_flogb, EA_SCALABLE, REG_V31, REG_P7, REG_V31, INS_OPTS_SCALABLE_H); + theEmitter->emitIns_R_R_R(INS_sve_flogb, EA_SCALABLE, REG_V31, REG_P7, REG_V31, INS_OPTS_SCALABLE_S); + theEmitter->emitIns_R_R_R(INS_sve_flogb, EA_SCALABLE, REG_V31, REG_P7, REG_V31, INS_OPTS_SCALABLE_D); + + // IF_SVE_HU_4B + theEmitter->emitIns_R_R_R_R(INS_sve_bfmla, EA_SCALABLE, REG_V1, REG_P5, REG_V4, REG_V3, + INS_OPTS_SCALABLE_H); // BFMLA .H, /M, .H, .H + theEmitter->emitIns_R_R_R_R(INS_sve_bfmls, EA_SCALABLE, REG_V0, REG_P6, REG_V1, REG_V2, + INS_OPTS_SCALABLE_H); // BFMLS .H, /M, .H, .H + + // IF_SVE_HV_4A + theEmitter->emitIns_R_R_R_R(INS_sve_fmad, EA_SCALABLE, REG_V3, REG_P4, REG_V5, REG_V6, + INS_OPTS_SCALABLE_H); // FMAD ., /M, ., . + theEmitter->emitIns_R_R_R_R(INS_sve_fmsb, EA_SCALABLE, REG_V1, REG_P2, REG_V3, REG_V7, + INS_OPTS_SCALABLE_S); // FMSB ., /M, ., . + theEmitter->emitIns_R_R_R_R(INS_sve_fnmad, EA_SCALABLE, REG_V0, REG_P5, REG_V4, REG_V3, + INS_OPTS_SCALABLE_D); // FNMAD ., /M, ., . + theEmitter->emitIns_R_R_R_R(INS_sve_fnmsb, EA_SCALABLE, REG_V5, REG_P3, REG_V1, REG_V2, + INS_OPTS_SCALABLE_S); // FNMSB ., /M, ., . } #endif // defined(TARGET_ARM64) && defined(DEBUG) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 7381e7c7cadd94..9f8e5cdf882d80 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -2073,42 +2073,45 @@ void emitter::emitInsSanityCheck(instrDesc* id) assert(isScalableVectorSize(elemsize)); break; - //case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient - // elemsize = id->idOpSize(); - // assert(insOptsScalable(id->idInsOpt())); - // assert(isVectorRegister(id->idReg10())); // mmmmm - // assert(isVectorRegister(id->idReg20())); // ddddd - // assert(isValidImm()); // iii - // assert(isValidVectorElemsize(id->idInsOpt())); // xx - // break; - - //case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer - // elemsize = id->idOpSize(); - // assert(insOptsScalable(id->idInsOpt())); - // assert(isVectorRegister(id->idReg10())); // nnnnn - // assert(isPredicateRegister(id->idReg20())); // ggg - // assert(isVectorRegister(id->idReg30())); // ddddd - // assert(isValidVectorElemsize(id->idInsOpt())); // xx - // break; - - //case IF_SVE_HU_4B: // ...........mmmmm ...gggnnnnnddddd -- SVE floating-point multiply-accumulate writing addend - // assert(insOptsScalable(id->idInsOpt())); - // assert(isVectorRegister(id->idReg10())); // mmmmm - // assert(isVectorRegister(id->idReg20())); // nnnnn - // assert(isPredicateRegister(id->idReg30())); // ggg - // assert(isVectorRegister(id->idReg40())); // ddddd - // break; - - //case IF_SVE_HV_4A: // ........xx.aaaaa ...gggmmmmmddddd -- SVE floating-point multiply-accumulate writing - // // multiplicand - // elemsize = id->idOpSize(); - // assert(insOptsScalable(id->idInsOpt())); - // assert(isVectorRegister(id->idReg10())); // aaaaa - // assert(isVectorRegister(id->idReg20())); // mmmmm - // assert(isPredicateRegister(id->idReg30())); // ggg - // assert(isVectorRegister(id->idReg40())); // ddddd - // assert(isValidVectorElemsize(id->idInsOpt())); // xx - // break; + case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient + imm = emitGetInsSC(id); + elemsize = id->idOpSize(); + assert(insOptsScalableAtLeastHalf(id->idInsOpt())); + assert(isVectorRegister(id->idReg1())); + assert(isVectorRegister(id->idReg2())); + assert(isValidUimm3(imm)); + assert(isScalableVectorSize(elemsize)); + break; + + case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer + elemsize = id->idOpSize(); + assert(insOptsScalableAtLeastHalf(id->idInsOpt())); + assert(isVectorRegister(id->idReg1())); + assert(isLowPredicateRegister(id->idReg2())); + assert(isVectorRegister(id->idReg3())); + assert(isScalableVectorSize(elemsize)); + break; + + case IF_SVE_HU_4B: // ...........mmmmm ...gggnnnnnddddd -- SVE floating-point multiply-accumulate writing addend + elemsize = id->idOpSize(); + assert(id->idInsOpt() == INS_OPTS_SCALABLE_H); + assert(isVectorRegister(id->idReg1())); + assert(isLowPredicateRegister(id->idReg2())); + assert(isVectorRegister(id->idReg3())); + assert(isVectorRegister(id->idReg4())); + assert(isScalableVectorSize(elemsize)); + break; + + case IF_SVE_HV_4A: // ........xx.aaaaa ...gggmmmmmddddd -- SVE floating-point multiply-accumulate writing + // multiplicand + elemsize = id->idOpSize(); + assert(insOptsScalableAtLeastHalf(id->idInsOpt())); + assert(isVectorRegister(id->idReg1())); + assert(isLowPredicateRegister(id->idReg2())); + assert(isVectorRegister(id->idReg3())); + assert(isVectorRegister(id->idReg4())); + assert(isScalableVectorSize(elemsize)); + break; default: printf("unexpected format %s\n", emitIfName(id->idInsFmt())); @@ -8831,6 +8834,16 @@ void emitter::emitIns_R_R_I(instruction ins, } break; + case INS_sve_ftmad: + assert(insOptsScalableAtLeastHalf(opt)); + assert(insScalableOptsNone(sopt)); + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isValidUimm3(imm)); + assert(isScalableVectorSize(size)); + fmt = IF_SVE_HN_2A; + break; + default: unreached(); break; @@ -10555,6 +10568,7 @@ void emitter::emitIns_R_R_R(instruction ins, case INS_sve_fcmle: case INS_sve_fcmne: assert(insOptsScalableAtLeastHalf(opt)); + assert(insScalableOptsNone(sopt)); assert(isPredicateRegister(reg1)); assert(isLowPredicateRegister(reg2)); assert(isVectorRegister(reg3)); @@ -10562,6 +10576,16 @@ void emitter::emitIns_R_R_R(instruction ins, fmt = IF_SVE_HI_3A; break; + case INS_sve_flogb: + assert(insOptsScalableAtLeastHalf(opt)); + assert(insScalableOptsNone(sopt)); + assert(isVectorRegister(reg1)); + assert(isLowPredicateRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isScalableVectorSize(size)); + fmt = IF_SVE_HP_3A; + break; + default: unreached(); break; @@ -13209,6 +13233,30 @@ void emitter::emitInsSve_R_R_R_R(instruction ins, fmt = IF_SVE_JF_4A; break; + case INS_sve_bfmla: + case INS_sve_bfmls: + assert(opt == INS_OPTS_SCALABLE_H); + assert(insScalableOptsNone(sopt)); + assert(isVectorRegister(reg1)); + assert(isLowPredicateRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isVectorRegister(reg4)); + fmt = IF_SVE_HU_4B; + break; + + case INS_sve_fmad: + case INS_sve_fmsb: + case INS_sve_fnmad: + case INS_sve_fnmsb: + assert(insOptsScalableAtLeastHalf(opt)); + assert(insScalableOptsNone(sopt)); + assert(isVectorRegister(reg1)); + assert(isLowPredicateRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isVectorRegister(reg4)); + fmt = IF_SVE_HV_4A; + break; + default: unreached(); break; @@ -16212,6 +16260,34 @@ void emitter::emitIns_Call(EmitCallType callType, return 0; } +/***************************************************************************** + * + * Returns the encoding to select the 1/2/4/8 byte elemsize for an Arm64 Sve vector instruction + * This specifically encodes the size at bit locations '18-17'. + */ + +/*static*/ emitter::code_t emitter::insEncodeSveElemsize_18_to_17(emitAttr size) +{ + switch (size) + { + case EA_1BYTE: + return 0; + + case EA_2BYTE: + return (1 << 17); // set the bit at location 17 + + case EA_4BYTE: + return (1 << 18); // set the bit at location 18 + + case EA_8BYTE: + return (1 << 18) | (1 << 17); // set the bit at location 18 and 17 + + 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 @@ -18030,6 +18106,18 @@ 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 '18-16'. + */ + +/*static*/ emitter::code_t emitter::insEncodeUimm3_18_to_16(ssize_t imm) +{ + assert(isValidUimm3(imm)); + return (code_t)imm << 16; +} + /***************************************************************************** * * Returns the encoding to select the 4/8-byte width specifier @@ -21172,43 +21260,44 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) } break; - //case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient - // code = emitInsCodeSve(ins, fmt); - // code |= insEncodeReg_V_9_to_5(id->idReg10()); // mmmmm - // code |= insEncodeReg_V_4_to_0(id->idReg20()); // ddddd - // code |= insEncodeImm(); // iii - // code |= insEncodeElemsize(id->idInsOpt()); // xx - // dst += emitOutput_Instr(dst, code); - // break; - - //case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer - // code = emitInsCodeSve(ins, fmt); - // code |= insEncodeReg_V_9_to_5(id->idReg10()); // nnnnn - // code |= insEncodeReg_P_12_to_10(id->idReg20()); // ggg - // code |= insEncodeReg_V_4_to_0(id->idReg30()); // ddddd - // code |= insEncodeElemsize(id->idInsOpt()); // xx - // dst += emitOutput_Instr(dst, code); - // break; - - //case IF_SVE_HU_4B: // ...........mmmmm ...gggnnnnnddddd -- SVE floating-point multiply-accumulate writing addend - // code = emitInsCodeSve(ins, fmt); - // code |= insEncodeReg_V_21_to_17(id->idReg10()); // mmmmm - // code |= insEncodeReg_V_9_to_5(id->idReg20()); // nnnnn - // code |= insEncodeReg_P_12_to_10(id->idReg30()); // ggg - // code |= insEncodeReg_V_4_to_0(id->idReg40()); // ddddd - // dst += emitOutput_Instr(dst, code); - // break; - - //case IF_SVE_HV_4A: // ........xx.aaaaa ...gggmmmmmddddd -- SVE floating-point multiply-accumulate writing - // // multiplicand - // code = emitInsCodeSve(ins, fmt); - // code |= insEncodeReg_V_21_to_17(id->idReg10()); // aaaaa - // code |= insEncodeReg_V_9_to_5(id->idReg20()); // mmmmm - // code |= insEncodeReg_P_12_to_10(id->idReg30()); // ggg - // code |= insEncodeReg_V_4_to_0(id->idReg40()); // ddddd - // code |= insEncodeElemsize(id->idInsOpt()); // xx - // dst += emitOutput_Instr(dst, code); - // break; + case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient + imm = emitGetInsSC(id); + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeReg_V_9_to_5(id->idReg2()); // mmmmm + code |= insEncodeUimm3_18_to_16(imm); // iii + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg + code |= insEncodeReg_V_9_to_5(id->idReg3()); // nnnnn + code |= insEncodeSveElemsize_18_to_17(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_HU_4B: // ...........mmmmm ...gggnnnnnddddd -- SVE floating-point multiply-accumulate writing addend + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg + code |= insEncodeReg_V_9_to_5(id->idReg3()); // nnnnn + code |= insEncodeReg_V_20_to_16(id->idReg4()); // mmmmm + dst += emitOutput_Instr(dst, code); + break; + + case IF_SVE_HV_4A: // ........xx.aaaaa ...gggmmmmmddddd -- SVE floating-point multiply-accumulate writing + // multiplicand + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + 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()); // aaaaa + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + break; default: assert(!"Unexpected format"); diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 3be2e1c6d2df83..9bb04bda9654d0 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -501,6 +501,10 @@ static code_t insEncodeSveElemsize(emitAttr size); // This specifically encodes the size at bit locations '22-21'. static code_t insEncodeSveElemsize_22_to_21(emitAttr size); +// Returns the encoding to select the 1/2/4/8 byte elemsize for an Arm64 Sve vector instruction +// 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 '21'. static code_t insEncodeSveElemsize_sz_21(emitAttr size); @@ -594,6 +598,9 @@ static code_t insEncodeUimm4From1_19_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 '18-16'. +static code_t insEncodeUimm3_18_to_16(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); From 7b6063ced3bd28aa0358fee800bfc6c35cbad41f Mon Sep 17 00:00:00 2001 From: TIHan Date: Wed, 7 Feb 2024 17:28:38 -0800 Subject: [PATCH 4/6] Small tweak to test --- src/coreclr/jit/codegenarm64test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp index 7e428f0262b7b3..96aa376be2b34b 100644 --- a/src/coreclr/jit/codegenarm64test.cpp +++ b/src/coreclr/jit/codegenarm64test.cpp @@ -6982,7 +6982,7 @@ void CodeGen::genArm64EmitterUnitTestsSve() INS_OPTS_SCALABLE_D); // FCMNE ., /Z, ., #0.0 // IF_SVE_HM_2A - theEmitter->emitIns_R_R_F(INS_sve_fadd, EA_SCALABLE, REG_V0, REG_P1, 0.5, + theEmitter->emitIns_R_R_F(INS_sve_fadd, EA_SCALABLE, REG_V0, REG_P0, 0.5, INS_OPTS_SCALABLE_H); // FADD ., /M, ., theEmitter->emitIns_R_R_F(INS_sve_fadd, EA_SCALABLE, REG_V0, REG_P1, 1.0, INS_OPTS_SCALABLE_H); // FADD ., /M, ., From bd126495914e0c61b7c2a1bb904dfc4af1001ed5 Mon Sep 17 00:00:00 2001 From: TIHan Date: Fri, 9 Feb 2024 12:36:56 -0800 Subject: [PATCH 5/6] Feedback --- src/coreclr/jit/emitarm64.cpp | 379 ++++++++++++++++++++++++---------- src/coreclr/jit/emitarm64.h | 23 ++- 2 files changed, 287 insertions(+), 115 deletions(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index abd8902d872e3b..0b90fcb7c05a87 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -2046,8 +2046,8 @@ void emitter::emitInsSanityCheck(instrDesc* id) assert(insOptsScalableAtLeastHalf(id->idInsOpt())); assert(isVectorRegister(id->idReg1())); assert(isLowPredicateRegister(id->idReg2())); - assert(isVectorRegister(id->idReg3())); - assert((imm == 90) || (imm == 270)); + assert(isVectorRegister(id->idReg3())); + assert(emitIsValidEncodedRotationImm90_or_270(imm)); assert(isScalableVectorSize(elemsize)); break; @@ -2059,7 +2059,7 @@ void emitter::emitInsSanityCheck(instrDesc* id) assert(isLowPredicateRegister(id->idReg2())); assert(isVectorRegister(id->idReg3())); assert(isVectorRegister(id->idReg4())); - assert((imm == 0) || (imm == 90) || (imm == 180) || (imm == 270)); + assert(emitIsValidEncodedRotationImm0_to_270(imm)); assert(isScalableVectorSize(elemsize)); break; @@ -2074,11 +2074,13 @@ void emitter::emitInsSanityCheck(instrDesc* id) case IF_SVE_HM_2A: // ........xx...... ...ggg....iddddd -- SVE floating-point arithmetic with immediate // (predicated) + imm = emitGetInsSC(id); elemsize = id->idOpSize(); assert(insOptsScalableAtLeastHalf(id->idInsOpt())); assert(isVectorRegister(id->idReg1())); assert(isLowPredicateRegister(id->idReg2())); assert(isScalableVectorSize(elemsize)); + assert(emitIsValidEncodedSmallFloatImm(imm)); break; case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient @@ -6011,6 +6013,235 @@ emitter::code_t emitter::emitInsCodeSve(instruction ins, insFormat fmt) return result; } +/************************************************************************ + * + * Convert a rotation value that is 90 or 270 into a smaller encoding that matches one-to-one with the 'rot' field. + */ + +/*static*/ ssize_t emitter::emitEncodeRotationImm90_or_270(ssize_t imm) +{ + switch (imm) + { + case 90: + return 0; + + case 270: + return 1; + + default: + break; + } + + assert(!"Invalid rotation value"); + return 0; +} + +/************************************************************************ + * + * Convert an encoded rotation value to 90 or 270. + */ + +/*static*/ ssize_t emitter::emitDecodeRotationImm90_or_270(ssize_t imm) +{ + assert(emitIsValidEncodedRotationImm0_to_270(imm)); + switch (imm) + { + case 0: + return 90; + + case 1: + return 270; + + default: + break; + } + + return 0; +} + +/************************************************************************ + * + * Check if the immediate value is a valid encoded rotation value for 90 or 270. + */ + +/*static*/ bool emitter::emitIsValidEncodedRotationImm90_or_270(ssize_t imm) +{ + return (imm == 0) || (imm == 1); +} + +/************************************************************************ + * + * Convert a rotation value that is 0, 90, 180 or 270 into a smaller encoding that matches one-to-one with the 'rot' field. + */ + +/*static*/ ssize_t emitter::emitEncodeRotationImm0_to_270(ssize_t imm) +{ + switch (imm) + { + case 0: + return 0; + + case 90: + return 1; + + case 180: + return 2; + + case 270: + return 3; + + default: + break; + } + + assert(!"Invalid rotation value"); + return 0; +} + +/************************************************************************ + * + * Convert an encoded rotation value to 0, 90, 180 or 270. + */ + +/*static*/ ssize_t emitter::emitDecodeRotationImm0_to_270(ssize_t imm) +{ + assert(emitIsValidEncodedRotationImm0_to_270(imm)); + switch (imm) + { + case 0: + return 0; + + case 1: + return 90; + + case 2: + return 180; + + case 3: + return 270; + + default: + break; + } + + return 0; +} + +/************************************************************************ + * + * Check if the immediate value is a valid encoded rotation value for 0, 90, 180 or 270. + */ + +/*static*/ bool emitter::emitIsValidEncodedRotationImm0_to_270(ssize_t imm) +{ + return (imm >= 0) && (imm <= 3); +} + +/************************************************************************ + * + * Convert a small immediate float value to an encoded version that matches one-to-one with the instructions. + * The instruction determines the value. + */ + +/*static*/ ssize_t emitter::emitEncodeSmallFloatImm(double immDbl, instruction ins) +{ +#ifdef DEBUG + switch (ins) + { + case INS_sve_fadd: + case INS_sve_fsub: + case INS_sve_fsubr: + assert((immDbl == 0.5) || (immDbl == 1.0)); + break; + + case INS_sve_fmax: + case INS_sve_fmaxnm: + case INS_sve_fmin: + case INS_sve_fminnm: + assert((immDbl == 0) || (immDbl == 1.0)); + break; + + case INS_sve_fmul: + assert((immDbl == 0.5) || (immDbl == 2.0)); + break; + + default: + assert(!"Invalid instruction"); + break; + } +#endif // DEBUG + if (immDbl < 1.0) + { + return 0; + } + return 1; +} + +/************************************************************************ + * + * Convert an encoded small float immediate value. The instruction determines the value. + */ + +/*static*/ double emitter::emitDecodeSmallFloatImm(ssize_t imm, instruction ins) +{ + assert(emitIsValidEncodedSmallFloatImm(imm)); + switch (ins) + { + case INS_sve_fadd: + case INS_sve_fsub: + case INS_sve_fsubr: + if (imm == 0) + { + return 0.5; + } + else + { + return 1.0; + } + + case INS_sve_fmax: + case INS_sve_fmaxnm: + case INS_sve_fmin: + case INS_sve_fminnm: + if (imm == 0) + { + return 0.0; + } + else + { + return 1.0; + } + break; + + case INS_sve_fmul: + if (imm == 0) + { + return 0.5; + } + else + { + return 2.0; + } + break; + + default: + break; + } + + assert(!"Invalid instruction"); + return 0.0; +} + +/************************************************************************ + * + * Check if the immediate value is a valid encoded small float. + */ + +/*static*/ bool emitter::emitIsValidEncodedSmallFloatImm(size_t imm) +{ + return (imm == 0) || (imm == 1); +} + /***************************************************************************** * * For the given 'ins' returns the reverse instruction @@ -9079,9 +9310,6 @@ void emitter::emitIns_R_R_F( emitAttr size = EA_SIZE(attr); insFormat fmt = IF_NONE; - bool canEncode = false; - floatImm8 fpi; - /* Figure out the encoding format of the instruction */ switch (ins) { @@ -9093,48 +9321,11 @@ void emitter::emitIns_R_R_F( case INS_sve_fsub: case INS_sve_fmin: case INS_sve_fsubr: -#ifdef DEBUG - switch (ins) - { - case INS_sve_fadd: - case INS_sve_fsub: - case INS_sve_fsubr: - assert((immDbl == 0.5) || (immDbl == 1.0)); - break; - - case INS_sve_fmax: - case INS_sve_fmaxnm: - case INS_sve_fmin: - case INS_sve_fminnm: - assert((immDbl == 0) || (immDbl == 1.0)); - break; - - case INS_sve_fmul: - assert((immDbl == 0.5) || (immDbl == 2.0)); - break; - - default: - assert(!"Invalid instruction"); - break; - } -#endif // DEBUG - assert(insOptsScalableAtLeastHalf(opt)); assert(isVectorRegister(reg1)); assert(isLowPredicateRegister(reg2)); assert(isScalableVectorSize(size)); - - if (immDbl != 0.0) - { - fpi.immFPIVal = 0; - canEncode = canEncodeFloatImm8(immDbl, &fpi); - imm = fpi.immFPIVal; - } - else - { - canEncode = true; - imm = 0; - } + imm = emitEncodeSmallFloatImm(immDbl, ins); fmt = IF_SVE_HM_2A; break; @@ -9144,7 +9335,6 @@ void emitter::emitIns_R_R_F( } // end switch (ins) - assert(canEncode); assert(fmt != IF_NONE); instrDesc* id = emitNewInstrSC(attr, imm); @@ -11800,9 +11990,9 @@ void emitter::emitIns_R_R_R_I(instruction ins, assert(insOptsScalableAtLeastHalf(opt)); assert(isVectorRegister(reg1)); assert(isLowPredicateRegister(reg2)); - assert(isVectorRegister(reg3)); - assert((imm == 90) || (imm == 270)); + assert(isVectorRegister(reg3)); assert(isScalableVectorSize(size)); + imm = emitEncodeRotationImm90_or_270(imm); fmt = IF_SVE_GP_3A; break; @@ -13420,8 +13610,8 @@ void emitter::emitIns_R_R_R_R_I(instruction ins, assert(isLowPredicateRegister(reg2)); assert(isVectorRegister(reg3)); assert(isVectorRegister(reg4)); - assert((imm == 0) || (imm == 90) || (imm == 180) || (imm == 270)); assert(isScalableVectorSize(size)); + imm = emitEncodeRotationImm0_to_270(imm); fmt = IF_SVE_GT_4A; break; @@ -16458,20 +16648,8 @@ void emitter::emitIns_Call(EmitCallType callType, /*static*/ emitter::code_t emitter::insEncodeSveImm90_or_270_rot(ssize_t imm) { - switch (imm) - { - case 90: - return 0; - - case 270: - return (1 << 16); - - default: - break; - } - - assert("Invalid immediate rotation value"); - return 0; + assert(emitIsValidEncodedRotationImm90_or_270(imm)); + return (code_t)(imm << 16); } /***************************************************************************** @@ -16480,28 +16658,10 @@ void emitter::emitIns_Call(EmitCallType callType, * This specifically encode the field 'rot' at bit locations '14-13'. */ -/*static*/ emitter::code_t emitter::insEncodeSveImm0_or_90_or_180_or_270_rot(ssize_t imm) +/*static*/ emitter::code_t emitter::insEncodeSveImm0_to_270_rot(ssize_t imm) { - switch (imm) - { - case 0: - return 0; - - case 90: - return (1 << 13); - - case 180: - return (1 << 14); - - case 270: - return (1 << 14) | (1 << 13); - - default: - break; - } - - assert("Invalid immediate rotation value"); - return 0; + assert(emitIsValidEncodedRotationImm0_to_270(imm)); + return (code_t)(imm << 13); } /***************************************************************************** @@ -16510,15 +16670,10 @@ void emitter::emitIns_Call(EmitCallType callType, * This specifically encode the field 'i1' at bit location '5'. */ -/*static*/ emitter::code_t emitter::insEncodeSveFloatImmZero_to_Two(double immDbl) +/*static*/ emitter::code_t emitter::insEncodeSveSmallFloatImm(ssize_t imm) { - assert((immDbl == 0.0) || (immDbl == 0.5) || (immDbl == 1.0) || (immDbl == 2.0)); - - if (immDbl < 1.0) - { - return 0; - } - return (1 << 5); + assert(emitIsValidEncodedSmallFloatImm(imm)); + return (code_t)(imm << 5); } /***************************************************************************** @@ -21333,7 +21488,7 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg code |= insEncodeReg_V_9_to_5(id->idReg3()); // nnnnn code |= insEncodeReg_V_20_to_16(id->idReg4()); // mmmmm - code |= insEncodeSveImm0_or_90_or_180_or_270_rot(imm); // rr + code |= insEncodeSveImm0_to_270_rot(imm); // rr code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx dst += emitOutput_Instr(dst, code); break; @@ -21350,21 +21505,11 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) case IF_SVE_HM_2A: // ........xx...... ...ggg....iddddd -- SVE floating-point arithmetic with immediate // (predicated) { - double immDbl = 0.0; - imm = emitGetInsSC(id); - - if (imm != 0) - { - floatImm8 fpImm; - fpImm.immFPIVal = (unsigned)imm; - immDbl = emitDecodeFloatImm8(fpImm); - } - code = emitInsCodeSve(ins, fmt); code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg - code |= insEncodeSveFloatImmZero_to_Two(immDbl); // i + code |= insEncodeSveSmallFloatImm(imm); // i code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx dst += emitOutput_Instr(dst, code); } @@ -21584,6 +21729,19 @@ void emitter::emitDispFloatImm(ssize_t imm8) printf("%.4f", result); } +/***************************************************************************** + * + * Display an encoded small float constant value + */ +void emitter::emitDispSmallFloatImm(ssize_t imm, instruction ins) +{ + if (strictArmAsm) + { + printf("#"); + } + printf("%.4f", emitDecodeSmallFloatImm(imm, ins)); +} + /***************************************************************************** * * Display an immediate with an optional left-shift. @@ -24674,20 +24832,22 @@ void emitter::emitDispInsHelp( // ., /M, ., ., case IF_SVE_GP_3A: // ........xx.....r ...gggmmmmmddddd -- SVE floating-point complex add (predicated) + imm = emitGetInsSC(id); emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispSveReg(id->idReg3(), id->idInsOpt(), true); - emitDispImm(emitGetInsSC(id), false); + emitDispImm(emitDecodeRotationImm90_or_270(imm), false); break; // ., /M, ., ., case IF_SVE_GT_4A: // ........xx.mmmmm .rrgggnnnnnddddd -- SVE floating-point complex multiply-add (predicated) + imm = emitGetInsSC(id); emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); emitDispSveReg(id->idReg3(), id->idInsOpt(), true); emitDispSveReg(id->idReg4(), id->idInsOpt(), true); - emitDispImm(emitGetInsSC(id), false); + emitDispImm(emitDecodeRotationImm0_to_270(imm), false); break; // ., /Z, ., #0.0 @@ -24705,14 +24865,7 @@ void emitter::emitDispInsHelp( emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); emitDispSveReg(id->idReg1(), id->idInsOpt(), true); - if (imm != 0) - { - emitDispFloatImm(imm); - } - else - { - emitDispFloatZero(); - } + emitDispSmallFloatImm(imm, id->idIns()); break; // ., ., ., # diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 56b90664cb4f8e..afaf54eefbb2e2 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -43,6 +43,7 @@ void emitDispImm(ssize_t imm, bool addComma, bool alwaysHex = false, bool isAddr void emitDispElementIndex(const ssize_t imm, const bool addComma); void emitDispFloatZero(); void emitDispFloatImm(ssize_t imm8); +void emitDispSmallFloatImm(ssize_t imm, instruction ins); void emitDispImmOptsLSL(ssize_t imm, bool hasShift, unsigned shiftAmount); void emitDispCond(insCond cond); void emitDispFlags(insCflags flags); @@ -294,6 +295,24 @@ static emitter::floatImm8 emitEncodeFloatImm8(double immDbl); static double emitDecodeFloatImm8(const emitter::floatImm8 fpImm); +static ssize_t emitEncodeRotationImm90_or_270(ssize_t imm); + +static ssize_t emitDecodeRotationImm90_or_270(ssize_t imm); + +static bool emitIsValidEncodedRotationImm90_or_270(ssize_t imm); + +static ssize_t emitEncodeRotationImm0_to_270(ssize_t imm); + +static ssize_t emitDecodeRotationImm0_to_270(ssize_t imm); + +static bool emitIsValidEncodedRotationImm0_to_270(ssize_t imm); + +static ssize_t emitEncodeSmallFloatImm(double immDbl, instruction ins); + +static double emitDecodeSmallFloatImm(ssize_t imm, instruction ins); + +static bool emitIsValidEncodedSmallFloatImm(size_t imm); + /************************************************************************ * * This union is used to encode/decode the cond, nzcv and imm5 values for @@ -520,11 +539,11 @@ static code_t insEncodeSveImm90_or_270_rot(ssize_t imm); // Returns the encoding to select the constant values 0, 90, 180 or 270 for an Arm64 SVE vector instruction // This specifically encode the field 'rot' at bit locations '14-13'. -static code_t insEncodeSveImm0_or_90_or_180_or_270_rot(ssize_t imm); +static code_t insEncodeSveImm0_to_270_rot(ssize_t imm); // Returns the encoding to select the constant float values 0, 0.5, 1.0 or 2.0 for an Arm64 SVE vector instruction // This specifically encode the field 'i1' at bit location '5'. -static code_t insEncodeSveFloatImmZero_to_Two(double immDbl); +static code_t insEncodeSveSmallFloatImm(ssize_t imm); // Returns the first register list size for the given SVE instruction. static int insGetSveReg1ListSize(instruction ins); From 92f4cd57a6d8187242a1f994ec811fe486d101bf Mon Sep 17 00:00:00 2001 From: TIHan Date: Fri, 9 Feb 2024 15:06:34 -0800 Subject: [PATCH 6/6] Formatting --- src/coreclr/jit/codegenarm64test.cpp | 4 +- src/coreclr/jit/emitarm64.cpp | 68 ++++++++++++++-------------- src/coreclr/jit/emitarm64.h | 16 +++---- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp index 0471ae2615a256..619047a20102d6 100644 --- a/src/coreclr/jit/codegenarm64test.cpp +++ b/src/coreclr/jit/codegenarm64test.cpp @@ -7205,7 +7205,7 @@ void CodeGen::genArm64EmitterUnitTestsSve() // IF_SVE_GP_3A theEmitter->emitIns_R_R_R_I(INS_sve_fcadd, EA_SCALABLE, REG_V0, REG_P1, REG_V2, 90, - INS_OPTS_SCALABLE_H); // FCADD ., /M, ., ., + INS_OPTS_SCALABLE_H); // FCADD ., /M, ., ., theEmitter->emitIns_R_R_R_I(INS_sve_fcadd, EA_SCALABLE, REG_V0, REG_P1, REG_V2, 270, INS_OPTS_SCALABLE_H); // FCADD ., /M, ., ., theEmitter->emitIns_R_R_R_I(INS_sve_fcadd, EA_SCALABLE, REG_V0, REG_P1, REG_V2, 270, @@ -7215,7 +7215,7 @@ void CodeGen::genArm64EmitterUnitTestsSve() // IF_SVE_GT_4A theEmitter->emitIns_R_R_R_R_I(INS_sve_fcmla, EA_SCALABLE, REG_V2, REG_P1, REG_V3, REG_V4, 0, - INS_OPTS_SCALABLE_H); // FCMLA ., /M, ., ., + INS_OPTS_SCALABLE_H); // FCMLA ., /M, ., ., theEmitter->emitIns_R_R_R_R_I(INS_sve_fcmla, EA_SCALABLE, REG_V0, REG_P2, REG_V1, REG_V5, 90, INS_OPTS_SCALABLE_S); // FCMLA ., /M, ., ., theEmitter->emitIns_R_R_R_R_I(INS_sve_fcmla, EA_SCALABLE, REG_V2, REG_P3, REG_V0, REG_V6, 180, diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 34afb90ca2f8d7..296623036d8df6 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -2079,10 +2079,10 @@ void emitter::emitInsSanityCheck(instrDesc* id) imm = emitGetInsSC(id); elemsize = id->idOpSize(); assert(insOptsScalableAtLeastHalf(id->idInsOpt())); - assert(isVectorRegister(id->idReg1())); + assert(isVectorRegister(id->idReg1())); assert(isLowPredicateRegister(id->idReg2())); assert(isVectorRegister(id->idReg3())); - assert(emitIsValidEncodedRotationImm90_or_270(imm)); + assert(emitIsValidEncodedRotationImm90_or_270(imm)); assert(isScalableVectorSize(elemsize)); break; @@ -2101,8 +2101,8 @@ void emitter::emitInsSanityCheck(instrDesc* id) case IF_SVE_HI_3A: // ........xx...... ...gggnnnnn.DDDD -- SVE floating-point compare with zero elemsize = id->idOpSize(); assert(insOptsScalableAtLeastHalf(id->idInsOpt())); - assert(isPredicateRegister(id->idReg1())); - assert(isLowPredicateRegister(id->idReg2())); + assert(isPredicateRegister(id->idReg1())); + assert(isLowPredicateRegister(id->idReg2())); assert(isVectorRegister(id->idReg3())); assert(isScalableVectorSize(elemsize)); break; @@ -6106,7 +6106,8 @@ emitter::code_t emitter::emitInsCodeSve(instruction ins, insFormat fmt) /************************************************************************ * - * Convert a rotation value that is 0, 90, 180 or 270 into a smaller encoding that matches one-to-one with the 'rot' field. + * Convert a rotation value that is 0, 90, 180 or 270 into a smaller encoding that matches one-to-one with the 'rot' + * field. */ /*static*/ ssize_t emitter::emitEncodeRotationImm0_to_270(ssize_t imm) @@ -9146,7 +9147,7 @@ void emitter::emitIns_R_R_I(instruction ins, assert(isScalableVectorSize(size)); fmt = IF_SVE_HN_2A; break; - + case INS_sve_ldr: assert(insOptsNone(opt)); assert(isScalableVectorSize(size)); @@ -12251,8 +12252,8 @@ void emitter::emitIns_R_R_R_I(instruction ins, case INS_sve_fcadd: assert(insOptsScalableAtLeastHalf(opt)); - assert(isVectorRegister(reg1)); - assert(isLowPredicateRegister(reg2)); + assert(isVectorRegister(reg1)); + assert(isLowPredicateRegister(reg2)); assert(isVectorRegister(reg3)); assert(isScalableVectorSize(size)); imm = emitEncodeRotationImm90_or_270(imm); @@ -13852,14 +13853,14 @@ void emitter::emitInsSve_R_R_R_R(instruction ins, * Add an instruction referencing four registers and a constant. */ -void emitter::emitIns_R_R_R_R_I(instruction ins, - emitAttr attr, - regNumber reg1, - regNumber reg2, - regNumber reg3, - regNumber reg4, - ssize_t imm, - insOpts opt /* = INS_OPT_NONE*/) +void emitter::emitIns_R_R_R_R_I(instruction ins, + emitAttr attr, + regNumber reg1, + regNumber reg2, + regNumber reg3, + regNumber reg4, + ssize_t imm, + insOpts opt /* = INS_OPT_NONE*/) { emitAttr size = EA_SIZE(attr); insFormat fmt = IF_NONE; @@ -17308,7 +17309,7 @@ void emitter::emitIns_Call(EmitCallType callType, case IF_SVE_HI_3A: assert((regpos == 1) || (regpos == 2)); return ((regpos == 2) ? PREDICATE_ZERO : PREDICATE_SIZED); - + case IF_SVE_ID_2A: case IF_SVE_JG_2A: return PREDICATE_NONE; @@ -18637,7 +18638,6 @@ 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 '18-16'. @@ -21827,16 +21827,16 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) case IF_SVE_HM_2A: // ........xx...... ...ggg....iddddd -- SVE floating-point arithmetic with immediate // (predicated) - { - imm = emitGetInsSC(id); - code = emitInsCodeSve(ins, fmt); - code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd - code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg - code |= insEncodeSveSmallFloatImm(imm); // i - code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx - dst += emitOutput_Instr(dst, code); - } - break; + { + imm = emitGetInsSC(id); + code = emitInsCodeSve(ins, fmt); + code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd + code |= insEncodeReg_P_12_to_10(id->idReg2()); // ggg + code |= insEncodeSveSmallFloatImm(imm); // i + code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx + dst += emitOutput_Instr(dst, code); + } + break; case IF_SVE_HN_2A: // ........xx...iii ......mmmmmddddd -- SVE floating-point trig multiply-add coefficient imm = emitGetInsSC(id); @@ -21876,7 +21876,7 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id) code |= insEncodeSveElemsize(optGetSveElemsize(id->idInsOpt())); // xx dst += emitOutput_Instr(dst, code); break; - + case IF_SVE_ID_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE load predicate register case IF_SVE_JG_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE store predicate register imm = emitGetInsSC(id); @@ -25215,8 +25215,8 @@ void emitter::emitDispInsHelp( // ., /Z, ., #0.0 case IF_SVE_HI_3A: // ........xx...... ...gggnnnnn.DDDD -- SVE floating-point compare with zero - emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt, 1), id->idInsOpt(), true); - emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt, 2), id->idInsOpt(), true); + emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt, 1), id->idInsOpt(), true); + emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt, 2), id->idInsOpt(), true); emitDispSveReg(id->idReg3(), id->idInsOpt(), true); emitDispFloatZero(); break; @@ -25236,14 +25236,14 @@ void emitter::emitDispInsHelp( emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispSveReg(id->idReg2(), id->idInsOpt(), true); - emitDispImm(emitGetInsSC(id), false); + emitDispImm(emitGetInsSC(id), false); break; // ., /M, . case IF_SVE_HP_3A: // .............xx. ...gggnnnnnddddd -- SVE floating-point convert to integer emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); - emitDispSveReg(id->idReg3(), id->idInsOpt(), false); + emitDispSveReg(id->idReg3(), id->idInsOpt(), false); break; // .H, /M, .H, .H @@ -25254,7 +25254,7 @@ void emitter::emitDispInsHelp( emitDispSveReg(id->idReg1(), id->idInsOpt(), true); emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); emitDispSveReg(id->idReg3(), id->idInsOpt(), true); - emitDispSveReg(id->idReg4(), id->idInsOpt(), false); + emitDispSveReg(id->idReg4(), id->idInsOpt(), false); break; default: diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 381d92e94ad959..6868f27f5bab94 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -1357,14 +1357,14 @@ void emitInsSve_R_R_R_R(instruction ins, insOpts opt = INS_OPTS_NONE, insScalableOpts sopt = INS_SCALABLE_OPTS_NONE); -void emitIns_R_R_R_R_I(instruction ins, - emitAttr attr, - regNumber reg1, - regNumber reg2, - regNumber reg3, - regNumber reg4, - ssize_t imm, - insOpts opt = INS_OPTS_NONE); +void emitIns_R_R_R_R_I(instruction ins, + emitAttr attr, + regNumber reg1, + regNumber reg2, + regNumber reg3, + regNumber reg4, + ssize_t imm, + insOpts opt = INS_OPTS_NONE); void emitIns_R_COND(instruction ins, emitAttr attr, regNumber reg, insCond cond);