[midend-Loop-InductionVarStrengthReduction]增加循环规约变量强度削弱优化
This commit is contained in:
535
src/midend/Pass/Optimize/LoopStrengthReduction.cpp
Normal file
535
src/midend/Pass/Optimize/LoopStrengthReduction.cpp
Normal file
@@ -0,0 +1,535 @@
|
||||
#include "LoopStrengthReduction.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include "IRBuilder.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
// 使用全局调试开关
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义 Pass 的唯一 ID
|
||||
void *LoopStrengthReduction::ID = (void *)&LoopStrengthReduction::ID;
|
||||
|
||||
bool LoopStrengthReduction::runOnFunction(Function* F, AnalysisManager& AM) {
|
||||
if (F->getBasicBlocks().empty()) {
|
||||
return false; // 空函数
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Running LoopStrengthReduction on function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 创建优化上下文并运行
|
||||
StrengthReductionContext context(builder);
|
||||
bool modified = context.run(F, AM);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "LoopStrengthReduction " << (modified ? "modified" : "did not modify")
|
||||
<< " function: " << F->getName() << std::endl;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
void LoopStrengthReduction::getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const {
|
||||
// 依赖的分析
|
||||
analysisDependencies.insert(&LoopAnalysisPass::ID);
|
||||
analysisDependencies.insert(&LoopCharacteristicsPass::ID);
|
||||
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
|
||||
|
||||
// 会使失效的分析(强度削弱会修改IR结构)
|
||||
analysisInvalidations.insert(&LoopCharacteristicsPass::ID);
|
||||
// 注意:支配树分析通常不会因为强度削弱而失效,因为我们不改变控制流
|
||||
}
|
||||
|
||||
// ========== StrengthReductionContext 实现 ==========
|
||||
|
||||
bool StrengthReductionContext::run(Function* F, AnalysisManager& AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Starting strength reduction analysis..." << std::endl;
|
||||
}
|
||||
|
||||
// 获取必要的分析结果
|
||||
loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
|
||||
if (!loopAnalysis || !loopAnalysis->hasLoops()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No loops found, skipping strength reduction" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
loopCharacteristics = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
|
||||
if (!loopCharacteristics) {
|
||||
if (DEBUG) {
|
||||
std::cout << " LoopCharacteristics analysis not available" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
dominatorTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
|
||||
if (!dominatorTree) {
|
||||
if (DEBUG) {
|
||||
std::cout << " DominatorTree analysis not available" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 执行三个阶段的优化
|
||||
|
||||
// 阶段1:识别候选项
|
||||
identifyStrengthReductionCandidates(F);
|
||||
|
||||
if (candidates.empty()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No strength reduction candidates found" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Found " << candidates.size() << " potential candidates" << std::endl;
|
||||
}
|
||||
|
||||
// 阶段2:分析优化潜力
|
||||
analyzeOptimizationPotential();
|
||||
|
||||
// 阶段3:执行优化
|
||||
bool modified = performStrengthReduction();
|
||||
|
||||
if (DEBUG) {
|
||||
printDebugInfo();
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
void StrengthReductionContext::identifyStrengthReductionCandidates(Function* F) {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 1: Identifying Strength Reduction Candidates ===" << std::endl;
|
||||
}
|
||||
|
||||
// 遍历所有循环
|
||||
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
|
||||
Loop* loop = loop_ptr.get();
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Analyzing loop: " << loop->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 获取循环特征
|
||||
const LoopCharacteristics* characteristics = loopCharacteristics->getCharacteristics(loop);
|
||||
if (!characteristics) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No characteristics available for loop" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (characteristics->InductionVars.empty()) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No induction variables found in loop" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 遍历循环中的所有指令
|
||||
for (BasicBlock* bb : loop->getBlocks()) {
|
||||
for (auto& inst_ptr : bb->getInstructions()) {
|
||||
Instruction* inst = inst_ptr.get();
|
||||
|
||||
// 检查是否为强度削弱候选项
|
||||
auto candidate = isStrengthReductionCandidate(inst, loop);
|
||||
if (candidate) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Found candidate: %" << inst->getName()
|
||||
<< " (IV: %" << candidate->inductionVar->getName()
|
||||
<< ", multiplier: " << candidate->multiplier
|
||||
<< ", offset: " << candidate->offset << ")" << std::endl;
|
||||
}
|
||||
|
||||
// 添加到候选项列表
|
||||
loopToCandidates[loop].push_back(candidate.get());
|
||||
candidates.push_back(std::move(candidate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " === End Phase 1: Found " << candidates.size() << " candidates ===" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<StrengthReductionCandidate>
|
||||
StrengthReductionContext::isStrengthReductionCandidate(Instruction* inst, Loop* loop) {
|
||||
// 只考虑乘法指令
|
||||
if (inst->getKind() != Instruction::Kind::kMul) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* mulInst = dynamic_cast<BinaryInst*>(inst);
|
||||
if (!mulInst) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value* op0 = mulInst->getOperand(0);
|
||||
Value* op1 = mulInst->getOperand(1);
|
||||
|
||||
// 检查模式:归纳变量 * 常数 或 常数 * 归纳变量
|
||||
Value* inductionVar = nullptr;
|
||||
int multiplier = 0;
|
||||
|
||||
// 获取循环特征信息
|
||||
const LoopCharacteristics* characteristics = loopCharacteristics->getCharacteristics(loop);
|
||||
if (!characteristics) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 模式1: IV * const
|
||||
const InductionVarInfo* ivInfo = getInductionVarInfo(op0, loop, characteristics);
|
||||
if (ivInfo && dynamic_cast<ConstantInteger*>(op1)) {
|
||||
inductionVar = op0;
|
||||
multiplier = dynamic_cast<ConstantInteger*>(op1)->getInt();
|
||||
}
|
||||
// 模式2: const * IV
|
||||
else {
|
||||
ivInfo = getInductionVarInfo(op1, loop, characteristics);
|
||||
if (ivInfo && dynamic_cast<ConstantInteger*>(op0)) {
|
||||
inductionVar = op1;
|
||||
multiplier = dynamic_cast<ConstantInteger*>(op0)->getInt();
|
||||
}
|
||||
}
|
||||
|
||||
if (!inductionVar || multiplier <= 1) {
|
||||
return nullptr; // 不是有效的候选项
|
||||
}
|
||||
|
||||
// 创建候选项
|
||||
return std::make_unique<StrengthReductionCandidate>(
|
||||
inst, inductionVar, multiplier, 0, inst->getParent(), loop
|
||||
);
|
||||
}
|
||||
|
||||
const InductionVarInfo*
|
||||
StrengthReductionContext::getInductionVarInfo(Value* val, Loop* loop,
|
||||
const LoopCharacteristics* characteristics) {
|
||||
for (const auto& iv : characteristics->InductionVars) {
|
||||
if (iv->div == val) {
|
||||
return iv.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void StrengthReductionContext::analyzeOptimizationPotential() {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 2: Analyzing Optimization Potential ===" << std::endl;
|
||||
}
|
||||
|
||||
// 为每个候选项计算优化收益,并过滤不值得优化的
|
||||
auto it = candidates.begin();
|
||||
while (it != candidates.end()) {
|
||||
StrengthReductionCandidate* candidate = it->get();
|
||||
|
||||
double benefit = estimateOptimizationBenefit(candidate);
|
||||
bool isLegal = isOptimizationLegal(candidate);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Candidate " << candidate->originalInst->getName()
|
||||
<< ": benefit=" << benefit
|
||||
<< ", legal=" << (isLegal ? "yes" : "no") << std::endl;
|
||||
}
|
||||
|
||||
// 如果收益太小或不合法,移除候选项
|
||||
if (benefit < 1.0 || !isLegal) {
|
||||
// 从 loopToCandidates 中移除
|
||||
auto& loopCandidates = loopToCandidates[candidate->containingLoop];
|
||||
loopCandidates.erase(
|
||||
std::remove(loopCandidates.begin(), loopCandidates.end(), candidate),
|
||||
loopCandidates.end()
|
||||
);
|
||||
|
||||
it = candidates.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " === End Phase 2: " << candidates.size() << " candidates remain ===" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
double StrengthReductionContext::estimateOptimizationBenefit(const StrengthReductionCandidate* candidate) {
|
||||
// 简单的收益估算模型
|
||||
double benefit = 0.0;
|
||||
|
||||
// 基础收益:乘法变加法的性能提升
|
||||
benefit += 2.0; // 假设乘法比加法慢2倍
|
||||
|
||||
// 乘数因子:乘数越大,收益越高
|
||||
if (candidate->multiplier >= 4) {
|
||||
benefit += 1.0;
|
||||
}
|
||||
if (candidate->multiplier >= 8) {
|
||||
benefit += 1.0;
|
||||
}
|
||||
|
||||
// 循环热度因子
|
||||
Loop* loop = candidate->containingLoop;
|
||||
double hotness = loop->getLoopHotness();
|
||||
benefit *= (1.0 + hotness / 100.0);
|
||||
|
||||
// 使用次数因子
|
||||
size_t useCount = candidate->originalInst->getUses().size();
|
||||
if (useCount > 1) {
|
||||
benefit *= (1.0 + useCount * 0.2);
|
||||
}
|
||||
|
||||
return benefit;
|
||||
}
|
||||
|
||||
bool StrengthReductionContext::isOptimizationLegal(const StrengthReductionCandidate* candidate) {
|
||||
// 检查优化的合法性
|
||||
|
||||
// 1. 确保归纳变量在循环头有 phi 指令
|
||||
auto* phiInst = dynamic_cast<PhiInst*>(candidate->inductionVar);
|
||||
if (!phiInst || phiInst->getParent() != candidate->containingLoop->getHeader()) {
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Illegal: induction variable is not a phi in loop header" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 确保乘法指令在循环内
|
||||
if (!candidate->containingLoop->contains(candidate->containingBlock)) {
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Illegal: instruction not in loop" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 检查是否有溢出风险(简化检查)
|
||||
if (candidate->multiplier > 1000) {
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Illegal: multiplier too large (overflow risk)" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 确保该指令不在循环的退出条件中(避免影响循环语义)
|
||||
for (BasicBlock* exitingBB : candidate->containingLoop->getExitingBlocks()) {
|
||||
auto terminatorIt = exitingBB->terminator();
|
||||
if (terminatorIt != exitingBB->end()) {
|
||||
Instruction* terminator = terminatorIt->get();
|
||||
if (terminator && (terminator->getOperand(0) == candidate->originalInst ||
|
||||
(terminator->getNumOperands() > 1 && terminator->getOperand(1) == candidate->originalInst))) {
|
||||
if (DEBUG >= 2) {
|
||||
std::cout << " Illegal: instruction used in loop exit condition" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StrengthReductionContext::performStrengthReduction() {
|
||||
if (DEBUG) {
|
||||
std::cout << " === Phase 3: Performing Strength Reduction ===" << std::endl;
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
|
||||
for (auto& candidate : candidates) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing candidate: " << candidate->originalInst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 创建新的归纳变量
|
||||
if (!createNewInductionVariable(candidate.get())) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Failed to create new induction variable" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 替换原始指令
|
||||
if (!replaceOriginalInstruction(candidate.get())) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Failed to replace original instruction" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Successfully optimized: " << candidate->originalInst->getName()
|
||||
<< " -> " << candidate->newInductionVar->getName() << std::endl;
|
||||
}
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " === End Phase 3: " << (modified ? "Optimizations applied" : "No optimizations") << " ===" << std::endl;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool StrengthReductionContext::createNewInductionVariable(StrengthReductionCandidate* candidate) {
|
||||
Loop* loop = candidate->containingLoop;
|
||||
BasicBlock* header = loop->getHeader();
|
||||
BasicBlock* preheader = loop->getPreHeader();
|
||||
|
||||
if (!preheader) {
|
||||
if (DEBUG) {
|
||||
std::cout << " No preheader found for loop" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取原始归纳变量的 phi 指令
|
||||
auto* originalPhi = dynamic_cast<PhiInst*>(candidate->inductionVar);
|
||||
if (!originalPhi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1. 在循环头创建新的 phi 指令
|
||||
builder->setPosition(header, header->begin());
|
||||
candidate->newPhi = builder->createPhiInst(originalPhi->getType());
|
||||
candidate->newPhi->setName(originalPhi->getName() + "_sr");
|
||||
|
||||
// 2. 找到原始归纳变量的初始值和步长
|
||||
Value* initialValue = nullptr;
|
||||
Value* stepValue = nullptr;
|
||||
BasicBlock* latchBlock = nullptr;
|
||||
|
||||
for (auto& [incomingBB, incomingVal] : originalPhi->getIncomingValues()) {
|
||||
if (!loop->contains(incomingBB)) {
|
||||
// 来自循环外的初始值
|
||||
initialValue = incomingVal;
|
||||
} else {
|
||||
// 来自循环内的递增值
|
||||
latchBlock = incomingBB;
|
||||
// 尝试找到步长
|
||||
if (auto* addInst = dynamic_cast<BinaryInst*>(incomingVal)) {
|
||||
if (addInst->getKind() == Instruction::Kind::kAdd) {
|
||||
if (addInst->getOperand(0) == originalPhi) {
|
||||
stepValue = addInst->getOperand(1);
|
||||
} else if (addInst->getOperand(1) == originalPhi) {
|
||||
stepValue = addInst->getOperand(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialValue || !stepValue || !latchBlock) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Failed to find initial value, step, or latch block" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 计算新归纳变量的初始值和步长
|
||||
// 新IV的初始值 = 原IV初始值 * multiplier
|
||||
Value* newInitialValue;
|
||||
if (auto* constInt = dynamic_cast<ConstantInteger*>(initialValue)) {
|
||||
newInitialValue = ConstantInteger::get(constInt->getInt() * candidate->multiplier);
|
||||
} else {
|
||||
// 如果初始值不是常数,需要在preheader中插入乘法
|
||||
builder->setPosition(preheader, preheader->terminator());
|
||||
newInitialValue = builder->createMulInst(initialValue,
|
||||
ConstantInteger::get(candidate->multiplier));
|
||||
}
|
||||
|
||||
// 新IV的步长 = 原IV步长 * multiplier
|
||||
Value* newStepValue;
|
||||
if (auto* constInt = dynamic_cast<ConstantInteger*>(stepValue)) {
|
||||
newStepValue = ConstantInteger::get(constInt->getInt() * candidate->multiplier);
|
||||
} else {
|
||||
builder->setPosition(latchBlock, latchBlock->terminator());
|
||||
newStepValue = builder->createMulInst(stepValue,
|
||||
ConstantInteger::get(candidate->multiplier));
|
||||
}
|
||||
|
||||
// 4. 创建新归纳变量的递增指令
|
||||
builder->setPosition(latchBlock, latchBlock->terminator());
|
||||
Value* newIncrementedValue = builder->createAddInst(candidate->newPhi, newStepValue);
|
||||
|
||||
// 5. 设置新 phi 的输入值
|
||||
candidate->newPhi->addIncoming(newInitialValue, preheader);
|
||||
candidate->newPhi->addIncoming(newIncrementedValue, latchBlock);
|
||||
|
||||
candidate->newInductionVar = candidate->newPhi;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Created new induction variable: " << candidate->newPhi->getName() << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StrengthReductionContext::replaceOriginalInstruction(StrengthReductionCandidate* candidate) {
|
||||
if (!candidate->newInductionVar) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 处理偏移量
|
||||
Value* replacementValue = candidate->newInductionVar;
|
||||
if (candidate->offset != 0) {
|
||||
builder->setPosition(candidate->containingBlock,
|
||||
candidate->containingBlock->findInstIterator(candidate->originalInst));
|
||||
replacementValue = builder->createAddInst(
|
||||
candidate->newInductionVar,
|
||||
ConstantInteger::get(candidate->offset)
|
||||
);
|
||||
}
|
||||
|
||||
// 替换所有使用
|
||||
candidate->originalInst->replaceAllUsesWith(replacementValue);
|
||||
|
||||
// 从基本块中移除原始指令
|
||||
auto* bb = candidate->originalInst->getParent();
|
||||
auto it = bb->findInstIterator(candidate->originalInst);
|
||||
if (it != bb->end()) {
|
||||
bb->getInstructions().erase(it);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << " Replaced and removed original instruction" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StrengthReductionContext::printDebugInfo() {
|
||||
if (!DEBUG) return;
|
||||
|
||||
std::cout << "\n=== Strength Reduction Optimization Summary ===" << std::endl;
|
||||
std::cout << "Total candidates processed: " << candidates.size() << std::endl;
|
||||
|
||||
for (auto& [loop, loopCandidates] : loopToCandidates) {
|
||||
if (!loopCandidates.empty()) {
|
||||
std::cout << "Loop " << loop->getName() << ": " << loopCandidates.size() << " optimizations" << std::endl;
|
||||
for (auto* candidate : loopCandidates) {
|
||||
if (candidate->newInductionVar) {
|
||||
std::cout << " " << candidate->inductionVar->getName() << " * " << candidate->multiplier
|
||||
<< " -> " << candidate->newInductionVar->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "===============================================" << std::endl;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
Reference in New Issue
Block a user