[backend]修复线性扫描逻辑

This commit is contained in:
Lixuanwang
2025-08-05 01:06:07 +08:00
parent f7f1cf2b41
commit dcc075b39c
4 changed files with 324 additions and 203 deletions

View File

@ -1,27 +1,82 @@
#include "RISCv64LinearScan.h"
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h"
#include "RISCv64Info.h"
#include <iostream>
#include <algorithm>
#include <set>
#include <sstream>
#include <functional>
// 外部调试级别控制变量
extern int DEBUG;
extern int DEEPDEBUG;
extern int DEEPERDEBUG;
namespace sysy {
// --- 调试辅助函数 ---
std::string pregToString(PhysicalReg preg) {
static const std::map<PhysicalReg, std::string> preg_names = {
{PhysicalReg::ZERO, "zero"}, {PhysicalReg::RA, "ra"}, {PhysicalReg::SP, "sp"}, {PhysicalReg::GP, "gp"}, {PhysicalReg::TP, "tp"},
{PhysicalReg::T0, "t0"}, {PhysicalReg::T1, "t1"}, {PhysicalReg::T2, "t2"}, {PhysicalReg::T3, "t3"}, {PhysicalReg::T4, "t4"}, {PhysicalReg::T5, "t5"}, {PhysicalReg::T6, "t6"},
{PhysicalReg::S0, "s0"}, {PhysicalReg::S1, "s1"}, {PhysicalReg::S2, "s2"}, {PhysicalReg::S3, "s3"}, {PhysicalReg::S4, "s4"}, {PhysicalReg::S5, "s5"}, {PhysicalReg::S6, "s6"}, {PhysicalReg::S7, "s7"}, {PhysicalReg::S8, "s8"}, {PhysicalReg::S9, "s9"}, {PhysicalReg::S10, "s10"}, {PhysicalReg::S11, "s11"},
{PhysicalReg::A0, "a0"}, {PhysicalReg::A1, "a1"}, {PhysicalReg::A2, "a2"}, {PhysicalReg::A3, "a3"}, {PhysicalReg::A4, "a4"}, {PhysicalReg::A5, "a5"}, {PhysicalReg::A6, "a6"}, {PhysicalReg::A7, "a7"},
{PhysicalReg::F0, "f0"}, {PhysicalReg::F1, "f1"}, {PhysicalReg::F2, "f2"}, {PhysicalReg::F3, "f3"}, {PhysicalReg::F4, "f4"}, {PhysicalReg::F5, "f5"}, {PhysicalReg::F6, "f6"}, {PhysicalReg::F7, "f7"},
{PhysicalReg::F8, "f8"}, {PhysicalReg::F9, "f9"}, {PhysicalReg::F10, "f10"}, {PhysicalReg::F11, "f11"}, {PhysicalReg::F12, "f12"}, {PhysicalReg::F13, "f13"}, {PhysicalReg::F14, "f14"}, {PhysicalReg::F15, "f15"},
{PhysicalReg::F16, "f16"}, {PhysicalReg::F17, "f17"}, {PhysicalReg::F18, "f18"}, {PhysicalReg::F19, "f19"}, {PhysicalReg::F20, "f20"}, {PhysicalReg::F21, "f21"}, {PhysicalReg::F22, "f22"}, {PhysicalReg::F23, "f23"},
{PhysicalReg::F24, "f24"}, {PhysicalReg::F25, "f25"}, {PhysicalReg::F26, "f26"}, {PhysicalReg::F27, "f27"}, {PhysicalReg::F28, "f28"}, {PhysicalReg::F29, "f29"}, {PhysicalReg::F30, "f30"}, {PhysicalReg::F31, "f31"},
{PhysicalReg::INVALID, "INVALID"}
};
if (preg_names.count(preg)) return preg_names.at(preg);
return "UnknownPreg";
}
template<typename T>
std::string setToString(const std::set<T>& s, std::function<std::string(T)> formatter) {
std::stringstream ss;
ss << "{ ";
for (auto it = s.begin(); it != s.end(); ++it) {
ss << formatter(*it) << (std::next(it) == s.end() ? "" : ", ");
}
ss << " }";
return ss.str();
}
std::string vregSetToString(const std::set<unsigned>& s) {
return setToString<unsigned>(s, [](unsigned v){ return "%v" + std::to_string(v); });
}
std::string pregSetToString(const std::set<PhysicalReg>& s) {
return setToString<PhysicalReg>(s, pregToString);
}
std::string opcodeToString(RVOpcodes opcode) {
static const std::map<RVOpcodes, std::string> opcode_names = {
{RVOpcodes::ADD, "add"}, {RVOpcodes::ADDI, "addi"}, {RVOpcodes::ADDW, "addw"}, {RVOpcodes::ADDIW, "addiw"},
{RVOpcodes::SUB, "sub"}, {RVOpcodes::SUBW, "subw"}, {RVOpcodes::MUL, "mul"}, {RVOpcodes::MULW, "mulw"},
{RVOpcodes::DIV, "div"}, {RVOpcodes::DIVW, "divw"}, {RVOpcodes::REM, "rem"}, {RVOpcodes::REMW, "remw"},
{RVOpcodes::SLT, "slt"}, {RVOpcodes::LW, "lw"}, {RVOpcodes::LD, "ld"}, {RVOpcodes::SW, "sw"}, {RVOpcodes::SD, "sd"},
{RVOpcodes::FLW, "flw"}, {RVOpcodes::FSW, "fsw"}, {RVOpcodes::CALL, "call"}, {RVOpcodes::RET, "ret"},
{RVOpcodes::MV, "mv"}, {RVOpcodes::LI, "li"}, {RVOpcodes::LA, "la"}, {RVOpcodes::BNE, "bne"},
{RVOpcodes::J, "j"}, {RVOpcodes::LABEL, "label"}
};
if (opcode_names.count(opcode)) return opcode_names.at(opcode);
return "Op(" + std::to_string(static_cast<int>(opcode)) + ")";
}
RISCv64LinearScan::RISCv64LinearScan(MachineFunction* mfunc)
: MFunc(mfunc),
ISel(mfunc->getISel()),
vreg_type_map(ISel->getVRegTypeMap()) {
// 初始化可用的物理寄存器池,与图着色版本保持一致
// 整数寄存器
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, /*T5保留作为大立即数加载寄存器*/ PhysicalReg::T6,
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 浮点寄存器
allocable_fp_regs = {
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
@ -29,24 +84,20 @@ RISCv64LinearScan::RISCv64LinearScan(MachineFunction* mfunc)
PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27,
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
};
// 新增识别所有通过寄存器传递的参数并建立vreg到物理寄存器(preg)的映射
// 这等同于图着色算法中的“预着色”步骤。
if (MFunc->getFunc()) {
int int_arg_idx = 0;
int fp_arg_idx = 0;
for (Argument* arg : MFunc->getFunc()->getArguments()) {
unsigned arg_vreg = ISel->getVReg(arg);
if (arg->getType()->isFloat()) {
if (fp_arg_idx < 8) { // fa0-fa7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_arg_idx);
if (fp_arg_idx < 8) {
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_arg_idx++);
abi_vreg_map[arg_vreg] = preg;
fp_arg_idx++;
}
} else { // 整数或指针
if (int_arg_idx < 8) { // a0-a7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
} else {
if (int_arg_idx < 8) {
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx++);
abi_vreg_map[arg_vreg] = preg;
int_arg_idx++;
}
}
}
@ -54,34 +105,33 @@ RISCv64LinearScan::RISCv64LinearScan(MachineFunction* mfunc)
}
void RISCv64LinearScan::run() {
if (DEBUG) std::cerr << "===== Running Linear Scan Register Allocation for function: " << MFunc->getName() << " =====\n";
if (DEBUG) std::cerr << "===== [LSRA] Running for function: " << MFunc->getName() << " =====\n";
bool changed = true;
int iteration = 1;
while(changed) {
// 1. 准备阶段
if (DEBUG && iteration > 1) {
std::cerr << "\n----- [LSRA] Re-running iteration " << iteration << " -----\n";
}
linearizeBlocks();
computeLiveIntervals();
// 2. 执行线性扫描
changed = linearScan();
// 3. 如果有溢出,重写代码,然后下一轮重新开始
if (changed) {
if (DEBUG) std::cerr << "[LSRA] Spilling detected, will rewrite program.\n";
rewriteProgram();
if (DEBUG) std::cerr << "--- Spilling detected, re-running linear scan ---\n";
}
iteration++;
}
// 4. 将最终分配结果应用到机器指令
if (DEBUG) std::cerr << "[LSRA] Applying final allocation.\n";
applyAllocation();
// 5. 收集用到的被调用者保存寄存器
MFunc->getFrameInfo().vreg_to_preg_map = this->vreg_to_preg_map;
collectUsedCalleeSavedRegs();
if (DEBUG) std::cerr << "===== Finished Linear Scan Register Allocation =====\n\n";
if (DEBUG) std::cerr << "===== [LSRA] Finished for function: " << MFunc->getName() << " =====\n\n";
}
// 步骤 1.1: 对基本块进行线性化,这里我们简单地按现有顺序排列
void RISCv64LinearScan::linearizeBlocks() {
linear_order_blocks.clear();
for (auto& mbb : MFunc->getBlocks()) {
@ -89,14 +139,14 @@ void RISCv64LinearScan::linearizeBlocks() {
}
}
// RISCv64LinearScan.cpp
// 步骤 1.2: 计算活跃区间 (最终修复版)
void RISCv64LinearScan::computeLiveIntervals() {
if (DEBUG) std::cerr << "[LSRA-Live] Starting live interval computation.\n";
instr_numbering.clear();
live_intervals.clear();
unhandled.clear();
// a. 对所有指令进行线性编号并记录CALL指令的位置
// a. 对所有指令进行线性编号
int num = 0;
std::set<int> call_locations;
for (auto* mbb : linear_order_blocks) {
@ -105,88 +155,143 @@ void RISCv64LinearScan::computeLiveIntervals() {
if (instr->getOpcode() == RVOpcodes::CALL) {
call_locations.insert(num);
}
num += 2; // 指令编号间隔为2方便在溢出重写时插入指令
num += 2;
}
}
// b. 遍历所有指令记录每个vreg首次和末次出现的位置
std::map<unsigned, std::pair<int, int>> vreg_ranges; // vreg -> {first_instr_num, last_instr_num}
// b. 活跃变量分析(数据流分析部分)
if (DEEPDEBUG) std::cerr << " [Live] Starting live variable dataflow analysis...\n";
std::map<const MachineBasicBlock*, std::set<unsigned>> live_in, live_out;
bool changed = true;
int df_iter = 0;
while(changed) {
changed = false;
df_iter++;
std::vector<MachineBasicBlock*> reversed_blocks = linear_order_blocks;
std::reverse(reversed_blocks.begin(), reversed_blocks.end());
for(auto* mbb : reversed_blocks) {
std::set<unsigned> current_live_out;
for (auto* succ : mbb->successors) {
current_live_out.insert(live_in[succ].begin(), live_in[succ].end());
}
for (auto* mbb : linear_order_blocks) {
for (auto& instr_ptr : mbb->getInstructions()) {
const MachineInstr* instr = instr_ptr.get();
int instr_num = instr_numbering.at(instr);
std::set<unsigned> use, def;
getInstrUseDef(instr, use, def);
std::set<unsigned> temp_live = current_live_out;
auto all_vregs = use;
all_vregs.insert(def.begin(), def.end());
for (unsigned vreg : all_vregs) {
if (vreg_ranges.find(vreg) == vreg_ranges.end()) {
vreg_ranges[vreg] = {instr_num, instr_num};
} else {
vreg_ranges[vreg].second = std::max(vreg_ranges[vreg].second, instr_num);
}
auto& instrs = mbb->getInstructions();
for (auto it = instrs.rbegin(); it != instrs.rend(); ++it) {
use.clear(); def.clear();
getInstrUseDef(it->get(), use, def);
for (unsigned vreg : def) temp_live.erase(vreg);
for (unsigned vreg : use) temp_live.insert(vreg);
}
if (live_in[mbb] != temp_live || live_out[mbb] != current_live_out) {
changed = true;
live_in[mbb] = temp_live;
live_out[mbb] = current_live_out;
}
}
}
if (DEEPDEBUG) std::cerr << " [Live] Dataflow analysis converged after " << df_iter << " iterations.\n";
// c. 根据记录的边界创建LiveInterval对象并检查是否跨越CALL
for (auto const& [vreg, range] : vreg_ranges) {
// c. 根据指令遍历和活跃出口信息,精确构建区间
if (DEEPDEBUG) std::cerr << " [Live] Building precise intervals...\n";
std::map<unsigned, int> first_occurrence, last_occurrence;
for (auto* mbb : linear_order_blocks) {
for (auto& instr_ptr : mbb->getInstructions()) {
int instr_num = instr_numbering.at(instr_ptr.get());
std::set<unsigned> use, def;
getInstrUseDef(instr_ptr.get(), use, def);
std::set<unsigned> all_vregs = use;
all_vregs.insert(def.begin(), def.end());
for (unsigned vreg : all_vregs) {
if (first_occurrence.find(vreg) == first_occurrence.end()) {
first_occurrence[vreg] = instr_num;
}
last_occurrence[vreg] = instr_num;
}
}
}
// 使用 live_out 信息修正区间的结束点
for (auto const& [mbb, live_set] : live_out) {
if (mbb->getInstructions().empty()) continue;
int block_end_num = instr_numbering.at(mbb->getInstructions().back().get());
for (unsigned vreg : live_set) {
if (last_occurrence.count(vreg)) {
last_occurrence[vreg] = std::max(last_occurrence[vreg], block_end_num);
}
}
}
// 创建最终的 LiveInterval 对象
for (auto const& [vreg, start] : first_occurrence) {
live_intervals.emplace(vreg, LiveInterval(vreg));
auto& interval = live_intervals.at(vreg);
interval.start = range.first;
interval.end = range.second;
interval.start = start;
interval.end = last_occurrence.at(vreg);
// 检查此区间是否跨越了任何CALL指令
auto it = call_locations.lower_bound(interval.start);
if (it != call_locations.end() && *it < interval.end) {
interval.crosses_call = true;
}
}
// d. 将所有计算出的活跃区间放入 unhandled 列表
// d. 排序并准备分配
for (auto& pair : live_intervals) {
unhandled.push_back(&pair.second);
}
std::sort(unhandled.begin(), unhandled.end(), [](const LiveInterval* a, const LiveInterval* b){
return a->start < b->start;
});
if (DEBUG) {
std::cerr << "[LSRA-Live] Finished. Total intervals: " << unhandled.size() << "\n";
if (DEEPDEBUG) {
std::cerr << " [Live] Computed Intervals (vreg: [start, end]):\n";
for(const auto* interval : unhandled) {
std::cerr << " %v" << interval->vreg << ": [" << interval->start << ", " << interval->end << "]"
<< (interval->crosses_call ? " (crosses call)" : "") << "\n";
}
}
}
}
// RISCv64LinearScan.cpp
// 在类的定义中添加一个辅助函数来判断寄存器类型
bool isCalleeSaved(PhysicalReg preg) {
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) return true;
if (preg == PhysicalReg::S0) return true; // s0 通常也作为被调用者保存
// 浮点寄存器
if (preg == PhysicalReg::S0) return true;
if (preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) return true;
if (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27) return true;
return false;
}
// 线性扫描主算法
bool RISCv64LinearScan::linearScan() {
if (DEBUG) std::cerr << "[LSRA-Scan] Starting main linear scan algorithm.\n";
active.clear();
spilled_vregs.clear();
vreg_to_preg_map.clear();
// 将寄存器池分为调用者保存和被调用者保存两类
std::set<PhysicalReg> free_caller_int_regs, free_callee_int_regs;
std::set<PhysicalReg> free_caller_fp_regs, free_callee_fp_regs;
for (auto preg : allocable_int_regs) {
if (isCalleeSaved(preg)) free_callee_int_regs.insert(preg);
else free_caller_int_regs.insert(preg);
if (isCalleeSaved(preg)) free_callee_int_regs.insert(preg); else free_caller_int_regs.insert(preg);
}
for (auto preg : allocable_fp_regs) {
if (isCalleeSaved(preg)) free_callee_fp_regs.insert(preg);
else free_caller_fp_regs.insert(preg);
if (isCalleeSaved(preg)) free_callee_fp_regs.insert(preg); else free_caller_fp_regs.insert(preg);
}
if (DEEPDEBUG) {
std::cerr << " [Scan] Initial free regs:\n";
std::cerr << " Caller-Saved Int: " << pregSetToString(free_caller_int_regs) << "\n";
std::cerr << " Callee-Saved Int: " << pregSetToString(free_callee_int_regs) << "\n";
}
// 预处理ABI参数寄存器
vreg_to_preg_map.insert(abi_vreg_map.begin(), abi_vreg_map.end());
std::vector<LiveInterval*> normal_unhandled;
for(LiveInterval* interval : unhandled) {
@ -205,13 +310,14 @@ bool RISCv64LinearScan::linearScan() {
unhandled = normal_unhandled;
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
// 主循环
for (LiveInterval* current : unhandled) {
// a. 释放active列表中已结束的区间
if (DEEPDEBUG) std::cerr << "\n [Scan] Processing interval %v" << current->vreg << " [" << current->start << ", " << current->end << "]\n";
std::vector<LiveInterval*> new_active;
for (LiveInterval* active_interval : active) {
if (active_interval->end < current->start) {
PhysicalReg preg = vreg_to_preg_map.at(active_interval->vreg);
if (DEEPDEBUG) std::cerr << " [Scan] Expiring interval %v" << active_interval->vreg << ", freeing " << pregToString(preg) << "\n";
if (isFPVReg(active_interval->vreg)) {
if(isCalleeSaved(preg)) free_callee_fp_regs.insert(preg); else free_caller_fp_regs.insert(preg);
} else {
@ -223,21 +329,17 @@ bool RISCv64LinearScan::linearScan() {
}
active = new_active;
// b. 约束化地为当前区间分配寄存器
bool is_fp = isFPVReg(current->vreg);
auto& free_caller = is_fp ? free_caller_fp_regs : free_caller_int_regs;
auto& free_callee = is_fp ? free_callee_fp_regs : free_callee_int_regs;
PhysicalReg allocated_preg = PhysicalReg::INVALID;
if (current->crosses_call) {
// 跨调用区间:必须使用被调用者保存寄存器
if (!free_callee.empty()) {
allocated_preg = *free_callee.begin();
free_callee.erase(allocated_preg);
}
} else {
// 非跨调用区间:优先使用调用者保存寄存器
if (!free_caller.empty()) {
allocated_preg = *free_caller.begin();
free_caller.erase(allocated_preg);
@ -248,75 +350,73 @@ bool RISCv64LinearScan::linearScan() {
}
if (allocated_preg != PhysicalReg::INVALID) {
if (DEEPDEBUG) std::cerr << " [Scan] Allocated " << pregToString(allocated_preg) << " to %v" << current->vreg << "\n";
vreg_to_preg_map[current->vreg] = allocated_preg;
active.push_back(current);
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
} else {
// c. 没有可用寄存器,需要溢出
if (DEEPDEBUG) std::cerr << " [Scan] No free registers for %v" << current->vreg << ". Spilling...\n";
spillAtInterval(current);
}
}
return !spilled_vregs.empty();
}
void RISCv64LinearScan::chooseRegForInterval(LiveInterval* current) {
bool is_fp = isFPVReg(current->vreg);
auto& free_regs = is_fp ? free_fp_regs : free_int_regs;
if (!free_regs.empty()) {
// 有可用寄存器
PhysicalReg preg = *free_regs.begin();
free_regs.erase(free_regs.begin());
vreg_to_preg_map[current->vreg] = preg;
active.push_back(current);
// 保持 active 列表按结束点排序
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){
return a->end < b->end;
});
} else {
// 没有可用寄存器,需要溢出
spillAtInterval(current);
}
}
void RISCv64LinearScan::spillAtInterval(LiveInterval* current) {
LiveInterval* spill_candidate = nullptr;
// 启发式溢出:
// 如果current需要callee-saved则从active中找一个占用callee-saved且结束最晚的区间比较
// 否则找active中结束最晚的区间
// 这里简化处理总是找active中结束最晚的区间
auto last_active = active.back();
if (!active.empty()) {
spill_candidate = active.back();
}
if (last_active->end > current->end) {
// 溢出active中的区间
spill_candidate = last_active;
if (spill_candidate && spill_candidate->end > current->end) {
if (DEEPDEBUG) std::cerr << " [Spill] Current interval ends at " << current->end << ", active interval %v" << spill_candidate->vreg << " ends at " << spill_candidate->end << ". Spilling active.\n";
PhysicalReg preg = vreg_to_preg_map.at(spill_candidate->vreg);
vreg_to_preg_map[current->vreg] = preg; // 把换出的寄存器给current
// 更新active列表
vreg_to_preg_map[current->vreg] = preg;
active.pop_back();
active.push_back(current);
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
spilled_vregs.insert(spill_candidate->vreg);
} else {
// 溢出当前区间
if (DEEPDEBUG) std::cerr << " [Spill] Current interval %v" << current->vreg << " ends at " << current->end << " which is later than all active intervals. Spilling current.\n";
spilled_vregs.insert(current->vreg);
}
}
// 步骤 3: 重写程序,插入溢出代码
void RISCv64LinearScan::rewriteProgram() {
if (DEBUG) {
std::cerr << "[LSRA-Rewrite] Starting program rewrite. Spilled vregs: " << vregSetToString(spilled_vregs) << "\n";
}
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int spill_offset = frame_info.locals_size; // 溢出区域接在局部变量之后
// 遵循后端流水线设计,在本地变量区域之下为溢出变量分配空间。
// locals_end_offset 是由 EliminateFrameIndices Pass 计算好的局部变量区域的下边界。
// 我们在此基础上,减去已有的溢出区大小,作为新溢出槽的起始点。
int spill_current_offset = frame_info.locals_end_offset - frame_info.spill_size;
for (unsigned vreg : spilled_vregs) {
if (frame_info.spill_offsets.count(vreg)) continue; // 避免重复分配
// 只为本轮新发现的溢出变量分配空间
if (frame_info.spill_offsets.count(vreg)) continue;
int size = isFPVReg(vreg) ? 4 : (vreg_type_map.at(vreg)->isPointer() ? 8 : 4);
spill_offset += size;
spill_offset = (spill_offset + 7) & ~7; // 8字节对齐
frame_info.spill_offsets[vreg] = -(16 + spill_offset);
Type* type = vreg_type_map.count(vreg) ? vreg_type_map.at(vreg) : Type::getIntType();
int size = isFPVReg(vreg) ? 4 : (type->isPointer() ? 8 : 4);
// 在当前偏移基础上继续向下(地址变得更负)分配空间
spill_current_offset -= size;
// 对齐新的、更小的地址RISC-V 要求8字节对齐
spill_current_offset = (spill_current_offset & ~7);
// 将计算出的、不会冲突的正确偏移量存入 spill_offsets
frame_info.spill_offsets[vreg] = spill_current_offset;
if (DEEPDEBUG) std::cerr << " [Rewrite] Assigned stack offset " << frame_info.spill_offsets.at(vreg) << " to spilled %v" << vreg << "\n";
}
frame_info.spill_size = spill_offset - frame_info.locals_size;
// 更新总的溢出区域大小。
// spill_size = -(结束偏移 - 开始偏移)
// 注意locals_end_offset 和 spill_current_offset 都是负数。
frame_info.spill_size = -(spill_current_offset - frame_info.locals_end_offset);
for (auto& mbb : MFunc->getBlocks()) {
auto& instrs = mbb->getInstructions();
@ -327,11 +427,10 @@ void RISCv64LinearScan::rewriteProgram() {
std::set<unsigned> use_vregs, def_vregs;
getInstrUseDef(instr.get(), use_vregs, def_vregs);
// 建立溢出vreg到新临时vreg的映射
std::map<unsigned, unsigned> use_remap;
std::map<unsigned, unsigned> def_remap;
// 1. 为所有溢出的USE创建LOAD指令和映射
// 为每个溢出的 use 操作数创建新vreg并插入 load
for (unsigned old_vreg : use_vregs) {
if (spilled_vregs.count(old_vreg) && use_remap.find(old_vreg) == use_remap.end()) {
Type* type = vreg_type_map.at(old_vreg);
@ -345,11 +444,12 @@ void RISCv64LinearScan::rewriteProgram() {
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))
));
if (DEEPDEBUG) std::cerr << " [Rewrite] Inserting LOAD for use of %v" << old_vreg << " into new %v" << new_temp_vreg << "\n";
new_instrs.push_back(std::move(load));
}
}
// 2. 为所有溢出的DEF创建映射
// 为每个溢出的 def 操作数创建新vreg
for (unsigned old_vreg : def_vregs) {
if (spilled_vregs.count(old_vreg) && def_remap.find(old_vreg) == def_remap.end()) {
Type* type = vreg_type_map.at(old_vreg);
@ -358,10 +458,8 @@ void RISCv64LinearScan::rewriteProgram() {
}
}
// 3. 基于角色精确地替换原指令中的操作数
auto opcode = instr->getOpcode();
auto& operands = instr->getOperands();
auto replace_reg_op = [](RegOperand* reg_op, const std::map<unsigned, unsigned>& remap) {
if (reg_op->isVirtual() && remap.count(reg_op->getVRegNum())) {
reg_op->setVRegNum(remap.at(reg_op->getVRegNum()));
@ -370,13 +468,11 @@ void RISCv64LinearScan::rewriteProgram() {
if (op_info.count(opcode)) {
const auto& info = op_info.at(opcode);
// 替换 Defs
for (int idx : info.first) {
if (idx < operands.size() && operands[idx]->getKind() == MachineOperand::KIND_REG) {
replace_reg_op(static_cast<RegOperand*>(operands[idx].get()), def_remap);
}
}
// 替换 Uses
for (int idx : info.second) {
if (idx < operands.size()) {
if (operands[idx]->getKind() == MachineOperand::KIND_REG) {
@ -387,7 +483,6 @@ void RISCv64LinearScan::rewriteProgram() {
}
}
} else if (opcode == RVOpcodes::CALL) {
// 特殊处理 CALL 指令
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
replace_reg_op(static_cast<RegOperand*>(operands[0].get()), def_remap);
}
@ -398,10 +493,9 @@ void RISCv64LinearScan::rewriteProgram() {
}
}
// 4. 将修改后的指令放入新列表
new_instrs.push_back(std::move(instr));
// 5. 为所有溢出的DEF创建STORE指令
// 为每个溢出的 def 操作数,在原指令后插入 store 指令
for(const auto& pair : def_remap) {
unsigned old_vreg = pair.first;
unsigned new_temp_vreg = pair.second;
@ -413,6 +507,7 @@ void RISCv64LinearScan::rewriteProgram() {
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))
));
if (DEEPDEBUG) std::cerr << " [Rewrite] Inserting STORE for def of %v" << old_vreg << " from new %v" << new_temp_vreg << "\n";
new_instrs.push_back(std::move(store));
}
}
@ -420,24 +515,25 @@ void RISCv64LinearScan::rewriteProgram() {
}
}
// 步骤 4: 应用最终分配结果
void RISCv64LinearScan::applyAllocation() {
if (DEBUG) std::cerr << "[LSRA-Apply] Applying final vreg->preg mapping.\n";
for (auto& mbb : MFunc->getBlocks()) {
if (DEEPDEBUG) std::cerr << " [Apply] In block " << mbb->getName() << ":\n";
for (auto& instr_ptr : mbb->getInstructions()) {
if (DEEPERDEBUG) std::cerr << " [Apply] Instr " << opcodeToString(instr_ptr->getOpcode()) << ": ";
for (auto& op_ptr : instr_ptr->getOperands()) {
if (op_ptr->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (DEEPERDEBUG) std::cerr << "%v" << vreg << " -> ";
if (vreg_to_preg_map.count(vreg)) {
reg_op->setPReg(vreg_to_preg_map.at(vreg));
PhysicalReg preg = vreg_to_preg_map.at(vreg);
reg_op->setPReg(preg);
if (DEEPERDEBUG) std::cerr << pregToString(preg) << ", ";
} else {
// 如果一个vreg最终没有颜色这通常意味着它是一个短生命周期的临时变量
// 在溢出重写中产生,但在下一轮分配前就被优化掉了。
// 或者是一个从未被使用的定义。
// 给他一个临时寄存器以防万一。
reg_op->setPReg(PhysicalReg::T5);
if (DEEPERDEBUG) std::cerr << "T5 (uncolored), ";
}
}
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
@ -445,24 +541,26 @@ void RISCv64LinearScan::applyAllocation() {
auto reg_op = mem_op->getBase();
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (DEEPERDEBUG) std::cerr << "mem[%v" << vreg << "] -> ";
if (vreg_to_preg_map.count(vreg)) {
reg_op->setPReg(vreg_to_preg_map.at(vreg));
PhysicalReg preg = vreg_to_preg_map.at(vreg);
reg_op->setPReg(preg);
if (DEEPERDEBUG) std::cerr << "mem[" << pregToString(preg) << "], ";
} else {
reg_op->setPReg(PhysicalReg::T5);
if (DEEPERDEBUG) std::cerr << "mem[T5] (uncolored), ";
}
}
}
}
if (DEEPERDEBUG) std::cerr << "\n";
}
}
}
void RISCv64LinearScan::getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def) {
// 这个函数与图着色版本中的 getInstrUseDef 逻辑完全相同,此处直接复用
auto opcode = instr->getOpcode();
const auto& operands = instr->getOperands();
// op_info 的定义已被移到函数外部的命名空间中
auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set<unsigned>& s) {
if (op->getKind() == MachineOperand::KIND_REG) {
@ -479,23 +577,17 @@ void RISCv64LinearScan::getInstrUseDef(const MachineInstr* instr, std::set<unsig
const auto& info = op_info.at(opcode);
for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def);
for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use);
// MemOperand 的基址寄存器总是一个 use
for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use);
} else if (opcode == RVOpcodes::CALL) {
// CALL指令的特殊处理
// 第一个操作数如果有是def返回值
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def);
// 后续的寄存器操作数是use参数
for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use);
}
}
// 辅助函数: 判断是否为浮点vreg
bool RISCv64LinearScan::isFPVReg(unsigned vreg) const {
return vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isFloat();
}
// 辅助函数: 收集被使用的被调用者保存寄存器
void RISCv64LinearScan::collectUsedCalleeSavedRegs() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
frame_info.used_callee_saved_regs.clear();
@ -504,7 +596,7 @@ void RISCv64LinearScan::collectUsedCalleeSavedRegs() {
const auto& callee_saved_fp = getCalleeSavedFpRegs();
std::set<PhysicalReg> callee_saved_set(callee_saved_int.begin(), callee_saved_int.end());
callee_saved_set.insert(callee_saved_fp.begin(), callee_saved_fp.end());
callee_saved_set.insert(PhysicalReg::S0); // s0总是被用作帧指针
callee_saved_set.insert(PhysicalReg::S0);
for(const auto& pair : vreg_to_preg_map) {
PhysicalReg preg = pair.second;

View File

@ -1,5 +1,6 @@
#include "RISCv64RegAlloc.h"
#include "RISCv64AsmPrinter.h"
#include "RISCv64Info.h"
#include <algorithm>
#include <iostream>
#include <sstream>
@ -855,53 +856,6 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet
auto opcode = instr->getOpcode();
const auto& operands = instr->getOperands();
// 映射表:指令操作码 -> {Def操作数索引列表, Use操作数索引列表}
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
// ===== 整数算术与逻辑指令 (R-type & I-type) =====
{RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}},
{RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}},
{RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}},
{RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}},
{RVOpcodes::XOR, {{0}, {1, 2}}}, {RVOpcodes::OR, {{0}, {1, 2}}}, {RVOpcodes::AND, {{0}, {1, 2}}},
{RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}},
{RVOpcodes::ORI, {{0}, {1}}}, {RVOpcodes::ANDI, {{0}, {1}}},
{RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}},
// ===== 移位指令 =====
{RVOpcodes::SLL, {{0}, {1, 2}}}, {RVOpcodes::SLLI, {{0}, {1}}},
{RVOpcodes::SLLW, {{0}, {1, 2}}}, {RVOpcodes::SLLIW, {{0}, {1}}},
{RVOpcodes::SRL, {{0}, {1, 2}}}, {RVOpcodes::SRLI, {{0}, {1}}},
{RVOpcodes::SRLW, {{0}, {1, 2}}}, {RVOpcodes::SRLIW, {{0}, {1}}},
{RVOpcodes::SRA, {{0}, {1, 2}}}, {RVOpcodes::SRAI, {{0}, {1}}},
{RVOpcodes::SRAW, {{0}, {1, 2}}}, {RVOpcodes::SRAIW, {{0}, {1}}},
// ===== 内存加载指令 (Def: 0, Use: MemBase) =====
{RVOpcodes::LB, {{0}, {}}}, {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}},
{RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}},
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}},
// ===== 内存存储指令 (Def: None, Use: ValToStore, MemBase) =====
{RVOpcodes::SB, {{}, {0, 1}}}, {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}},
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}},
// ===== 控制流指令 =====
{RVOpcodes::BEQ, {{}, {0, 1}}}, {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}},
{RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::BLTU, {{}, {0, 1}}}, {RVOpcodes::BGEU, {{}, {0, 1}}},
{RVOpcodes::JALR, {{0}, {1}}}, // def: ra (implicit) and op0, use: op1
// ===== 浮点指令 =====
{RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}},
{RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}},
{RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}},
{RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}},
// ===== 伪指令 =====
{RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
{RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}},
{RVOpcodes::NEG, {{0}, {1}}}, {RVOpcodes::NEGW, {{0}, {1}}},
};
// lambda表达式用于获取操作数的寄存器ID虚拟或物理
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned {

View File

@ -0,0 +1,97 @@
#ifndef RISCV64_INFO_H
#define RISCV64_INFO_H
#include "RISCv64LLIR.h"
#include <map>
#include <vector>
namespace sysy {
// 定义一个全局的、权威的指令信息表
// 它包含了指令的定义(def)和使用(use)操作数索引
// defs: {0} -> 第一个操作数是定义
// uses: {1, 2} -> 第二、三个操作数是使用
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
// --- 整数计算 (R-Type) ---
{RVOpcodes::ADD, {{0}, {1, 2}}},
{RVOpcodes::SUB, {{0}, {1, 2}}},
{RVOpcodes::MUL, {{0}, {1, 2}}},
{RVOpcodes::MULH, {{0}, {1, 2}}},
{RVOpcodes::DIV, {{0}, {1, 2}}},
{RVOpcodes::DIVW, {{0}, {1, 2}}},
{RVOpcodes::REM, {{0}, {1, 2}}},
{RVOpcodes::REMW, {{0}, {1, 2}}},
{RVOpcodes::ADDW, {{0}, {1, 2}}},
{RVOpcodes::SUBW, {{0}, {1, 2}}},
{RVOpcodes::MULW, {{0}, {1, 2}}},
{RVOpcodes::SLT, {{0}, {1, 2}}},
{RVOpcodes::SLTU, {{0}, {1, 2}}},
{RVOpcodes::XOR, {{0}, {1, 2}}},
{RVOpcodes::OR, {{0}, {1, 2}}},
{RVOpcodes::AND, {{0}, {1, 2}}},
{RVOpcodes::SLL, {{0}, {1, 2}}},
{RVOpcodes::SRL, {{0}, {1, 2}}},
{RVOpcodes::SRA, {{0}, {1, 2}}},
{RVOpcodes::SLLW, {{0}, {1, 2}}},
{RVOpcodes::SRLW, {{0}, {1, 2}}},
{RVOpcodes::SRAW, {{0}, {1, 2}}},
// --- 整数计算 (I-Type) ---
{RVOpcodes::ADDI, {{0}, {1}}},
{RVOpcodes::ADDIW, {{0}, {1}}},
{RVOpcodes::XORI, {{0}, {1}}},
{RVOpcodes::ORI, {{0}, {1}}},
{RVOpcodes::ANDI, {{0}, {1}}},
{RVOpcodes::SLTI, {{0}, {1}}},
{RVOpcodes::SLTIU, {{0}, {1}}},
{RVOpcodes::SLLI, {{0}, {1}}},
{RVOpcodes::SLLIW, {{0}, {1}}},
{RVOpcodes::SRLI, {{0}, {1}}},
{RVOpcodes::SRLIW, {{0}, {1}}},
{RVOpcodes::SRAI, {{0}, {1}}},
{RVOpcodes::SRAIW, {{0}, {1}}},
// --- 内存加载 ---
{RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LB, {{0}, {}}},
{RVOpcodes::LWU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LBU, {{0}, {}}},
{RVOpcodes::LD, {{0}, {}}},
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}},
// --- 内存存储 ---
{RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SB, {{}, {0, 1}}},
{RVOpcodes::SD, {{}, {0, 1}}},
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}},
// --- 分支指令 ---
{RVOpcodes::BEQ, {{}, {0, 1}}}, {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}},
{RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::BLTU, {{}, {0, 1}}}, {RVOpcodes::BGEU, {{}, {0, 1}}},
// --- 跳转 ---
{RVOpcodes::JAL, {{0}, {}}}, // JAL的rd是def但通常用x0表示不关心返回值这里简化
{RVOpcodes::JALR, {{0}, {1}}},
{RVOpcodes::RET, {{}, {}}}, // RET是伪指令通常展开为JALR
// --- 伪指令 & 其他 ---
{RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
{RVOpcodes::MV, {{0}, {1}}},
{RVOpcodes::NEG, {{0}, {1}}}, // sub rd, zero, rs1
{RVOpcodes::NEGW, {{0}, {1}}}, // subw rd, zero, rs1
{RVOpcodes::SEQZ, {{0}, {1}}},
{RVOpcodes::SNEZ, {{0}, {1}}},
// --- 函数调用 ---
// CALL的use/def在getInstrUseDef中有特殊处理逻辑这里可以不列出
// --- 浮点指令 ---
{RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}},
{RVOpcodes::FEQ_S, {{0}, {1, 2}}}, {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}},
{RVOpcodes::FCVT_S_W, {{0}, {1}}}, {RVOpcodes::FCVT_W_S, {{0}, {1}}},
{RVOpcodes::FCVT_W_S_RTZ, {{0}, {1}}},
{RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, {RVOpcodes::FMV_X_W, {{0}, {1}}},
{RVOpcodes::FNEG_S, {{0}, {1}}}
};
} // namespace sysy
#endif // RISCV64_INFO_H

View File

@ -77,28 +77,6 @@ private:
const std::map<unsigned, Type*>& vreg_type_map;
};
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
{RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}},
{RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}},
{RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}},
{RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}},
{RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}},
{RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}}, {RVOpcodes::LB, {{0}, {}}},
{RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}},
{RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}},
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}}, {RVOpcodes::SB, {{}, {0, 1}}},
{RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}},
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}}, {RVOpcodes::BEQ, {{}, {0, 1}}},
{RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}}, {RVOpcodes::BGE, {{}, {0, 1}}},
{RVOpcodes::JALR, {{0}, {1}}}, {RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
{RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}},
{RVOpcodes::RET, {{}, {}}}, {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}},
{RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}},
{RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}},
{RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}}
};
} // namespace sysy
#endif // RISCV64_LINEARSCAN_H