Optimize function code structure in runtime_core

Signed-off-by: ah <liangahui@h-partners.com>
This commit is contained in:
ah 2024-05-25 12:56:11 +08:00
parent b5d0c45d2d
commit acfa8d38c6
4 changed files with 254 additions and 186 deletions

View File

@ -28,6 +28,36 @@ constexpr size_t BIN_BASE = 2;
constexpr size_t MAX_DWORD = 65536;
inline bool IsHexNumber(const std::string_view &token)
{
for (auto i : token) {
if (!((i >= '0' && i <= '9') || (i >= 'A' && i <= 'F') || (i >= 'a' && i <= 'f'))) {
return false;
}
}
return true;
}
inline bool IsBinaryNumber(const std::string_view &token)
{
for (auto i : token) {
if (!(i == '0' || i == '1')) {
return false;
}
}
return true;
}
inline bool IsOctalNumber(const std::string_view &token)
{
for (auto i : token) {
if (!(i >= '0' && i <= '7')) {
return false;
}
}
return true;
}
inline bool ValidateInteger(const std::string_view &p)
{
constexpr size_t GENERAL_SHIFT = 2;
@ -45,40 +75,17 @@ inline bool ValidateInteger(const std::string_view &p)
if (token[0] == '0' && token.size() > 1 && token.find('.') == std::string::npos) {
if (token[1] == 'x') {
token.remove_prefix(GENERAL_SHIFT);
for (auto i : token) {
if (!((i >= '0' && i <= '9') || (i >= 'A' && i <= 'F') || (i >= 'a' && i <= 'f'))) {
return false;
}
}
return true;
return IsHexNumber(token);
}
if (token[1] == 'b') {
token.remove_prefix(GENERAL_SHIFT);
if (token.empty()) {
return false;
}
for (auto i : token) {
if (!(i == '0' || i == '1')) {
return false;
}
}
return true;
return (!token.empty() && IsBinaryNumber(token));
}
if (token[1] >= '0' && token[1] <= '9' && token.find('e') == std::string::npos) {
token.remove_prefix(1);
for (auto i : token) {
if (!(i >= '0' && i <= '7')) {
return false;
}
}
return true;
return IsOctalNumber(token);
}
}

View File

@ -185,18 +185,8 @@ void RegAccAlloc::SetNeedLda(compiler::Inst *inst, bool need)
inst->SetSrcReg(AccReadIndex(inst), reg);
}
/**
* Determine the accumulator usage between instructions.
* Eliminate unnecessary register allocations by applying
* a special value (ACC_REG_ID) to the destination and
* source registers.
* This special value is a marker for the code generator
* not to produce lda/sta instructions.
*/
bool RegAccAlloc::RunImpl()
void RegAccAlloc::InitializeSourceRegisters()
{
GetGraph()->InitDefaultLocations();
// Initialize all source register of all instructions.
for (auto block : GetGraph()->GetBlocksRPO()) {
for (auto inst : block->Insts()) {
if (inst->IsSaveState() || inst->IsCatchPhi()) {
@ -207,14 +197,16 @@ bool RegAccAlloc::RunImpl()
}
for (size_t i = 0; i < inst->GetInputsCount(); ++i) {
inst->SetSrcReg(i, compiler::INVALID_REG);
}
if (inst->IsConst()) {
inst->SetDstReg(compiler::INVALID_REG);
}
}
}
}
}
// Mark Phi instructions if they can be optimized for acc.
void RegAccAlloc::MarkAccForPhiInstructions()
{
for (auto block : GetGraph()->GetBlocksRPO()) {
for (auto phi : block->PhiInsts()) {
if (IsPhiAccReady(phi)) {
@ -222,9 +214,10 @@ bool RegAccAlloc::RunImpl()
}
}
}
}
// Mark instructions if they can be optimized for acc.
for (auto block : GetGraph()->GetBlocksRPO()) {
void RegAccAlloc::MarkAccForInstructions(compiler::BasicBlock *block)
{
for (auto inst : block->AllInsts()) {
if (inst->NoDest() || !IsAccWrite(inst)) {
continue;
@ -246,18 +239,29 @@ bool RegAccAlloc::RunImpl()
if (use_acc_dst_reg) {
inst->SetDstReg(compiler::ACC_REG_ID);
} else if (inst->IsConst()) {
continue;
}
if (!inst->IsConst()) {
continue;
}
inst->ClearFlag(compiler::inst_flags::ACC_WRITE);
for (auto &user : inst->GetUsers()) {
compiler::Inst *uinst = user.GetInst();
if (uinst->IsSaveState()) {
continue;
}
SetNeedLda(uinst, true);
}
}
}
}
void RegAccAlloc::UpdateInstructionsAfterMark(compiler::BasicBlock *block)
{
for (auto inst : block->Insts()) {
if (inst->GetInputsCount() == 0) {
continue;
@ -268,8 +272,10 @@ bool RegAccAlloc::RunImpl()
}
compiler::Inst *input = inst->GetInput(AccReadIndex(inst)).GetInst();
if (!IsAccWriteBetween(input, inst)) {
continue;
}
if (IsAccWriteBetween(input, inst)) {
input->SetDstReg(compiler::INVALID_REG);
SetNeedLda(inst, true);
@ -281,7 +287,27 @@ bool RegAccAlloc::RunImpl()
}
}
}
}
}
/**
* Determine the accumulator usage between instructions.
* Eliminate unnecessary register allocations by applying
* a special value (ACC_REG_ID) to the destination and
* source registers.
* This special value is a marker for the code generator
* not to produce lda/sta instructions.
*/
bool RegAccAlloc::RunImpl()
{
GetGraph()->InitDefaultLocations();
// Initialize all source register of all instructions.
InitializeSourceRegisters();
// Mark Phi instructions if they can be optimized for acc.
MarkAccForPhiInstructions();
// Mark instructions if they can be optimized for acc.
for (auto block : GetGraph()->GetBlocksRPO()) {
MarkAccForInstructions(block);
UpdateInstructionsAfterMark(block);
}
#ifndef NDEBUG

View File

@ -51,6 +51,11 @@ private:
bool IsPhiAccReady(compiler::Inst *phi) const;
void SetNeedLda(compiler::Inst *inst, bool need);
void InitializeSourceRegisters();
void MarkAccForPhiInstructions();
void MarkAccForInstructions(compiler::BasicBlock *block);
void UpdateInstructionsAfterMark(compiler::BasicBlock *block);
compiler::Marker acc_marker_ {0};
};

