Skip to content
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
28 changes: 28 additions & 0 deletions src/coreclr/jit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -2214,6 +2214,18 @@ class emitter
};
#endif

#ifdef TARGET_RISCV64
struct instrDescLoadImm : instrDescCns
{
instrDescLoadImm() = delete;

static const int absMaxInsCount = 8;

instruction ins[absMaxInsCount];
int32_t values[absMaxInsCount];
};
#endif // TARGET_RISCV64

struct instrDescCGCA : instrDesc // call with ...
{
instrDescCGCA() = delete;
Expand Down Expand Up @@ -3149,6 +3161,10 @@ class emitter
instrDesc* emitNewInstrLclVarPair(emitAttr attr, cnsval_ssize_t cns);
#endif // !TARGET_ARM64

#ifdef TARGET_RISCV64
instrDesc* emitNewInstrLoadImm(emitAttr attr, cnsval_ssize_t cns);
#endif // TARGET_RISCV64

static const BYTE emitFmtToOps[];

#ifdef DEBUG
Expand Down Expand Up @@ -3981,6 +3997,18 @@ inline emitter::instrDesc* emitter::emitNewInstrReloc(emitAttr attr, BYTE* addr)

#endif // TARGET_ARM

#ifdef TARGET_RISCV64

inline emitter::instrDesc* emitter::emitNewInstrLoadImm(emitAttr attr, cnsval_ssize_t cns)
{
instrDescLoadImm* id = static_cast<instrDescLoadImm*>(emitAllocAnyInstr(sizeof(instrDescLoadImm), attr));
id->idInsOpt(INS_OPTS_I);
id->idcCnsVal = cns;
return id;
}

#endif // TARGET_RISCV64

#ifdef TARGET_XARCH

/*****************************************************************************
Expand Down
116 changes: 87 additions & 29 deletions src/coreclr/jit/emitriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ size_t emitter::emitSizeOfInsDsc(instrDesc* id) const
case INS_OPTS_RELOC:
case INS_OPTS_NONE:
return sizeof(instrDesc);
case INS_OPTS_I:
return sizeof(instrDescLoadImm);
default:
NO_WAY("unexpected instruction descriptor format");
break;
Expand Down Expand Up @@ -1362,7 +1364,7 @@ void emitter::emitLoadImmediate(emitAttr size, regNumber reg, ssize_t imm)
* b <-a
* */

constexpr int absMaxInsCount = 8;
constexpr int absMaxInsCount = instrDescLoadImm::absMaxInsCount;
constexpr int prefMaxInsCount = 5;
assert(prefMaxInsCount <= absMaxInsCount);

Expand Down Expand Up @@ -1553,33 +1555,21 @@ void emitter::emitLoadImmediate(emitAttr size, regNumber reg, ssize_t imm)

if (numberOfInstructions <= insCountLimit)
{
for (int i = 0; i < numberOfInstructions; i++)
{
if ((i == 0) && (ins[0] == INS_lui))
{
emitIns_R_I(ins[i], size, reg, values[i]);
}
else if ((i == 0) && ((ins[0] == INS_addiw) || (ins[0] == INS_addi)))
{
emitIns_R_R_I(ins[i], size, reg, REG_R0, values[i]);
}
else if (i == 0)
{
assert(false && "First instruction must be lui / addiw / addi");
}
else if ((ins[i] == INS_addi) || (ins[i] == INS_addiw) || (ins[i] == INS_slli))
{
emitIns_R_R_I(ins[i], size, reg, reg, values[i]);
}
else
{
assert(false && "Remainding instructions must be addi / addiw / slli");
}
}
instrDescLoadImm* id = static_cast<instrDescLoadImm*>(emitNewInstrLoadImm(size, originalImm));
id->idReg1(reg);
memcpy(id->ins, ins, sizeof(instruction) * numberOfInstructions);
memcpy(id->values, values, sizeof(int32_t) * numberOfInstructions);
if (utilizeSRLI)
{
emitIns_R_R_I(INS_srli, size, reg, reg, srliShiftAmount);
numberOfInstructions += 1;
assert(numberOfInstructions < absMaxInsCount);
id->ins[numberOfInstructions - 1] = INS_srli;
id->values[numberOfInstructions - 1] = srliShiftAmount;
}
id->idCodeSize(numberOfInstructions * 4);
id->idIns(id->ins[numberOfInstructions - 1]);

appendToCurIG(id);
}
else if (size == EA_PTRSIZE)
{
Expand Down Expand Up @@ -3444,6 +3434,50 @@ BYTE* emitter::emitOutputInstr_OptsC(BYTE* dst, instrDesc* id, const insGroup* i
return dst;
}

BYTE* emitter::emitOutputInstr_OptsI(BYTE* dst, instrDesc* id, instruction* lastIns)
{
assert(id->idInsOpt() == INS_OPTS_I);

instrDescLoadImm* idli = static_cast<instrDescLoadImm*>(id);
instruction* ins = idli->ins;
int32_t* values = idli->values;
regNumber reg = idli->idReg1();

assert((reg != REG_NA) && (reg != REG_R0));

int numberOfInstructions = idli->idCodeSize() / sizeof(code_t);
for (int i = 0; i < numberOfInstructions; i++)
{
if ((i == 0) && (ins[0] == INS_lui))
{
assert(isValidSimm20(values[i]));
dst += emitOutput_UTypeInstr(dst, ins[i], reg, values[i] & 0xfffff);
}
else if ((i == 0) && ((ins[0] == INS_addiw) || (ins[0] == INS_addi)))
{
assert(isValidSimm12(values[i]) || ((ins[i] == INS_addiw) && isValidUimm12(values[i])));
dst += emitOutput_ITypeInstr(dst, ins[i], reg, REG_R0, values[i] & 0xfff);
}
else if (i == 0)
{
assert(false && "First instruction must be lui / addiw / addi");
}
else if ((ins[i] == INS_addi) || (ins[i] == INS_addiw) || (ins[i] == INS_slli) || (ins[i] == INS_srli))
{
assert(isValidSimm12(values[i]) || ((ins[i] == INS_addiw) && isValidUimm12(values[i])));
dst += emitOutput_ITypeInstr(dst, ins[i], reg, reg, values[i] & 0xfff);
}
else
{
assert(false && "Remaining instructions must be addi / addiw / slli / srli");
}
}

*lastIns = ins[numberOfInstructions - 1];

return dst;
}

/*****************************************************************************
*
* Append the machine code corresponding to the given instruction descriptor
Expand Down Expand Up @@ -3497,6 +3531,10 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst2 = dst;
ins = INS_nop;
break;
case INS_OPTS_I:
dst = emitOutputInstr_OptsI(dst, id, &ins);
sz = sizeof(instrDescLoadImm);
break;
default: // case INS_OPTS_NONE:
dst += emitOutput_Instr(dst, id->idAddr()->iiaGetInstrEncode());
ins = id->idIns();
Expand Down Expand Up @@ -3752,6 +3790,8 @@ void emitter::emitDispInsName(

printf(" ");

bool willPrintLoadImmValue = (id->idInsOpt() == INS_OPTS_I) && !emitComp->opts.disDiffable;

switch (GetMajorOpcode(code))
{
case MajorOpcode::Lui:
Expand All @@ -3763,7 +3803,7 @@ void emitter::emitDispInsName(
imm20 |= 0xfff00000;
}
printf("lui %s, ", rd);
emitDispImmediate(imm20);
emitDispImmediate(imm20, !willPrintLoadImmValue);
return;
}
case MajorOpcode::Auipc:
Expand Down Expand Up @@ -3881,7 +3921,10 @@ void emitter::emitDispInsName(
printf("%d", imm12);
}
}
printf("\n");
if (!willPrintLoadImmValue)
{
printf("\n");
}

return;
}
Expand All @@ -3901,7 +3944,7 @@ void emitter::emitDispInsName(
else
{
printf("addiw %s, %s, ", rd, rs1);
emitDispImmediate(imm12);
emitDispImmediate(imm12, !willPrintLoadImmValue);
}
return;
case 0x1:
Expand Down Expand Up @@ -4749,6 +4792,8 @@ void emitter::emitDispIns(

emitDispInsInstrNum(id);

bool willPrintLoadImmValue = (id->idInsOpt() == INS_OPTS_I) && !emitComp->opts.disDiffable;

const BYTE* instr = pCode + writeableOffset;
unsigned instrSize;
for (size_t i = 0; i < sz; instr += instrSize, i += instrSize, offset += instrSize)
Expand All @@ -4764,6 +4809,17 @@ void emitter::emitDispIns(
}
#endif
emitDispInsName(instruction, instr, doffs, offset, id, ig);

if (willPrintLoadImmValue && ((i + instrSize) < sz))
{
printf("\n");
}
}

if (willPrintLoadImmValue)
{
instrDescLoadImm* liid = static_cast<instrDescLoadImm*>(id);
printf("\t\t;; load imm: hex=0x%016lX dec=%ld\n", liid->idcCnsVal, liid->idcCnsVal);
}
}

Expand Down Expand Up @@ -5446,13 +5502,15 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins

unsigned codeSize = id->idCodeSize();
assert((codeSize >= 4) && (codeSize % sizeof(code_t) == 0));

// Some instructions like jumps or loads may have not-yet-known simple auxilliary instructions (lui, addi, slli,
// etc) for building immediates, assume cost of one each.
// instrDescLoadImm consists of OpImm, OpImm32, and Lui instructions.
float immediateBuildingCost = ((codeSize / sizeof(code_t)) - 1) * PERFSCORE_LATENCY_1C;

instruction ins = id->idIns();
assert(ins != INS_invalid);
if (ins == INS_lea)
if ((ins == INS_lea) || (id->idInsOpt() == INS_OPTS_I))
{
result.insLatency += immediateBuildingCost;
result.insThroughput += immediateBuildingCost;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/emitriscv64.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ BYTE* emitOutputInstr_OptsJalr28(BYTE* dst, const instrDescJmp* jmp, ssize_t imm
BYTE* emitOutputInstr_OptsJCond(BYTE* dst, instrDesc* id, const insGroup* ig, instruction* ins);
BYTE* emitOutputInstr_OptsJ(BYTE* dst, instrDesc* id, const insGroup* ig, instruction* ins);
BYTE* emitOutputInstr_OptsC(BYTE* dst, instrDesc* id, const insGroup* ig, size_t* size);
BYTE* emitOutputInstr_OptsI(BYTE* dst, instrDesc* id, instruction* ins);

static unsigned TrimSignedToImm12(ssize_t imm12);
static unsigned TrimSignedToImm13(ssize_t imm13);
Expand Down
25 changes: 13 additions & 12 deletions src/coreclr/jit/instr.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ enum insFlags : uint64_t
Encoding_REX2 = 1ULL << 44,

// APX: EVEX.ND:
INS_Flags_Has_NDD = 1ULL << 45,
INS_Flags_Has_NDD = 1ULL << 45,

// APX: EVEX.NF:
INS_Flags_Has_NF = 1ULL << 46,

Expand Down Expand Up @@ -438,16 +438,16 @@ enum insSvePattern : unsigned
enum insSvePrfop : unsigned
{
SVE_PRFOP_PLDL1KEEP = 0b0000,
SVE_PRFOP_PLDL1STRM = 0b0001,
SVE_PRFOP_PLDL2KEEP = 0b0010,
SVE_PRFOP_PLDL2STRM = 0b0011,
SVE_PRFOP_PLDL3KEEP = 0b0100,
SVE_PRFOP_PLDL3STRM = 0b0101,
SVE_PRFOP_PSTL1KEEP = 0b1000,
SVE_PRFOP_PSTL1STRM = 0b1001,
SVE_PRFOP_PSTL2KEEP = 0b1010,
SVE_PRFOP_PSTL2STRM = 0b1011,
SVE_PRFOP_PSTL3KEEP = 0b1100,
SVE_PRFOP_PLDL1STRM = 0b0001,
SVE_PRFOP_PLDL2KEEP = 0b0010,
SVE_PRFOP_PLDL2STRM = 0b0011,
SVE_PRFOP_PLDL3KEEP = 0b0100,
SVE_PRFOP_PLDL3STRM = 0b0101,
SVE_PRFOP_PSTL1KEEP = 0b1000,
SVE_PRFOP_PSTL1STRM = 0b1001,
SVE_PRFOP_PSTL2KEEP = 0b1010,
SVE_PRFOP_PSTL2STRM = 0b1011,
SVE_PRFOP_PSTL3KEEP = 0b1100,
SVE_PRFOP_PSTL3STRM = 0b1101,

SVE_PRFOP_CONST6 = 0b0110,
Expand Down Expand Up @@ -532,6 +532,7 @@ enum insOpts : unsigned
INS_OPTS_JALR, // see ::emitIns_J_R().
INS_OPTS_J, // see ::emitIns_J().
INS_OPTS_J_cond, // see ::emitIns_J_cond_la().
INS_OPTS_I, // see ::emitLoadImmediate().
INS_OPTS_C, // see ::emitIns_Call().
INS_OPTS_RELOC, // see ::emitIns_R_AI().
};
Expand Down
Loading