2016-07-21 21:48:45 +01:00
|
|
|
/* This file is part of the dynarmic project.
|
|
|
|
* Copyright (c) 2016 MerryMage
|
|
|
|
* This software may be used and distributed according to the terms of the GNU
|
|
|
|
* General Public License version 2 or any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/assert.h"
|
2016-08-17 15:53:36 +01:00
|
|
|
#include "frontend/ir/basic_block.h"
|
|
|
|
#include "frontend/ir/opcodes.h"
|
2016-07-21 21:48:45 +01:00
|
|
|
#include "ir_opt/passes.h"
|
|
|
|
|
|
|
|
namespace Dynarmic {
|
|
|
|
namespace Optimization {
|
|
|
|
|
|
|
|
void DeadCodeElimination(IR::Block& block) {
|
|
|
|
const auto is_side_effect_free = [](IR::Opcode op) -> bool {
|
TranslateArm: Implement CLREX, LDREX, LDREXB, LDREXD, LDREXH, STREX, STREXB, STREXD, STREXH, SWP, SWPB
2016-08-09 22:48:20 +01:00
|
|
|
switch (op) {
|
|
|
|
case IR::Opcode::Breakpoint:
|
|
|
|
case IR::Opcode::SetRegister:
|
|
|
|
case IR::Opcode::SetExtendedRegister32:
|
|
|
|
case IR::Opcode::SetExtendedRegister64:
|
|
|
|
case IR::Opcode::SetNFlag:
|
|
|
|
case IR::Opcode::SetZFlag:
|
|
|
|
case IR::Opcode::SetCFlag:
|
|
|
|
case IR::Opcode::SetVFlag:
|
|
|
|
case IR::Opcode::OrQFlag:
|
|
|
|
case IR::Opcode::BXWritePC:
|
|
|
|
case IR::Opcode::CallSupervisor:
|
2016-08-13 00:10:23 +01:00
|
|
|
case IR::Opcode::PushRSB:
|
TranslateArm: Implement CLREX, LDREX, LDREXB, LDREXD, LDREXH, STREX, STREXB, STREXD, STREXH, SWP, SWPB
2016-08-09 22:48:20 +01:00
|
|
|
case IR::Opcode::FPAbs32:
|
|
|
|
case IR::Opcode::FPAbs64:
|
|
|
|
case IR::Opcode::FPAdd32:
|
|
|
|
case IR::Opcode::FPAdd64:
|
|
|
|
case IR::Opcode::FPDiv32:
|
|
|
|
case IR::Opcode::FPDiv64:
|
|
|
|
case IR::Opcode::FPMul32:
|
|
|
|
case IR::Opcode::FPMul64:
|
|
|
|
case IR::Opcode::FPNeg32:
|
|
|
|
case IR::Opcode::FPNeg64:
|
|
|
|
case IR::Opcode::FPSqrt32:
|
|
|
|
case IR::Opcode::FPSqrt64:
|
|
|
|
case IR::Opcode::FPSub32:
|
|
|
|
case IR::Opcode::FPSub64:
|
|
|
|
case IR::Opcode::ClearExclusive:
|
|
|
|
case IR::Opcode::SetExclusive:
|
|
|
|
case IR::Opcode::WriteMemory8:
|
|
|
|
case IR::Opcode::WriteMemory16:
|
|
|
|
case IR::Opcode::WriteMemory32:
|
|
|
|
case IR::Opcode::WriteMemory64:
|
|
|
|
case IR::Opcode::ExclusiveWriteMemory8:
|
|
|
|
case IR::Opcode::ExclusiveWriteMemory16:
|
|
|
|
case IR::Opcode::ExclusiveWriteMemory32:
|
|
|
|
case IR::Opcode::ExclusiveWriteMemory64:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
ASSERT(IR::GetTypeOf(op) != IR::Type::Void);
|
|
|
|
return true;
|
|
|
|
}
|
2016-07-21 21:48:45 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// We iterate over the instructions in reverse order.
|
|
|
|
// This is because removing an instruction reduces the number of uses for earlier instructions.
|
|
|
|
|
basic_block: Add proxy member functions for the instruction list
Currently basic block kind of acts like a 'dumb struct' which makes things
a little more verbose to write (as opposed to keeping it all in one place,
I guess). It's also a little wonky conceptually, considering a block is
composed of instructions (i.e. 'contains' them).
So providing accessors that make it act more like a container can make working
with algorithms a little nicer. It also makes the API a little more
defined.
Ideally, the list would be only available through a function, but
currently, the pool allocator is exposed, which seems somewhat odd,
considering the block itself should manage its overall allocations
(with placement new, and regular new), rather than putting that
sanitizing directly on the IR emitter (it should just care about emission,
not block state). However, recontaining that can be followed up with,
as it's very trivial to do.
2016-08-21 17:35:30 +01:00
|
|
|
if (block.empty()) {
|
2016-07-21 21:48:45 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
basic_block: Add proxy member functions for the instruction list
Currently basic block kind of acts like a 'dumb struct' which makes things
a little more verbose to write (as opposed to keeping it all in one place,
I guess). It's also a little wonky conceptually, considering a block is
composed of instructions (i.e. 'contains' them).
So providing accessors that make it act more like a container can make working
with algorithms a little nicer. It also makes the API a little more
defined.
Ideally, the list would be only available through a function, but
currently, the pool allocator is exposed, which seems somewhat odd,
considering the block itself should manage its overall allocations
(with placement new, and regular new), rather than putting that
sanitizing directly on the IR emitter (it should just care about emission,
not block state). However, recontaining that can be followed up with,
as it's very trivial to do.
2016-08-21 17:35:30 +01:00
|
|
|
auto iter = block.end();
|
2016-07-21 21:48:45 +01:00
|
|
|
do {
|
|
|
|
--iter;
|
2016-07-22 23:55:00 +01:00
|
|
|
if (!iter->HasUses() && is_side_effect_free(iter->GetOpcode())) {
|
|
|
|
iter->Invalidate();
|
2016-07-21 21:48:45 +01:00
|
|
|
iter = block.instructions.erase(iter);
|
|
|
|
}
|
basic_block: Add proxy member functions for the instruction list
Currently basic block kind of acts like a 'dumb struct' which makes things
a little more verbose to write (as opposed to keeping it all in one place,
I guess). It's also a little wonky conceptually, considering a block is
composed of instructions (i.e. 'contains' them).
So providing accessors that make it act more like a container can make working
with algorithms a little nicer. It also makes the API a little more
defined.
Ideally, the list would be only available through a function, but
currently, the pool allocator is exposed, which seems somewhat odd,
considering the block itself should manage its overall allocations
(with placement new, and regular new), rather than putting that
sanitizing directly on the IR emitter (it should just care about emission,
not block state). However, recontaining that can be followed up with,
as it's very trivial to do.
2016-08-21 17:35:30 +01:00
|
|
|
} while (iter != block.begin());
|
2016-07-21 21:48:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Optimization
|
|
|
|
} // namespace Dynarmic
|