Simplification pass handles redundant truncate/extend & extend/truncate.
This commit is contained in:
parent
4db1b13e98
commit
e362a65189
|
@ -23,6 +23,94 @@ SimplificationPass::~SimplificationPass() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int SimplificationPass::Run(HIRBuilder* builder) {
|
int SimplificationPass::Run(HIRBuilder* builder) {
|
||||||
|
EliminateConversions(builder);
|
||||||
|
SimplifyAssignments(builder);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplificationPass::EliminateConversions(HIRBuilder* builder) {
|
||||||
|
// First, we check for truncates/extensions that can be skipped.
|
||||||
|
// This generates some assignments which then the second step will clean up.
|
||||||
|
// Only zero extend truncates can be skipped:
|
||||||
|
// v1.i32 = truncate v0.i64
|
||||||
|
// v2.i64 = zero_extend v1.i32
|
||||||
|
// becomes:
|
||||||
|
// v1.i32 = truncate v0.i64 (may be dead code removed later)
|
||||||
|
// v2.i64 = v0.i64
|
||||||
|
// But both zero/sign extends can be skipped:
|
||||||
|
// v1.i64 = zero/sign_extend v0.i32
|
||||||
|
// v2.i32 = truncate v1.i64
|
||||||
|
// becomes:
|
||||||
|
// v1.i64 = zero/sign_extend v0.i32 (may be dead code removed later)
|
||||||
|
// v2.i32 = v0.i32
|
||||||
|
|
||||||
|
auto block = builder->first_block();
|
||||||
|
while (block) {
|
||||||
|
auto i = block->instr_head;
|
||||||
|
while (i) {
|
||||||
|
// To make things easier we check in reverse (source of truncate/extend
|
||||||
|
// back to definition).
|
||||||
|
if (i->opcode == &OPCODE_TRUNCATE_info) {
|
||||||
|
// Matches zero/sign_extend + truncate.
|
||||||
|
CheckTruncate(i);
|
||||||
|
} else if (i->opcode == &OPCODE_ZERO_EXTEND_info) {
|
||||||
|
// Matches truncate + zero_extend.
|
||||||
|
CheckZeroExtend(i);
|
||||||
|
}
|
||||||
|
i = i->next;
|
||||||
|
}
|
||||||
|
block = block->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplificationPass::CheckTruncate(Instr* i) {
|
||||||
|
// Walk backward up src's chain looking for an extend. We may have
|
||||||
|
// assigns, so skip those.
|
||||||
|
auto src = i->src1.value;
|
||||||
|
Instr* def = src->def;
|
||||||
|
while (def && def->opcode == &OPCODE_ASSIGN_info) {
|
||||||
|
// Skip asignments.
|
||||||
|
def = def->src1.value->def;
|
||||||
|
}
|
||||||
|
if (def) {
|
||||||
|
if (def->opcode == &OPCODE_SIGN_EXTEND_info) {
|
||||||
|
// Value comes from a sign extend.
|
||||||
|
if (def->src1.value->type == i->dest->type) {
|
||||||
|
// Types match, use original by turning this into an assign.
|
||||||
|
i->Replace(&OPCODE_ASSIGN_info, 0);
|
||||||
|
i->set_src1(def->src1.value);
|
||||||
|
}
|
||||||
|
} else if (def->opcode == &OPCODE_ZERO_EXTEND_info) {
|
||||||
|
// Value comes from a zero extend.
|
||||||
|
if (def->src1.value->type == i->dest->type) {
|
||||||
|
// Types match, use original by turning this into an assign.
|
||||||
|
i->Replace(&OPCODE_ASSIGN_info, 0);
|
||||||
|
i->set_src1(def->src1.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplificationPass::CheckZeroExtend(Instr* i) {
|
||||||
|
// Walk backward up src's chain looking for a truncate. We may have
|
||||||
|
// assigns, so skip those.
|
||||||
|
auto src = i->src1.value;
|
||||||
|
Instr* def = src->def;
|
||||||
|
while (def && def->opcode == &OPCODE_ASSIGN_info) {
|
||||||
|
// Skip asignments.
|
||||||
|
def = def->src1.value->def;
|
||||||
|
}
|
||||||
|
if (def && def->opcode == &OPCODE_TRUNCATE_info) {
|
||||||
|
// Value comes from a truncate.
|
||||||
|
if (def->src1.value->type == i->dest->type) {
|
||||||
|
// Types match, use original by turning this into an assign.
|
||||||
|
i->Replace(&OPCODE_ASSIGN_info, 0);
|
||||||
|
i->set_src1(def->src1.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplificationPass::SimplifyAssignments(HIRBuilder* builder) {
|
||||||
// Run over the instructions and rename assigned variables:
|
// Run over the instructions and rename assigned variables:
|
||||||
// v1 = v0
|
// v1 = v0
|
||||||
// v2 = v1
|
// v2 = v1
|
||||||
|
@ -40,9 +128,9 @@ int SimplificationPass::Run(HIRBuilder* builder) {
|
||||||
// of that instr. Because we may have chains, we do this recursively until
|
// of that instr. Because we may have chains, we do this recursively until
|
||||||
// we find a non-assign def.
|
// we find a non-assign def.
|
||||||
|
|
||||||
Block* block = builder->first_block();
|
auto block = builder->first_block();
|
||||||
while (block) {
|
while (block) {
|
||||||
Instr* i = block->instr_head;
|
auto i = block->instr_head;
|
||||||
while (i) {
|
while (i) {
|
||||||
uint32_t signature = i->opcode->signature;
|
uint32_t signature = i->opcode->signature;
|
||||||
if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) {
|
if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) {
|
||||||
|
@ -56,11 +144,8 @@ int SimplificationPass::Run(HIRBuilder* builder) {
|
||||||
}
|
}
|
||||||
i = i->next;
|
i = i->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* SimplificationPass::CheckValue(Value* value) {
|
Value* SimplificationPass::CheckValue(Value* value) {
|
||||||
|
|
|
@ -26,6 +26,11 @@ public:
|
||||||
virtual int Run(hir::HIRBuilder* builder);
|
virtual int Run(hir::HIRBuilder* builder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void EliminateConversions(hir::HIRBuilder* builder);
|
||||||
|
void CheckTruncate(hir::Instr* i);
|
||||||
|
void CheckZeroExtend(hir::Instr* i);
|
||||||
|
|
||||||
|
void SimplifyAssignments(hir::HIRBuilder* builder);
|
||||||
hir::Value* CheckValue(hir::Value* value);
|
hir::Value* CheckValue(hir::Value* value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue