Skip to content

Commit 118e05d

Browse files
committed
fix(ra): 消除寄存器分配的非确定性,使上板缓存生效
后端多处按指针地址迭代无序容器,导致同一份 IR 每次编译产出不同的 寄存器名与栈槽偏移(opcode 流相同,仅命名/布局变)。其后果是上板对 所有非平凡函数永远 cache miss 为 Value 增加单调递增的创建序号 getCreationId(),作为确定性全序排序键 (含已脱离 CFG 的残留指令也有稳定序号),并修正两处顺序敏感点: - CodeGeneratorRiscV64::stackAlloc:栈槽候选改按 creationId 排序,替代 按 allocMap(unordered_map) 指针序分配,固定栈槽偏移 - GreedyRegAllocator::allocate:callInstNumbers 由 instNumbering (std::map<Instruction*,int>) 指针序构建,排序后再用,固定分裂点等决策
1 parent b9cc184 commit 118e05d

4 files changed

Lines changed: 28 additions & 1 deletion

File tree

backend/riscv64/CodeGeneratorRiscV64.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,12 @@ void CodeGeneratorRiscV64::stackAlloc(Function * func, bool useFramePointer)
716716
stackSlotCandidates.push_back(val);
717717
}
718718
}
719+
// allocMap 是 unordered_map,按指针序迭代会让栈槽偏移每次编译都变(非确定性)。
720+
// 改为按 Value 的创建序号这一确定性全序键排序(含已脱离 CFG 的残留指令也有
721+
// 稳定序号),保证同一份 IR 每次生成完全相同的栈布局,使上板缓存生效
722+
std::sort(stackSlotCandidates.begin(), stackSlotCandidates.end(), [](Value * lhs, Value * rhs) {
723+
return lhs->getCreationId() < rhs->getCreationId();
724+
});
719725
for (auto * val : stackSlotCandidates) {
720726
Value * representative = greedyAllocator.getCoalescedRepresentative(val);
721727
if (representative != nullptr && representative != val) {

backend/riscv64/GreedyRegAllocator.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ void GreedyRegAllocator::allocate(Function * func)
124124
callInstNumbers.push_back(num);
125125
}
126126
}
127+
// instNumbering 是 std::map<Instruction*,int>,按指针序迭代得到的 callInstNumbers
128+
// 顺序每次编译都不同,会影响分裂点选择等顺序敏感决策。按调用位置升序排序使其确定
129+
std::sort(callInstNumbers.begin(), callInstNumbers.end());
127130

128131
// 建立活跃区间到索引的映射
129132
auto & intervals = analysis.getIntervals();

ir/Value.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@
1010
#include "Use.h"
1111
#include "User.h"
1212

13+
namespace {
14+
/// 全局单调递增的 Value 创建计数器。单线程编译,无需同步。
15+
/// 按构造顺序分配,使同一份输入每次编译得到完全一致的 Value 序号,
16+
/// 供寄存器分配等阶段作确定性排序键,消除按指针地址迭代的非确定性
17+
uint64_t g_nextValueCreationId = 0;
18+
} // namespace
19+
1320
/// @brief 构造一个 Value 对象
1421
/// @param _type 当前值的类型
15-
Value::Value(Type * _type) : type(_type)
22+
Value::Value(Type * _type) : type(_type), creationId(g_nextValueCreationId++)
1623
{}
1724

1825
/// @brief 析构函数

ir/Value.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,21 @@ class Value {
2121
Type * type;
2222
std::vector<Use *> uses;
2323

24+
private:
25+
/// 单调递增的创建序号,按构造顺序分配,跨整个编译唯一且确定。
26+
/// 用作寄存器分配等阶段的稳定排序键,替代按指针地址排序带来的非确定性
27+
uint64_t creationId;
28+
2429
public:
2530
/// @brief 构造一个 Value 对象
2631
explicit Value(Type * _type);
2732

33+
/// @brief 获取该值的创建序号(确定性稳定排序键)
34+
[[nodiscard]] uint64_t getCreationId() const
35+
{
36+
return creationId;
37+
}
38+
2839
/// @brief 析构函数
2940
virtual ~Value();
3041

0 commit comments

Comments
 (0)