Skip to content

JIT: ARM64 SVE format encodings, SVE_ID_2A to SVE_JH_2A #98015

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/coreclr/jit/codegenarm64test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6946,6 +6946,48 @@ 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 {<Zt>.D }, <Pg>, [<Xn|SP>, <Zm>.D]

// IF_SVE_ID_2A
// LDR <Pt>, [<Xn|SP>{, #<imm>, MUL VL}]
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, 0);
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, 76);
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, -25);
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, -256);
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_P1, REG_R5, 255);

// IF_SVE_JG_2A
// STR <Pt>, [<Xn|SP>{, #<imm>, MUL VL}]
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, 0);
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, 221);
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, -117);
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, -256);
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_P3, REG_R1, 255);

// IF_SVE_IE_2A
// LDR <Zt>, [<Xn|SP>{, #<imm>, MUL VL}]
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, 0, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, 33, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, -173, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, -256, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
theEmitter->emitIns_R_R_I(INS_sve_ldr, EA_SCALABLE, REG_V3, REG_R4, 255, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);

// IF_SVE_JH_2A
// STR <Zt>, [<Xn|SP>{, #<imm>, MUL VL}]
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, 0, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, 71, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, -165, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, -256, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
theEmitter->emitIns_R_R_I(INS_sve_str, EA_SCALABLE, REG_V2, REG_R3, 255, INS_OPTS_NONE,
INS_SCALABLE_OPTS_UNPREDICATED);
}

#endif // defined(TARGET_ARM64) && defined(DEBUG)
172 changes: 156 additions & 16 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2032,6 +2032,28 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(isScalableVectorSize(elemsize));
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
elemsize = id->idOpSize();
assert(insOptsNone(id->idInsOpt()));
assert(isScalableVectorSize(elemsize));
assert(isPredicateRegister(id->idReg1())); // TTTT
assert(isGeneralRegister(id->idReg2())); // nnnnn
assert(isValidSimm9(emitGetInsSC(id))); // iii
// iiiiii
break;

case IF_SVE_IE_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE load vector register
case IF_SVE_JH_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE store vector register
elemsize = id->idOpSize();
assert(insOptsNone(id->idInsOpt()));
assert(isScalableVectorSize(elemsize));
assert(isVectorRegister(id->idReg1())); // ttttt
assert(isGeneralRegister(id->idReg2())); // nnnnn
assert(isValidSimm9(emitGetInsSC(id))); // iii
// iiiiii
break;

default:
printf("unexpected format %s\n", emitIfName(id->idInsFmt()));
assert(!"Unexpected format");
Expand Down Expand Up @@ -8753,6 +8775,46 @@ void emitter::emitIns_R_R_I(instruction ins,
}
break;

case INS_sve_ldr:
assert(insOptsNone(opt));
assert(isScalableVectorSize(size));
assert(isGeneralRegister(reg2)); // nnnnn
assert(isValidSimm9(imm)); // iii
// iiiiii

if (sopt == INS_SCALABLE_OPTS_UNPREDICATED)
{
assert(isVectorRegister(reg1));
fmt = IF_SVE_IE_2A;
}
else
{
assert(insScalableOptsNone(sopt));
assert(isPredicateRegister(reg1));
fmt = IF_SVE_ID_2A;
}
break;

case INS_sve_str:
assert(insOptsNone(opt));
assert(isScalableVectorSize(size));
assert(isGeneralRegister(reg2)); // nnnnn
assert(isValidSimm9(imm)); // iii
// iiiiii

if (sopt == INS_SCALABLE_OPTS_UNPREDICATED)
{
assert(isVectorRegister(reg1));
fmt = IF_SVE_JH_2A;
}
else
{
assert(insScalableOptsNone(sopt));
assert(isPredicateRegister(reg1));
fmt = IF_SVE_JG_2A;
}
break;

default:
unreached();
break;
Expand Down Expand Up @@ -16416,6 +16478,10 @@ void emitter::emitIns_Call(EmitCallType callType,
assert((regpos == 2) || (regpos == 3));
return ((regpos == 2) ? PREDICATE_NONE : PREDICATE_SIZED);

case IF_SVE_ID_2A:
case IF_SVE_JG_2A:
return PREDICATE_NONE;

default:
break;
}
Expand Down Expand Up @@ -17562,6 +17628,26 @@ void emitter::emitIns_Call(EmitCallType callType,
return (code_t)imm << 16;
}

