Make context promotion pass use bitmaps.

This commit is contained in:
Ben Vanik 2014-08-06 14:19:07 -07:00
parent 71ca8993b9
commit bba3315f58
2 changed files with 32 additions and 29 deletions

View File

@ -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();

View File

@ -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