Skip to content
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

ARM64-SVE: Implement IF_SVE_BV_2A #99049

Merged
merged 7 commits into from
Mar 5, 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
40 changes: 40 additions & 0 deletions src/coreclr/jit/codegenarm64test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5431,6 +5431,46 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_zip2, EA_SCALABLE, REG_V15, REG_V16, REG_V17, INS_OPTS_SCALABLE_Q,
INS_SCALABLE_OPTS_UNPREDICATED); // ZIP2 <Zd>.Q, <Zn>.Q, <Zm>.Q

// IF_SVE_BV_2A
theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V15, REG_P5, 0,
INS_OPTS_SCALABLE_B); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V5, REG_P15, 27,
INS_OPTS_SCALABLE_B); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V31, REG_P0, -128,
INS_OPTS_SCALABLE_B); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_mov, EA_SCALABLE, REG_V0, REG_P5, 127,
INS_OPTS_SCALABLE_B); // MOV <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}

theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V15, REG_P5, 0,
INS_OPTS_SCALABLE_H); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_mov, EA_SCALABLE, REG_V23, REG_P12, 10,
INS_OPTS_SCALABLE_S); // MOV <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V4, REG_P0, -128,
INS_OPTS_SCALABLE_D); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_mov, EA_SCALABLE, REG_V19, REG_P15, 127,
INS_OPTS_SCALABLE_H); // MOV <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}

theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V1, REG_P0, 256,
INS_OPTS_SCALABLE_S); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V1, REG_P0, 3072,
INS_OPTS_SCALABLE_D); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V1, REG_P0, -3072,
INS_OPTS_SCALABLE_H); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V1, REG_P0, -32768,
INS_OPTS_SCALABLE_S); // CPY <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_mov, EA_SCALABLE, REG_P0, REG_V0, 32512,
INS_OPTS_SCALABLE_D); // MOV <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}

// IF_SVE_BV_2A_A
theEmitter->emitIns_R_R_I(INS_sve_cpy, EA_SCALABLE, REG_V1, REG_P12, 5, INS_OPTS_SCALABLE_B,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be removed I assume?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can do it in a follow-up PR though.

INS_SCALABLE_OPTS_PREDICATE_MERGE); // CPY <Zd>.<T>, <Pg>/M, #<imm>{, <shift>}

// IF_SVE_BV_2A_J
theEmitter->emitIns_R_R_I(INS_sve_mov, EA_SCALABLE, REG_V27, REG_P13, 5632, INS_OPTS_SCALABLE_H,
INS_SCALABLE_OPTS_PREDICATE_MERGE); // MOV <Zd>.<T>, <Pg>/M, #<imm>{, <shift>}
theEmitter->emitIns_R_R_I(INS_sve_mov, EA_SCALABLE, REG_V27, REG_P13, -5632, INS_OPTS_SCALABLE_H,
INS_SCALABLE_OPTS_PREDICATE_MERGE); // MOV <Zd>.<T>, <Pg>/M, #<imm>{, <shift>}

// IF_SVE_BZ_3A
theEmitter->emitIns_R_R_R(INS_sve_tbl, EA_SCALABLE, REG_V0, REG_V1, REG_V2,
INS_OPTS_SCALABLE_B); // TBL <Zd>.<T>, {<Zn>.<T>}, <Zm>.<T>
Expand Down
98 changes: 87 additions & 11 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,17 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(isValidUimm4From1(emitGetInsSC(id)));
break;

case IF_SVE_BV_2A: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated)
case IF_SVE_BV_2A_J: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated)
assert(insOptsScalableStandard(id->idInsOpt())); // xx
// Size specifier must be able to fit left-shifted immediate
assert(insOptsScalableAtLeastHalf(id->idInsOpt()) || !id->idOptionalShift());
assert(isVectorRegister(id->idReg1())); // ddddd
assert(isPredicateRegister(id->idReg2())); // gggg
assert(isValidSimm8(emitGetInsSC(id))); // iiiiiiii
assert(isValidVectorElemsize(optGetSveElemsize(id->idInsOpt()))); // xx
break;

case IF_SVE_CE_2A: // ................ ......nnnnn.DDDD -- SVE move predicate from vector
assert(isPredicateRegister(id->idReg1())); // DDDD
assert(isVectorRegister(id->idReg2())); // nnnnn
Expand Down Expand Up @@ -9404,16 +9415,18 @@ void emitter::emitIns_R_R_I(instruction ins,
insOpts opt /* = INS_OPTS_NONE */,
insScalableOpts sopt /* = INS_SCALABLE_OPTS_NONE */)
{
emitAttr size = EA_SIZE(attr);
emitAttr elemsize = EA_UNKNOWN;
insFormat fmt = IF_NONE;
bool isLdSt = false;
bool isLdrStr = false;
bool isSIMD = false;
bool isAddSub = false;
bool setFlags = false;
unsigned scale = 0;
bool unscaledOp = false;
emitAttr size = EA_SIZE(attr);
emitAttr elemsize = EA_UNKNOWN;
insFormat fmt = IF_NONE;
bool isLdSt = false;
bool isLdrStr = false;
bool isSIMD = false;
bool isAddSub = false;
bool setFlags = false;
unsigned scale = 0;
bool unscaledOp = false;
bool optionalShift = false;
bool hasShift = false;

/* Figure out the encoding format of the instruction */
switch (ins)
Expand Down Expand Up @@ -10058,6 +10071,32 @@ void emitter::emitIns_R_R_I(instruction ins,
fmt = IF_SVE_BB_2A;
break;

case INS_sve_mov:
case INS_sve_cpy:
optionalShift = true;
assert(insOptsScalableStandard(opt));
assert(isVectorRegister(reg1)); // DDDDD
assert(isPredicateRegister(reg2)); // GGGG
if (!isValidSimm8(imm))
{
assert(isValidSimm8_MultipleOf256(imm));
assert(insOptsScalableAtLeastHalf(opt));
hasShift = true;
imm = imm / 256;
}
if (sopt == INS_SCALABLE_OPTS_PREDICATE_MERGE)
{
fmt = IF_SVE_BV_2A_J;
}
else
{
assert(sopt == INS_SCALABLE_OPTS_NONE);
fmt = IF_SVE_BV_2A;
}
// MOV is an alias for CPY, and is always the preferred disassembly.
ins = INS_sve_mov;
break;

case INS_sve_pmov:
if (sopt == INS_SCALABLE_OPTS_TO_PREDICATE)
{
Expand Down Expand Up @@ -10477,7 +10516,18 @@ void emitter::emitIns_R_R_I(instruction ins,

assert(fmt != IF_NONE);

instrDesc* id = emitNewInstrSC(attr, imm);
instrDesc* id;

if (!optionalShift)
{
id = emitNewInstrSC(attr, imm);
}
else
{
// Instructions with optional shifts (MOV, DUP, etc.) need larger instrDesc to store state
id = emitNewInstrCns(attr, imm);
id->idOptionalShift(hasShift);
}

id->idIns(ins);
id->idInsFmt(fmt);
Expand Down Expand Up @@ -24365,6 +24415,17 @@ BYTE* emitter::emitOutput_InstrSve(BYTE* dst, instrDesc* id)
dst += emitOutput_Instr(dst, code);
break;

case IF_SVE_BV_2A: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated)
case IF_SVE_BV_2A_J: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated)
imm = emitGetInsSC(id);
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_V_4_to_0(id->idReg1()); // ddddd
code |= insEncodeReg_P_19_to_16(id->idReg2()); // gggg
code |= insEncodeImm8_12_to_5(imm); // iiiiiiii
code |= (id->idOptionalShift() ? 0x2000 : 0); // h
code |= insEncodeElemsize(optGetSveElemsize(id->idInsOpt())); // xx
break;

case IF_SVE_CE_2A: // ................ ......nnnnn.DDDD -- SVE move predicate from vector
code = emitInsCodeSve(ins, fmt);
code |= insEncodeReg_P_3_to_0(id->idReg1()); // DDDD
Expand Down Expand Up @@ -30012,6 +30073,15 @@ void emitter::emitDispInsHelp(
emitDispImm(imm, false);
break;

// <Zd>.<T>, <Pg>/Z, #<imm>{, <shift>}
case IF_SVE_BV_2A: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated)
case IF_SVE_BV_2A_J: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated)
imm = emitGetInsSC(id);
emitDispSveReg(id->idReg1(), id->idInsOpt(), true); // ddddd
emitDispPredicateReg(id->idReg2(), insGetPredicateType(fmt), id->idInsOpt(), true); // gggg
emitDispImmOptsLSL(emitGetInsSC(id), id->idOptionalShift(), 8); // iiiiiiii, h
break;

// <Zd>.<T>, <Zn>.<T>[<imm>]
case IF_SVE_BX_2A: // ...........ixxxx ......nnnnnddddd -- sve_int_perm_dupq_i
imm = emitGetInsSC(id);
Expand Down Expand Up @@ -32554,6 +32624,12 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
result.insLatency = PERFSCORE_LATENCY_2C;
break;

case IF_SVE_BV_2A: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated)
case IF_SVE_BV_2A_J: // ........xx..gggg ..hiiiiiiiiddddd -- SVE copy integer immediate (predicated)
result.insThroughput = PERFSCORE_THROUGHPUT_2C;
result.insLatency = PERFSCORE_LATENCY_2C;
break;

case IF_SVE_CE_2A: // ................ ......nnnnn.DDDD -- SVE move predicate from vector
case IF_SVE_CE_2B: // .........i...ii. ......nnnnn.DDDD -- SVE move predicate from vector
case IF_SVE_CE_2C: // ..............i. ......nnnnn.DDDD -- SVE move predicate from vector
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/emitarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,12 @@ static bool isValidSimm8(ssize_t value)
return (-0x80 <= value) && (value <= 0x7F);
};

// Returns true if 'value' is a legal signed multiple of 256 immediate 8 bit encoding (such as for MOV).
static bool isValidSimm8_MultipleOf256(ssize_t value)
{
return (-0x8000 <= value) && (value <= 0x7f00) && (value % 256 == 0);
};

// Returns true if 'value' is a legal unsigned immediate 12 bit encoding (such as for CMP, CMN).
static bool isValidUimm12(ssize_t value)
{
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/instr.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ enum insScalableOpts : unsigned
INS_SCALABLE_OPTS_WITH_PREDICATE_PAIR, // Variants with {<Pd1>.<T>, <Pd2>.<T>} predicate pair (eg whilege)
INS_SCALABLE_OPTS_VL_2X, // Variants with a vector length specifier of 2x (eg whilege)
INS_SCALABLE_OPTS_VL_4X, // Variants with a vector length specifier of 4x (eg whilege)

// TODO-SVE: Remove and pass the full immediate value instead.
INS_SCALABLE_OPTS_SHIFT, // Variants with an optional shift operation (eg dup)

INS_SCALABLE_OPTS_LSL_N, // Variants with a LSL #N (eg {<Zt>.<T>}, <Pg>, [<Xn|SP>, <Xm>, LSL #2])
Expand Down