Oh my. Basic CFA/DFA, local variable support, misc fixes, etc.
This commit is contained in:
@@ -12,15 +12,37 @@
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
XEDECLARECLASS1(llvm, BitVector);
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace hir {
|
||||
|
||||
class Block;
|
||||
class HIRBuilder;
|
||||
class Instr;
|
||||
class Label;
|
||||
|
||||
|
||||
class Edge {
|
||||
public:
|
||||
enum EdgeFlags {
|
||||
UNCONDITIONAL = (1 << 0),
|
||||
DOMINATES = (1 << 1),
|
||||
};
|
||||
public:
|
||||
Edge* outgoing_next;
|
||||
Edge* outgoing_prev;
|
||||
Edge* incoming_next;
|
||||
Edge* incoming_prev;
|
||||
|
||||
Block* src;
|
||||
Block* dest;
|
||||
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
|
||||
class Block {
|
||||
public:
|
||||
Arena* arena;
|
||||
@@ -28,6 +50,10 @@ public:
|
||||
Block* next;
|
||||
Block* prev;
|
||||
|
||||
Edge* incoming_edge_head;
|
||||
Edge* outgoing_edge_head;
|
||||
llvm::BitVector* incoming_values;
|
||||
|
||||
Label* label_head;
|
||||
Label* label_tail;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ void HIRBuilder::Reset() {
|
||||
attributes_ = 0;
|
||||
next_label_id_ = 0;
|
||||
next_value_ordinal_ = 0;
|
||||
locals_.clear();
|
||||
block_head_ = block_tail_ = NULL;
|
||||
current_block_ = NULL;
|
||||
#if XE_DEBUG
|
||||
@@ -141,6 +142,13 @@ void HIRBuilder::Dump(StringBuffer* str) {
|
||||
str->Append("; attributes = %.8X\n", attributes_);
|
||||
}
|
||||
|
||||
for (auto it = locals_.begin(); it != locals_.end(); ++it) {
|
||||
auto local = *it;
|
||||
str->Append(" ; local ");
|
||||
DumpValue(str, local);
|
||||
str->Append("\n");
|
||||
}
|
||||
|
||||
uint32_t block_ordinal = 0;
|
||||
Block* block = block_head_;
|
||||
while (block) {
|
||||
@@ -161,6 +169,39 @@ void HIRBuilder::Dump(StringBuffer* str) {
|
||||
label = label->next;
|
||||
}
|
||||
|
||||
Edge* incoming_edge = block->incoming_edge_head;
|
||||
while (incoming_edge) {
|
||||
auto src_label = incoming_edge->src->label_head;
|
||||
if (src_label && src_label->name) {
|
||||
str->Append(" ; in: %s", src_label->name);
|
||||
} else if (src_label) {
|
||||
str->Append(" ; in: label%d", src_label->id);
|
||||
} else {
|
||||
str->Append(" ; in: <block%d>",
|
||||
incoming_edge->src->ordinal);
|
||||
}
|
||||
str->Append(", dom:%d, uncond:%d\n",
|
||||
(incoming_edge->flags & Edge::DOMINATES) ? 1 : 0,
|
||||
(incoming_edge->flags & Edge::UNCONDITIONAL) ? 1 : 0);
|
||||
incoming_edge = incoming_edge->incoming_next;
|
||||
}
|
||||
Edge* outgoing_edge = block->outgoing_edge_head;
|
||||
while (outgoing_edge) {
|
||||
auto dest_label = outgoing_edge->dest->label_head;
|
||||
if (dest_label && dest_label->name) {
|
||||
str->Append(" ; out: %s", dest_label->name);
|
||||
} else if (dest_label) {
|
||||
str->Append(" ; out: label%d", dest_label->id);
|
||||
} else {
|
||||
str->Append(" ; out: <block%d>",
|
||||
outgoing_edge->dest->ordinal);
|
||||
}
|
||||
str->Append(", dom:%d, uncond:%d\n",
|
||||
(outgoing_edge->flags & Edge::DOMINATES) ? 1 : 0,
|
||||
(outgoing_edge->flags & Edge::UNCONDITIONAL) ? 1 : 0);
|
||||
outgoing_edge = outgoing_edge->outgoing_next;
|
||||
}
|
||||
|
||||
Instr* i = block->instr_head;
|
||||
while (i) {
|
||||
if (i->opcode->flags & OPCODE_FLAG_HIDE) {
|
||||
@@ -303,6 +344,7 @@ void HIRBuilder::InsertLabel(Label* label, Instr* prev_instr) {
|
||||
block_tail_ = new_block;
|
||||
}
|
||||
new_block->label_head = new_block->label_tail = label;
|
||||
new_block->incoming_edge_head = new_block->outgoing_edge_head = NULL;
|
||||
label->block = new_block;
|
||||
label->prev = label->next = NULL;
|
||||
|
||||
@@ -319,8 +361,7 @@ void HIRBuilder::InsertLabel(Label* label, Instr* prev_instr) {
|
||||
new_block->instr_tail = old_prev_tail;
|
||||
}
|
||||
|
||||
for (auto instr = new_block->instr_head; instr != new_block->instr_tail;
|
||||
instr = instr->next) {
|
||||
for (auto instr = new_block->instr_head; instr; instr = instr->next) {
|
||||
instr->block = new_block;
|
||||
}
|
||||
|
||||
@@ -342,6 +383,19 @@ void HIRBuilder::ResetLabelTags() {
|
||||
}
|
||||
}
|
||||
|
||||
void HIRBuilder::AddEdge(Block* src, Block* dest, uint32_t flags) {
|
||||
Edge* edge = arena_->Alloc<Edge>();
|
||||
edge->src = src;
|
||||
edge->dest = dest;
|
||||
edge->flags = flags;
|
||||
edge->outgoing_prev = NULL;
|
||||
edge->outgoing_next = src->outgoing_edge_head;
|
||||
src->outgoing_edge_head = edge;
|
||||
edge->incoming_prev = NULL;
|
||||
edge->incoming_next = dest->incoming_edge_head;
|
||||
dest->incoming_edge_head = edge;
|
||||
}
|
||||
|
||||
Block* HIRBuilder::AppendBlock() {
|
||||
Block* block = arena_->Alloc<Block>();
|
||||
block->arena = arena_;
|
||||
@@ -356,6 +410,7 @@ Block* HIRBuilder::AppendBlock() {
|
||||
}
|
||||
current_block_ = block;
|
||||
block->label_head = block->label_tail = NULL;
|
||||
block->incoming_edge_head = block->outgoing_edge_head = NULL;
|
||||
block->instr_head = block->instr_tail = NULL;
|
||||
return block;
|
||||
}
|
||||
@@ -420,6 +475,7 @@ Value* HIRBuilder::AllocValue(TypeName type) {
|
||||
value->def = NULL;
|
||||
value->use_head = NULL;
|
||||
value->last_use = NULL;
|
||||
value->local_slot = NULL;
|
||||
value->tag = NULL;
|
||||
value->reg = -1;
|
||||
return value;
|
||||
@@ -434,6 +490,7 @@ Value* HIRBuilder::CloneValue(Value* source) {
|
||||
value->def = NULL;
|
||||
value->use_head = NULL;
|
||||
value->last_use = NULL;
|
||||
value->local_slot = NULL;
|
||||
value->tag = NULL;
|
||||
value->reg = -1;
|
||||
return value;
|
||||
@@ -877,6 +934,28 @@ Value* HIRBuilder::LoadClock() {
|
||||
return i->dest;
|
||||
}
|
||||
|
||||
Value* HIRBuilder::AllocLocal(TypeName type) {
|
||||
Value* slot = AllocValue(type);
|
||||
locals_.push_back(slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
Value* HIRBuilder::LoadLocal(Value* slot) {
|
||||
Instr* i = AppendInstr(
|
||||
OPCODE_LOAD_LOCAL_info, 0,
|
||||
AllocValue(slot->type));
|
||||
i->set_src1(slot);
|
||||
i->src2.value = i->src3.value = NULL;
|
||||
return i->dest;
|
||||
}
|
||||
|
||||
void HIRBuilder::StoreLocal(Value* slot, Value* value) {
|
||||
Instr* i = AppendInstr(OPCODE_STORE_LOCAL_info, 0);
|
||||
i->set_src1(slot);
|
||||
i->set_src2(value);
|
||||
i->src3.value = NULL;
|
||||
}
|
||||
|
||||
Value* HIRBuilder::LoadContext(size_t offset, TypeName type) {
|
||||
Instr* i = AppendInstr(
|
||||
OPCODE_LOAD_CONTEXT_info, 0,
|
||||
|
||||
@@ -41,7 +41,12 @@ public:
|
||||
uint32_t attributes() const { return attributes_; }
|
||||
void set_attributes(uint32_t value) { attributes_ = value; }
|
||||
|
||||
std::vector<Value*>& locals() { return locals_; }
|
||||
|
||||
uint32_t max_value_ordinal() const { return next_value_ordinal_; }
|
||||
|
||||
Block* first_block() const { return block_head_; }
|
||||
Block* last_block() const { return block_tail_; }
|
||||
Block* current_block() const;
|
||||
Instr* last_instr() const;
|
||||
|
||||
@@ -50,12 +55,11 @@ public:
|
||||
void InsertLabel(Label* label, Instr* prev_instr);
|
||||
void ResetLabelTags();
|
||||
|
||||
void AddEdge(Block* src, Block* dest, uint32_t flags);
|
||||
|
||||
// static allocations:
|
||||
// Value* AllocStatic(size_t length);
|
||||
|
||||
// stack allocations:
|
||||
// Value* AllocLocal(TypeName type);
|
||||
|
||||
void Comment(const char* format, ...);
|
||||
|
||||
void Nop();
|
||||
@@ -116,6 +120,10 @@ public:
|
||||
|
||||
Value* LoadClock();
|
||||
|
||||
Value* AllocLocal(TypeName type);
|
||||
Value* LoadLocal(Value* slot);
|
||||
void StoreLocal(Value* slot, Value* value);
|
||||
|
||||
Value* LoadContext(size_t offset, TypeName type);
|
||||
void StoreContext(size_t offset, Value* value);
|
||||
|
||||
@@ -230,6 +238,8 @@ protected:
|
||||
uint32_t next_label_id_;
|
||||
uint32_t next_value_ordinal_;
|
||||
|
||||
std::vector<Value*> locals_;
|
||||
|
||||
Block* block_head_;
|
||||
Block* block_tail_;
|
||||
Block* current_block_;
|
||||
|
||||
@@ -61,6 +61,36 @@ bool Instr::Match(SignatureType dest_req,
|
||||
((src3_req == SIG_TYPE_IGNORE) || (src3_req == TO_SIG_TYPE(src3.value)));
|
||||
}
|
||||
|
||||
void Instr::MoveBefore(Instr* other) {
|
||||
if (next == other) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove from current location.
|
||||
if (prev) {
|
||||
prev->next = next;
|
||||
} else {
|
||||
block->instr_head = next;
|
||||
}
|
||||
if (next) {
|
||||
next->prev = prev;
|
||||
} else {
|
||||
block->instr_tail = prev;
|
||||
}
|
||||
|
||||
// Insert into new location.
|
||||
block = other->block;
|
||||
next = other;
|
||||
prev = other->prev;
|
||||
other->prev = this;
|
||||
if (prev) {
|
||||
prev->next = this;
|
||||
}
|
||||
if (other == block->instr_head) {
|
||||
block->instr_head = this;
|
||||
}
|
||||
}
|
||||
|
||||
void Instr::Replace(const OpcodeInfo* opcode, uint16_t flags) {
|
||||
this->opcode = opcode;
|
||||
this->flags = flags;
|
||||
|
||||
@@ -79,6 +79,7 @@ public:
|
||||
SignatureType src2 = SIG_TYPE_X,
|
||||
SignatureType src3 = SIG_TYPE_X) const;
|
||||
|
||||
void MoveBefore(Instr* other);
|
||||
void Replace(const OpcodeInfo* opcode, uint16_t flags);
|
||||
void Remove();
|
||||
};
|
||||
|
||||
@@ -117,6 +117,9 @@ enum Opcode {
|
||||
|
||||
OPCODE_LOAD_CLOCK,
|
||||
|
||||
OPCODE_LOAD_LOCAL,
|
||||
OPCODE_STORE_LOCAL,
|
||||
|
||||
OPCODE_LOAD_CONTEXT,
|
||||
OPCODE_STORE_CONTEXT,
|
||||
|
||||
@@ -202,6 +205,7 @@ enum OpcodeFlags {
|
||||
OPCODE_FLAG_VOLATILE = (1 << 4),
|
||||
OPCODE_FLAG_IGNORE = (1 << 5),
|
||||
OPCODE_FLAG_HIDE = (1 << 6),
|
||||
OPCODE_FLAG_PAIRED_PREV = (1 << 7),
|
||||
};
|
||||
|
||||
enum OpcodeSignatureType {
|
||||
|
||||
@@ -182,6 +182,18 @@ DEFINE_OPCODE(
|
||||
OPCODE_SIG_V,
|
||||
0);
|
||||
|
||||
DEFINE_OPCODE(
|
||||
OPCODE_LOAD_LOCAL,
|
||||
"load_local",
|
||||
OPCODE_SIG_V_V,
|
||||
0);
|
||||
|
||||
DEFINE_OPCODE(
|
||||
OPCODE_STORE_LOCAL,
|
||||
"store_local",
|
||||
OPCODE_SIG_X_V_V,
|
||||
0);
|
||||
|
||||
DEFINE_OPCODE(
|
||||
OPCODE_LOAD_CONTEXT,
|
||||
"load_context",
|
||||
@@ -297,17 +309,17 @@ DEFINE_OPCODE(
|
||||
OPCODE_DID_CARRY,
|
||||
"did_carry",
|
||||
OPCODE_SIG_V_V,
|
||||
0);
|
||||
OPCODE_FLAG_PAIRED_PREV);
|
||||
DEFINE_OPCODE(
|
||||
OPCODE_DID_OVERFLOW,
|
||||
"did_overflow",
|
||||
OPCODE_SIG_V_V,
|
||||
0);
|
||||
OPCODE_FLAG_PAIRED_PREV);
|
||||
DEFINE_OPCODE(
|
||||
OPCODE_DID_SATURATE,
|
||||
"did_saturate",
|
||||
OPCODE_SIG_V_V,
|
||||
0);
|
||||
OPCODE_FLAG_PAIRED_PREV);
|
||||
|
||||
DEFINE_OPCODE(
|
||||
OPCODE_VECTOR_COMPARE_EQ,
|
||||
|
||||
@@ -42,6 +42,25 @@ static bool IsFloatType(TypeName type_name) {
|
||||
static bool IsVecType(TypeName type_name) {
|
||||
return type_name == VEC128_TYPE;
|
||||
}
|
||||
static size_t GetTypeSize(TypeName type_name) {
|
||||
switch (type_name) {
|
||||
case INT8_TYPE:
|
||||
return 1;
|
||||
case INT16_TYPE:
|
||||
return 2;
|
||||
case INT32_TYPE:
|
||||
return 4;
|
||||
case INT64_TYPE:
|
||||
return 8;
|
||||
case FLOAT32_TYPE:
|
||||
return 4;
|
||||
case FLOAT64_TYPE:
|
||||
return 8;
|
||||
default:
|
||||
case VEC128_TYPE:
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
enum ValueFlags {
|
||||
VALUE_IS_CONSTANT = (1 << 1),
|
||||
@@ -78,6 +97,7 @@ public:
|
||||
Use* use_head;
|
||||
// NOTE: for performance reasons this is not maintained during construction.
|
||||
Instr* last_use;
|
||||
Value* local_slot;
|
||||
|
||||
// TODO(benvanik): remove to shrink size.
|
||||
void* tag;
|
||||
|
||||
Reference in New Issue
Block a user