Skip to content

Commit

Permalink
Merge pull request #18282 from unknownbrackets/ir-compiling
Browse files Browse the repository at this point in the history
Improve IR compilation performance
  • Loading branch information
hrydgard committed Oct 1, 2023
2 parents 7bb7c2f + cd46f0b commit db805cc
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 113 deletions.
15 changes: 9 additions & 6 deletions Core/MIPS/ARM64/Arm64IRJit.cpp
Expand Up @@ -93,12 +93,11 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload)

regs_.Start(block);

std::map<const u8 *, int> addresses;
std::vector<const u8 *> addresses;
for (int i = 0; i < block->GetNumInstructions(); ++i) {
const IRInst &inst = block->GetInstructions()[i];
regs_.SetIRIndex(i);
// TODO: This might be a little wasteful when compiling if we're not debugging jit...
addresses[GetCodePtr()] = i;
addresses.push_back(GetCodePtr());

CompileIRInst(inst);

Expand Down Expand Up @@ -150,10 +149,14 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload)
if (logBlocks_ > 0) {
--logBlocks_;

std::map<const u8 *, int> addressesLookup;
for (int i = 0; i < (int)addresses.size(); ++i)
addressesLookup[addresses[i]] = i;

INFO_LOG(JIT, "=============== ARM64 (%08x, %d bytes) ===============", startPC, len);
for (const u8 *p = blockStart; p < GetCodePointer(); ) {
auto it = addresses.find(p);
if (it != addresses.end()) {
auto it = addressesLookup.find(p);
if (it != addressesLookup.end()) {
const IRInst &inst = block->GetInstructions()[it->second];

char temp[512];
Expand All @@ -162,7 +165,7 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload)
}

auto next = std::next(it);
const u8 *nextp = next == addresses.end() ? GetCodePointer() : next->first;
const u8 *nextp = next == addressesLookup.end() ? GetCodePointer() : next->first;

auto lines = DisassembleArm64(p, (int)(nextp - p));
for (const auto &line : lines)
Expand Down
97 changes: 42 additions & 55 deletions Core/MIPS/IR/IRAnalysis.cpp
Expand Up @@ -21,65 +21,60 @@
#include <algorithm>


static bool IRReadsFrom(const IRInst &inst, int reg, char type, bool *directly) {
const IRMeta *m = GetIRMeta(inst.op);

if (m->types[1] == type && inst.src1 == reg) {
static bool IRReadsFrom(const IRInstMeta &inst, int reg, char type, bool *directly) {
if (inst.m.types[1] == type && inst.src1 == reg) {
if (directly)
*directly = true;
return true;
}
if (m->types[2] == type && inst.src2 == reg) {
if (inst.m.types[2] == type && inst.src2 == reg) {
if (directly)
*directly = true;
return true;
}
if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == type && inst.src3 == reg) {
if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == type && inst.src3 == reg) {
if (directly)
*directly = true;
return true;
}

if (directly)
*directly = false;
if ((m->flags & (IRFLAG_EXIT | IRFLAG_BARRIER)) != 0)
if ((inst.m.flags & (IRFLAG_EXIT | IRFLAG_BARRIER)) != 0)
return true;
return false;
}

bool IRReadsFromFPR(const IRInst &inst, int reg, bool *directly) {
bool IRReadsFromFPR(const IRInstMeta &inst, int reg, bool *directly) {
if (IRReadsFrom(inst, reg, 'F', directly))
return true;

const IRMeta *m = GetIRMeta(inst.op);

// We also need to check V and 2. Indirect reads already checked, don't check again.
if (m->types[1] == 'V' && reg >= inst.src1 && reg < inst.src1 + 4)
if (inst.m.types[1] == 'V' && reg >= inst.src1 && reg < inst.src1 + 4)
return true;
if (m->types[1] == '2' && reg >= inst.src1 && reg < inst.src1 + 2)
if (inst.m.types[1] == '2' && reg >= inst.src1 && reg < inst.src1 + 2)
return true;
if (m->types[2] == 'V' && reg >= inst.src2 && reg < inst.src2 + 4)
if (inst.m.types[2] == 'V' && reg >= inst.src2 && reg < inst.src2 + 4)
return true;
if (m->types[2] == '2' && reg >= inst.src2 && reg < inst.src2 + 2)
if (inst.m.types[2] == '2' && reg >= inst.src2 && reg < inst.src2 + 2)
return true;
if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {
if (m->types[0] == 'V' && reg >= inst.src3 && reg <= inst.src3 + 4)
if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {
if (inst.m.types[0] == 'V' && reg >= inst.src3 && reg <= inst.src3 + 4)
return true;
if (m->types[0] == '2' && reg >= inst.src3 && reg <= inst.src3 + 2)
if (inst.m.types[0] == '2' && reg >= inst.src3 && reg <= inst.src3 + 2)
return true;
}
return false;
}

static int IRReadsFromList(const IRInst &inst, IRReg regs[4], char type) {
const IRMeta *m = GetIRMeta(inst.op);
static int IRReadsFromList(const IRInstMeta &inst, IRReg regs[4], char type) {
int c = 0;

if (m->types[1] == type)
if (inst.m.types[1] == type)
regs[c++] = inst.src1;
if (m->types[2] == type)
if (inst.m.types[2] == type)
regs[c++] = inst.src2;
if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == type)
if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == type)
regs[c++] = inst.src3;

if (inst.op == IROp::Interpret || inst.op == IROp::CallReplacement || inst.op == IROp::Syscall || inst.op == IROp::Break)
Expand All @@ -90,86 +85,78 @@ static int IRReadsFromList(const IRInst &inst, IRReg regs[4], char type) {
return c;
}

bool IRReadsFromGPR(const IRInst &inst, int reg, bool *directly) {
bool IRReadsFromGPR(const IRInstMeta &inst, int reg, bool *directly) {
return IRReadsFrom(inst, reg, 'G', directly);
}

int IRDestGPR(const IRInst &inst) {
const IRMeta *m = GetIRMeta(inst.op);

if ((m->flags & IRFLAG_SRC3) == 0 && m->types[0] == 'G') {
int IRDestGPR(const IRInstMeta &inst) {
if ((inst.m.flags & IRFLAG_SRC3) == 0 && inst.m.types[0] == 'G') {
return inst.dest;
}
return -1;
}

bool IRWritesToGPR(const IRInst &inst, int reg) {
bool IRWritesToGPR(const IRInstMeta &inst, int reg) {
return IRDestGPR(inst) == reg;
}

bool IRWritesToFPR(const IRInst &inst, int reg) {
const IRMeta *m = GetIRMeta(inst.op);

bool IRWritesToFPR(const IRInstMeta &inst, int reg) {
// Doesn't write to anything.
if ((m->flags & IRFLAG_SRC3) != 0)
if ((inst.m.flags & IRFLAG_SRC3) != 0)
return false;

if (m->types[0] == 'F' && reg == inst.dest)
if (inst.m.types[0] == 'F' && reg == inst.dest)
return true;
if (m->types[0] == 'V' && reg >= inst.dest && reg < inst.dest + 4)
if (inst.m.types[0] == 'V' && reg >= inst.dest && reg < inst.dest + 4)
return true;
if (m->types[0] == '2' && reg >= inst.dest && reg < inst.dest + 2)
if (inst.m.types[0] == '2' && reg >= inst.dest && reg < inst.dest + 2)
return true;
return false;
}

int IRDestFPRs(const IRInst &inst, IRReg regs[4]) {
const IRMeta *m = GetIRMeta(inst.op);

int IRDestFPRs(const IRInstMeta &inst, IRReg regs[4]) {
// Doesn't write to anything.
if ((m->flags & IRFLAG_SRC3) != 0)
if ((inst.m.flags & IRFLAG_SRC3) != 0)
return 0;

if (m->types[0] == 'F') {
if (inst.m.types[0] == 'F') {
regs[0] = inst.dest;
return 1;
}
if (m->types[0] == 'V') {
if (inst.m.types[0] == 'V') {
for (int i = 0; i < 4; ++i)
regs[i] = inst.dest + i;
return 4;
}
if (m->types[0] == '2') {
if (inst.m.types[0] == '2') {
for (int i = 0; i < 2; ++i)
regs[i] = inst.dest + i;
return 2;
}
return 0;
}

int IRReadsFromGPRs(const IRInst &inst, IRReg regs[4]) {
int IRReadsFromGPRs(const IRInstMeta &inst, IRReg regs[4]) {
return IRReadsFromList(inst, regs, 'G');
}

int IRReadsFromFPRs(const IRInst &inst, IRReg regs[16]) {
int IRReadsFromFPRs(const IRInstMeta &inst, IRReg regs[16]) {
int c = IRReadsFromList(inst, regs, 'F');
if (c != 0)
return c;

const IRMeta *m = GetIRMeta(inst.op);

// We also need to check V and 2. Indirect reads already checked, don't check again.
if (m->types[1] == 'V' || m->types[1] == '2') {
for (int i = 0; i < (m->types[1] == 'V' ? 4 : 2); ++i)
if (inst.m.types[1] == 'V' || inst.m.types[1] == '2') {
for (int i = 0; i < (inst.m.types[1] == 'V' ? 4 : 2); ++i)
regs[c++] = inst.src1 + i;
}
if (m->types[2] == 'V' || m->types[2] == '2') {
for (int i = 0; i < (m->types[2] == 'V' ? 4 : 2); ++i)
if (inst.m.types[2] == 'V' || inst.m.types[2] == '2') {
for (int i = 0; i < (inst.m.types[2] == 'V' ? 4 : 2); ++i)
regs[c++] = inst.src2 + i;
}
if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {
if (m->types[0] == 'V' || m->types[0] == '2') {
for (int i = 0; i < (m->types[0] == 'V' ? 4 : 2); ++i)
if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) {
if (inst.m.types[0] == 'V' || inst.m.types[0] == '2') {
for (int i = 0; i < (inst.m.types[0] == 'V' ? 4 : 2); ++i)
regs[c++] = inst.src3 + i;
}
}
Expand All @@ -183,7 +170,7 @@ IRUsage IRNextGPRUsage(int gpr, const IRSituation &info) {

int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);
for (int i = 0; i < count; ++i) {
const IRInst inst = info.instructions[info.currentIndex + i];
const IRInstMeta inst = GetIRMeta(info.instructions[info.currentIndex + i]);
if (IRReadsFromGPR(inst, gpr))
return IRUsage::READ;
// We say WRITE when the current instruction writes. It's not useful for spilling.
Expand All @@ -202,7 +189,7 @@ IRUsage IRNextFPRUsage(int fpr, const IRSituation &info) {

int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount);
for (int i = 0; i < count; ++i) {
const IRInst inst = info.instructions[info.currentIndex + i];
const IRInstMeta inst = GetIRMeta(info.instructions[info.currentIndex + i]);

if (IRReadsFromFPR(inst, fpr)) {
// Special case a broadcast that clobbers it.
Expand Down
39 changes: 31 additions & 8 deletions Core/MIPS/IR/IRAnalysis.h
Expand Up @@ -19,14 +19,37 @@

#include "Core/MIPS/IR/IRInst.h"

bool IRReadsFromFPR(const IRInst &inst, int reg, bool *directly = nullptr);
bool IRReadsFromGPR(const IRInst &inst, int reg, bool *directly = nullptr);
bool IRWritesToGPR(const IRInst &inst, int reg);
bool IRWritesToFPR(const IRInst &inst, int reg);
int IRDestGPR(const IRInst &inst);
int IRDestFPRs(const IRInst &inst, IRReg regs[4]);
int IRReadsFromGPRs(const IRInst &inst, IRReg regs[4]);
int IRReadsFromFPRs(const IRInst &inst, IRReg regs[16]);
struct IRInstMeta {
union {
IRInst i;
struct {
IROp op;
union {
IRReg dest;
IRReg src3;
};
IRReg src1;
IRReg src2;
u32 constant;
};
};
IRMeta m;
};

static_assert(offsetof(IRInst, src2) == offsetof(IRInstMeta, src2));

inline IRInstMeta GetIRMeta(const IRInst &inst) {
return { { inst }, *GetIRMeta(inst.op) };
}

bool IRReadsFromFPR(const IRInstMeta &inst, int reg, bool *directly = nullptr);
bool IRReadsFromGPR(const IRInstMeta &inst, int reg, bool *directly = nullptr);
bool IRWritesToGPR(const IRInstMeta &inst, int reg);
bool IRWritesToFPR(const IRInstMeta &inst, int reg);
int IRDestGPR(const IRInstMeta &inst);
int IRDestFPRs(const IRInstMeta &inst, IRReg regs[4]);
int IRReadsFromGPRs(const IRInstMeta &inst, IRReg regs[4]);
int IRReadsFromFPRs(const IRInstMeta &inst, IRReg regs[16]);

struct IRSituation {
int lookaheadCount;
Expand Down
2 changes: 1 addition & 1 deletion Core/MIPS/IR/IRInst.h
Expand Up @@ -341,7 +341,7 @@ enum IRFlags {
struct IRMeta {
IROp op;
const char *name;
const char types[5]; // GGG
char types[5]; // GGG
u32 flags;
};

Expand Down

0 comments on commit db805cc

Please sign in to comment.