From e362a65189af58016c33d0f647e43f3e00be07ba Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 4 Jan 2014 11:56:32 -0800 Subject: [PATCH] Simplification pass handles redundant truncate/extend & extend/truncate. --- .../compiler/passes/simplification_pass.cc | 95 ++++++++++++++++++- .../compiler/passes/simplification_pass.h | 5 + 2 files changed, 95 insertions(+), 5 deletions(-) diff --git a/src/alloy/compiler/passes/simplification_pass.cc b/src/alloy/compiler/passes/simplification_pass.cc index 519eff811..8290e7054 100644 --- a/src/alloy/compiler/passes/simplification_pass.cc +++ b/src/alloy/compiler/passes/simplification_pass.cc @@ -23,6 +23,94 @@ SimplificationPass::~SimplificationPass() { } 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: // v1 = v0 // v2 = v1 @@ -40,9 +128,9 @@ int SimplificationPass::Run(HIRBuilder* builder) { // of that instr. Because we may have chains, we do this recursively until // we find a non-assign def. - Block* block = builder->first_block(); + auto block = builder->first_block(); while (block) { - Instr* i = block->instr_head; + auto i = block->instr_head; while (i) { uint32_t signature = i->opcode->signature; if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) { @@ -56,11 +144,8 @@ int SimplificationPass::Run(HIRBuilder* builder) { } i = i->next; } - block = block->next; } - - return 0; } Value* SimplificationPass::CheckValue(Value* value) { diff --git a/src/alloy/compiler/passes/simplification_pass.h b/src/alloy/compiler/passes/simplification_pass.h index 3fc62ce80..d987ceef0 100644 --- a/src/alloy/compiler/passes/simplification_pass.h +++ b/src/alloy/compiler/passes/simplification_pass.h @@ -26,6 +26,11 @@ public: virtual int Run(hir::HIRBuilder* builder); 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); };