From 5fbcb8991ed6a63b1ac32a65828729032cfee712 Mon Sep 17 00:00:00 2001 From: gibbed Date: Fri, 23 Nov 2018 11:59:29 -0600 Subject: [PATCH] [JIT] Run the SimplificationPass/ConstantPropagationPass until there are no changes. --- src/xenia/cpu/compiler/compiler_passes.h | 2 + .../compiler/passes/conditional_group_pass.cc | 85 +++++++++++++++++ .../compiler/passes/conditional_group_pass.h | 45 +++++++++ .../passes/conditional_group_subpass.cc | 26 ++++++ .../passes/conditional_group_subpass.h | 47 ++++++++++ .../passes/constant_propagation_pass.cc | 92 ++++++++++++++++++- .../passes/constant_propagation_pass.h | 6 +- .../compiler/passes/simplification_pass.cc | 46 +++++++--- .../cpu/compiler/passes/simplification_pass.h | 16 ++-- src/xenia/cpu/ppc/ppc_translator.cc | 19 ++-- 10 files changed, 348 insertions(+), 36 deletions(-) create mode 100644 src/xenia/cpu/compiler/passes/conditional_group_pass.cc create mode 100644 src/xenia/cpu/compiler/passes/conditional_group_pass.h create mode 100644 src/xenia/cpu/compiler/passes/conditional_group_subpass.cc create mode 100644 src/xenia/cpu/compiler/passes/conditional_group_subpass.h diff --git a/src/xenia/cpu/compiler/compiler_passes.h b/src/xenia/cpu/compiler/compiler_passes.h index 6b81d1fb5..fc58ec710 100644 --- a/src/xenia/cpu/compiler/compiler_passes.h +++ b/src/xenia/cpu/compiler/compiler_passes.h @@ -10,6 +10,8 @@ #ifndef XENIA_CPU_COMPILER_COMPILER_PASSES_H_ #define XENIA_CPU_COMPILER_COMPILER_PASSES_H_ +#include "xenia/cpu/compiler/passes/conditional_group_pass.h" +#include "xenia/cpu/compiler/passes/conditional_group_subpass.h" #include "xenia/cpu/compiler/passes/constant_propagation_pass.h" #include "xenia/cpu/compiler/passes/context_promotion_pass.h" #include "xenia/cpu/compiler/passes/control_flow_analysis_pass.h" diff --git a/src/xenia/cpu/compiler/passes/conditional_group_pass.cc b/src/xenia/cpu/compiler/passes/conditional_group_pass.cc new file mode 100644 index 000000000..ef84991e8 --- /dev/null +++ b/src/xenia/cpu/compiler/passes/conditional_group_pass.cc @@ -0,0 +1,85 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/cpu/compiler/passes/conditional_group_pass.h" + +#include + +#include "xenia/base/profiling.h" +#include "xenia/cpu/compiler/compiler.h" +#include "xenia/cpu/ppc/ppc_context.h" +#include "xenia/cpu/processor.h" + +namespace xe { +namespace cpu { +namespace compiler { +namespace passes { + +// TODO(benvanik): remove when enums redefined. +using namespace xe::cpu::hir; + +using xe::cpu::hir::Block; +using xe::cpu::hir::HIRBuilder; +using xe::cpu::hir::Instr; +using xe::cpu::hir::Value; + +ConditionalGroupPass::ConditionalGroupPass() : CompilerPass() {} + +ConditionalGroupPass::~ConditionalGroupPass() {} + +bool ConditionalGroupPass::Initialize(Compiler* compiler) { + if (!CompilerPass::Initialize(compiler)) { + return false; + } + + for (size_t i = 0; i < passes_.size(); ++i) { + auto& pass = passes_[i]; + if (!pass->Initialize(compiler)) { + return false; + } + } + + return true; +} + +bool ConditionalGroupPass::Run(HIRBuilder* builder) { + bool dirty; + int loops = 0; + do { + assert_true(loops < 20); // arbitrary number + dirty = false; + for (size_t i = 0; i < passes_.size(); ++i) { + scratch_arena()->Reset(); + auto& pass = passes_[i]; + auto subpass = dynamic_cast(pass.get()); + if (!subpass) { + if (!pass->Run(builder)) { + return false; + } + } else { + bool result = false; + if (!subpass->Run(builder, result)) { + return false; + } + dirty |= result; + } + } + loops++; + } while (dirty); + return true; +} + +void ConditionalGroupPass::AddPass(std::unique_ptr pass) { + passes_.push_back(std::move(pass)); +} + +} // namespace passes +} // namespace compiler +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/compiler/passes/conditional_group_pass.h b/src/xenia/cpu/compiler/passes/conditional_group_pass.h new file mode 100644 index 000000000..7421fe1b5 --- /dev/null +++ b/src/xenia/cpu/compiler/passes/conditional_group_pass.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_CPU_COMPILER_PASSES_CONDITIONAL_GROUP_PASS_H_ +#define XENIA_CPU_COMPILER_PASSES_CONDITIONAL_GROUP_PASS_H_ + +#include +#include + +#include "xenia/base/platform.h" +#include "xenia/cpu/compiler/compiler_pass.h" +#include "xenia/cpu/compiler/passes/conditional_group_subpass.h" + +namespace xe { +namespace cpu { +namespace compiler { +namespace passes { + +class ConditionalGroupPass : public CompilerPass { + public: + ConditionalGroupPass(); + virtual ~ConditionalGroupPass() override; + + bool Initialize(Compiler* compiler) override; + + bool Run(hir::HIRBuilder* builder) override; + + void AddPass(std::unique_ptr pass); + + private: + std::vector> passes_; +}; + +} // namespace passes +} // namespace compiler +} // namespace cpu +} // namespace xe + +#endif // XENIA_CPU_COMPILER_PASSES_CONDITIONAL_GROUP_PASS_H_ diff --git a/src/xenia/cpu/compiler/passes/conditional_group_subpass.cc b/src/xenia/cpu/compiler/passes/conditional_group_subpass.cc new file mode 100644 index 000000000..39780e2f5 --- /dev/null +++ b/src/xenia/cpu/compiler/passes/conditional_group_subpass.cc @@ -0,0 +1,26 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/cpu/compiler/passes/conditional_group_subpass.h" + +#include "xenia/cpu/compiler/compiler.h" + +namespace xe { +namespace cpu { +namespace compiler { +namespace passes { + +ConditionalGroupSubpass::ConditionalGroupSubpass() : CompilerPass() {} + +ConditionalGroupSubpass::~ConditionalGroupSubpass() = default; + +} // namespace passes +} // namespace compiler +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/compiler/passes/conditional_group_subpass.h b/src/xenia/cpu/compiler/passes/conditional_group_subpass.h new file mode 100644 index 000000000..f62c50ed3 --- /dev/null +++ b/src/xenia/cpu/compiler/passes/conditional_group_subpass.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_CPU_COMPILER_PASSES_CONDITIONAL_GROUP_SUBPASS_H_ +#define XENIA_CPU_COMPILER_PASSES_CONDITIONAL_GROUP_SUBPASS_H_ + +#include "xenia/base/arena.h" +#include "xenia/cpu/compiler/compiler_pass.h" +#include "xenia/cpu/hir/hir_builder.h" + +namespace xe { +namespace cpu { +class Processor; +} // namespace cpu +} // namespace xe + +namespace xe { +namespace cpu { +namespace compiler { +class Compiler; +namespace passes { + +class ConditionalGroupSubpass : public CompilerPass { + public: + ConditionalGroupSubpass(); + virtual ~ConditionalGroupSubpass(); + + bool Run(hir::HIRBuilder* builder) override { + bool dummy; + return Run(builder, dummy); + } + + virtual bool Run(hir::HIRBuilder* builder, bool& result) = 0; +}; + +} // namespace passes +} // namespace compiler +} // namespace cpu +} // namespace xe + +#endif // XENIA_CPU_COMPILER_PASSES_CONDITIONAL_GROUP_SUBPASS_H_ diff --git a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc index 3db8e99d6..3a399cefd 100644 --- a/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc +++ b/src/xenia/cpu/compiler/passes/constant_propagation_pass.cc @@ -31,11 +31,12 @@ using xe::cpu::hir::HIRBuilder; using xe::cpu::hir::TypeName; using xe::cpu::hir::Value; -ConstantPropagationPass::ConstantPropagationPass() : CompilerPass() {} +ConstantPropagationPass::ConstantPropagationPass() + : ConditionalGroupSubpass() {} ConstantPropagationPass::~ConstantPropagationPass() {} -bool ConstantPropagationPass::Run(HIRBuilder* builder) { +bool ConstantPropagationPass::Run(HIRBuilder* builder, bool& result) { // Once ContextPromotion has run there will likely be a whole slew of // constants that can be pushed through the function. // Example: @@ -63,6 +64,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { // v1 = 19 // v2 = 0 + result = false; auto block = builder->first_block(); while (block) { auto i = block->instr_head; @@ -76,6 +78,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { } else { i->Remove(); } + result = true; } break; @@ -86,6 +89,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { } else { i->Remove(); } + result = true; } break; @@ -98,6 +102,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { } else { i->Remove(); } + result = true; } break; case OPCODE_CALL_INDIRECT: @@ -109,6 +114,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { } i->Replace(&OPCODE_CALL_info, i->flags); i->src1.symbol = function; + result = true; } break; case OPCODE_CALL_INDIRECT_TRUE: @@ -120,6 +126,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { } else { i->Remove(); } + result = true; } break; @@ -132,6 +139,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { } else { i->Remove(); } + result = true; } break; case OPCODE_BRANCH_FALSE: @@ -143,6 +151,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { } else { i->Remove(); } + result = true; } break; @@ -152,6 +161,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Cast(target_type); i->Remove(); + result = true; } break; case OPCODE_CONVERT: @@ -160,6 +170,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Convert(target_type, RoundMode(i->flags)); i->Remove(); + result = true; } break; case OPCODE_ROUND: @@ -167,6 +178,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Round(RoundMode(i->flags)); i->Remove(); + result = true; } break; case OPCODE_ZERO_EXTEND: @@ -175,6 +187,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->ZeroExtend(target_type); i->Remove(); + result = true; } break; case OPCODE_SIGN_EXTEND: @@ -183,6 +196,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->SignExtend(target_type); i->Remove(); + result = true; } break; case OPCODE_TRUNCATE: @@ -191,6 +205,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Truncate(target_type); i->Remove(); + result = true; } break; @@ -210,6 +225,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { i->Replace(&OPCODE_LOAD_MMIO_info, 0); i->src1.offset = reinterpret_cast(mmio_range); i->src2.offset = address; + result = true; } else { auto heap = memory->LookupHeap(address); uint32_t protect; @@ -222,18 +238,22 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { case INT8_TYPE: v->set_constant(xe::load(host_addr)); i->Remove(); + result = true; break; case INT16_TYPE: v->set_constant(xe::load(host_addr)); i->Remove(); + result = true; break; case INT32_TYPE: v->set_constant(xe::load(host_addr)); i->Remove(); + result = true; break; case INT64_TYPE: v->set_constant(xe::load(host_addr)); i->Remove(); + result = true; break; case VEC128_TYPE: vec128_t val; @@ -241,6 +261,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { val.high = xe::load(host_addr + 8); v->set_constant(val); i->Remove(); + result = true; break; default: assert_unhandled_case(v->type); @@ -270,6 +291,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { i->src1.offset = reinterpret_cast(mmio_range); i->src2.offset = address; i->set_src3(value); + result = true; } } break; @@ -281,10 +303,12 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { auto src2 = i->src2.value; i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(src2); + result = true; } else if (i->src1.value->IsConstantFalse()) { auto src3 = i->src3.value; i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(src3); + result = true; } else if (i->src2.value->IsConstant() && i->src3.value->IsConstant()) { // TODO: Select @@ -305,6 +329,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_constant(uint8_t(0)); } i->Remove(); + result = true; } break; case OPCODE_IS_FALSE: @@ -315,6 +340,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_constant(uint8_t(0)); } i->Remove(); + result = true; } break; case OPCODE_IS_NAN: @@ -329,6 +355,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_constant(uint8_t(0)); } i->Remove(); + result = true; } break; @@ -338,6 +365,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantEQ(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_NE: @@ -345,6 +373,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantNE(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_SLT: @@ -352,6 +381,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantSLT(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_SLE: @@ -359,6 +389,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantSLE(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_SGT: @@ -366,6 +397,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantSGT(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_SGE: @@ -373,6 +405,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantSGE(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_ULT: @@ -380,6 +413,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantULT(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_ULE: @@ -387,6 +421,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantULE(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_UGT: @@ -394,6 +429,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantUGT(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; case OPCODE_COMPARE_UGE: @@ -401,6 +437,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { bool value = i->src1.value->IsConstantUGE(i->src2.value); i->dest->set_constant(uint8_t(value)); i->Remove(); + result = true; } break; @@ -413,6 +450,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Add(i->src2.value); i->Remove(); + result = true; } break; case OPCODE_ADD_CARRY: @@ -433,6 +471,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { i->set_src1(ca); } } + result = true; } break; case OPCODE_SUB: @@ -440,6 +479,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Sub(i->src2.value); i->Remove(); + result = true; } break; case OPCODE_MUL: @@ -447,6 +487,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Mul(i->src2.value); i->Remove(); + result = true; } else if (i->src1.value->IsConstant() || i->src2.value->IsConstant()) { // Reorder the sources to make things simpler. @@ -460,12 +501,14 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { if (s2->type != VEC128_TYPE && s2->IsConstantOne()) { i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(s1); + result = true; } else if (s2->type == VEC128_TYPE) { auto& c = s2->constant; if (c.v128.f32[0] == 1.f && c.v128.f32[1] == 1.f && c.v128.f32[2] == 1.f && c.v128.f32[3] == 1.f) { i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(s1); + result = true; } } } @@ -475,6 +518,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->MulHi(i->src2.value, (i->flags & ARITHMETIC_UNSIGNED) != 0); i->Remove(); + result = true; } break; case OPCODE_DIV: @@ -482,6 +526,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Div(i->src2.value, (i->flags & ARITHMETIC_UNSIGNED) != 0); i->Remove(); + result = true; } else if (i->src2.value->IsConstant()) { // Division by one = no-op. Value* src1 = i->src1.value; @@ -489,12 +534,14 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { i->src2.value->IsConstantOne()) { i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(src1); + result = true; } else if (i->src2.value->type == VEC128_TYPE) { auto& c = i->src2.value->constant; if (c.v128.f32[0] == 1.f && c.v128.f32[1] == 1.f && c.v128.f32[2] == 1.f && c.v128.f32[3] == 1.f) { i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(src1); + result = true; } } } @@ -505,6 +552,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); Value::MulAdd(v, i->src1.value, i->src2.value, i->src3.value); i->Remove(); + result = true; } else { // Multiply part is constant. Value* mul = builder->AllocValue(); @@ -515,6 +563,8 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { i->Replace(&OPCODE_ADD_info, 0); i->set_src1(mul); i->set_src2(add); + + result = true; } } break; @@ -525,6 +575,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); Value::MulSub(v, i->src1.value, i->src2.value, i->src3.value); i->Remove(); + result = true; } else { // Multiply part is constant. Value* mul = builder->AllocValue(); @@ -535,6 +586,8 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { i->Replace(&OPCODE_SUB_info, 0); i->set_src1(mul); i->set_src2(add); + + result = true; } } break; @@ -543,6 +596,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Max(i->src2.value); i->Remove(); + result = true; } break; case OPCODE_NEG: @@ -550,6 +604,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Neg(); i->Remove(); + result = true; } break; case OPCODE_ABS: @@ -557,6 +612,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Abs(); i->Remove(); + result = true; } break; case OPCODE_SQRT: @@ -564,6 +620,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Sqrt(); i->Remove(); + result = true; } break; case OPCODE_RSQRT: @@ -571,6 +628,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->RSqrt(); i->Remove(); + result = true; } break; case OPCODE_RECIP: @@ -578,6 +636,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Recip(); i->Remove(); + result = true; } break; case OPCODE_AND: @@ -585,6 +644,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->And(i->src2.value); i->Remove(); + result = true; } break; case OPCODE_OR: @@ -592,6 +652,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Or(i->src2.value); i->Remove(); + result = true; } break; case OPCODE_XOR: @@ -599,11 +660,13 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Xor(i->src2.value); i->Remove(); + result = true; } else if (!i->src1.value->IsConstant() && !i->src2.value->IsConstant() && i->src1.value == i->src2.value) { v->set_zero(v->type); i->Remove(); + result = true; } break; case OPCODE_NOT: @@ -611,6 +674,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Not(); i->Remove(); + result = true; } break; case OPCODE_SHL: @@ -618,10 +682,12 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Shl(i->src2.value); i->Remove(); + result = true; } else if (i->src2.value->IsConstantZero()) { auto src1 = i->src1.value; i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(src1); + result = true; } break; case OPCODE_SHR: @@ -629,10 +695,12 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Shr(i->src2.value); i->Remove(); + result = true; } else if (i->src2.value->IsConstantZero()) { auto src1 = i->src1.value; i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(src1); + result = true; } break; case OPCODE_SHA: @@ -640,6 +708,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->Sha(i->src2.value); i->Remove(); + result = true; } break; // TODO(benvanik): ROTATE_LEFT @@ -648,6 +717,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->ByteSwap(); i->Remove(); + result = true; } break; case OPCODE_CNTLZ: @@ -655,6 +725,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_zero(v->type); v->CountLeadingZeros(i->src1.value); i->Remove(); + result = true; } break; // TODO(benvanik): INSERT/EXTRACT @@ -664,6 +735,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_zero(v->type); v->Extract(i->src1.value, i->src2.value); i->Remove(); + result = true; } break; case OPCODE_SPLAT: @@ -671,6 +743,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_zero(v->type); v->Splat(i->src1.value); i->Remove(); + result = true; } break; case OPCODE_VECTOR_COMPARE_EQ: @@ -678,6 +751,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->VectorCompareEQ(i->src2.value, hir::TypeName(i->flags)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_COMPARE_SGT: @@ -685,6 +759,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->VectorCompareSGT(i->src2.value, hir::TypeName(i->flags)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_COMPARE_SGE: @@ -692,6 +767,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->VectorCompareSGE(i->src2.value, hir::TypeName(i->flags)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_COMPARE_UGT: @@ -699,6 +775,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->VectorCompareUGT(i->src2.value, hir::TypeName(i->flags)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_COMPARE_UGE: @@ -706,6 +783,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->VectorCompareUGE(i->src2.value, hir::TypeName(i->flags)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_CONVERT_F2I: @@ -714,6 +792,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->VectorConvertF2I(i->src1.value, !!(i->flags & ARITHMETIC_UNSIGNED)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_CONVERT_I2F: @@ -722,6 +801,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->VectorConvertI2F(i->src1.value, !!(i->flags & ARITHMETIC_UNSIGNED)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_SHL: @@ -729,6 +809,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->VectorShl(i->src2.value, hir::TypeName(i->flags)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_SHR: @@ -736,6 +817,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->VectorShr(i->src2.value, hir::TypeName(i->flags)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_ROTATE_LEFT: @@ -743,6 +825,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->VectorRol(i->src2.value, hir::TypeName(i->flags)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_ADD: @@ -753,6 +836,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { !!(arith_flags & ARITHMETIC_UNSIGNED), !!(arith_flags & ARITHMETIC_SATURATE)); i->Remove(); + result = true; } break; case OPCODE_VECTOR_SUB: @@ -763,6 +847,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { !!(arith_flags & ARITHMETIC_UNSIGNED), !!(arith_flags & ARITHMETIC_SATURATE)); i->Remove(); + result = true; } break; @@ -771,6 +856,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->DotProduct3(i->src2.value); i->Remove(); + result = true; } break; @@ -779,6 +865,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { v->set_from(i->src1.value); v->DotProduct4(i->src2.value); i->Remove(); + result = true; } break; @@ -790,6 +877,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) { !!(arith_flags & ARITHMETIC_UNSIGNED), !!(arith_flags & ARITHMETIC_SATURATE)); i->Remove(); + result = true; } break; diff --git a/src/xenia/cpu/compiler/passes/constant_propagation_pass.h b/src/xenia/cpu/compiler/passes/constant_propagation_pass.h index 021bdc981..08bd25b4a 100644 --- a/src/xenia/cpu/compiler/passes/constant_propagation_pass.h +++ b/src/xenia/cpu/compiler/passes/constant_propagation_pass.h @@ -10,19 +10,19 @@ #ifndef XENIA_CPU_COMPILER_PASSES_CONSTANT_PROPAGATION_PASS_H_ #define XENIA_CPU_COMPILER_PASSES_CONSTANT_PROPAGATION_PASS_H_ -#include "xenia/cpu/compiler/compiler_pass.h" +#include "xenia/cpu/compiler/passes/conditional_group_subpass.h" namespace xe { namespace cpu { namespace compiler { namespace passes { -class ConstantPropagationPass : public CompilerPass { +class ConstantPropagationPass : public ConditionalGroupSubpass { public: ConstantPropagationPass(); ~ConstantPropagationPass() override; - bool Run(hir::HIRBuilder* builder) override; + bool Run(hir::HIRBuilder* builder, bool& result) override; private: }; diff --git a/src/xenia/cpu/compiler/passes/simplification_pass.cc b/src/xenia/cpu/compiler/passes/simplification_pass.cc index 3278ab7c6..3569887a4 100644 --- a/src/xenia/cpu/compiler/passes/simplification_pass.cc +++ b/src/xenia/cpu/compiler/passes/simplification_pass.cc @@ -23,17 +23,18 @@ using xe::cpu::hir::HIRBuilder; using xe::cpu::hir::Instr; using xe::cpu::hir::Value; -SimplificationPass::SimplificationPass() : CompilerPass() {} +SimplificationPass::SimplificationPass() : ConditionalGroupSubpass() {} SimplificationPass::~SimplificationPass() {} -bool SimplificationPass::Run(HIRBuilder* builder) { - EliminateConversions(builder); - SimplifyAssignments(builder); +bool SimplificationPass::Run(HIRBuilder* builder, bool& result) { + result = false; + result |= EliminateConversions(builder); + result |= SimplifyAssignments(builder); return true; } -void SimplificationPass::EliminateConversions(HIRBuilder* builder) { +bool 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. // Both zero/sign extends can be skipped: @@ -43,6 +44,7 @@ void SimplificationPass::EliminateConversions(HIRBuilder* builder) { // v1.i64 = zero/sign_extend v0.i32 (may be dead code removed later) // v2.i32 = v0.i32 + bool result = false; auto block = builder->first_block(); while (block) { auto i = block->instr_head; @@ -51,20 +53,21 @@ void SimplificationPass::EliminateConversions(HIRBuilder* builder) { // back to definition). if (i->opcode == &OPCODE_TRUNCATE_info) { // Matches zero/sign_extend + truncate. - CheckTruncate(i); + result |= CheckTruncate(i); } else if (i->opcode == &OPCODE_BYTE_SWAP_info) { // Matches byte swap + byte swap. // This is pretty rare within the same basic block, but is in the // memcpy hot path and (probably) worth it. Maybe. - CheckByteSwap(i); + result |= CheckByteSwap(i); } i = i->next; } block = block->next; } + return result; } -void SimplificationPass::CheckTruncate(Instr* i) { +bool 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; @@ -80,6 +83,7 @@ void SimplificationPass::CheckTruncate(Instr* i) { // Types match, use original by turning this into an assign. i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(def->src1.value); + return true; } } else if (def->opcode == &OPCODE_ZERO_EXTEND_info) { // Value comes from a zero extend. @@ -87,12 +91,14 @@ void SimplificationPass::CheckTruncate(Instr* i) { // Types match, use original by turning this into an assign. i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(def->src1.value); + return true; } } } + return false; } -void SimplificationPass::CheckByteSwap(Instr* i) { +bool SimplificationPass::CheckByteSwap(Instr* i) { // Walk backward up src's chain looking for a byte swap. We may have // assigns, so skip those. auto src = i->src1.value; @@ -107,11 +113,13 @@ void SimplificationPass::CheckByteSwap(Instr* i) { // Types match, use original by turning this into an assign. i->Replace(&OPCODE_ASSIGN_info, 0); i->set_src1(def->src1.value); + return true; } } + return false; } -void SimplificationPass::SimplifyAssignments(HIRBuilder* builder) { +bool SimplificationPass::SimplifyAssignments(HIRBuilder* builder) { // Run over the instructions and rename assigned variables: // v1 = v0 // v2 = v1 @@ -129,27 +137,35 @@ void SimplificationPass::SimplifyAssignments(HIRBuilder* builder) { // of that instr. Because we may have chains, we do this recursively until // we find a non-assign def. + bool result = false; auto block = builder->first_block(); while (block) { auto i = block->instr_head; while (i) { uint32_t signature = i->opcode->signature; if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) { - i->set_src1(CheckValue(i->src1.value)); + bool modified = false; + i->set_src1(CheckValue(i->src1.value, modified)); + result |= modified; } if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) { - i->set_src2(CheckValue(i->src2.value)); + bool modified = false; + i->set_src2(CheckValue(i->src2.value, modified)); + result |= modified; } if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) { - i->set_src3(CheckValue(i->src3.value)); + bool modified = false; + i->set_src3(CheckValue(i->src3.value, modified)); + result |= modified; } i = i->next; } block = block->next; } + return result; } -Value* SimplificationPass::CheckValue(Value* value) { +Value* SimplificationPass::CheckValue(Value* value, bool& result) { auto def = value->def; if (def && def->opcode == &OPCODE_ASSIGN_info) { // Value comes from an assignment - recursively find if it comes from @@ -162,8 +178,10 @@ Value* SimplificationPass::CheckValue(Value* value) { } replacement = def->src1.value; } + result = true; return replacement; } + result = false; return value; } diff --git a/src/xenia/cpu/compiler/passes/simplification_pass.h b/src/xenia/cpu/compiler/passes/simplification_pass.h index 70275f8b4..2ba6efad7 100644 --- a/src/xenia/cpu/compiler/passes/simplification_pass.h +++ b/src/xenia/cpu/compiler/passes/simplification_pass.h @@ -10,27 +10,27 @@ #ifndef XENIA_CPU_COMPILER_PASSES_SIMPLIFICATION_PASS_H_ #define XENIA_CPU_COMPILER_PASSES_SIMPLIFICATION_PASS_H_ -#include "xenia/cpu/compiler/compiler_pass.h" +#include "xenia/cpu/compiler/passes/conditional_group_subpass.h" namespace xe { namespace cpu { namespace compiler { namespace passes { -class SimplificationPass : public CompilerPass { +class SimplificationPass : public ConditionalGroupSubpass { public: SimplificationPass(); ~SimplificationPass() override; - bool Run(hir::HIRBuilder* builder) override; + bool Run(hir::HIRBuilder* builder, bool& result) override; private: - void EliminateConversions(hir::HIRBuilder* builder); - void CheckTruncate(hir::Instr* i); - void CheckByteSwap(hir::Instr* i); + bool EliminateConversions(hir::HIRBuilder* builder); + bool CheckTruncate(hir::Instr* i); + bool CheckByteSwap(hir::Instr* i); - void SimplifyAssignments(hir::HIRBuilder* builder); - hir::Value* CheckValue(hir::Value* value); + bool SimplifyAssignments(hir::HIRBuilder* builder); + hir::Value* CheckValue(hir::Value* value, bool& result); }; } // namespace passes diff --git a/src/xenia/cpu/ppc/ppc_translator.cc b/src/xenia/cpu/ppc/ppc_translator.cc index ec1768163..d408f75b1 100644 --- a/src/xenia/cpu/ppc/ppc_translator.cc +++ b/src/xenia/cpu/ppc/ppc_translator.cc @@ -53,15 +53,16 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) { if (validate) compiler_->AddPass(std::make_unique()); compiler_->AddPass(std::make_unique()); if (validate) compiler_->AddPass(std::make_unique()); - // TODO(gibbed): loop until these passes stop making changes? - for (int i = 0; i < 5; ++i) { - compiler_->AddPass(std::make_unique()); - if (validate) - compiler_->AddPass(std::make_unique()); - compiler_->AddPass(std::make_unique()); - if (validate) - compiler_->AddPass(std::make_unique()); - } + + // Grouped simplification + constant propagation. + // Loops until no changes are made. + auto sap = std::make_unique(); + sap->AddPass(std::make_unique()); + if (validate) sap->AddPass(std::make_unique()); + sap->AddPass(std::make_unique()); + if (validate) sap->AddPass(std::make_unique()); + compiler_->AddPass(std::move(sap)); + if (backend->machine_info()->supports_extended_load_store) { // Backend supports the advanced LOAD/STORE instructions. // These will save us a lot of HIR opcodes.