forked from NUDT-compiler/nudt-compiler-cpp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
586 lines
19 KiB
586 lines
19 KiB
#include "mir/MIR.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "utils/Log.h"
|
|
|
|
namespace mir
|
|
{
|
|
namespace
|
|
{
|
|
|
|
static bool IsSamePhysReg(PhysReg a, PhysReg b)
|
|
{
|
|
int an = static_cast<int>(a);
|
|
int bn = static_cast<int>(b);
|
|
|
|
if (an == bn)
|
|
return true;
|
|
|
|
int aw = static_cast<int>(PhysReg::W0);
|
|
int ax = static_cast<int>(PhysReg::X0);
|
|
|
|
if (an >= aw && an <= static_cast<int>(PhysReg::W30) &&
|
|
bn >= ax && bn <= static_cast<int>(PhysReg::X30))
|
|
{
|
|
return (an - aw) == (bn - ax);
|
|
}
|
|
if (an >= ax && an <= static_cast<int>(PhysReg::X30) &&
|
|
bn >= aw && bn <= static_cast<int>(PhysReg::W30))
|
|
{
|
|
return (an - ax) == (bn - aw);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool IsWReg(PhysReg r)
|
|
{
|
|
int n = static_cast<int>(r);
|
|
return n >= static_cast<int>(PhysReg::W0) && n <= static_cast<int>(PhysReg::W30);
|
|
}
|
|
|
|
static bool IsXReg(PhysReg r)
|
|
{
|
|
int n = static_cast<int>(r);
|
|
return n >= static_cast<int>(PhysReg::X0) && n <= static_cast<int>(PhysReg::X30);
|
|
}
|
|
|
|
static bool IsSameRegClass(PhysReg a, PhysReg b)
|
|
{
|
|
return (IsWReg(a) && IsWReg(b)) || (IsXReg(a) && IsXReg(b));
|
|
}
|
|
|
|
static bool IsRedundantMovReg(const MachineInstr &inst)
|
|
{
|
|
if (inst.GetOpcode() != Opcode::MovReg)
|
|
return false;
|
|
const auto &ops = inst.GetOperands();
|
|
if (ops.size() < 2)
|
|
return false;
|
|
if (ops[0].GetKind() != Operand::Kind::Reg || ops[1].GetKind() != Operand::Kind::Reg)
|
|
return false;
|
|
return ops[0].GetReg() == ops[1].GetReg();
|
|
}
|
|
|
|
static bool IsIdentityAddSub(const MachineInstr &inst)
|
|
{
|
|
if (inst.GetOpcode() != Opcode::AddRR && inst.GetOpcode() != Opcode::SubRR)
|
|
return false;
|
|
const auto &ops = inst.GetOperands();
|
|
if (ops.size() < 3)
|
|
return false;
|
|
if (ops[2].GetKind() != Operand::Kind::Imm)
|
|
return false;
|
|
return ops[2].GetImm() == 0;
|
|
}
|
|
|
|
static bool IsRedundantStoreLoad(const MachineInstr &store,
|
|
const MachineInstr &load)
|
|
{
|
|
if (store.GetOpcode() != Opcode::StoreStack || load.GetOpcode() != Opcode::LoadStack)
|
|
return false;
|
|
const auto &s_ops = store.GetOperands();
|
|
const auto &l_ops = load.GetOperands();
|
|
if (s_ops.size() < 2 || l_ops.size() < 2)
|
|
return false;
|
|
if (s_ops[1].GetKind() != Operand::Kind::FrameIndex ||
|
|
l_ops[1].GetKind() != Operand::Kind::FrameIndex)
|
|
return false;
|
|
return s_ops[1].GetFrameIndex() == l_ops[1].GetFrameIndex();
|
|
}
|
|
|
|
static bool InstDefinesReg(const MachineInstr &inst, PhysReg reg)
|
|
{
|
|
const auto opcode = inst.GetOpcode();
|
|
const auto &ops = inst.GetOperands();
|
|
|
|
switch (opcode)
|
|
{
|
|
case Opcode::Call:
|
|
case Opcode::Prologue:
|
|
case Opcode::Epilogue:
|
|
return true;
|
|
case Opcode::StoreStack:
|
|
case Opcode::StoreMem:
|
|
case Opcode::StoreGlobal:
|
|
case Opcode::CmpRR:
|
|
case Opcode::CmpImm:
|
|
case Opcode::FCmpRR:
|
|
case Opcode::Br:
|
|
case Opcode::CondBr:
|
|
case Opcode::Ret:
|
|
return false;
|
|
default:
|
|
if (!ops.empty() && ops[0].GetKind() == Operand::Kind::Reg)
|
|
return IsSamePhysReg(ops[0].GetReg(), reg);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool InstUsesReg(const MachineInstr &inst, PhysReg reg)
|
|
{
|
|
const auto opcode = inst.GetOpcode();
|
|
const auto &ops = inst.GetOperands();
|
|
|
|
switch (opcode)
|
|
{
|
|
case Opcode::Call:
|
|
case Opcode::Prologue:
|
|
case Opcode::Epilogue:
|
|
return true;
|
|
case Opcode::MovImm:
|
|
case Opcode::Br:
|
|
case Opcode::CondBr:
|
|
case Opcode::Ret:
|
|
return false;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
size_t start = 1;
|
|
if (opcode == Opcode::StoreStack || opcode == Opcode::StoreMem ||
|
|
opcode == Opcode::StoreGlobal || opcode == Opcode::CmpRR ||
|
|
opcode == Opcode::CmpImm || opcode == Opcode::FCmpRR)
|
|
{
|
|
start = 0;
|
|
}
|
|
|
|
for (size_t i = start; i < ops.size(); ++i)
|
|
{
|
|
if (ops[i].GetKind() == Operand::Kind::Reg && IsSamePhysReg(ops[i].GetReg(), reg))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void RunPeepholeOnBlock(MachineBasicBlock &block)
|
|
{
|
|
auto &insts = block.GetInstructions();
|
|
bool changed = true;
|
|
while (changed)
|
|
{
|
|
changed = false;
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (IsRedundantMovReg(*it))
|
|
{
|
|
it = insts.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
|
|
if (IsIdentityAddSub(*it))
|
|
{
|
|
const auto &ops = it->GetOperands();
|
|
if (ops[0].GetKind() == Operand::Kind::Reg &&
|
|
ops[1].GetKind() == Operand::Kind::Reg &&
|
|
ops[0].GetReg() == ops[1].GetReg())
|
|
{
|
|
it = insts.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!changed)
|
|
{
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (it->GetOpcode() == Opcode::StoreStack)
|
|
{
|
|
auto next = std::next(it);
|
|
if (next != insts.end() && IsRedundantStoreLoad(*it, *next))
|
|
{
|
|
const auto &s_ops = it->GetOperands();
|
|
const auto &l_ops = next->GetOperands();
|
|
if (s_ops[0].GetKind() == Operand::Kind::Reg &&
|
|
l_ops[0].GetKind() == Operand::Kind::Reg &&
|
|
s_ops[0].GetReg() == l_ops[0].GetReg())
|
|
{
|
|
next = insts.erase(next);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!changed)
|
|
{
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (it->GetOpcode() == Opcode::MovReg)
|
|
{
|
|
const auto &ops = it->GetOperands();
|
|
if (ops.size() >= 2 &&
|
|
ops[0].GetKind() == Operand::Kind::Reg &&
|
|
ops[1].GetKind() == Operand::Kind::Reg)
|
|
{
|
|
PhysReg dst = ops[0].GetReg();
|
|
PhysReg src = ops[1].GetReg();
|
|
for (auto pit = insts.begin(); pit != it; ++pit)
|
|
{
|
|
if (pit->GetOpcode() == Opcode::MovImm)
|
|
{
|
|
const auto &pops = pit->GetOperands();
|
|
if (pops.size() >= 2 &&
|
|
pops[0].GetKind() == Operand::Kind::Reg &&
|
|
IsSamePhysReg(pops[0].GetReg(), src) &&
|
|
IsSameRegClass(pops[0].GetReg(), src) &&
|
|
pops[1].GetKind() == Operand::Kind::Imm)
|
|
{
|
|
bool src_redefined = false;
|
|
for (auto mid = std::next(pit); mid != it; ++mid)
|
|
{
|
|
if (InstDefinesReg(*mid, src))
|
|
{
|
|
src_redefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!src_redefined)
|
|
{
|
|
int imm = pops[1].GetImm();
|
|
*it = MachineInstr(Opcode::MovImm, {Operand::Reg(dst), Operand::Imm(imm)});
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (changed)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!changed)
|
|
{
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (it->GetOpcode() == Opcode::AddRR || it->GetOpcode() == Opcode::SubRR)
|
|
{
|
|
const auto &ops = it->GetOperands();
|
|
if (ops.size() >= 3 &&
|
|
ops[0].GetKind() == Operand::Kind::Reg &&
|
|
ops[1].GetKind() == Operand::Kind::Reg &&
|
|
ops[2].GetKind() == Operand::Kind::Reg)
|
|
{
|
|
PhysReg add_dst = ops[0].GetReg();
|
|
PhysReg add_lhs = ops[1].GetReg();
|
|
PhysReg add_rhs = ops[2].GetReg();
|
|
for (auto pit = insts.begin(); pit != it; ++pit)
|
|
{
|
|
if (pit->GetOpcode() == Opcode::MulRR)
|
|
{
|
|
const auto &mops = pit->GetOperands();
|
|
if (mops.size() >= 3 &&
|
|
mops[0].GetKind() == Operand::Kind::Reg &&
|
|
mops[1].GetKind() == Operand::Kind::Reg &&
|
|
mops[2].GetKind() == Operand::Kind::Reg)
|
|
{
|
|
PhysReg mul_dst = mops[0].GetReg();
|
|
PhysReg mul_lhs = mops[1].GetReg();
|
|
PhysReg mul_rhs = mops[2].GetReg();
|
|
if (IsSamePhysReg(mul_dst, add_lhs) || IsSamePhysReg(mul_dst, add_rhs))
|
|
{
|
|
bool mul_dst_is_lhs = IsSamePhysReg(mul_dst, add_lhs);
|
|
PhysReg acc_reg = mul_dst_is_lhs ? add_rhs : add_lhs;
|
|
bool valid = true;
|
|
for (auto mid = std::next(pit); mid != it; ++mid)
|
|
{
|
|
if (InstDefinesReg(*mid, mul_dst) || InstDefinesReg(*mid, acc_reg))
|
|
{
|
|
valid = false;
|
|
break;
|
|
}
|
|
if (InstUsesReg(*mid, mul_dst))
|
|
{
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
if (valid)
|
|
{
|
|
for (auto after = std::next(it); after != insts.end(); ++after)
|
|
{
|
|
if (InstUsesReg(*after, mul_dst))
|
|
{
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (valid)
|
|
{
|
|
if (it->GetOpcode() == Opcode::AddRR)
|
|
{
|
|
*it = MachineInstr(Opcode::Madd,
|
|
{Operand::Reg(add_dst),
|
|
Operand::Reg(mul_lhs),
|
|
Operand::Reg(mul_rhs),
|
|
Operand::Reg(acc_reg)});
|
|
}
|
|
else
|
|
{
|
|
*it = MachineInstr(Opcode::Msub,
|
|
{Operand::Reg(add_dst),
|
|
Operand::Reg(mul_lhs),
|
|
Operand::Reg(mul_rhs),
|
|
Operand::Reg(acc_reg)});
|
|
}
|
|
it = insts.erase(pit);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (changed)
|
|
break;
|
|
}
|
|
if (changed)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!changed)
|
|
{
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (it->GetOpcode() == Opcode::MovImm)
|
|
{
|
|
const auto &ops = it->GetOperands();
|
|
if (ops.size() >= 1 &&
|
|
ops[0].GetKind() == Operand::Kind::Reg)
|
|
{
|
|
PhysReg dst = ops[0].GetReg();
|
|
bool dead = false;
|
|
for (auto fit = std::next(it); fit != insts.end(); ++fit)
|
|
{
|
|
if (InstUsesReg(*fit, dst))
|
|
{
|
|
break;
|
|
}
|
|
if (InstDefinesReg(*fit, dst))
|
|
{
|
|
dead = true;
|
|
break;
|
|
}
|
|
}
|
|
if (dead)
|
|
{
|
|
it = insts.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!changed)
|
|
{
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (it->GetOpcode() == Opcode::LoadStack)
|
|
{
|
|
const auto &l_ops = it->GetOperands();
|
|
if (l_ops.size() >= 2 &&
|
|
l_ops[0].GetKind() == Operand::Kind::Reg &&
|
|
l_ops[1].GetKind() == Operand::Kind::FrameIndex)
|
|
{
|
|
PhysReg ld = l_ops[0].GetReg();
|
|
int fi = l_ops[1].GetFrameIndex();
|
|
for (auto pit = insts.begin(); pit != it; ++pit)
|
|
{
|
|
if (pit->GetOpcode() == Opcode::StoreStack)
|
|
{
|
|
const auto &pops = pit->GetOperands();
|
|
if (pops.size() >= 2 &&
|
|
pops[0].GetKind() == Operand::Kind::Reg &&
|
|
pops[1].GetKind() == Operand::Kind::FrameIndex &&
|
|
pops[1].GetFrameIndex() == fi)
|
|
{
|
|
PhysReg rs = pops[0].GetReg();
|
|
bool valid = true;
|
|
for (auto mid = std::next(pit); mid != it; ++mid)
|
|
{
|
|
if (mid->GetOpcode() == Opcode::StoreStack)
|
|
{
|
|
const auto &mops = mid->GetOperands();
|
|
if (mops.size() >= 2 &&
|
|
mops[1].GetKind() == Operand::Kind::FrameIndex &&
|
|
mops[1].GetFrameIndex() == fi)
|
|
{
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
if (InstDefinesReg(*mid, rs))
|
|
{
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
if (valid && IsSameRegClass(ld, rs))
|
|
{
|
|
*it = MachineInstr(Opcode::MovReg, {Operand::Reg(ld), Operand::Reg(rs)});
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (changed)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!changed)
|
|
{
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (it->GetOpcode() == Opcode::MovReg)
|
|
{
|
|
const auto &ops = it->GetOperands();
|
|
if (ops.size() >= 2 &&
|
|
ops[0].GetKind() == Operand::Kind::Reg)
|
|
{
|
|
PhysReg dst = ops[0].GetReg();
|
|
bool dead = false;
|
|
for (auto fit = std::next(it); fit != insts.end(); ++fit)
|
|
{
|
|
if (InstUsesReg(*fit, dst))
|
|
{
|
|
break;
|
|
}
|
|
if (InstDefinesReg(*fit, dst))
|
|
{
|
|
dead = true;
|
|
break;
|
|
}
|
|
}
|
|
if (dead)
|
|
{
|
|
it = insts.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!changed)
|
|
{
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (it->GetOpcode() == Opcode::LoadStack)
|
|
{
|
|
const auto &l_ops = it->GetOperands();
|
|
if (l_ops.size() >= 2 &&
|
|
l_ops[0].GetKind() == Operand::Kind::Reg &&
|
|
l_ops[1].GetKind() == Operand::Kind::FrameIndex)
|
|
{
|
|
PhysReg rd = l_ops[0].GetReg();
|
|
int fi = l_ops[1].GetFrameIndex();
|
|
for (auto pit = insts.begin(); pit != it; ++pit)
|
|
{
|
|
if (pit->GetOpcode() == Opcode::LoadStack)
|
|
{
|
|
const auto &pops = pit->GetOperands();
|
|
if (pops.size() >= 2 &&
|
|
pops[0].GetKind() == Operand::Kind::Reg &&
|
|
IsSamePhysReg(pops[0].GetReg(), rd) &&
|
|
pops[1].GetKind() == Operand::Kind::FrameIndex &&
|
|
pops[1].GetFrameIndex() == fi)
|
|
{
|
|
bool valid = true;
|
|
for (auto mid = std::next(pit); mid != it; ++mid)
|
|
{
|
|
if (mid->GetOpcode() == Opcode::StoreStack)
|
|
{
|
|
const auto &mops = mid->GetOperands();
|
|
if (mops.size() >= 2 &&
|
|
mops[1].GetKind() == Operand::Kind::FrameIndex &&
|
|
mops[1].GetFrameIndex() == fi)
|
|
{
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
if (InstDefinesReg(*mid, rd))
|
|
{
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
if (valid)
|
|
{
|
|
it = insts.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (changed)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!changed)
|
|
{
|
|
for (auto it = insts.begin(); it != insts.end(); ++it)
|
|
{
|
|
if (it->GetOpcode() == Opcode::MovReg)
|
|
{
|
|
const auto &ops = it->GetOperands();
|
|
if (ops.size() >= 2 &&
|
|
ops[0].GetKind() == Operand::Kind::Reg &&
|
|
ops[1].GetKind() == Operand::Kind::Reg &&
|
|
IsSamePhysReg(ops[0].GetReg(), ops[1].GetReg()))
|
|
{
|
|
it = insts.erase(it);
|
|
changed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void RunPeephole(MachineFunction &function)
|
|
{
|
|
for (auto &block : function.GetBlocks())
|
|
{
|
|
if (block)
|
|
RunPeepholeOnBlock(*block);
|
|
}
|
|
}
|
|
|
|
void RunPeephole(MachineModule &module)
|
|
{
|
|
for (auto &function : module.GetFunctions())
|
|
{
|
|
if (function)
|
|
RunPeephole(*function);
|
|
}
|
|
}
|
|
|
|
} // namespace mir
|