Skip to content

Commit

Permalink
irjit: Cache IR metadata lookups.
Browse files Browse the repository at this point in the history
This improves compilation performance, because all those lookups were
adding up.
  • Loading branch information
unknownbrackets committed Sep 30, 2023
1 parent 00c80ce commit cd46f0b
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 95 deletions.
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 cd46f0b

Please sign in to comment.