Make context promotion pass use bitmaps.
This commit is contained in:
parent
71ca8993b9
commit
bba3315f58
|
@ -30,14 +30,9 @@ using alloy::hir::HIRBuilder;
|
||||||
using alloy::hir::Instr;
|
using alloy::hir::Instr;
|
||||||
using alloy::hir::Value;
|
using alloy::hir::Value;
|
||||||
|
|
||||||
ContextPromotionPass::ContextPromotionPass()
|
ContextPromotionPass::ContextPromotionPass() : CompilerPass() {}
|
||||||
: CompilerPass(), context_values_size_(0), context_values_(0) {}
|
|
||||||
|
|
||||||
ContextPromotionPass::~ContextPromotionPass() {
|
ContextPromotionPass::~ContextPromotionPass() {}
|
||||||
if (context_values_) {
|
|
||||||
xe_free(context_values_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ContextPromotionPass::Initialize(Compiler* compiler) {
|
int ContextPromotionPass::Initialize(Compiler* compiler) {
|
||||||
if (CompilerPass::Initialize(compiler)) {
|
if (CompilerPass::Initialize(compiler)) {
|
||||||
|
@ -46,8 +41,8 @@ int ContextPromotionPass::Initialize(Compiler* compiler) {
|
||||||
|
|
||||||
// This is a terrible implementation.
|
// This is a terrible implementation.
|
||||||
ContextInfo* context_info = runtime_->frontend()->context_info();
|
ContextInfo* context_info = runtime_->frontend()->context_info();
|
||||||
context_values_size_ = context_info->size() * sizeof(Value*);
|
context_values_.resize(context_info->size());
|
||||||
context_values_ = (Value**)xe_calloc(context_values_size_);
|
context_validity_.resize(static_cast<uint32_t>(context_info->size()));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -91,57 +86,55 @@ int ContextPromotionPass::Run(HIRBuilder* builder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextPromotionPass::PromoteBlock(Block* block) {
|
void ContextPromotionPass::PromoteBlock(Block* block) {
|
||||||
// Clear the context values list.
|
auto& validity = context_validity_;
|
||||||
// TODO(benvanik): new data structure that isn't so stupid.
|
validity.reset();
|
||||||
// Bitvector of validity, perhaps?
|
|
||||||
xe_zero_struct(context_values_, context_values_size_);
|
|
||||||
|
|
||||||
Instr* i = block->instr_head;
|
Instr* i = block->instr_head;
|
||||||
while (i) {
|
while (i) {
|
||||||
|
auto next = i->next;
|
||||||
if (i->opcode->flags & OPCODE_FLAG_VOLATILE) {
|
if (i->opcode->flags & OPCODE_FLAG_VOLATILE) {
|
||||||
// Volatile instruction - requires all context values be flushed.
|
// Volatile instruction - requires all context values be flushed.
|
||||||
xe_zero_struct(context_values_, context_values_size_);
|
validity.reset();
|
||||||
} else if (i->opcode == &OPCODE_LOAD_CONTEXT_info) {
|
} else if (i->opcode == &OPCODE_LOAD_CONTEXT_info) {
|
||||||
size_t offset = i->src1.offset;
|
size_t offset = i->src1.offset;
|
||||||
Value* previous_value = context_values_[offset];
|
if (validity.test(static_cast<uint32_t>(offset))) {
|
||||||
if (previous_value) {
|
|
||||||
// Legit previous value, reuse.
|
// Legit previous value, reuse.
|
||||||
|
Value* previous_value = context_values_[offset];
|
||||||
i->opcode = &hir::OPCODE_ASSIGN_info;
|
i->opcode = &hir::OPCODE_ASSIGN_info;
|
||||||
i->set_src1(previous_value);
|
i->set_src1(previous_value);
|
||||||
} else {
|
} else {
|
||||||
// Store the loaded value into the table.
|
// Store the loaded value into the table.
|
||||||
context_values_[offset] = i->dest;
|
context_values_[offset] = i->dest;
|
||||||
|
validity.set(static_cast<uint32_t>(offset));
|
||||||
}
|
}
|
||||||
} else if (i->opcode == &OPCODE_STORE_CONTEXT_info) {
|
} else if (i->opcode == &OPCODE_STORE_CONTEXT_info) {
|
||||||
size_t offset = i->src1.offset;
|
size_t offset = i->src1.offset;
|
||||||
Value* value = i->src2.value;
|
Value* value = i->src2.value;
|
||||||
// Store value into the table for later.
|
// Store value into the table for later.
|
||||||
context_values_[offset] = value;
|
context_values_[offset] = value;
|
||||||
|
validity.set(static_cast<uint32_t>(offset));
|
||||||
}
|
}
|
||||||
|
i = next;
|
||||||
i = i->next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextPromotionPass::RemoveDeadStoresBlock(Block* block) {
|
void ContextPromotionPass::RemoveDeadStoresBlock(Block* block) {
|
||||||
// TODO(benvanik): use a bitvector.
|
auto& validity = context_validity_;
|
||||||
// To avoid clearing the structure, we use a token.
|
validity.reset();
|
||||||
// Upper bits are block address, lower bits increment each reset.
|
|
||||||
uint64_t token = reinterpret_cast<uint64_t>(block) << 16;
|
|
||||||
|
|
||||||
// Walk backwards and mark offsets that are written to.
|
// Walk backwards and mark offsets that are written to.
|
||||||
// If the offset was written to earlier, ignore the store.
|
// If the offset was written to earlier, ignore the store.
|
||||||
Instr* i = block->instr_tail;
|
Instr* i = block->instr_tail;
|
||||||
while (i) {
|
while (i) {
|
||||||
Instr* prev = i->prev;
|
Instr* prev = i->prev;
|
||||||
if (i->opcode->flags & OPCODE_FLAG_VOLATILE) {
|
if (i->opcode->flags & (OPCODE_FLAG_VOLATILE | OPCODE_FLAG_BRANCH)) {
|
||||||
// Volatile instruction - requires all context values be flushed.
|
// Volatile instruction - requires all context values be flushed.
|
||||||
++token;
|
validity.reset();
|
||||||
} else if (i->opcode == &OPCODE_STORE_CONTEXT_info) {
|
} else if (i->opcode == &OPCODE_STORE_CONTEXT_info) {
|
||||||
size_t offset = i->src1.offset;
|
size_t offset = i->src1.offset;
|
||||||
if (context_values_[offset] != reinterpret_cast<Value*>(token)) {
|
if (!validity.test(static_cast<uint32_t>(offset))) {
|
||||||
// Mark offset as written to.
|
// Offset not yet written, mark and continue.
|
||||||
context_values_[offset] = reinterpret_cast<Value*>(token);
|
validity.set(static_cast<uint32_t>(offset));
|
||||||
} else {
|
} else {
|
||||||
// Already written to. Remove this store.
|
// Already written to. Remove this store.
|
||||||
i->Remove();
|
i->Remove();
|
||||||
|
|
|
@ -12,6 +12,16 @@
|
||||||
|
|
||||||
#include <alloy/compiler/compiler_pass.h>
|
#include <alloy/compiler/compiler_pass.h>
|
||||||
|
|
||||||
|
#if XE_COMPILER_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4244)
|
||||||
|
#pragma warning(disable : 4267)
|
||||||
|
#include <llvm/ADT/BitVector.h>
|
||||||
|
#pragma warning(pop)
|
||||||
|
#else
|
||||||
|
#include <llvm/ADT/BitVector.h>
|
||||||
|
#endif // XE_COMPILER_MSVC
|
||||||
|
|
||||||
namespace alloy {
|
namespace alloy {
|
||||||
namespace compiler {
|
namespace compiler {
|
||||||
namespace passes {
|
namespace passes {
|
||||||
|
@ -30,8 +40,8 @@ class ContextPromotionPass : public CompilerPass {
|
||||||
void RemoveDeadStoresBlock(hir::Block* block);
|
void RemoveDeadStoresBlock(hir::Block* block);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t context_values_size_;
|
std::vector<hir::Value*> context_values_;
|
||||||
hir::Value** context_values_;
|
llvm::BitVector context_validity_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace passes
|
} // namespace passes
|
||||||
|
|
Loading…
Reference in New Issue