/*****************************************************************************
*
* Returns the encoding for the immediate value as 9-bits at bit locations '21-16' for high and '12-10' for low.
*/

/*static*/ emitter::code_t emitter::insEncodeSimm9h9l_21_to_16_and_12_to_10(ssize_t imm)
{
assert(isValidSimm9(imm));

if (imm < 0)
{
imm = (imm & 0x1FF);
}

code_t h = (code_t)(imm & 0x1F8) << 13; // encode high 6-bits at locations '21-16'
code_t l = (code_t)((imm & ~0x1F8) & 0x7) << 10; // encode low 3-bits at locations '12-10'

return (h | l);
}

/*****************************************************************************
*
* Returns the encoding for the immediate value that is a multiple of 2 as 4-bits at bit locations '19-16'.
Expand Down Expand Up @@ -20796,6 +20882,28 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id)
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);
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_3_to_0(id->idReg1()); // TTTT
code |= insEncodeReg_R_9_to_5(id->idReg2()); // nnnnn
code |= insEncodeSimm9h9l_21_to_16_and_12_to_10(imm); // iii
// iiiiii
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_IE_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE load vector register
case IF_SVE_JH_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE store vector register
imm = emitGetInsSC(id);
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ttttt
code |= insEncodeReg_R_9_to_5(id->idReg2()); // nnnnn
code |= insEncodeSimm9h9l_21_to_16_and_12_to_10(imm); // iii
// iiiiii
dst += emitOutput_Instr(dst, code);
break;

default:
assert(!"Unexpected format");
break;
Expand Down Expand Up @@ -21181,6 +21289,22 @@ void emitter::emitDispSveModAddr(instruction ins, regNumber reg1, regNumber reg2
printf("]");
}

/*****************************************************************************
*
* Prints the encoding for format [<Xn|SP>{, #<imm>, MUL VL}]
*/
void emitter::emitDispSveImmMulVl(regNumber reg1, ssize_t imm)
{
printf("[");
emitDispReg(reg1, EA_8BYTE, imm != 0);
if (imm != 0)
{
emitDispImm(imm, true);
printf("mul vl");
}
printf("]");
}