View File

@ -85,35 +85,13 @@ public:
inst_compare_map_.erase(inst1);
return false;
}
if (inst1->GetOpcode() != Opcode::Phi) {
auto inst1_begin = inst1->GetInputs().begin();
auto inst1_end = inst1->GetInputs().end();
auto inst2_begin = inst2->GetInputs().begin();
auto eq_lambda = [this](Input input1, Input input2) { return Compare(input1.GetInst(), input2.GetInst()); };
if (!std::equal(inst1_begin, inst1_end, inst2_begin, eq_lambda)) {
bool result = (inst1->GetOpcode() != Opcode::Phi) ?
CompareNonPhiInputs(inst1, inst2) : ComparePhiInputs(inst1, inst2);
if (!result) {
inst_compare_map_.erase(inst1);
return false;
}
} else {
if (inst1->GetInputsCount() != inst2->GetInputsCount()) {
inst_compare_map_.erase(inst1);
return false;
}
for (size_t index1 = 0; index1 < inst1->GetInputsCount(); index1++) {
auto input1 = inst1->GetInput(index1).GetInst();
auto bb1 = inst1->CastToPhi()->GetPhiInputBb(index1);
if (bb_map_.count(bb1) == 0) {
inst_compare_map_.erase(inst1);
return false;
}
auto bb2 = bb_map_.at(bb1);
auto input2 = inst2->CastToPhi()->GetPhiInput(bb2);
if (!Compare(input1, input2)) {
inst_compare_map_.erase(inst1);
return false;
}
}
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage
#define CAST(Opc) CastTo##Opc()
@ -218,7 +196,68 @@ public:
// CHECK(LoadType, GetTypeId)
#undef CHECK
#undef CAST
if (inst1->GetOpcode() == Opcode::Constant) {
if (!CompareConstantInst(inst1, inst2)) {
inst_compare_map_.erase(inst1);
return false;
}
}
if (inst1->GetOpcode() == Opcode::Cmp && IsFloatType(inst1->GetInput(0).GetInst()->GetType())) {
auto cmp1 = static_cast<CmpInst *>(inst1);
auto cmp2 = static_cast<CmpInst *>(inst2);
if (cmp1->IsFcmpg() != cmp2->IsFcmpg()) {
inst_compare_map_.erase(inst1);
return false;
}
}
if (!CompareInputTypes(inst1, inst2) || !CompareSaveStateInst(inst1, inst2)) {
inst_compare_map_.erase(inst1);
return false;
}
return true;
}
private:
std::unordered_map<Inst *, Inst *> inst_compare_map_;
std::unordered_map<BasicBlock *, BasicBlock *> bb_map_;
bool CompareNonPhiInputs(Inst *inst1, Inst *inst2)
{
auto inst1_begin = inst1->GetInputs().begin();
auto inst1_end = inst1->GetInputs().end();
auto inst2_begin = inst2->GetInputs().begin();
auto eq_lambda = [this](Input input1, Input input2) {
return Compare(input1.GetInst(), input2.GetInst());
};
return std::equal(inst1_begin, inst1_end, inst2_begin, eq_lambda);
}
bool ComparePhiInputs(Inst *inst1, Inst *inst2)
{
if (inst1->GetInputsCount() != inst2->GetInputsCount()) {
return false;
}
for (size_t index1 = 0; index1 < inst1->GetInputsCount(); index1++) {
auto input1 = inst1->GetInput(index1).GetInst();
auto bb1 = inst1->CastToPhi()->GetPhiInputBb(index1);
if (bb_map_.count(bb1) == 0) {
return false;
}
auto bb2 = bb_map_.at(bb1);
auto input2 = inst2->CastToPhi()->GetPhiInput(bb2);
if (!Compare(input1, input2)) {
return false;
}
}
return true;
}
bool CompareConstantInst(Inst *inst1, Inst *inst2)
{
auto c1 = inst1->CastToConstant();
auto c2 = inst2->CastToConstant();
bool same = false;
@ -231,30 +270,28 @@ public:
same = c1->GetRawValue() == c2->GetRawValue();
break;
}
if (!same) {
inst_compare_map_.erase(inst1);
return false;
}
}
if (inst1->GetOpcode() == Opcode::Cmp && IsFloatType(inst1->GetInput(0).GetInst()->GetType())) {
auto cmp1 = static_cast<CmpInst *>(inst1);
auto cmp2 = static_cast<CmpInst *>(inst2);
if (cmp1->IsFcmpg() != cmp2->IsFcmpg()) {
inst_compare_map_.erase(inst1);
return false;
}
return same;
}
bool CompareInputTypes(Inst *inst1, Inst *inst2)
{
for (size_t i = 0; i < inst2->GetInputsCount(); i++) {
if (inst1->GetInputType(i) != inst2->GetInputType(i)) {
inst_compare_map_.erase(inst1);
return false;
}
}
if (inst1->IsSaveState()) {
return true;
}
bool CompareSaveStateInst(Inst *inst1, Inst *inst2)
{
if (!inst1->IsSaveState()) {
return true;
}
auto *sv_st1 = static_cast<SaveStateInst *>(inst1);
auto *sv_st2 = static_cast<SaveStateInst *>(inst2);
if (sv_st1->GetImmediatesCount() != sv_st2->GetImmediatesCount()) {
inst_compare_map_.erase(inst1);
return false;
}
@ -269,7 +306,6 @@ public:
std::sort(regs1.begin(), regs1.end());
std::sort(regs2.begin(), regs2.end());
if (regs1 != regs2) {
inst_compare_map_.erase(inst1);
return false;
}
if (sv_st1->GetImmediatesCount() != 0) {
@ -278,17 +314,11 @@ public:
};
if (!std::equal(sv_st1->GetImmediates()->begin(), sv_st1->GetImmediates()->end(),
sv_st2->GetImmediates()->begin(), eq_lambda)) {
inst_compare_map_.erase(inst1);
return false;
}
}
}
return true;
}
private:
std::unordered_map<Inst *, Inst *> inst_compare_map_;
std::unordered_map<BasicBlock *, BasicBlock *> bb_map_;
};
} // namespace panda::compiler