remove blocks from IRBuilder

This commit is contained in:
Anthony Pesch 2016-03-05 02:53:22 -08:00
parent c44133d574
commit 5a8b1bd530
13 changed files with 109 additions and 252 deletions

View File

@ -34,10 +34,8 @@ bool InterpreterEmitter::Emit(ir::IRBuilder &builder, void *guest_ctx,
// do an initial pass assigning ordinals to instructions so local branches
// can be resolved
int32_t ordinal = 0;
for (auto ir_block : builder.blocks()) {
for (auto ir_instr : ir_block->instrs()) {
ir_instr->set_tag((intptr_t)ordinal++);
}
for (auto ir_instr : builder.instrs()) {
ir_instr->set_tag((intptr_t)ordinal++);
}
// assign local offsets
@ -51,15 +49,13 @@ bool InterpreterEmitter::Emit(ir::IRBuilder &builder, void *guest_ctx,
// translate each instruction
*instr = reinterpret_cast<IntInstr *>(codegen_);
for (auto ir_block : builder.blocks()) {
for (auto ir_instr : ir_block->instrs()) {
IntInstr *instr = AllocInstr();
if (!instr) {
return false;
}
TranslateInstr(*ir_instr, instr);
for (auto ir_instr : builder.instrs()) {
IntInstr *instr = AllocInstr();
if (!instr) {
return false;
}
TranslateInstr(*ir_instr, instr);
}
IntInstr *instr_end = reinterpret_cast<IntInstr *>(codegen_);

View File

@ -136,20 +136,18 @@ void X64Emitter::EmitProlog(IRBuilder &builder, int *out_stack_size) {
// mark which registers have been modified
modified_marker_++;
for (auto block : builder.blocks()) {
for (auto instr : block->instrs()) {
Value *result = instr->result();
if (!result) {
continue;
}
int i = result->reg();
if (i == NO_REGISTER) {
continue;
}
modified_[i] = modified_marker_;
for (auto instr : builder.instrs()) {
Value *result = instr->result();
if (!result) {
continue;
}
int i = result->reg();
if (i == NO_REGISTER) {
continue;
}
modified_[i] = modified_marker_;
}
// push the callee-saved registers which have been modified
@ -182,16 +180,14 @@ void X64Emitter::EmitProlog(IRBuilder &builder, int *out_stack_size) {
}
void X64Emitter::EmitBody(IRBuilder &builder) {
for (auto block : builder.blocks()) {
for (auto instr : block->instrs()) {
X64Emit emit = x64_emitters[instr->op()];
CHECK(emit, "Failed to find emitter for %s", Opnames[instr->op()]);
for (auto instr : builder.instrs()) {
X64Emit emit = x64_emitters[instr->op()];
CHECK(emit, "Failed to find emitter for %s", Opnames[instr->op()]);
// reset temp count used by GetRegister
num_temps_ = 0;
// reset temp count used by GetRegister
num_temps_ = 0;
emit(*this, instr);
}
emit(*this, instr);
}
}

View File

@ -82,8 +82,7 @@ void SH4Builder::Emit(uint32_t start_addr, int max_instrs) {
}
}
ir::Block *tail_block = blocks_.tail();
ir::Instr *tail_instr = tail_block->instrs().tail();
ir::Instr *tail_instr = instrs_.tail();
// if the block was terminated before a branch instruction, emit a
// fallthrough branch to the next pc
@ -93,7 +92,6 @@ void SH4Builder::Emit(uint32_t start_addr, int max_instrs) {
}
// emit block epilog
current_block_ = tail_block;
current_instr_ = tail_instr->prev();
Value *remaining_cycles =

View File

@ -66,61 +66,14 @@ Local::Local(ValueType ty, Value *offset) : type_(ty), offset_(offset) {}
//
// Instr
//
Instr::Instr(Op op)
: block_(nullptr),
op_(op),
args_{{this}, {this}, {this}, {this}},
tag_(0) {}
Instr::Instr(Op op) : op_(op), args_{{this}, {this}, {this}, {this}}, tag_(0) {}
Instr::~Instr() {}
//
// Block
//
Block::Block() : tag_(0) {}
Block::~Block() {
while (instrs_.tail()) {
RemoveInstr(instrs_.tail());
}
}
void Block::InsertInstr(Instr *after, Instr *instr) {
instr->set_block(this);
instrs_.Insert(after, instr);
}
void Block::ReplaceInstr(Instr *replace, Instr *with) {
// insert the new instruction
InsertInstr(replace, with);
// replace references to our result with other result
if (replace->result()) {
CHECK_NOTNULL(with->result());
replace->result()->ReplaceRefsWith(with->result());
}
// remove old instruction
RemoveInstr(replace);
}
void Block::RemoveInstr(Instr *instr) {
instr->set_block(nullptr);
instrs_.Remove(instr);
// call destructor manually
instr->~Instr();
}
void Block::UnlinkInstr(Instr *instr) {
instr->set_block(nullptr);
instrs_.Remove(instr);
}
//
// IRBuilder
//
IRBuilder::IRBuilder()
: arena_(1024), current_block_(nullptr), current_instr_(nullptr) {}
IRBuilder::IRBuilder() : arena_(1024), current_instr_(nullptr) {}
void IRBuilder::Dump() const {
IRWriter writer;
@ -129,41 +82,17 @@ void IRBuilder::Dump() const {
LOG_INFO(ss.str().c_str());
}
InsertPoint IRBuilder::GetInsertPoint() {
return {current_block_, current_instr_};
}
InsertPoint IRBuilder::GetInsertPoint() { return {current_instr_}; }
void IRBuilder::SetInsertPoint(const InsertPoint &point) {
current_block_ = point.block;
current_instr_ = point.instr;
}
Block *IRBuilder::InsertBlock(Block *after) {
Block *block = arena_.Alloc<Block>();
new (block) Block();
void IRBuilder::RemoveInstr(Instr *instr) {
instrs_.Remove(instr);
// insert at beginning if no after specified
if (!after) {
blocks_.Insert(nullptr, block);
} else {
blocks_.Insert(after, block);
}
return block;
}
Block *IRBuilder::AppendBlock() { return InsertBlock(blocks_.tail()); }
void IRBuilder::RemoveBlock(Block *block) {
if (current_block_ == block) {
current_block_ = block->next() ? block->next() : block->prev();
current_instr_ = current_block_->instrs().tail();
}
blocks_.Remove(block);
// call destructor manually
block->~Block();
// call destructor manually to release value references
instr->~Instr();
}
Value *IRBuilder::LoadHost(Value *addr, ValueType type) {
@ -678,13 +607,8 @@ Instr *IRBuilder::AllocInstr(Op op) {
}
Instr *IRBuilder::AppendInstr(Op op) {
if (!current_block_) {
current_block_ = InsertBlock(current_block_);
current_instr_ = nullptr;
}
Instr *instr = AllocInstr(op);
current_block_->InsertInstr(current_instr_, instr);
instrs_.Insert(current_instr_, instr);
current_instr_ = instr;
return instr;
}

View File

@ -50,7 +50,6 @@ enum {
NO_REGISTER = -1,
};
class Block;
class Instr;
class ValueRef;
@ -254,15 +253,10 @@ class Local : public IntrusiveListNode<Local> {
// instructions
//
class Instr : public IntrusiveListNode<Instr> {
friend class Block;
public:
Instr(Op op);
~Instr();
const Block *block() const { return block_; }
Block *block() { return block_; }
Op op() const { return op_; }
const Value *arg0() const { return arg(0); }
@ -289,47 +283,17 @@ class Instr : public IntrusiveListNode<Instr> {
void set_tag(intptr_t tag) { tag_ = tag; }
private:
Block *set_block(Block *block) { return block_ = block; }
Block *block_;
Op op_;
ValueRef args_[4];
intptr_t tag_;
};
//
// blocks
//
class Block : public IntrusiveListNode<Block> {
friend class IRBuilder;
public:
Block();
~Block();
const IntrusiveList<Instr> &instrs() const { return instrs_; }
IntrusiveList<Instr> &instrs() { return instrs_; }
intptr_t tag() const { return tag_; }
void set_tag(intptr_t tag) { tag_ = tag; }
void InsertInstr(Instr *after, Instr *instr);
void ReplaceInstr(Instr *replace, Instr *with);
void RemoveInstr(Instr *instr);
void UnlinkInstr(Instr *instr);
private:
IntrusiveList<Instr> instrs_;
intptr_t tag_;
};
//
// IRBuilder
//
typedef void (*ExternalFn)(void *);
struct InsertPoint {
Block *block;
Instr *instr;
};
@ -339,8 +303,8 @@ class IRBuilder {
public:
IRBuilder();
const IntrusiveList<Block> &blocks() const { return blocks_; }
IntrusiveList<Block> &blocks() { return blocks_; }
const IntrusiveList<Instr> &instrs() const { return instrs_; }
IntrusiveList<Instr> &instrs() { return instrs_; }
const IntrusiveList<Local> &locals() const { return locals_; }
IntrusiveList<Local> &locals() { return locals_; }
@ -350,10 +314,7 @@ class IRBuilder {
InsertPoint GetInsertPoint();
void SetInsertPoint(const InsertPoint &point);
// blocks
Block *InsertBlock(Block *after);
Block *AppendBlock();
void RemoveBlock(Block *block);
void RemoveInstr(Instr *instr);
// direct access to host memory
Value *LoadHost(Value *addr, ValueType type);
@ -437,9 +398,8 @@ class IRBuilder {
Instr *AppendInstr(Op op);
Arena arena_;
IntrusiveList<Block> blocks_;
IntrusiveList<Instr> instrs_;
IntrusiveList<Local> locals_;
Block *current_block_;
Instr *current_instr_;
};
}

View File

@ -8,10 +8,8 @@ void IRWriter::Print(const IRBuilder &builder, std::ostream &output) {
slots_.clear();
next_slot_ = 0;
for (auto block : builder.blocks()) {
for (auto instr : block->instrs()) {
PrintInstruction(instr, output);
}
for (auto instr : builder.instrs()) {
PrintInstruction(instr, output);
}
}

View File

@ -6,7 +6,7 @@
using namespace re::jit::ir;
using namespace re::jit::ir::passes;
typedef void (*FoldFn)(IRBuilder &, Block *, Instr *i);
typedef void (*FoldFn)(IRBuilder &, Instr *i);
// specify which arguments must be constant in order for fold operation to run
enum {
@ -35,7 +35,7 @@ int fold_masks[NUM_OPS];
} op##_init; \
template <typename R = ValueInfo<VALUE_V>, typename A0 = ValueInfo<VALUE_V>, \
typename A1 = ValueInfo<VALUE_V>> \
void Handle##op(IRBuilder &builder, Block *block, Instr *instr)
void Handle##op(IRBuilder &builder, Instr *instr)
// registers a fold callback for the specified signature
#define REGISTER_FOLD(op, r, a0, a1) \
@ -57,7 +57,7 @@ int fold_masks[NUM_OPS];
#define RESULT(expr) \
instr->result()->ReplaceRefsWith( \
builder.AllocConstant(static_cast<typename R::signed_type>(expr))); \
block->RemoveInstr(instr)
builder.RemoveInstr(instr)
static FoldFn GetFoldFn(Instr *instr) {
auto it = fold_cbs.find(CALLBACK_IDX(
@ -93,32 +93,30 @@ static int GetConstantSig(Instr *instr) {
void ConstantPropagationPass::Run(IRBuilder &builder) {
PROFILER_RUNTIME("ConstantPropagationPass::Run");
for (auto block : builder.blocks()) {
auto it = block->instrs().begin();
auto end = block->instrs().end();
auto it = builder.instrs().begin();
auto end = builder.instrs().end();
while (it != end) {
Instr *instr = *(it++);
while (it != end) {
Instr *instr = *(it++);
int fold_mask = GetFoldMask(instr);
int cnst_sig = GetConstantSig(instr);
if (!fold_mask || (cnst_sig & fold_mask) != fold_mask) {
continue;
}
FoldFn fold = GetFoldFn(instr);
if (!fold) {
continue;
}
fold(builder, block, instr);
int fold_mask = GetFoldMask(instr);
int cnst_sig = GetConstantSig(instr);
if (!fold_mask || (cnst_sig & fold_mask) != fold_mask) {
continue;
}
FoldFn fold = GetFoldFn(instr);
if (!fold) {
continue;
}
fold(builder, instr);
}
}
FOLD(SELECT, ARG0_CNST) {
instr->result()->ReplaceRefsWith(ARG0() ? instr->arg1() : instr->arg2());
block->RemoveInstr(instr);
builder.RemoveInstr(instr);
}
REGISTER_FOLD(SELECT, I8, I8, I8);
REGISTER_FOLD(SELECT, I16, I16, I16);

View File

@ -12,18 +12,10 @@ void LoadStoreEliminationPass::Run(IRBuilder &builder) {
Reset();
for (auto block : builder.blocks()) {
ProcessBlock(block);
}
}
void LoadStoreEliminationPass::Reset() { ClearAvailable(); }
void LoadStoreEliminationPass::ProcessBlock(Block *block) {
// eliminate redundant loads
{
auto it = block->instrs().begin();
auto end = block->instrs().end();
auto it = builder.instrs().begin();
auto end = builder.instrs().end();
ClearAvailable();
@ -39,7 +31,7 @@ void LoadStoreEliminationPass::ProcessBlock(Block *block) {
if (available && available->type() == instr->result()->type()) {
instr->result()->ReplaceRefsWith(available);
CHECK_EQ(instr->result(), available);
block->RemoveInstr(instr);
builder.RemoveInstr(instr);
continue;
}
@ -56,8 +48,8 @@ void LoadStoreEliminationPass::ProcessBlock(Block *block) {
// eliminate dead stores
{
// iterate in reverse so the current instruction is the one being removed
auto it = block->instrs().rbegin();
auto end = block->instrs().rend();
auto it = builder.instrs().rbegin();
auto end = builder.instrs().rend();
ClearAvailable();
@ -78,7 +70,7 @@ void LoadStoreEliminationPass::ProcessBlock(Block *block) {
int store_size = SizeForType(instr->arg1()->type());
if (available_size >= store_size) {
block->RemoveInstr(instr);
builder.RemoveInstr(instr);
continue;
}
@ -88,6 +80,8 @@ void LoadStoreEliminationPass::ProcessBlock(Block *block) {
}
}
void LoadStoreEliminationPass::Reset() { ClearAvailable(); }
void LoadStoreEliminationPass::Reserve(int offset) {
int reserve = offset + 1;

View File

@ -21,7 +21,6 @@ class LoadStoreEliminationPass : public Pass {
private:
void Reset();
void ProcessBlock(Block *block);
void Reserve(int offset);
void ClearAvailable();

View File

@ -93,47 +93,45 @@ RegisterAllocationPass::~RegisterAllocationPass() { delete[] intervals_; }
void RegisterAllocationPass::Run(IRBuilder &builder) {
PROFILER_RUNTIME("RegisterAllocationPass::Run");
for (auto block : builder.blocks()) {
Reset();
Reset();
AssignOrdinals(block);
AssignOrdinals(builder);
for (auto instr : block->instrs()) {
Value *result = instr->result();
for (auto instr : builder.instrs()) {
Value *result = instr->result();
// only allocate registers for results, assume constants can always be
// encoded as immediates or that the backend has registers reserved
// for storing the constants
if (!result) {
continue;
}
// sort the value's ref list
result->refs().Sort([](const ValueRef *a, const ValueRef *b) {
return GetOrdinal(a->instr()) < GetOrdinal(b->instr());
});
// get the live range of the value
ValueRef *start = result->refs().head();
ValueRef *end = result->refs().tail();
// expire any old intervals, freeing up the registers they claimed
ExpireOldIntervals(start->instr());
// first, try and reuse the register of one of the incoming arguments
int reg = ReuuseArgRegister(instr, start, end);
if (reg == NO_REGISTER) {
// else, allocate a new register for the result
reg = AllocFreeRegister(result, start, end);
if (reg == NO_REGISTER) {
// if a register couldn't be allocated, spill a register and try again
reg = AllocBlockedRegister(builder, result, start, end);
CHECK_NE(reg, NO_REGISTER, "Failed to allocate register");
}
}
result->set_reg(reg);
// only allocate registers for results, assume constants can always be
// encoded as immediates or that the backend has registers reserved
// for storing the constants
if (!result) {
continue;
}
// sort the value's ref list
result->refs().Sort([](const ValueRef *a, const ValueRef *b) {
return GetOrdinal(a->instr()) < GetOrdinal(b->instr());
});
// get the live range of the value
ValueRef *start = result->refs().head();
ValueRef *end = result->refs().tail();
// expire any old intervals, freeing up the registers they claimed
ExpireOldIntervals(start->instr());
// first, try and reuse the register of one of the incoming arguments
int reg = ReuuseArgRegister(instr, start, end);
if (reg == NO_REGISTER) {
// else, allocate a new register for the result
reg = AllocFreeRegister(result, start, end);
if (reg == NO_REGISTER) {
// if a register couldn't be allocated, spill a register and try again
reg = AllocBlockedRegister(builder, result, start, end);
CHECK_NE(reg, NO_REGISTER, "Failed to allocate register");
}
}
result->set_reg(reg);
}
}
@ -168,11 +166,11 @@ void RegisterAllocationPass::Reset() {
}
}
void RegisterAllocationPass::AssignOrdinals(Block *block) {
void RegisterAllocationPass::AssignOrdinals(IRBuilder &builder) {
// assign each instruction an ordinal. these ordinals are used to describe
// the live range of a particular value
int ordinal = 0;
for (auto instr : block->instrs()) {
for (auto instr : builder.instrs()) {
SetOrdinal(instr, ordinal);
// space out ordinals to leave available values for instructions inserted
@ -308,7 +306,7 @@ int RegisterAllocationPass::AllocBlockedRegister(IRBuilder &builder,
Local *local = builder.AllocLocal(interval->value->type());
// insert load before next use
builder.SetInsertPoint({insert_point.block, next_ref->instr()->prev()});
builder.SetInsertPoint({next_ref->instr()->prev()});
Value *load_local = builder.LoadLocal(local);
Instr *load_instr = builder.GetInsertPoint().instr;
@ -337,7 +335,7 @@ int RegisterAllocationPass::AllocBlockedRegister(IRBuilder &builder,
// instruction is created and added as a reference, the sorted order will be
// invalidated. because of this, the save instruction needs to be added after
// the load instruction has updated the sorted references.
builder.SetInsertPoint({insert_point.block, prev_ref->instr()});
builder.SetInsertPoint({prev_ref->instr()});
builder.StoreLocal(local, interval->value);
Instr *store_instr = builder.GetInsertPoint().instr;

View File

@ -63,7 +63,7 @@ class RegisterAllocationPass : public Pass {
RegisterSet &GetRegisterSet(ValueType type);
void Reset();
void AssignOrdinals(ir::Block *block);
void AssignOrdinals(IRBuilder &builder);
void ExpireOldIntervals(Instr *start);
int ReuuseArgRegister(Instr *instr, ValueRef *start, ValueRef *end);
int AllocFreeRegister(Value *value, ValueRef *start, ValueRef *end);

View File

@ -11,8 +11,6 @@ namespace passes {
class ValidatePass : public Pass {
public:
void Run(IRBuilder &builder);
void ValidateBlock(IRBuilder &builder, Block *block);
void ValidateInstr(IRBuilder &builder, Block *block, Instr *instr);
};
}
}

View File

@ -34,8 +34,7 @@ TEST(LoadStoreEliminationPassTest, Aliasing) {
"i32 %8 = load_context i32 0x2c\n"
"i32 %9 = load_context i32 0x20\n"
"i32 %10 = sub i32 %9, i32 0x10\n"
"store_context i32 0x20, i32 %10\n"
"branch i32 %8\n";
"store_context i32 0x20, i32 %10\n";
static const char *output =
"store_context i32 0x104, i32 0x0\n"
@ -57,8 +56,7 @@ TEST(LoadStoreEliminationPassTest, Aliasing) {
"i32 %3 = load_context i32 0x2c\n"
"i32 %4 = load_context i32 0x20\n"
"i32 %5 = sub i32 %4, i32 0x10\n"
"store_context i32 0x20, i32 %5\n"
"branch i32 %3\n";
"store_context i32 0x20, i32 %5\n";
IRBuilder builder;