/*****************************************************************************
*
* Prints the encoding for the Extend Type encoding in loads/stores
Expand Down Expand Up @@ -23986,29 +24110,33 @@ void emitter::emitDispInsHelp(
imm = emitGetInsSC(id);
emitDispSveConsecutiveRegList(id->idReg1(), insGetSveReg1ListSize(ins), id->idInsOpt(), true); // ttttt
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); // ggg
printf("[");
emitDispReg(id->idReg3(), EA_8BYTE, imm != 0); // nnnnn
if (imm != 0)
{
emitDispImm(emitGetInsSC(id), true); // iiii
printf("mul vl");
}
printf("]");
emitDispSveImmMulVl(id->idReg3(), imm);
break;

// {<Zt>.<T>}, <Pg>, [<Xn|SP>{, #<imm>, MUL VL}]
case IF_SVE_JN_3B: // ..........x.iiii ...gggnnnnnttttt -- SVE contiguous store (scalar plus immediate)
imm = emitGetInsSC(id);
emitDispSveConsecutiveRegList(id->idReg1(), insGetSveReg1ListSize(ins), id->idInsOpt(), true); // ttttt
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); // ggg
printf("[");
emitDispReg(id->idReg3(), EA_8BYTE, imm != 0); // nnnnn
if (imm != 0)
{
emitDispImm(emitGetInsSC(id), true); // iiii
printf("mul vl");
}
printf("]");
emitDispSveImmMulVl(id->idReg3(), imm);
break;

// <Pt>, [<Xn|SP>{, #<imm>, MUL VL}]
case IF_SVE_ID_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE load predicate register
// <Pt>, [<Xn|SP>{, #<imm>, MUL VL}]
case IF_SVE_JG_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE store predicate register
imm = emitGetInsSC(id);
emitDispPredicateReg(id->idReg1(), insGetPredicateType(fmt), id->idInsOpt(), true); // TTTT
emitDispSveImmMulVl(id->idReg2(), imm);
break;

// <Zt>, [<Xn|SP>{, #<imm>, MUL VL}]
case IF_SVE_IE_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE load vector register
// <Zt>, [<Xn|SP>{, #<imm>, MUL VL}]
case IF_SVE_JH_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE store vector register
imm = emitGetInsSC(id);
emitDispReg(id->idReg1(), EA_SCALABLE, true); // ttttt
emitDispSveImmMulVl(id->idReg2(), imm);
break;

default:
Expand Down Expand Up @@ -27431,6 +27559,18 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
result.insLatency = PERFSCORE_LATENCY_2C;
break;

case IF_SVE_ID_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE load predicate register
case IF_SVE_IE_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE load vector register
result.insThroughput = PERFSCORE_THROUGHPUT_3C;
result.insLatency = PERFSCORE_LATENCY_6C;
break;

case IF_SVE_JG_2A: // ..........iiiiii ...iiinnnnn.TTTT -- SVE store predicate register
case IF_SVE_JH_2A: // ..........iiiiii ...iiinnnnnttttt -- SVE store vector register
result.insThroughput = PERFSCORE_THROUGHPUT_2C;
result.insLatency = PERFSCORE_LATENCY_2C;
break;

default:
// all other instructions
perfScoreUnhandledInstruction(id, &result);
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/jit/emitarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ void emitDispExtendOpts(insOpts opt);
void emitDispSveExtendOpts(insOpts opt);
void emitDispSveExtendOptsModN(insOpts opt, int n);
void emitDispSveModAddr(instruction ins, regNumber reg1, regNumber reg2, insOpts opt, insFormat fmt);
void emitDispSveImmMulVl(regNumber reg1, ssize_t imm);
void emitDispLSExtendOpts(insOpts opt);
void emitDispReg(regNumber reg, emitAttr attr, bool addComma);
void emitDispSveReg(regNumber reg, insOpts opt, bool addComma);
Expand Down Expand Up @@ -543,6 +544,9 @@ static code_t insEncodeSveElemsize_dtype_ld1w(instruction ins, insFormat fmt, em
// Returns the encoding for the immediate value as 4-bits at bit locations '19-16'.
static code_t insEncodeSimm4_19_to_16(ssize_t imm);

// Returns the encoding for the immediate value as 9-bits at bit locations '21-16' for high and '12-10' for low.
static code_t insEncodeSimm9h9l_21_to_16_and_12_to_10(ssize_t imm);

// Returns the encoding for the immediate value that is a multiple of 2 as 4-bits at bit locations '19-16'.
static code_t insEncodeSimm4_MultipleOf2_19_to_16(ssize_t imm);

Expand Down Expand Up @@ -611,6 +615,12 @@ static bool isValidSimm4(ssize_t value)
return (-8 <= value) && (value <= 7);
};

// Returns true if 'value' is a legal signed immediate 9 bit encoding (such as for LDR).
static bool isValidSimm9(ssize_t value)
{
return (-256 <= value) && (value <= 255);
};

// Returns true if 'value' is a legal signed multiple of 2 immediate 4 bit encoding (such as for LD2Q).
static bool isValidSimm4_MultipleOf2(ssize_t value)
{
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/instrsarm64sve.h
Original file line number Diff line number Diff line change
Expand Up @@ -942,13 +942,13 @@ INST3(stnt1d, "stnt1d", 0, IF_SV


// enum name info SVE_ID_2A SVE_IE_2A
INST2(ldr, "ldr", LD, IF_SVE_2AA, 0x85800000, 0x85804000 )
INST2(ldr, "ldr", 0, IF_SVE_2AA, 0x85800000, 0x85804000 )
// LDR <Pt>, [<Xn|SP>{, #<imm>, MUL VL}] SVE_ID_2A 1000010110iiiiii 000iiinnnnn0TTTT 8580 0000
// LDR <Zt>, [<Xn|SP>{, #<imm>, MUL VL}] SVE_IE_2A 1000010110iiiiii 010iiinnnnnttttt 8580 4000


// enum name info SVE_JG_2A SVE_JH_2A
INST2(str, "str", ST, IF_SVE_2AB, 0xE5800000, 0xE5804000 )
INST2(str, "str", 0, IF_SVE_2AB, 0xE5800000, 0xE5804000 )
// STR <Pt>, [<Xn|SP>{, #<imm>, MUL VL}] SVE_JG_2A 1110010110iiiiii 000iiinnnnn0TTTT E580 0000
// STR <Zt>, [<Xn|SP>{, #<imm>, MUL VL}] SVE_JH_2A 1110010110iiiiii 010iiinnnnnttttt E580 4000

Expand Down