a64_get_set_elimination_pass: Simplify algorithm
This commit is contained in:
parent
54de64f5bf
commit
f4f774f9f6
1 changed files with 58 additions and 58 deletions
|
@ -17,8 +17,15 @@ namespace Dynarmic::Optimization {
|
||||||
|
|
||||||
void A64GetSetElimination(IR::Block& block) {
|
void A64GetSetElimination(IR::Block& block) {
|
||||||
using Iterator = IR::Block::iterator;
|
using Iterator = IR::Block::iterator;
|
||||||
|
|
||||||
|
enum TrackingType {
|
||||||
|
W, X,
|
||||||
|
S, D, Q,
|
||||||
|
SP, NZCV,
|
||||||
|
};
|
||||||
struct RegisterInfo {
|
struct RegisterInfo {
|
||||||
IR::Value register_value;
|
IR::Value register_value;
|
||||||
|
TrackingType tracking_type;
|
||||||
bool set_instruction_present = false;
|
bool set_instruction_present = false;
|
||||||
Iterator last_set_instruction;
|
Iterator last_set_instruction;
|
||||||
};
|
};
|
||||||
|
@ -27,108 +34,101 @@ void A64GetSetElimination(IR::Block& block) {
|
||||||
RegisterInfo sp_info;
|
RegisterInfo sp_info;
|
||||||
RegisterInfo nzcv_info;
|
RegisterInfo nzcv_info;
|
||||||
|
|
||||||
const auto do_set = [&block](RegisterInfo& info, IR::Value value, Iterator set_inst) {
|
const auto do_set = [&block](RegisterInfo& info, IR::Value value, Iterator set_inst, TrackingType tracking_type) {
|
||||||
if (info.set_instruction_present) {
|
if (info.set_instruction_present) {
|
||||||
info.last_set_instruction->Invalidate();
|
info.last_set_instruction->Invalidate();
|
||||||
block.Instructions().erase(info.last_set_instruction);
|
block.Instructions().erase(info.last_set_instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
info.register_value = value;
|
info.register_value = value;
|
||||||
|
info.tracking_type = tracking_type;
|
||||||
info.set_instruction_present = true;
|
info.set_instruction_present = true;
|
||||||
info.last_set_instruction = set_inst;
|
info.last_set_instruction = set_inst;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto do_get = [&block](RegisterInfo& info, Iterator get_inst) {
|
const auto do_get = [&block](RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
|
||||||
if (info.register_value.IsEmpty()) {
|
const auto do_nothing = [&] {
|
||||||
|
info = {};
|
||||||
info.register_value = IR::Value(&*get_inst);
|
info.register_value = IR::Value(&*get_inst);
|
||||||
return;
|
info.tracking_type = tracking_type;
|
||||||
}
|
|
||||||
|
|
||||||
if (!info.set_instruction_present) {
|
|
||||||
static const std::vector<IR::Opcode> ordering {
|
|
||||||
IR::Opcode::A64GetW,
|
|
||||||
IR::Opcode::A64GetX,
|
|
||||||
IR::Opcode::A64GetS,
|
|
||||||
IR::Opcode::A64GetD,
|
|
||||||
IR::Opcode::A64GetQ,
|
|
||||||
};
|
};
|
||||||
const auto source_order = std::find(ordering.begin(), ordering.end(), info.register_value.GetInst()->GetOpcode());
|
|
||||||
const auto dest_order = std::find(ordering.begin(), ordering.end(), get_inst->GetOpcode());
|
if (info.register_value.IsEmpty()) {
|
||||||
if (source_order < dest_order) {
|
do_nothing();
|
||||||
// Zero extension of the value is not appropriate in this case.
|
|
||||||
// Replace currently known value with the new value.
|
|
||||||
info.register_value = IR::Value(&*get_inst);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (get_inst->GetType() == info.register_value.GetType()) {
|
if (info.tracking_type == tracking_type) {
|
||||||
get_inst->ReplaceUsesWith(info.register_value);
|
get_inst->ReplaceUsesWith(info.register_value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value replacement = [&]() -> IR::Value {
|
do_nothing();
|
||||||
IR::IREmitter ir{block};
|
return;
|
||||||
ir.SetInsertionPoint(get_inst);
|
|
||||||
|
|
||||||
const IR::UAny value_to_convert{info.register_value};
|
|
||||||
switch (get_inst->GetType()) {
|
|
||||||
case IR::Type::U8:
|
|
||||||
return ir.LeastSignificantByte(ir.ZeroExtendToWord(value_to_convert));
|
|
||||||
case IR::Type::U16:
|
|
||||||
return ir.LeastSignificantHalf(ir.ZeroExtendToWord(value_to_convert));
|
|
||||||
case IR::Type::U32:
|
|
||||||
return ir.ZeroExtendToWord(value_to_convert);
|
|
||||||
case IR::Type::U64:
|
|
||||||
return ir.ZeroExtendToLong(value_to_convert);
|
|
||||||
case IR::Type::U128:
|
|
||||||
return ir.ZeroExtendToQuad(value_to_convert);
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
get_inst->ReplaceUsesWith(replacement);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
||||||
switch (inst->GetOpcode()) {
|
switch (inst->GetOpcode()) {
|
||||||
case IR::Opcode::A64GetW:
|
case IR::Opcode::A64GetW: {
|
||||||
case IR::Opcode::A64GetX: {
|
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_get(reg_info.at(index), inst);
|
do_get(reg_info.at(index), inst, TrackingType::W);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A64GetX: {
|
||||||
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
|
do_get(reg_info.at(index), inst, TrackingType::X);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A64GetS: {
|
||||||
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
|
do_get(vec_info.at(index), inst, TrackingType::S);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A64GetD: {
|
||||||
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
|
do_get(vec_info.at(index), inst, TrackingType::D);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetS:
|
|
||||||
case IR::Opcode::A64GetD:
|
|
||||||
case IR::Opcode::A64GetQ: {
|
case IR::Opcode::A64GetQ: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_get(vec_info.at(index), inst);
|
do_get(vec_info.at(index), inst, TrackingType::Q);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64GetSP: {
|
case IR::Opcode::A64GetSP: {
|
||||||
do_get(sp_info, inst);
|
do_get(sp_info, inst, TrackingType::SP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A64SetW: {
|
||||||
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
|
do_set(reg_info.at(index), inst->GetArg(1), inst, TrackingType::W);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetW:
|
|
||||||
case IR::Opcode::A64SetX: {
|
case IR::Opcode::A64SetX: {
|
||||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||||
do_set(reg_info.at(index), inst->GetArg(1), inst);
|
do_set(reg_info.at(index), inst->GetArg(1), inst, TrackingType::X);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A64SetS: {
|
||||||
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
|
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::S);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A64SetD: {
|
||||||
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
|
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::D);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetS:
|
|
||||||
case IR::Opcode::A64SetD:
|
|
||||||
case IR::Opcode::A64SetQ: {
|
case IR::Opcode::A64SetQ: {
|
||||||
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
const size_t index = A64::VecNumber(inst->GetArg(0).GetA64VecRef());
|
||||||
do_set(vec_info.at(index), inst->GetArg(1), inst);
|
do_set(vec_info.at(index), inst->GetArg(1), inst, TrackingType::Q);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetSP: {
|
case IR::Opcode::A64SetSP: {
|
||||||
do_set(sp_info, inst->GetArg(0), inst);
|
do_set(sp_info, inst->GetArg(0), inst, TrackingType::SP);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A64SetNZCV: {
|
case IR::Opcode::A64SetNZCV: {
|
||||||
do_set(nzcv_info, inst->GetArg(0), inst);
|
do_set(nzcv_info, inst->GetArg(0), inst, TrackingType::NZCV);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
Loading…
Reference in a new issue