forked from ppxf25tqu/nudt-compiler-cpp
commit
99826566e6
@ -0,0 +1,3 @@
|
||||
bash scripts/run_ir_test.sh --run # 优化模式,计时
|
||||
bash scripts/run_ir_test.sh --run --O0 # 无优化,计时
|
||||
bash scripts/bench_ir.sh # 同时对比 O0 vs O1
|
||||
@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env bash
|
||||
# 优化效果对比:测量 O0 vs O1 的编译时间和运行时间
|
||||
# 用法: bash scripts/bench_ir.sh [--test-dir=<dir>] [--result-dir=<dir>]
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
PROJECT_ROOT=$(cd "$(dirname "$0")/.." ; pwd)
|
||||
TEST_CASE_DIR="${PROJECT_ROOT}/test/test_case"
|
||||
RESULT_DIR="${PROJECT_ROOT}/test/test_result/bench"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--test-dir=*) TEST_CASE_DIR="${1#*=}" ;;
|
||||
--result-dir=*) RESULT_DIR="${1#*=}" ;;
|
||||
*) echo "未知参数: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
compiler="${PROJECT_ROOT}/build/bin/compiler"
|
||||
[[ -x "$compiler" ]] || { echo "错误:未找到编译器 $compiler" >&2; exit 1; }
|
||||
command -v llc >/dev/null 2>&1 || { echo "错误:未找到 llc" >&2; exit 1; }
|
||||
command -v clang >/dev/null 2>&1 || { echo "错误:未找到 clang" >&2; exit 1; }
|
||||
|
||||
mkdir -p "$RESULT_DIR"
|
||||
|
||||
# 时间测量:使用 date +%s.%N
|
||||
now() { date +%s.%N; }
|
||||
elapsed() { python3 -c "print(f'{float($2)-float($1):.4f}')" 2>/dev/null || awk "BEGIN{printf \"%.4f\\n\",$2-$1}"; }
|
||||
|
||||
summary_file="${RESULT_DIR}/summary.csv"
|
||||
echo "test,opt,compile_s,exec_s,compile+exec_s" > "$summary_file"
|
||||
|
||||
total=0
|
||||
o0_ct_total=0; o1_ct_total=0
|
||||
o0_et_total=0; o1_et_total=0
|
||||
|
||||
echo "=== 优化效果对比 O0 vs O1 ==="
|
||||
echo ""
|
||||
|
||||
while read -r test_file; do
|
||||
full_path=$(readlink -f "$test_file")
|
||||
tcdir=$(readlink -f "$TEST_CASE_DIR")
|
||||
rel="${full_path#$tcdir}"
|
||||
[[ "${rel:0:1}" != "/" ]] && rel="/$rel"
|
||||
|
||||
base=$(basename "$test_file")
|
||||
stem="${base%.sy}"
|
||||
idir=$(dirname "$test_file")
|
||||
stdin="${idir}/${stem}.in"
|
||||
expected="${idir}/${stem}.out"
|
||||
|
||||
total=$((total+1))
|
||||
printf "[%4d] %s" "$total" "$rel"
|
||||
|
||||
o0_ll="${RESULT_DIR}/O0/${rel%.sy}.ll"
|
||||
o1_ll="${RESULT_DIR}/O1/${rel%.sy}.ll"
|
||||
mkdir -p "$(dirname "$o0_ll")" "$(dirname "$o1_ll")"
|
||||
|
||||
# --- 编译 O0 ---
|
||||
t1=$(now)
|
||||
"$compiler" "$test_file" -IR -o "$o0_ll" 2>/dev/null; rc0=$?
|
||||
t2=$(now)
|
||||
if [[ $rc0 -ne 0 ]]; then
|
||||
echo " | O0编译失败"
|
||||
echo "$stem,O0,-,-,-" >> "$summary_file"
|
||||
echo "$stem,O1,-,-,-" >> "$summary_file"
|
||||
continue
|
||||
fi
|
||||
o0_ct=$(elapsed "$t1" "$t2")
|
||||
|
||||
# --- 编译 O1 ---
|
||||
t1=$(now)
|
||||
"$compiler" "$test_file" -IR -o "$o1_ll" -O1 2>/dev/null; rc1=$?
|
||||
t2=$(now)
|
||||
if [[ $rc1 -ne 0 ]]; then
|
||||
echo " | O1编译失败"
|
||||
echo "$stem,O0,$o0_ct,-,-" >> "$summary_file"
|
||||
echo "$stem,O1,-,-,-" >> "$summary_file"
|
||||
continue
|
||||
fi
|
||||
o1_ct=$(elapsed "$t1" "$t2")
|
||||
|
||||
# --- llc + clang O0 ---
|
||||
o0_obj="${RESULT_DIR}/O0/${stem}.o"
|
||||
o1_obj="${RESULT_DIR}/O1/${stem}.o"
|
||||
o0_exe="${RESULT_DIR}/O0/${stem}.exe"
|
||||
o1_exe="${RESULT_DIR}/O1/${stem}.exe"
|
||||
|
||||
llc -filetype=obj "$o0_ll" -o "$o0_obj" 2>/dev/null
|
||||
llc -filetype=obj "$o1_ll" -o "$o1_obj" 2>/dev/null
|
||||
clang "$o0_obj" "${PROJECT_ROOT}/sylib/sylib.c" -o "$o0_exe" -lm 2>/dev/null
|
||||
clang "$o1_obj" "${PROJECT_ROOT}/sylib/sylib.c" -o "$o1_exe" -lm 2>/dev/null
|
||||
|
||||
# --- 运行 O0 ---
|
||||
t1=$(now)
|
||||
sr0=0
|
||||
if [[ -f "$stdin" ]]; then
|
||||
(ulimit -s unlimited; "$o0_exe" < "$stdin") > /dev/null 2>&1 || sr0=$?
|
||||
else
|
||||
(ulimit -s unlimited; "$o0_exe") > /dev/null 2>&1 || sr0=$?
|
||||
fi
|
||||
t2=$(now)
|
||||
o0_et=$(elapsed "$t1" "$t2")
|
||||
|
||||
# --- 运行 O1 ---
|
||||
t1=$(now)
|
||||
sr1=0
|
||||
if [[ -f "$stdin" ]]; then
|
||||
(ulimit -s unlimited; "$o1_exe" < "$stdin") > /dev/null 2>&1 || sr1=$?
|
||||
else
|
||||
(ulimit -s unlimited; "$o1_exe") > /dev/null 2>&1 || sr1=$?
|
||||
fi
|
||||
t2=$(now)
|
||||
o1_et=$(elapsed "$t1" "$t2")
|
||||
|
||||
# 验证一致性
|
||||
flag=""
|
||||
if [[ $sr0 -ne $sr1 ]]; then
|
||||
flag=" EXIT:O0=$sr0 O1=$sr1"
|
||||
fi
|
||||
|
||||
# 累计 & 比率
|
||||
o0_ct_total=$(awk "BEGIN{printf \"%.4f\",$o0_ct_total+$o0_ct}")
|
||||
o1_ct_total=$(awk "BEGIN{printf \"%.4f\",$o1_ct_total+$o1_ct}")
|
||||
o0_et_total=$(awk "BEGIN{printf \"%.4f\",$o0_et_total+$o0_et}")
|
||||
o1_et_total=$(awk "BEGIN{printf \"%.4f\",$o1_et_total+$o1_et}")
|
||||
|
||||
cspd=$(awk "BEGIN{if($o1_ct>0)printf \"%.1fx\",$o0_ct/$o1_ct; else print \"-\"}")
|
||||
espd=$(awk "BEGIN{if($o1_et>0)printf \"%.1fx\",$o0_et/$o1_et; else print \"-\"}")
|
||||
|
||||
printf " | 编译 O0:%.4fs O1:%.4fs(%s) 运行 O0:%.4fs O1:%.4fs(%s)%s\n" \
|
||||
"$o0_ct" "$o1_ct" "$cspd" "$o0_et" "$o1_et" "$espd" "$flag"
|
||||
|
||||
echo "$stem,O0,$o0_ct,$o0_et,$(awk "BEGIN{printf \"%.4f\",$o0_ct+$o0_et}")" >> "$summary_file"
|
||||
echo "$stem,O1,$o1_ct,$o1_et,$(awk "BEGIN{printf \"%.4f\",$o1_ct+$o1_et}")" >> "$summary_file"
|
||||
|
||||
done < <(find "$TEST_CASE_DIR" -name "*.sy" | sort)
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo "总用例: $total"
|
||||
echo "O0 编译总耗时: ${o0_ct_total}s"
|
||||
echo "O1 编译总耗时: ${o1_ct_total}s"
|
||||
echo "O0 运行总耗时: ${o0_et_total}s"
|
||||
echo "O1 运行总耗时: ${o1_et_total}s"
|
||||
echo "CSV: $summary_file"
|
||||
@ -1,4 +1,205 @@
|
||||
// 支配树分析:
|
||||
// - 构建/查询 Dominator Tree 及相关关系
|
||||
// - 为 mem2reg、CFG 优化与循环分析提供基础能力
|
||||
// - 使用 Cooper-Harvey-Kennedy 算法,近线性时间复杂度
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
|
||||
void DominatorTree::Compute(Function& func) {
|
||||
func.RebuildCFG();
|
||||
|
||||
// Build block list and reverse postorder (RPO)
|
||||
std::vector<BasicBlock*> blocks;
|
||||
std::unordered_map<BasicBlock*, int> rpo;
|
||||
{
|
||||
std::vector<BasicBlock*> rpo_vec;
|
||||
std::unordered_set<BasicBlock*> visited;
|
||||
std::function<void(BasicBlock*)> dfs = [&](BasicBlock* bb) {
|
||||
if (!bb || visited.count(bb)) return;
|
||||
visited.insert(bb);
|
||||
for (auto* succ : bb->GetSuccessors()) {
|
||||
dfs(succ);
|
||||
}
|
||||
rpo_vec.push_back(bb);
|
||||
};
|
||||
dfs(func.GetEntry());
|
||||
// Reverse to get RPO (postorder reversed)
|
||||
std::reverse(rpo_vec.begin(), rpo_vec.end());
|
||||
blocks = rpo_vec;
|
||||
for (int i = 0; i < (int)blocks.size(); ++i) {
|
||||
rpo[blocks[i]] = i;
|
||||
}
|
||||
}
|
||||
if (blocks.empty()) return;
|
||||
int n = (int)blocks.size();
|
||||
|
||||
auto* entry = func.GetEntry();
|
||||
if (!entry) return;
|
||||
|
||||
// ─── 1. CHK algorithm for immediate dominators ─────────────────────────
|
||||
idom_.clear();
|
||||
idom_[entry] = entry; // entry is its own dominator
|
||||
|
||||
// Intersect: find common ancestor of b1 and b2 walking up the dom tree
|
||||
// Uses RPO number: a dominator always has lower RPO number
|
||||
auto intersect = [&](BasicBlock* b1, BasicBlock* b2) -> BasicBlock* {
|
||||
auto i1 = rpo.find(b1), i2 = rpo.find(b2);
|
||||
if (i1 == rpo.end() || i2 == rpo.end()) return entry;
|
||||
int r1 = i1->second, r2 = i2->second;
|
||||
while (b1 != b2) {
|
||||
while (r1 > r2) {
|
||||
auto it = idom_.find(b1);
|
||||
if (it == idom_.end() || it->second == b1) return b1;
|
||||
b1 = it->second;
|
||||
r1 = rpo[b1];
|
||||
}
|
||||
while (r2 > r1) {
|
||||
auto it = idom_.find(b2);
|
||||
if (it == idom_.end() || it->second == b2) return b2;
|
||||
b2 = it->second;
|
||||
r2 = rpo[b2];
|
||||
}
|
||||
}
|
||||
return b1;
|
||||
};
|
||||
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
// Process in RPO (skip entry which is first in RPO)
|
||||
for (int i = 1; i < n; ++i) {
|
||||
auto* bb = blocks[i];
|
||||
// Find first predecessor with defined IDOM
|
||||
BasicBlock* new_idom = nullptr;
|
||||
for (auto* pred : bb->GetPredecessors()) {
|
||||
if (idom_.count(pred) && pred != bb) {
|
||||
new_idom = pred;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!new_idom) continue;
|
||||
|
||||
// Intersect with remaining predecessors
|
||||
for (auto* pred : bb->GetPredecessors()) {
|
||||
if (pred == new_idom || pred == bb) continue;
|
||||
if (idom_.count(pred)) {
|
||||
new_idom = intersect(pred, new_idom);
|
||||
}
|
||||
}
|
||||
|
||||
auto old = idom_.find(bb);
|
||||
if (old == idom_.end() || old->second != new_idom) {
|
||||
idom_[bb] = new_idom;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Entry is its own IDOM, set to nullptr for external queries
|
||||
idom_[entry] = nullptr;
|
||||
|
||||
// Unreached blocks get entry as IDOM
|
||||
for (auto* bb : blocks) {
|
||||
if (!idom_.count(bb)) idom_[bb] = entry;
|
||||
}
|
||||
|
||||
// ─── 2. Build children map and dom levels ──────────────────────────────
|
||||
children_.clear();
|
||||
dom_level_.clear();
|
||||
for (auto& [child, parent] : idom_) {
|
||||
if (parent) children_[parent].push_back(child);
|
||||
}
|
||||
|
||||
// BFS to compute dom levels
|
||||
std::queue<BasicBlock*> q;
|
||||
dom_level_[entry] = 0;
|
||||
q.push(entry);
|
||||
while (!q.empty()) {
|
||||
auto* cur = q.front();
|
||||
q.pop();
|
||||
size_t cur_level = dom_level_[cur];
|
||||
auto it = children_.find(cur);
|
||||
if (it != children_.end()) {
|
||||
for (auto* child : it->second) {
|
||||
dom_level_[child] = cur_level + 1;
|
||||
q.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 3. Compute dominance frontier ─────────────────────────────────────
|
||||
df_.clear();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
auto* b = blocks[i];
|
||||
if (b->GetPredecessors().size() < 2) continue;
|
||||
for (auto* p : b->GetPredecessors()) {
|
||||
auto* runner = p;
|
||||
auto* b_idom = GetIDom(b);
|
||||
while (runner != b_idom) {
|
||||
if (!runner) break;
|
||||
df_[runner].push_back(b);
|
||||
runner = GetIDom(runner);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Deduplicate DF entries
|
||||
for (auto& [bb, vec] : df_) {
|
||||
std::sort(vec.begin(), vec.end());
|
||||
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
||||
}
|
||||
|
||||
// ─── 4. Compute DFS order of dominator tree ────────────────────────────
|
||||
df_order_.clear();
|
||||
visited_.clear();
|
||||
std::function<void(BasicBlock*)> dfs_tree = [&](BasicBlock* bb) {
|
||||
if (!bb || visited_.count(bb)) return;
|
||||
visited_.insert(bb);
|
||||
df_order_.push_back(bb);
|
||||
auto it = children_.find(bb);
|
||||
if (it != children_.end()) {
|
||||
for (auto* child : it->second) {
|
||||
dfs_tree(child);
|
||||
}
|
||||
}
|
||||
};
|
||||
dfs_tree(entry);
|
||||
}
|
||||
|
||||
BasicBlock* DominatorTree::GetIDom(BasicBlock* bb) const {
|
||||
auto it = idom_.find(bb);
|
||||
return (it != idom_.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
const std::vector<BasicBlock*>& DominatorTree::GetChildren(
|
||||
BasicBlock* bb) const {
|
||||
static const std::vector<BasicBlock*> empty;
|
||||
auto it = children_.find(bb);
|
||||
return (it != children_.end()) ? it->second : empty;
|
||||
}
|
||||
|
||||
const std::vector<BasicBlock*>& DominatorTree::GetDominanceFrontier(
|
||||
BasicBlock* bb) const {
|
||||
static const std::vector<BasicBlock*> empty;
|
||||
auto it = df_.find(bb);
|
||||
return (it != df_.end()) ? it->second : empty;
|
||||
}
|
||||
|
||||
bool DominatorTree::Dominates(BasicBlock* a, BasicBlock* b) const {
|
||||
if (a == b) return true;
|
||||
BasicBlock* runner = b;
|
||||
while (runner) {
|
||||
runner = GetIDom(runner);
|
||||
if (runner == a) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@ -1,4 +1,187 @@
|
||||
// IR 常量折叠:
|
||||
// - 折叠可判定的常量表达式
|
||||
// - 简化常量控制流分支(按实现范围裁剪)
|
||||
// - 简化常量控制流分支
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
|
||||
namespace {
|
||||
|
||||
// 在释放指令前断开其 use-def 链,避免其他值的 uses_ 中有悬空指针
|
||||
static void DetachAndRemove(Instruction* inst) {
|
||||
// 先断开自身对操作数的引用,清除 use-def 链
|
||||
for (size_t i = 0; i < inst->GetNumOperands(); ++i)
|
||||
inst->SetOperand(i, nullptr);
|
||||
// 然后从父块中移除(清除父指针后不会再次尝试访问)
|
||||
if (auto* parent = inst->GetParent()) {
|
||||
parent->RemoveInstruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
bool FoldICmp(ICmpInst* cmp, Context& ctx) {
|
||||
auto* lhs = dynamic_cast<ConstantInt*>(cmp->GetLhs());
|
||||
auto* rhs = dynamic_cast<ConstantInt*>(cmp->GetRhs());
|
||||
if (!lhs || !rhs) return false;
|
||||
|
||||
int lv = lhs->GetValue(), rv = rhs->GetValue();
|
||||
bool result = false;
|
||||
switch (cmp->GetPredicate()) {
|
||||
case ICmpPredicate::EQ: result = lv == rv; break;
|
||||
case ICmpPredicate::NE: result = lv != rv; break;
|
||||
case ICmpPredicate::SLT: result = lv < rv; break;
|
||||
case ICmpPredicate::SLE: result = lv <= rv; break;
|
||||
case ICmpPredicate::SGT: result = lv > rv; break;
|
||||
case ICmpPredicate::SGE: result = lv >= rv; break;
|
||||
}
|
||||
cmp->ReplaceAllUsesWith(ctx.GetConstInt(result ? 1 : 0));
|
||||
DetachAndRemove(cmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FoldFCmp(FCmpInst* cmp, Context& ctx) {
|
||||
auto* lhs = dynamic_cast<ConstantFloat*>(cmp->GetLhs());
|
||||
auto* rhs = dynamic_cast<ConstantFloat*>(cmp->GetRhs());
|
||||
if (!lhs || !rhs) return false;
|
||||
|
||||
float lv = lhs->GetValue(), rv = rhs->GetValue();
|
||||
bool result = false;
|
||||
switch (cmp->GetPredicate()) {
|
||||
case FCmpPredicate::OEQ: result = lv == rv; break;
|
||||
case FCmpPredicate::ONE: result = lv != rv; break;
|
||||
case FCmpPredicate::OLT: result = lv < rv; break;
|
||||
case FCmpPredicate::OLE: result = lv <= rv; break;
|
||||
case FCmpPredicate::OGT: result = lv > rv; break;
|
||||
case FCmpPredicate::OGE: result = lv >= rv; break;
|
||||
}
|
||||
cmp->ReplaceAllUsesWith(ctx.GetConstInt(result ? 1 : 0));
|
||||
DetachAndRemove(cmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FoldZExt(ZExtInst* zext, Context& ctx) {
|
||||
auto* src = dynamic_cast<ConstantInt*>(zext->GetSrc());
|
||||
if (!src) return false;
|
||||
zext->ReplaceAllUsesWith(ctx.GetConstInt(src->GetValue() != 0 ? 1 : 0));
|
||||
DetachAndRemove(zext);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FoldSIToFP(SIToFPInst* inst, Context& ctx) {
|
||||
auto* src = dynamic_cast<ConstantInt*>(inst->GetSrc());
|
||||
if (!src) return false;
|
||||
inst->ReplaceAllUsesWith(ctx.GetConstFloat(static_cast<float>(src->GetValue())));
|
||||
DetachAndRemove(inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FoldFPToSI(FPToSIInst* inst, Context& ctx) {
|
||||
auto* src = dynamic_cast<ConstantFloat*>(inst->GetSrc());
|
||||
if (!src) return false;
|
||||
inst->ReplaceAllUsesWith(ctx.GetConstInt(static_cast<int>(src->GetValue())));
|
||||
DetachAndRemove(inst);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fold constant binary operations (int and float)
|
||||
bool FoldBinaryWithCtx(BinaryInst* bin, Context& ctx) {
|
||||
auto* lhs_c = dynamic_cast<ConstantInt*>(bin->GetLhs());
|
||||
auto* rhs_c = dynamic_cast<ConstantInt*>(bin->GetRhs());
|
||||
auto* lhs_f = dynamic_cast<ConstantFloat*>(bin->GetLhs());
|
||||
auto* rhs_f = dynamic_cast<ConstantFloat*>(bin->GetRhs());
|
||||
|
||||
if (lhs_c && rhs_c) {
|
||||
int lv = lhs_c->GetValue(), rv = rhs_c->GetValue();
|
||||
int result = 0;
|
||||
bool valid = true;
|
||||
switch (bin->GetOpcode()) {
|
||||
case Opcode::Add: result = lv + rv; break;
|
||||
case Opcode::Sub: result = lv - rv; break;
|
||||
case Opcode::Mul: result = lv * rv; break;
|
||||
case Opcode::Div: if (rv != 0) result = lv / rv; else valid = false; break;
|
||||
case Opcode::Mod: if (rv != 0) result = lv % rv; else valid = false; break;
|
||||
default: valid = false; break;
|
||||
}
|
||||
if (valid) {
|
||||
bin->ReplaceAllUsesWith(ctx.GetConstInt(result));
|
||||
DetachAndRemove(bin);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (lhs_f && rhs_f) {
|
||||
float lv = lhs_f->GetValue(), rv = rhs_f->GetValue();
|
||||
float result = 0.0f;
|
||||
bool valid = true;
|
||||
switch (bin->GetOpcode()) {
|
||||
case Opcode::FAdd: result = lv + rv; break;
|
||||
case Opcode::FSub: result = lv - rv; break;
|
||||
case Opcode::FMul: result = lv * rv; break;
|
||||
case Opcode::FDiv: if (rv != 0.0f) result = lv / rv; else valid = false; break;
|
||||
default: valid = false; break;
|
||||
}
|
||||
if (valid) {
|
||||
bin->ReplaceAllUsesWith(ctx.GetConstFloat(result));
|
||||
DetachAndRemove(bin);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool RunConstFold(Function& func, Context& ctx) {
|
||||
bool changed = false;
|
||||
std::unordered_set<void*> removed;
|
||||
|
||||
bool any_changed = true;
|
||||
while (any_changed) {
|
||||
any_changed = false;
|
||||
for (auto& bb : func.GetBlocks()) {
|
||||
// 每轮重新收集(因为指令列表在变化)
|
||||
std::vector<Instruction*> insts;
|
||||
for (auto& inst : bb->GetInstructions())
|
||||
insts.push_back(inst.get());
|
||||
|
||||
for (auto* inst : insts) {
|
||||
if (removed.count(inst)) continue;
|
||||
bool folded = false;
|
||||
switch (inst->GetOpcode()) {
|
||||
case Opcode::Add: case Opcode::Sub: case Opcode::Mul:
|
||||
case Opcode::Div: case Opcode::Mod:
|
||||
case Opcode::FAdd: case Opcode::FSub:
|
||||
case Opcode::FMul: case Opcode::FDiv:
|
||||
folded = FoldBinaryWithCtx(static_cast<BinaryInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::ICmp:
|
||||
folded = FoldICmp(static_cast<ICmpInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::FCmp:
|
||||
folded = FoldFCmp(static_cast<FCmpInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::ZExt:
|
||||
folded = FoldZExt(static_cast<ZExtInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::SIToFP:
|
||||
folded = FoldSIToFP(static_cast<SIToFPInst*>(inst), ctx);
|
||||
break;
|
||||
case Opcode::FPToSI:
|
||||
folded = FoldFPToSI(static_cast<FPToSIInst*>(inst), ctx);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
if (folded) {
|
||||
removed.insert(inst);
|
||||
any_changed = true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
Loading…
Reference in new issue