基本快重排

zhm
zhm 2 days ago
parent a669efb7a5
commit 1d4c59d7ec

@ -408,6 +408,9 @@ namespace mir
void RunPeephole(MachineFunction &function);
void RunPeephole(MachineModule &module);
void RunBlockLayout(MachineFunction &function);
void RunBlockLayout(MachineModule &module);
void PrintAsm(const MachineFunction &function, std::ostream &os);
void PrintAsm(const MachineModule &module, std::ostream &os);

@ -0,0 +1,29 @@
#pragma once
#include <map>
#include <vector>
namespace mir
{
class MachineBasicBlock;
class MachineFunction;
struct CFGEdge
{
MachineBasicBlock *src = nullptr;
MachineBasicBlock *dst = nullptr;
double weight = 0.0;
};
struct CFGAnalysisResult
{
std::map<MachineBasicBlock *, std::vector<MachineBasicBlock *>> successors;
std::map<MachineBasicBlock *, std::vector<MachineBasicBlock *>> predecessors;
std::map<MachineBasicBlock *, double> block_freq;
std::vector<CFGEdge> edges;
};
CFGAnalysisResult AnalyzeCFG(MachineFunction &function);
} // namespace mir

@ -53,6 +53,7 @@ int main(int argc, char** argv) {
auto machine_module = mir::LowerModuleToMIR(*module);
mir::RunRegAlloc(*machine_module);
mir::RunFrameLowering(*machine_module);
mir::RunBlockLayout(*machine_module);
mir::RunPeephole(*machine_module);
std::ostringstream asm_ss;

@ -8,6 +8,7 @@ add_library(mir_core STATIC
RegAlloc.cpp
FrameLowering.cpp
AsmPrinter.cpp
analysis/CFGAnalysis.cpp
)
target_link_libraries(mir_core PUBLIC

@ -0,0 +1,177 @@
#include "mir/analysis/CFGAnalysis.h"
#include "mir/MIR.h"
namespace mir
{
namespace
{
MachineBasicBlock *FindBlockByLabel(MachineFunction &function,
int label_id)
{
if (label_id < 0)
return nullptr;
for (auto &block : function.GetBlocks())
{
if (block && block->GetLabelId() == label_id)
return block.get();
}
return nullptr;
}
void BuildSuccessors(MachineFunction &function,
CFGAnalysisResult &result)
{
for (auto &block : function.GetBlocks())
{
if (!block)
continue;
const auto &insts = block->GetInstructions();
if (insts.empty())
continue;
auto &succs = result.successors[block.get()];
for (const auto &inst : insts)
{
if (inst.GetOpcode() == Opcode::Br)
{
const auto &ops = inst.GetOperands();
if (!ops.empty() && ops[0].GetKind() == Operand::Kind::Label)
{
auto *target = FindBlockByLabel(function, ops[0].GetLabel());
if (target)
{
bool dup = false;
for (auto *s : succs)
if (s == target)
{
dup = true;
break;
}
if (!dup)
succs.push_back(target);
}
}
}
else if (inst.GetOpcode() == Opcode::CondBr)
{
const auto &ops = inst.GetOperands();
if (ops.size() >= 2 && ops[1].GetKind() == Operand::Kind::Label)
{
auto *target = FindBlockByLabel(function, ops[1].GetLabel());
if (target)
{
bool dup = false;
for (auto *s : succs)
if (s == target)
{
dup = true;
break;
}
if (!dup)
succs.push_back(target);
}
}
}
}
}
}
void BuildPredecessors(CFGAnalysisResult &result)
{
for (auto &kv : result.successors)
{
auto *src = kv.first;
for (auto *dst : kv.second)
{
result.predecessors[dst].push_back(src);
}
}
}
void BuildEdges(CFGAnalysisResult &result)
{
for (auto &kv : result.successors)
{
auto *src = kv.first;
for (auto *dst : kv.second)
{
CFGEdge edge;
edge.src = src;
edge.dst = dst;
result.edges.push_back(edge);
}
}
}
void EstimateBlockFrequencies(MachineFunction &function,
CFGAnalysisResult &result)
{
if (function.GetBlocks().empty())
return;
auto *entry = function.GetEntryPtr();
if (!entry)
return;
result.block_freq[entry] = 1.0;
for (auto &block : function.GetBlocks())
{
if (block && block.get() != entry)
result.block_freq[block.get()] = 0.0;
}
for (int iter = 0; iter < 20; ++iter)
{
for (auto &block : function.GetBlocks())
{
if (!block)
continue;
auto it = result.successors.find(block.get());
if (it == result.successors.end() || it->second.empty())
continue;
double freq = result.block_freq[block.get()];
if (freq <= 0.0)
continue;
double per_succ = freq / static_cast<double>(it->second.size());
for (auto *succ : it->second)
{
result.block_freq[succ] += per_succ;
}
}
}
}
void ComputeEdgeWeights(CFGAnalysisResult &result)
{
for (auto &edge : result.edges)
{
auto it = result.successors.find(edge.src);
if (it == result.successors.end() || it->second.empty())
continue;
double src_freq = 0.0;
auto fit = result.block_freq.find(edge.src);
if (fit != result.block_freq.end())
src_freq = fit->second;
edge.weight = src_freq / static_cast<double>(it->second.size());
}
}
} // namespace
CFGAnalysisResult AnalyzeCFG(MachineFunction &function)
{
CFGAnalysisResult result;
BuildSuccessors(function, result);
BuildPredecessors(result);
BuildEdges(result);
EstimateBlockFrequencies(function, result);
ComputeEdgeWeights(result);
return result;
}
} // namespace mir

@ -0,0 +1,370 @@
#include "mir/MIR.h"
#include "mir/analysis/CFGAnalysis.h"
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>
namespace mir
{
namespace
{
static CondCode NegateCondCode(CondCode cond)
{
switch (cond)
{
case CondCode::EQ:
return CondCode::NE;
case CondCode::NE:
return CondCode::EQ;
case CondCode::LT:
return CondCode::GE;
case CondCode::LE:
return CondCode::GT;
case CondCode::GT:
return CondCode::LE;
case CondCode::GE:
return CondCode::LT;
default:
return CondCode::NE;
}
}
static bool IsDebugEnabled()
{
return std::getenv("UPDATE_COMPILER_BLOCK_LAYOUT_DEBUG") != nullptr;
}
static std::string GetDebugFilter()
{
const char *filter = std::getenv("UPDATE_COMPILER_BLOCK_LAYOUT_DEBUG_FILTER");
return filter ? filter : "";
}
struct Chain
{
std::vector<MachineBasicBlock *> blocks;
double total_weight = 0.0;
};
struct EdgeInfo
{
MachineBasicBlock *src = nullptr;
MachineBasicBlock *dst = nullptr;
double weight = 0.0;
};
static std::vector<MachineBasicBlock *> GetOriginalOrder(
MachineFunction &function)
{
std::vector<MachineBasicBlock *> order;
for (auto &block : function.GetBlocks())
{
if (block)
order.push_back(block.get());
}
return order;
}
static double ComputeLayoutScore(const std::vector<MachineBasicBlock *> &order,
const CFGAnalysisResult &cfg)
{
double score = 0.0;
std::map<MachineBasicBlock *, int> position;
for (int i = 0; i < static_cast<int>(order.size()); ++i)
position[order[i]] = i;
for (const auto &edge : cfg.edges)
{
auto src_it = position.find(edge.src);
auto dst_it = position.find(edge.dst);
if (src_it == position.end() || dst_it == position.end())
continue;
if (src_it->second + 1 == dst_it->second)
score += edge.weight;
}
return score;
}
static std::vector<EdgeInfo> CollectEdges(const CFGAnalysisResult &cfg)
{
std::vector<EdgeInfo> edges;
for (const auto &edge : cfg.edges)
{
if (edge.src == edge.dst)
continue;
EdgeInfo ei;
ei.src = edge.src;
ei.dst = edge.dst;
ei.weight = edge.weight;
edges.push_back(ei);
}
std::sort(edges.begin(), edges.end(),
[](const EdgeInfo &a, const EdgeInfo &b)
{
return a.weight > b.weight;
});
return edges;
}
static std::vector<MachineBasicBlock *> PettisHansenLayout(
MachineFunction &function,
const CFGAnalysisResult &cfg)
{
auto &blocks = function.GetBlocks();
if (blocks.size() <= 2)
return GetOriginalOrder(function);
std::map<MachineBasicBlock *, Chain *> block_to_chain;
std::vector<std::unique_ptr<Chain>> chains;
for (auto &block : blocks)
{
if (!block)
continue;
auto chain = std::make_unique<Chain>();
chain->blocks.push_back(block.get());
block_to_chain[block.get()] = chain.get();
chains.push_back(std::move(chain));
}
auto edges = CollectEdges(cfg);
for (const auto &edge : edges)
{
auto *src_chain = block_to_chain[edge.src];
auto *dst_chain = block_to_chain[edge.dst];
if (!src_chain || !dst_chain)
continue;
if (src_chain == dst_chain)
continue;
bool src_is_tail = (edge.src == src_chain->blocks.back());
bool dst_is_head = (edge.dst == dst_chain->blocks.front());
if (src_is_tail && dst_is_head)
{
for (auto *b : dst_chain->blocks)
{
src_chain->blocks.push_back(b);
block_to_chain[b] = src_chain;
}
src_chain->total_weight += edge.weight;
dst_chain->blocks.clear();
dst_chain->total_weight = 0.0;
}
}
std::vector<MachineBasicBlock *> result;
std::set<Chain *> emitted;
MachineBasicBlock *entry = function.GetEntryPtr();
if (entry)
{
auto *entry_chain = block_to_chain[entry];
if (entry_chain && !entry_chain->blocks.empty())
{
for (auto *b : entry_chain->blocks)
result.push_back(b);
emitted.insert(entry_chain);
}
}
for (auto &chain : chains)
{
if (!chain || chain->blocks.empty())
continue;
if (emitted.count(chain.get()))
continue;
for (auto *b : chain->blocks)
result.push_back(b);
emitted.insert(chain.get());
}
return result;
}
static void ApplyLayout(MachineFunction &function,
const std::vector<MachineBasicBlock *> &new_order)
{
auto &blocks = function.GetBlocks();
std::map<MachineBasicBlock *, std::unique_ptr<MachineBasicBlock>> block_map;
for (auto &block : blocks)
{
if (block)
block_map[block.get()] = std::move(block);
}
blocks.clear();
for (auto *block : new_order)
{
auto it = block_map.find(block);
if (it != block_map.end())
{
blocks.push_back(std::move(it->second));
block_map.erase(it);
}
}
for (auto &kv : block_map)
{
blocks.push_back(std::move(kv.second));
}
}
static MachineBasicBlock *GetFallThroughTarget(
const MachineFunction &function,
MachineBasicBlock *block)
{
const auto &blocks = function.GetBlocks();
for (size_t i = 0; i + 1 < blocks.size(); ++i)
{
if (blocks[i].get() == block)
return blocks[i + 1].get();
}
return nullptr;
}
static void FixFallThrough(MachineFunction &function)
{
for (auto &block : function.GetBlocks())
{
if (!block)
continue;
auto &insts = block->GetInstructions();
MachineBasicBlock *fallthrough = GetFallThroughTarget(function, block.get());
for (auto it = insts.begin(); it != insts.end();)
{
if (it->GetOpcode() == Opcode::Br)
{
const auto &ops = it->GetOperands();
if (!ops.empty() && ops[0].GetKind() == Operand::Kind::Label)
{
int target_label = ops[0].GetLabel();
if (fallthrough && fallthrough->GetLabelId() == target_label)
{
it = insts.erase(it);
continue;
}
}
}
++it;
}
auto rit = insts.rbegin();
if (rit != insts.rend() && rit->GetOpcode() == Opcode::CondBr)
{
auto next_rit = std::next(rit);
if (next_rit != insts.rend() && next_rit->GetOpcode() == Opcode::Br)
{
const auto &cond_ops = rit->GetOperands();
const auto &br_ops = next_rit->GetOperands();
if (cond_ops.size() >= 2 && br_ops.size() >= 1 &&
cond_ops[1].GetKind() == Operand::Kind::Label &&
br_ops[0].GetKind() == Operand::Kind::Label)
{
int cond_target = cond_ops[1].GetLabel();
int br_target = br_ops[0].GetLabel();
if (fallthrough)
{
int ft_label = fallthrough->GetLabelId();
if (ft_label == br_target)
{
// CondBr already falls through to Br target on false, nothing to do
}
else if (ft_label == cond_target)
{
CondCode orig_cond = static_cast<CondCode>(cond_ops[0].GetImm());
CondCode new_cond = NegateCondCode(orig_cond);
auto new_condbr = MachineInstr(
Opcode::CondBr,
{Operand::Imm(static_cast<int>(new_cond)),
Operand::Label(br_target)});
*rit = std::move(new_condbr);
auto br_it = std::prev(insts.end());
insts.erase(br_it);
}
}
}
}
}
}
}
static void RunBlockLayoutOnFunction(MachineFunction &function)
{
auto &blocks = function.GetBlocks();
if (blocks.size() <= 1)
return;
bool debug = IsDebugEnabled();
std::string filter = GetDebugFilter();
bool should_log = debug;
if (!filter.empty() && function.GetName().find(filter) == std::string::npos)
should_log = false;
CFGAnalysisResult cfg = AnalyzeCFG(function);
auto original_order = GetOriginalOrder(function);
double original_score = ComputeLayoutScore(original_order, cfg);
auto new_order = PettisHansenLayout(function, cfg);
double new_score = ComputeLayoutScore(new_order, cfg);
static constexpr double kBenefitThreshold = 0.01;
bool should_apply = (new_score > original_score + kBenefitThreshold);
if (should_log)
{
std::cerr << "[BlockLayout] " << function.GetName()
<< ": original_score=" << original_score
<< " candidate_score=" << new_score
<< " apply=" << (should_apply ? "yes" : "no") << "\n";
}
if (!should_apply)
return;
ApplyLayout(function, new_order);
FixFallThrough(function);
if (should_log)
{
auto final_order = GetOriginalOrder(function);
double final_score = ComputeLayoutScore(final_order, cfg);
std::cerr << "[BlockLayout] " << function.GetName()
<< ": final_score=" << final_score << "\n";
}
}
} // namespace
void RunBlockLayout(MachineFunction &function)
{
RunBlockLayoutOnFunction(function);
}
void RunBlockLayout(MachineModule &module)
{
for (auto &function : module.GetFunctions())
{
if (function)
RunBlockLayout(*function);
}
}
} // namespace mir

@ -1,6 +1,7 @@
add_library(mir_passes STATIC
PassManager.cpp
Peephole.cpp
BlockLayoutOpt.cpp
)
target_link_libraries(mir_passes PUBLIC

Loading…
Cancel
Save