|
|
|
|
@ -1,101 +1,256 @@
|
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
PROJECT_ROOT=$(cd "$(dirname "$0")/.." ; pwd)
|
|
|
|
|
|
|
|
|
|
if [[ $# -lt 1 || $# -gt 3 ]]; then
|
|
|
|
|
echo "用法: $0 <input.sy> [output_dir] [--run]" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
input=$1
|
|
|
|
|
out_dir="test/test_result/riscv_asm"
|
|
|
|
|
run_exec=false
|
|
|
|
|
input_dir=$(dirname "$input")
|
|
|
|
|
|
|
|
|
|
shift
|
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--run)
|
|
|
|
|
run_exec=true
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
out_dir="$1"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
shift
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
if [[ ! -f "$input" ]]; then
|
|
|
|
|
echo "输入文件不存在: $input" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
compiler="$PROJECT_ROOT/build/bin/compiler"
|
|
|
|
|
if [[ ! -x "$compiler" ]]; then
|
|
|
|
|
echo "未找到编译器: $compiler ,请先构建。" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! command -v riscv64-linux-gnu-gcc >/dev/null 2>&1; then
|
|
|
|
|
echo "未找到 riscv64-linux-gnu-gcc,无法汇编/链接。" >&2
|
|
|
|
|
echo "请安装: sudo apt install gcc-riscv64-linux-gnu" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
mkdir -p "$out_dir"
|
|
|
|
|
base=$(basename "$input")
|
|
|
|
|
stem=${base%.sy}
|
|
|
|
|
asm_file="$out_dir/$stem.s"
|
|
|
|
|
exe="$out_dir/$stem"
|
|
|
|
|
stdin_file="$input_dir/$stem.in"
|
|
|
|
|
expected_file="$input_dir/$stem.out"
|
|
|
|
|
|
|
|
|
|
"$compiler" --emit-asm "$input" 2>/dev/null > "$asm_file"
|
|
|
|
|
echo "汇编已生成: $asm_file"
|
|
|
|
|
|
|
|
|
|
# 使用静态链接避免动态链接器问题
|
|
|
|
|
riscv64-linux-gnu-gcc -static "$asm_file" -o "$exe" -no-pie
|
|
|
|
|
echo "可执行文件已生成: $exe"
|
|
|
|
|
|
|
|
|
|
if [[ "$run_exec" == true ]]; then
|
|
|
|
|
if ! command -v qemu-riscv64 >/dev/null 2>&1; then
|
|
|
|
|
echo "未找到 qemu-riscv64,无法运行生成的可执行文件。" >&2
|
|
|
|
|
echo "请安装: sudo apt install qemu-user" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
stdout_file="$out_dir/$stem.stdout"
|
|
|
|
|
actual_file="$out_dir/$stem.actual.out"
|
|
|
|
|
echo "运行 $exe ..."
|
|
|
|
|
set +e
|
|
|
|
|
if [[ -f "$stdin_file" ]]; then
|
|
|
|
|
qemu-riscv64 "$exe" < "$stdin_file" > "$stdout_file"
|
|
|
|
|
else
|
|
|
|
|
qemu-riscv64 "$exe" > "$stdout_file"
|
|
|
|
|
fi
|
|
|
|
|
status=$?
|
|
|
|
|
set -e
|
|
|
|
|
cat "$stdout_file"
|
|
|
|
|
echo "退出码: $status"
|
|
|
|
|
{
|
|
|
|
|
cat "$stdout_file"
|
|
|
|
|
if [[ -s "$stdout_file" ]] && (( $(tail -c 1 "$stdout_file" | wc -l) == 0 )); then
|
|
|
|
|
printf '\n'
|
|
|
|
|
fi
|
|
|
|
|
printf '%s\n' "$status"
|
|
|
|
|
} > "$actual_file"
|
|
|
|
|
|
|
|
|
|
if [[ -f "$expected_file" ]]; then
|
|
|
|
|
if diff -u "$expected_file" "$actual_file"; then
|
|
|
|
|
echo "输出匹配: $expected_file"
|
|
|
|
|
else
|
|
|
|
|
echo "输出不匹配: $expected_file" >&2
|
|
|
|
|
echo "实际输出已保存: $actual_file" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
else
|
|
|
|
|
echo "未找到预期输出文件,跳过比对: $expected_file"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <initializer_list>
|
|
|
|
|
#include <iosfwd>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
namespace ir {
|
|
|
|
|
class Module;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace mir {
|
|
|
|
|
|
|
|
|
|
class MIRContext {
|
|
|
|
|
public:
|
|
|
|
|
MIRContext() = default;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
MIRContext& DefaultContext();
|
|
|
|
|
|
|
|
|
|
// RISC-V 64位寄存器定义
|
|
|
|
|
enum class PhysReg {
|
|
|
|
|
// 通用寄存器
|
|
|
|
|
ZERO, // x0, 恒为0
|
|
|
|
|
RA, // x1, 返回地址
|
|
|
|
|
SP, // x2, 栈指针
|
|
|
|
|
GP, // x3, 全局指针
|
|
|
|
|
TP, // x4, 线程指针
|
|
|
|
|
T0, // x5, 临时寄存器
|
|
|
|
|
T1, // x6, 临时寄存器
|
|
|
|
|
T2, // x7, 临时寄存器
|
|
|
|
|
S0, // x8, 帧指针/保存寄存器
|
|
|
|
|
S1, // x9, 保存寄存器
|
|
|
|
|
A0, // x10, 参数/返回值
|
|
|
|
|
A1, // x11, 参数
|
|
|
|
|
A2, // x12, 参数
|
|
|
|
|
A3, // x13, 参数
|
|
|
|
|
A4, // x14, 参数
|
|
|
|
|
A5, // x15, 参数
|
|
|
|
|
A6, // x16, 参数
|
|
|
|
|
A7, // x17, 参数
|
|
|
|
|
S2, // x18, 保存寄存器
|
|
|
|
|
S3, // x19, 保存寄存器
|
|
|
|
|
S4, // x20, 保存寄存器
|
|
|
|
|
S5, // x21, 保存寄存器
|
|
|
|
|
S6, // x22, 保存寄存器
|
|
|
|
|
S7, // x23, 保存寄存器
|
|
|
|
|
S8, // x24, 保存寄存器
|
|
|
|
|
S9, // x25, 保存寄存器
|
|
|
|
|
S10, // x26, 保存寄存器
|
|
|
|
|
S11, // x27, 保存寄存器
|
|
|
|
|
T3, // x28, 临时寄存器
|
|
|
|
|
T4, // x29, 临时寄存器
|
|
|
|
|
T5, // x30, 临时寄存器
|
|
|
|
|
T6, // x31, 临时寄存器
|
|
|
|
|
FT0, FT1, FT2, FT3, FT4, FT5, FT6, FT7,
|
|
|
|
|
FS0, FS1,
|
|
|
|
|
FA0, FA1, FA2, FA3, FA4, FA5, FA6, FA7,
|
|
|
|
|
FT8, FT9, FT10, FT11,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char* PhysRegName(PhysReg reg);
|
|
|
|
|
|
|
|
|
|
// 在 MIR.h 中添加(在 Opcode 枚举之前)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct GlobalVarInfo {
|
|
|
|
|
std::string name;
|
|
|
|
|
int value;
|
|
|
|
|
float valueF;
|
|
|
|
|
bool isConst;
|
|
|
|
|
bool isArray;
|
|
|
|
|
bool isFloat;
|
|
|
|
|
std::vector<int> arrayValues;
|
|
|
|
|
std::vector<float> arrayValuesF;
|
|
|
|
|
int arraySize;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class Opcode {
|
|
|
|
|
Prologue,
|
|
|
|
|
Epilogue,
|
|
|
|
|
MovImm,
|
|
|
|
|
Load,
|
|
|
|
|
Store,
|
|
|
|
|
Add,
|
|
|
|
|
Addi,
|
|
|
|
|
Sub,
|
|
|
|
|
Mul,
|
|
|
|
|
Div,
|
|
|
|
|
Rem,
|
|
|
|
|
Slt,
|
|
|
|
|
Slti,
|
|
|
|
|
Slli,
|
|
|
|
|
Sltu, // 无符号小于
|
|
|
|
|
Xori,
|
|
|
|
|
LoadGlobalAddr,
|
|
|
|
|
LoadGlobal,
|
|
|
|
|
StoreGlobal,
|
|
|
|
|
LoadIndirect, // lw rd, 0(rs1) 从寄存器地址加载
|
|
|
|
|
StoreIndirect, // sw rs2, 0(rs1)
|
|
|
|
|
Call,
|
|
|
|
|
GEP,
|
|
|
|
|
LoadAddr,
|
|
|
|
|
Ret,
|
|
|
|
|
// 浮点指令
|
|
|
|
|
FMov, // 浮点移动
|
|
|
|
|
FMovWX, // fmv.w.x fs, x 整数寄存器移动到浮点寄存器
|
|
|
|
|
FMovXW, // fmv.x.w x, fs 浮点寄存器移动到整数寄存器
|
|
|
|
|
FAdd,
|
|
|
|
|
FSub,
|
|
|
|
|
FMul,
|
|
|
|
|
FDiv,
|
|
|
|
|
FEq, // 浮点相等比较
|
|
|
|
|
FLt, // 浮点小于比较
|
|
|
|
|
FLe, // 浮点小于等于比较
|
|
|
|
|
FNeg, // 浮点取反
|
|
|
|
|
FAbs, // 浮点绝对值
|
|
|
|
|
SIToFP, // int 转 float
|
|
|
|
|
FPToSI, // float 转 int
|
|
|
|
|
LoadFloat, // 浮点加载 (flw)
|
|
|
|
|
StoreFloat, // 浮点存储 (fsw)
|
|
|
|
|
Br,
|
|
|
|
|
CondBr,
|
|
|
|
|
Label,
|
|
|
|
|
Srli,
|
|
|
|
|
Srai,
|
|
|
|
|
Srl,
|
|
|
|
|
Sra,
|
|
|
|
|
And,
|
|
|
|
|
Andi,
|
|
|
|
|
Or,
|
|
|
|
|
Ori,
|
|
|
|
|
Xor,
|
|
|
|
|
FNeg,
|
|
|
|
|
FAbs
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class GlobalKind {
|
|
|
|
|
Data, // .data 段(已初始化)
|
|
|
|
|
BSS, // .bss 段(未初始化,初始为0)
|
|
|
|
|
RoData // .rodata 段(只读常量)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 全局变量信息
|
|
|
|
|
struct GlobalInfo {
|
|
|
|
|
std::string name;
|
|
|
|
|
GlobalKind kind;
|
|
|
|
|
int size; // 大小(字节)
|
|
|
|
|
int value; // 初始值(对于简单变量)
|
|
|
|
|
bool isArray;
|
|
|
|
|
int arraySize;
|
|
|
|
|
|
|
|
|
|
std::vector<int> dimensions; // 数组维度
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Operand {
|
|
|
|
|
public:
|
|
|
|
|
enum class Kind { Reg, Imm, FrameIndex, Global, Func };
|
|
|
|
|
|
|
|
|
|
static Operand Reg(PhysReg reg);
|
|
|
|
|
static Operand Imm(int value);
|
|
|
|
|
static Operand Imm64(int64_t value); // 新增:存储 64 位值
|
|
|
|
|
static Operand FrameIndex(int index);
|
|
|
|
|
static Operand Global(const std::string& name);
|
|
|
|
|
static Operand Func(const std::string& name);
|
|
|
|
|
|
|
|
|
|
Kind GetKind() const { return kind_; }
|
|
|
|
|
PhysReg GetReg() const { return reg_; }
|
|
|
|
|
int GetImm() const { return imm_; }
|
|
|
|
|
int64_t GetImm64() const { return imm64_; } // 新增
|
|
|
|
|
int GetFrameIndex() const { return imm_; }
|
|
|
|
|
const std::string& GetGlobalName() const { return global_name_; }
|
|
|
|
|
const std::string& GetFuncName() const { return func_name_; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Operand(Kind kind, PhysReg reg, int imm);
|
|
|
|
|
Operand(Kind kind, PhysReg reg, int64_t imm64); // 新增构造函数
|
|
|
|
|
Operand(Kind kind, PhysReg reg, int imm, const std::string& name);
|
|
|
|
|
|
|
|
|
|
Kind kind_;
|
|
|
|
|
PhysReg reg_;
|
|
|
|
|
int imm_;
|
|
|
|
|
int64_t imm64_; // 新增
|
|
|
|
|
std::string global_name_;
|
|
|
|
|
std::string func_name_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class MachineInstr {
|
|
|
|
|
public:
|
|
|
|
|
MachineInstr(Opcode opcode, std::vector<Operand> operands = {});
|
|
|
|
|
|
|
|
|
|
Opcode GetOpcode() const { return opcode_; }
|
|
|
|
|
const std::vector<Operand>& GetOperands() const { return operands_; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Opcode opcode_;
|
|
|
|
|
std::vector<Operand> operands_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct FrameSlot {
|
|
|
|
|
int index = 0;
|
|
|
|
|
int size = 4;
|
|
|
|
|
int offset = 0;
|
|
|
|
|
};
|
|
|
|
|
class MachineBasicBlock {
|
|
|
|
|
public:
|
|
|
|
|
explicit MachineBasicBlock(std::string name);
|
|
|
|
|
|
|
|
|
|
const std::string& GetName() const { return name_; }
|
|
|
|
|
std::vector<MachineInstr>& GetInstructions() { return instructions_; }
|
|
|
|
|
const std::vector<MachineInstr>& GetInstructions() const { return instructions_; }
|
|
|
|
|
|
|
|
|
|
MachineInstr& Append(Opcode opcode,
|
|
|
|
|
std::initializer_list<Operand> operands = {});
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::string name_;
|
|
|
|
|
std::vector<MachineInstr> instructions_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class MachineFunction {
|
|
|
|
|
public:
|
|
|
|
|
explicit MachineFunction(std::string name);
|
|
|
|
|
|
|
|
|
|
const std::string& GetName() const { return name_; }
|
|
|
|
|
|
|
|
|
|
// 基本块管理
|
|
|
|
|
MachineBasicBlock* CreateBlock(const std::string& name);
|
|
|
|
|
MachineBasicBlock* GetEntry() { return entry_; }
|
|
|
|
|
const MachineBasicBlock* GetEntry() const { return entry_; }
|
|
|
|
|
const std::vector<std::unique_ptr<MachineBasicBlock>>& GetBlocks() const { return blocks_; }
|
|
|
|
|
|
|
|
|
|
// 栈帧管理
|
|
|
|
|
int CreateFrameIndex(int size = 4);
|
|
|
|
|
FrameSlot& GetFrameSlot(int index);
|
|
|
|
|
const FrameSlot& GetFrameSlot(int index) const;
|
|
|
|
|
const std::vector<FrameSlot>& GetFrameSlots() const { return frame_slots_; }
|
|
|
|
|
|
|
|
|
|
int GetFrameSize() const { return frame_size_; }
|
|
|
|
|
void SetFrameSize(int size) { frame_size_ = size; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::string name_;
|
|
|
|
|
MachineBasicBlock* entry_ = nullptr;
|
|
|
|
|
std::vector<std::unique_ptr<MachineBasicBlock>> blocks_;
|
|
|
|
|
std::vector<FrameSlot> frame_slots_;
|
|
|
|
|
int frame_size_ = 0;
|
|
|
|
|
};
|
|
|
|
|
//std::unique_ptr<MachineFunction> LowerToMIR(const ir::Module& module);
|
|
|
|
|
void RunRegAlloc(MachineFunction& function);
|
|
|
|
|
void RunFrameLowering(MachineFunction& function);
|
|
|
|
|
//void PrintAsm(const MachineFunction& function, std::ostream& os);
|
|
|
|
|
std::vector<std::unique_ptr<MachineFunction>> LowerToMIR(const ir::Module& module);
|
|
|
|
|
void PrintAsm(const std::vector<std::unique_ptr<MachineFunction>>& functions, std::ostream& os);
|
|
|
|
|
} // namespace mir
|