[midend-LICM]将能够外提的循环不变量进行Kanh拓扑排序保证外提后的计算顺序正确。

This commit is contained in:
rain2133
2025-08-12 16:18:00 +08:00
parent f634273852
commit baef82677b

View File

@@ -12,33 +12,62 @@ bool LICMContext::run() { return hoistInstructions(); }
bool LICMContext::hoistInstructions() {
bool changed = false;
BasicBlock *preheader = loop->getPreHeader();
if (!preheader || !chars){
if(DEBUG) {
std::cerr << "LICM: No preheader or loop characteristics found, skipping hoisting." << std::endl;
if (!preheader || !chars)
return false;
// 1. 先收集所有可外提指令
std::unordered_set<Instruction *> workSet(chars->invariantInsts.begin(), chars->invariantInsts.end());
// 2. 计算每个指令被依赖的次数(入度)
std::unordered_map<Instruction *, int> indegree;
for (auto *inst : workSet) {
indegree[inst] = 0;
}
for (auto *inst : workSet) {
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
if (workSet.count(dep)) {
indegree[inst]++;
}
}
}
}
// 3. Kahn拓扑排序
std::vector<Instruction *> sorted;
std::queue<Instruction *> q;
for (auto &[inst, deg] : indegree) {
if (deg == 0)
q.push(inst);
}
while (!q.empty()) {
auto *inst = q.front();
q.pop();
sorted.push_back(inst);
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
if (workSet.count(dep)) {
indegree[dep]--;
if (indegree[dep] == 0)
q.push(dep);
}
}
}
}
// 检查是否全部排序,若未全部排序,说明有环(理论上不会)
if (sorted.size() != workSet.size()) {
if (DEBUG)
std::cerr << "LICM: Topological sort failed, possible dependency cycle." << std::endl;
return false;
}
for (auto *inst : chars->invariantInsts) {
if (!inst) {
if(DEBUG) {
std::cerr << "LICM: Invalid instruction found, skipping." << std::endl;
}
continue; // 跳过无效指令
}
else{
if(DEBUG) {
std::cout << "LICM: Processing instruction " << inst->getName() << " for hoisting." << std::endl;
}
}
// 4. 按拓扑序外提
for (auto *inst : sorted) {
if (!inst)
continue;
BasicBlock *parent = inst->getParent();
// 只外提当前还在循环体内的指令
if (parent && loop->contains(parent)) {
// 获取源和槽的迭代器并移动指令到前置块
if(DEBUG) {
std::cout << "LICM: Hoisting instruction " << inst->getName() << " from "
<< parent->getName() << " to preheader " << preheader->getName() << std::endl;
}
auto sourcePos = parent->findInstIterator(inst);
auto targetPos = preheader->terminator();
parent->moveInst(sourcePos, targetPos, preheader);
@@ -47,7 +76,6 @@ bool LICMContext::hoistInstructions() {
}
return changed;
}
// ---- LICM Pass Implementation ----
bool LICM::runOnFunction(Function *F, AnalysisManager &AM) {
@@ -60,7 +88,7 @@ bool LICM::runOnFunction(Function *F, AnalysisManager &AM) {
// 对每个函数内的所有循环做处理
for (const auto &loop_ptr : loopAnalysis->getAllLoops()) {
Loop *loop = loop_ptr.get();
if(DEBUG){
if (DEBUG) {
std::cout << "LICM: Processing loop in function " << F->getName() << ": " << loop->getName() << std::endl;
}
const LoopCharacteristics *chars = loopCharsResult->getCharacteristics(loop);