中间代码生成

mirror 1 week ago
parent 17bcbd7b7b
commit d9085935f2

@ -26,7 +26,6 @@ target_include_directories(build_options INTERFACE
"${ANTLR4_GENERATED_DIR}"
# 使 -Xexact-output-dir ANTLR
"${ANTLR4_GENERATED_DIR}/src/antlr4"
"${PROJECT_SOURCE_DIR}/src/antlr4"
)
option(COMPILER_ENABLE_WARNINGS "Enable common compiler warnings" ON)

@ -0,0 +1,59 @@
# 测试结果总结
## 功能测试 (Functional Tests): 10/11 通过 (90.9%)
### ✓ 通过的测试 (10个):
1. 05_arr_defn4 - 数组定义和初始化
2. 09_func_defn - 函数定义
3. 11_add2 - 加法运算
4. 13_sub2 - 减法运算
5. 15_graph_coloring - 图着色算法 (使用2D数组和指针参数)
6. 22_matrix_multiply - 矩阵乘法 (2D数组)
7. 25_scope3 - 作用域测试
8. 29_break - break语句
9. 36_op_priority2 - 运算符优先级
10. simple_add - 简单加法
### ✗ 失败的测试 (1个):
- 95_float - **需要浮点数常量支持** (当前仅支持int)
## 性能测试 (Performance Tests): 8/10 编译成功 (80%)
### ✓ 编译成功 (8个):
1. 01_mm2 - 矩阵乘法 (已验证输出正确: 1691748973)
2. 02_mv3 - 矩阵向量乘法
3. 03_sort1 - 排序算法
4. 2025-MYO-20 - 综合测试
5. fft0 - 快速傅里叶变换
6. gameoflife-oscillator - 生命游戏
7. if-combine3 - 条件分支优化
8. transpose0 - 矩阵转置
### ✗ 编译失败 (2个):
- large_loop_array_2 - **需要float返回类型支持**
- vector_mul3 - **需要float变量支持**
## 总体成绩
- **总计**: 18/21 测试通过/编译成功 (85.7%)
- **整数支持**: 完整 (所有整数相关测试100%通过)
- **浮点支持**: 未实现 (3个浮点测试全部失败)
## 已实现功能
✓ 基本运算 (加减乘除、取模、比较、逻辑运算)
✓ 控制流 (if/else, while, break, continue)
✓ 函数调用 (参数传递、返回值)
✓ 数组支持 (1D/2D数组、全局/局部数组)
✓ 指针参数传递 (函数接收数组指针)
✓ GEP指令 (数组元素地址计算)
✓ AArch64代码生成 (完整的汇编输出)
## 未实现功能
✗ 浮点数类型 (float/double)
✗ 浮点运算
✗ 浮点常量
## 关键修复
1. **GEP指令实现** - 支持全局数组、局部数组、指针参数的元素访问
2. **指针参数传递** - 区分数组地址传递和指针值加载
3. **2D数组支持** - 完整的多维数组线性化和访问
4. **栈帧管理** - 正确的栈偏移计算和指针存储

@ -19,9 +19,11 @@ find test/test_case -name '*.sy' | sort | while read f; do ./build/bin/compiler
1. 每次开始前先同步主干
```bash
git switch master
git fetch origin
git pull --ff-only origin master
git stash
git checkout master
git pull origin master
git checkout Shrink
git rebase master
```
2. 从最新 master 拉功能分支开发

@ -53,8 +53,11 @@ cmake --build build -j "$(nproc)"
推荐使用统一脚本验证 “源码 -> 汇编 -> 可执行程序” 整体链路。`--run` 模式下会自动读取同名 `.in`,并将程序输出与退出码和同名 `.out` 比对,用于验证后端代码生成的正确性:
```bash
./scripts/verify_asm.sh test/test_case/functional/simple_add.sy test/test_result/function/asm --run
./scripts/verify_asm.sh test/test_case/performance/vector_mul3.sy test/test_result/performance/asm --run
```
for test_file in test/test_case/performance/*.sy; do if [ -f "$test_file" ]; then echo "正在测试: $test_file"; scripts/verify_asm.sh "$test_file" "test/test_result/performance/asm" --run; fi; done
若最终输出 `输出匹配: test/test_case/simple_add.out`,说明当前示例用例 `return a + b` 的完整后端链路已经跑通。
但最终不能只检查 `simple_add`。完成 Lab3 后,应对 `test/test_case` 下全部测试用例逐个回归,确认代码生成结果能够通过统一验证;如有需要,也可以自行编写批量测试脚本统一执行。

@ -45,6 +45,7 @@ class Value;
class User;
class ConstantValue;
class ConstantInt;
class ConstantFloat;
class GlobalValue;
class Instruction;
class BasicBlock;
@ -83,17 +84,20 @@ class Context {
~Context();
// 去重创建 i32 常量。
ConstantInt* GetConstInt(int v);
// 去重创建 float 常量。
ConstantFloat* GetConstFloat(float v);
std::string NextTemp();
private:
std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_;
std::unordered_map<float, std::unique_ptr<ConstantFloat>> const_floats_;
int temp_index_ = -1;
};
class Type {
public:
enum class Kind { Void, Int32, PtrInt32 };
enum class Kind { Void, Int32, PtrInt32, Float32, PtrFloat32 };
explicit Type(Kind k);
// 使用静态共享对象获取类型。
// 同一类型可直接比较返回值是否相等,例如:
@ -101,10 +105,14 @@ class Type {
static const std::shared_ptr<Type>& GetVoidType();
static const std::shared_ptr<Type>& GetInt32Type();
static const std::shared_ptr<Type>& GetPtrInt32Type();
static const std::shared_ptr<Type>& GetFloat32Type();
static const std::shared_ptr<Type>& GetPtrFloat32Type();
Kind GetKind() const;
bool IsVoid() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsFloat32() const;
bool IsPtrFloat32() const;
private:
Kind kind_;
@ -120,6 +128,8 @@ class Value {
bool IsVoid() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsFloat32() const;
bool IsPtrFloat32() const;
bool IsConstant() const;
bool IsInstruction() const;
bool IsUser() const;
@ -151,6 +161,15 @@ class ConstantInt : public ConstantValue {
int value_{};
};
class ConstantFloat : public ConstantValue {
public:
ConstantFloat(std::shared_ptr<Type> ty, float v);
float GetValue() const { return value_; }
private:
float value_{};
};
// Argument 表示函数的形式参数,作为 Value 在函数体内直接被引用。
class Argument : public Value {
public:
@ -169,6 +188,7 @@ enum class Opcode {
Div,
Mod,
Cmp,
Cast,
Br,
CondBr,
Call,
@ -180,6 +200,7 @@ enum class Opcode {
};
enum class CmpOp { Eq, Ne, Lt, Le, Gt, Ge };
enum class CastOp { IntToFloat, FloatToInt };
// User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
// 当前实现中只有 Instruction 继承自 User。
@ -210,14 +231,19 @@ class GlobalValue : public User {
// 数组:打印为 @name = global [count x i32] zeroinitializer。
class GlobalVariable : public GlobalValue {
public:
GlobalVariable(std::string name, int init_val = 0, int count = 1);
GlobalVariable(std::string name, std::shared_ptr<Type> ptr_ty,
int init_val = 0, int count = 1,
std::vector<int> init_elems = {});
int GetInitValue() const { return init_val_; }
int GetCount() const { return count_; }
bool IsArray() const { return count_ > 1; }
bool IsFloat() const { return GetType() && GetType()->IsPtrFloat32(); }
const std::vector<int>& GetInitElements() const { return init_elems_; }
private:
int init_val_;
int count_;
std::vector<int> init_elems_;
};
class Instruction : public User {
@ -253,6 +279,16 @@ class CmpInst : public Instruction {
CmpOp cmp_op_;
};
class CastInst : public Instruction {
public:
CastInst(CastOp op, std::shared_ptr<Type> ty, Value* val, std::string name);
CastOp GetCastOp() const;
Value* GetValue() const;
private:
CastOp cast_op_;
};
class ReturnInst : public Instruction {
public:
ReturnInst(std::shared_ptr<Type> void_ty, Value* val);
@ -391,7 +427,10 @@ class Module {
Function* FindFunction(const std::string& name) const;
const std::vector<std::unique_ptr<Function>>& GetFunctions() const;
GlobalVariable* CreateGlobalVar(const std::string& name, int init_val = 0, int count = 1);
GlobalVariable* CreateGlobalVar(const std::string& name, int init_val = 0,
int count = 1,
std::shared_ptr<Type> ptr_ty = Type::GetPtrInt32Type(),
std::vector<int> init_elems = {});
GlobalVariable* FindGlobalVar(const std::string& name) const;
const std::vector<std::unique_ptr<GlobalVariable>>& GetGlobalVars() const;
@ -417,8 +456,12 @@ class IRBuilder {
BinaryInst* CreateDiv(Value* lhs, Value* rhs, const std::string& name);
BinaryInst* CreateMod(Value* lhs, Value* rhs, const std::string& name);
CmpInst* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name);
CastInst* CreateSIToFP(Value* v, const std::string& name);
CastInst* CreateFPToSI(Value* v, const std::string& name);
AllocaInst* CreateAllocaI32(const std::string& name);
AllocaInst* CreateAllocaArray(int count, const std::string& name);
AllocaInst* CreateAllocaF32(const std::string& name);
AllocaInst* CreateAllocaF32Array(int count, const std::string& name);
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
BranchInst* CreateBr(BasicBlock* target);

@ -25,6 +25,8 @@ class IRGenImpl final : public SysYBaseVisitor {
public:
// const 变量名 -> 编译期整数值,用于数组维度折叠。
using ConstEnv = std::unordered_map<std::string, int>;
// const 变量名 -> 编译期浮点值,用于 float const 折叠。
using ConstFloatEnv = std::unordered_map<std::string, float>;
IRGenImpl(ir::Module& module, const SemanticContext& sema);
@ -81,8 +83,12 @@ class IRGenImpl final : public SysYBaseVisitor {
// 编译期常量整数求值(用于数组维度)。
int EvalConstExpr(SysYParser::ConstExpContext* ctx) const;
// 编译期常量浮点求值(用于 float const
float EvalConstExprAsFloat(SysYParser::ConstExpContext* ctx) const;
// 将 ExpContext即 addExp按编译期常量求值用于 funcFParam 维度)。
int EvalExpAsConst(SysYParser::ExpContext* ctx) const;
// 将 ExpContext 按编译期常量浮点求值(用于 float 全局初始化等)。
float EvalExpAsConstFloat(SysYParser::ExpContext* ctx) const;
// 查找变量的数组维度(先查局部,再查全局)。
const std::vector<int>* FindArrayDims(const std::string& name) const;
@ -91,23 +97,41 @@ class IRGenImpl final : public SysYBaseVisitor {
ir::Value* ComputeLinearIndex(const std::vector<int>& dims,
const std::vector<SysYParser::ExpContext*>& subs);
// 简单隐式类型转换i32 <-> float。
ir::Value* CastToFloat(ir::Value* v);
ir::Value* CastToInt(ir::Value* v);
// 扁平化 constInitValue 到整数数组(供 const 数组初始化使用)。
void FlattenConstInit(SysYParser::ConstInitValueContext* ctx,
const std::vector<int>& dims, int dim_idx,
std::vector<int>& out, int& pos);
void FlattenConstInitFloat(SysYParser::ConstInitValueContext* ctx,
const std::vector<int>& dims, int dim_idx,
std::vector<float>& out, int& pos);
// 扁平化 initValue 到 ir::Value* 数组(供普通数组初始化使用)。
void FlattenInit(SysYParser::InitValueContext* ctx,
const std::vector<int>& dims, int dim_idx,
std::vector<ir::Value*>& out, int& pos);
void FlattenGlobalInitInt(SysYParser::InitValueContext* ctx,
const std::vector<int>& dims, int dim_idx,
std::vector<int>& out, int& pos);
void FlattenGlobalInitFloat(SysYParser::InitValueContext* ctx,
const std::vector<int>& dims, int dim_idx,
std::vector<float>& out, int& pos);
ir::AllocaInst* CreateEntryAllocaI32(const std::string& name);
ir::AllocaInst* CreateEntryAllocaArray(int count, const std::string& name);
// 创建float类型alloca
ir::AllocaInst* CreateEntryAllocaF32(const std::string& name);
ir::AllocaInst* CreateEntryAllocaF32Array(int count, const std::string& name);
ir::Module& module_;
const SemanticContext& sema_;
ir::Function* func_;
ir::IRBuilder builder_;
// 当前正在处理的变量声明类型用于varDecl/constDecl中传递类型信息
std::shared_ptr<ir::Type> current_decl_type_;
// 声明 -> 存储槽位(局部 alloca 或全局变量,均为 i32*)。
std::unordered_map<SysYParser::VarDefContext*, ir::Value*> storage_map_;
// 名称 -> 槽位参数、const 变量等不经 sema binding 的后备查找)。
@ -116,6 +140,8 @@ class IRGenImpl final : public SysYBaseVisitor {
std::unordered_map<std::string, ir::Value*> global_storage_;
// 编译期 const 整数环境(全局 + 当前函数)。
ConstEnv const_env_;
// 编译期 const 浮点环境(全局 + 当前函数)。
ConstFloatEnv const_float_env_;
// 数组维度信息:全局数组(跨函数持久)。
std::unordered_map<std::string, std::vector<int>> global_array_dims_;
// 数组维度信息:局部数组/参数(每函数清空)。

@ -19,7 +19,14 @@ class MIRContext {
MIRContext& DefaultContext();
enum class PhysReg { W0, W8, W9, X29, X30, SP };
enum class PhysReg {
W0, W1, W2, W3, W4, W5, W6, W7,
W8, W9, W10, W11,
X0, X1, X2, X3, X4, X5, X6, X7,
X8, X9, X10, X11, X29, X30, SP,
S0, S1, S2, S3, S4, S5, S6, S7, // 单精度浮点寄存器
S8, S9, S10
};
const char* PhysRegName(PhysReg reg);
@ -27,31 +34,71 @@ enum class Opcode {
Prologue,
Epilogue,
MovImm,
MovReg,
FMovImm, // 浮点立即数加载
FMovReg, // 浮点寄存器移动
LoadStack,
StoreStack,
LoadStackOffset, // 加载数组元素ldr w8, [x29, base_offset + element_offset]
StoreStackOffset, // 存储数组元素str w8, [x29, base_offset + element_offset]
LoadStackAddr, // 加载栈地址add x9, x29, #offset用于数组基址
LoadIndirect, // 间接加载ldr w8, [x9]
StoreIndirect, // 间接存储str w8, [x9]
LoadGlobal,
StoreGlobal,
LoadGlobalAddr, // 加载全局变量地址(用于数组)
AddRI,
SubRI,
AddRR,
SubRR,
MulRR,
DivRR,
ModRR,
LsrRI,
LslRI,
LslRR, // 逻辑左移(用于 index * 4
FAddRR, // 浮点加法
FSubRR, // 浮点减法
FMulRR, // 浮点乘法
FDivRR, // 浮点除法
FSqrtRR, // 浮点平方根
SIToFP, // 有符号整型转浮点
FPToSI, // 浮点转有符号整型
CmpOnlyRR,
FCmpOnlyRR,
CmpRR,
FCmpRR, // 浮点比较
Bl,
B, // 无条件跳转
Bcond, // 条件跳转(基于之前的 cmp
FBcond, // 浮点条件跳转(基于之前的 fcmp使用 IEEE 754 兼容的条件码)
Cbnz, // 非零跳转
Cbz, // 零跳转
Ret,
};
class Operand {
public:
enum class Kind { Reg, Imm, FrameIndex };
enum class Kind { Reg, Imm, FrameIndex, Symbol };
static Operand Reg(PhysReg reg);
static Operand Imm(int value);
static Operand FrameIndex(int index);
static Operand Symbol(std::string name);
Kind GetKind() const { return kind_; }
PhysReg GetReg() const { return reg_; }
int GetImm() const { return imm_; }
int GetFrameIndex() const { return imm_; }
const std::string& GetSymbol() const { return symbol_; }
private:
Operand(Kind kind, PhysReg reg, int imm);
Operand(Kind kind, PhysReg reg, int imm, std::string symbol = "");
Kind kind_;
PhysReg reg_;
int imm_;
std::string symbol_;
};
class MachineInstr {
@ -93,8 +140,14 @@ class MachineFunction {
explicit MachineFunction(std::string name);
const std::string& GetName() const { return name_; }
MachineBasicBlock& GetEntry() { return entry_; }
const MachineBasicBlock& GetEntry() const { return entry_; }
MachineBasicBlock& GetEntry() { return *blocks_.front(); }
const MachineBasicBlock& GetEntry() const { return *blocks_.front(); }
MachineBasicBlock* CreateBlock(std::string name);
MachineBasicBlock* FindBlock(const std::string& name);
const std::vector<std::unique_ptr<MachineBasicBlock>>& GetBlocks() const {
return blocks_;
}
int CreateFrameIndex(int size = 4);
FrameSlot& GetFrameSlot(int index);
@ -106,14 +159,36 @@ class MachineFunction {
private:
std::string name_;
MachineBasicBlock entry_;
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);
class MachineModule {
public:
MachineModule() = default;
MachineFunction* CreateFunction(std::string name);
const std::vector<std::unique_ptr<MachineFunction>>& GetFunctions() const {
return functions_;
}
void AddGlobalVar(std::string name, int init_val, int count, bool is_float,
std::vector<int> init_elems = {});
const std::vector<std::tuple<std::string, int, int, bool, std::vector<int>>>&
GetGlobalVars() const {
return global_vars_;
}
private:
std::vector<std::unique_ptr<MachineFunction>> functions_;
std::vector<std::tuple<std::string, int, int, bool, std::vector<int>>>
global_vars_; // (name, init, count, is_float, init_elements)
};
std::unique_ptr<MachineModule> LowerToMIR(const ir::Module& module);
void RunPeephole(MachineFunction& function);
void RunRegAlloc(MachineFunction& function);
void RunFrameLowering(MachineFunction& function);
void PrintAsm(const MachineFunction& function, std::ostream& os);
void PrintAsm(const MachineModule& module, std::ostream& os);
} // namespace mir

@ -0,0 +1,76 @@
---
📊 Lab3 完成情况总结
✅ 最终测试结果
- 通过率: 21/21 测试全部通过 ✓ (100%)
- Functional 测试: 11/11 通过
- Performance 测试: 10/10 通过
- 测试时间: 2026年04月24日
- 状态: Lab3 要求完全满足 ✓
---
🎯 核心技术实现
1. 完整数组支持 (主要提交: 1fbdbb2)
- ✅ 实现 GEP 指令支持全局数组、局部数组、指针参数
- ✅ 2D 数组线性化及正确地址计算
- ✅ 指针参数传递机制(区分数组地址传递和指针值加载)
- ✅ 新增 MIR 指令: LoadIndirect, StoreIndirect, LoadStackAddr
- ✅ 支持多维数组访问 array[i][j]
2. 浮点数支持 (提交: 1fbdbb2 + 346a9c4)
- ✅ IR 类型系统扩展: Float32 和 PtrFloat32
- ✅ 浮点常量 ConstantFloat 及 Context 管理
- ✅ IRGen 支持浮点变量、字面量、函数参数/返回值
- ✅ MIR 浮点寄存器: S0-S10
- ✅ MIR 浮点指令: FAddRR, FSubRR, FMulRR, FDivRR, FCmpRR
- ✅ IEEE 754 合规: 修复 NaN 比较的正确处理
3. 关键 Bug 修复
- ✅ 大偏移量栈访问 (提交: 3078c4c): 修复寄存器冲突问题
- ✅ 控制流指令 (提交: 693f54a): 消除 Br 和 CondBr 编译警告
- ✅ 浮点比较 (提交: 346a9c4): IEEE 754 标准 NaN 处理
- ✅ GEP 结果存储: 使用 8 字节指针槽
- ✅ 函数调用: 修复数组参数传递机制
---
🛠️ 测试效率优化
创建批量测试脚本 scripts/batch_test.sh
功能特性:
- 📁 自动测试 functional 和 performance 两个目录
- ⏱️ 智能超时控制 (functional: 60s, performance: 600s)
- 📊 自动对比输出和退出码
- 📝 生成详细测试报告 (test_results.txt)
- 📈 实时统计: 总计/通过/失败/跳过/通过率
使用方式:
./scripts/batch_test.sh
---
📈 代码变更统计
涉及 30 个文件, 主要修改:
- src/mir/Lowering.cpp: +994 行 (核心指令选择逻辑)
- src/mir/AsmPrinter.cpp: +421 行 (汇编生成)
- src/irgen/IRGenDecl.cpp: +330 行 (数组/浮点声明)
- src/mir/passes/Peephole.cpp: +292 行 (窥孔优化)
- include/mir/MIR.h: +91 行 (MIR 指令扩展)
- 总计: +2700 行, -257 行
---
🎓 技术亮点
1. 完整的编译链路: SysY源码 → IR → MIR → AArch64汇编 → 可执行程序
2. 严格的语义支持: 完全覆盖 Lab3 要求的 SysY 语义
3. 健壮的测试: 包含矩阵乘法、图算法、FFT、康威生命游戏等复杂测试
4. 自动化工具: 显著提升测试效率和开发体验
---
结论: Lab3 不仅完成了基本要求,还在数组、浮点、测试自动化方面做了深度优化,实现了 100%
测试通过率 🎉

@ -0,0 +1,133 @@
#!/usr/bin/env bash
output_file="test_results.txt"
test_dirs=("test/test_case/functional" "test/test_case/performance")
# 初始化输出文件
{
echo "开始批量测试..."
echo "测试时间: $(date)"
echo "========================================"
echo ""
} > "$output_file"
total=0
passed=0
failed=0
skipped=0
for test_dir in "${test_dirs[@]}"; do
if [[ ! -d "$test_dir" ]]; then
continue
fi
echo "测试目录: $test_dir" | tee -a "$output_file"
echo "----------------------------------------" >> "$output_file"
# 使用简单的 for 循环
for test_file in "$test_dir"/*.sy; do
if [[ ! -f "$test_file" ]]; then
continue
fi
((total++))
name=$(basename "$test_file" .sy)
# 显示当前测试
echo -n "测试 $name ... "
echo ""
# 根据目录设置输出路径和超时时间
if [[ "$test_dir" == *"functional"* ]]; then
out_dir="test/test_result/function/asm"
timeout_sec=60
else
out_dir="test/test_result/performance/asm"
timeout_sec=600 # 性能测试增加到 3 分钟
fi
# 运行测试
temp_output=$(mktemp)
if timeout ${timeout_sec}s ./scripts/verify_asm.sh "$test_file" "$out_dir" --run > "$temp_output" 2>&1; then
# 提取并保存关键信息到文件
{
grep "运行 " "$temp_output" || echo "运行 $out_dir/$name ..."
grep "退出码:" "$temp_output" || echo "退出码: 失败"
if grep -q "输出匹配:" "$temp_output"; then
grep "输出匹配:" "$temp_output"
echo ""
((passed++))
echo "✓"
echo ""
elif grep -q "输出不匹配:" "$temp_output"; then
grep "输出不匹配:" "$temp_output"
echo ""
((failed++))
echo "✗ (输出不匹配)"
elif grep -q "未找到预期输出文件" "$temp_output"; then
echo "未找到预期输出文件,跳过比对"
echo ""
((skipped++))
echo "⊘ (无期望输出)"
else
echo "测试完成"
echo ""
((passed++))
echo "✓"
echo ""
fi
} >> "$output_file"
else
# 测试失败或超时
{
echo "运行 $out_dir/$name ..."
echo "退出码: 超时或失败"
echo "测试失败"
echo ""
} >> "$output_file"
((failed++))
echo "✗ (失败/超时)"
fi
rm -f "$temp_output"
done
echo "" >> "$output_file"
done
# 输出统计
echo ""
echo "========================================"
echo "测试统计:"
echo " 总计: $total"
echo " 通过: $passed"
echo " 失败: $failed"
echo " 跳过: $skipped"
if [[ $total -gt 0 ]]; then
pass_rate=$(awk "BEGIN {printf \"%.1f\", ($passed/$total)*100}")
echo " 通过率: ${pass_rate}%"
fi
echo ""
echo "详细结果已保存到: $output_file"
# 保存统计到文件
{
echo "========================================"
echo "测试统计:"
echo " 总计: $total"
echo " 通过: $passed"
echo " 失败: $failed"
echo " 跳过: $skipped"
if [[ $total -gt 0 ]]; then
pass_rate=$(awk "BEGIN {printf \"%.1f\", ($passed/$total)*100}")
echo " 通过率: ${pass_rate}%"
fi
} >> "$output_file"
# 返回状态码
if [[ $failed -eq 0 ]]; then
exit 0
else
exit 1
fi

@ -52,7 +52,7 @@ expected_file="$input_dir/$stem.out"
"$compiler" --emit-asm "$input" > "$asm_file"
echo "汇编已生成: $asm_file"
aarch64-linux-gnu-gcc "$asm_file" -o "$exe"
aarch64-linux-gnu-gcc "$asm_file" sylib/sylib.c -o "$exe" -static
echo "可执行文件已生成: $exe"
if [[ "$run_exec" == true ]]; then
@ -83,7 +83,8 @@ if [[ "$run_exec" == true ]]; then
} > "$actual_file"
if [[ -f "$expected_file" ]]; then
if diff -u "$expected_file" "$actual_file"; then
if diff -u <(perl -0pe 's/\n\z//' "$expected_file") \
<(perl -0pe 's/\n\z//' "$actual_file"); then
echo "输出匹配: $expected_file"
else
echo "输出不匹配: $expected_file" >&2

@ -0,0 +1,7 @@
// Generated from SysY.g4 by ANTLR 4.7.2
#include "SysYBaseVisitor.h"

@ -0,0 +1,144 @@
// Generated from SysY.g4 by ANTLR 4.7.2
#pragma once
#include "antlr4-runtime.h"
#include "SysYVisitor.h"
/**
* This class provides an empty implementation of SysYVisitor, which can be
* extended to create a visitor which only needs to handle a subset of the available methods.
*/
class SysYBaseVisitor : public SysYVisitor {
public:
virtual antlrcpp::Any visitCompUnit(SysYParser::CompUnitContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitDecl(SysYParser::DeclContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitConstDecl(SysYParser::ConstDeclContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitBType(SysYParser::BTypeContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitConstDef(SysYParser::ConstDefContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitConstInitVal(SysYParser::ConstInitValContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitVarDecl(SysYParser::VarDeclContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitVarDef(SysYParser::VarDefContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitInitVal(SysYParser::InitValContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitFuncDef(SysYParser::FuncDefContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitFuncType(SysYParser::FuncTypeContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitFuncFParams(SysYParser::FuncFParamsContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitFuncFParam(SysYParser::FuncFParamContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitBlock(SysYParser::BlockContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitBlockItem(SysYParser::BlockItemContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitStmt(SysYParser::StmtContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitExp(SysYParser::ExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitCond(SysYParser::CondContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitLVal(SysYParser::LValContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitPrimaryExp(SysYParser::PrimaryExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitNumber(SysYParser::NumberContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitUnaryExp(SysYParser::UnaryExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitUnaryOp(SysYParser::UnaryOpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitFuncRParams(SysYParser::FuncRParamsContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitMulExp(SysYParser::MulExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitAddExp(SysYParser::AddExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitRelExp(SysYParser::RelExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitEqExp(SysYParser::EqExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitLAndExp(SysYParser::LAndExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitLOrExp(SysYParser::LOrExpContext *ctx) override {
return visitChildren(ctx);
}
virtual antlrcpp::Any visitConstExp(SysYParser::ConstExpContext *ctx) override {
return visitChildren(ctx);
}
};

@ -0,0 +1,377 @@
// Generated from SysY.g4 by ANTLR 4.7.2
#include "SysYLexer.h"
using namespace antlr4;
SysYLexer::SysYLexer(CharStream *input) : Lexer(input) {
_interpreter = new atn::LexerATNSimulator(this, _atn, _decisionToDFA, _sharedContextCache);
}
SysYLexer::~SysYLexer() {
delete _interpreter;
}
std::string SysYLexer::getGrammarFileName() const {
return "SysY.g4";
}
const std::vector<std::string>& SysYLexer::getRuleNames() const {
return _ruleNames;
}
const std::vector<std::string>& SysYLexer::getChannelNames() const {
return _channelNames;
}
const std::vector<std::string>& SysYLexer::getModeNames() const {
return _modeNames;
}
const std::vector<std::string>& SysYLexer::getTokenNames() const {
return _tokenNames;
}
dfa::Vocabulary& SysYLexer::getVocabulary() const {
return _vocabulary;
}
const std::vector<uint16_t> SysYLexer::getSerializedATN() const {
return _serializedATN;
}
const atn::ATN& SysYLexer::getATN() const {
return _atn;
}
// Static vars and initialization.
std::vector<dfa::DFA> SysYLexer::_decisionToDFA;
atn::PredictionContextCache SysYLexer::_sharedContextCache;
// We own the ATN which in turn owns the ATN states.
atn::ATN SysYLexer::_atn;
std::vector<uint16_t> SysYLexer::_serializedATN;
std::vector<std::string> SysYLexer::_ruleNames = {
u8"T__0", u8"T__1", u8"T__2", u8"T__3", u8"T__4", u8"T__5", u8"T__6",
u8"T__7", u8"T__8", u8"T__9", u8"T__10", u8"T__11", u8"T__12", u8"T__13",
u8"T__14", u8"T__15", u8"T__16", u8"T__17", u8"T__18", u8"T__19", u8"T__20",
u8"T__21", u8"T__22", u8"T__23", u8"T__24", u8"T__25", u8"T__26", u8"T__27",
u8"T__28", u8"T__29", u8"T__30", u8"T__31", u8"T__32", u8"DIGIT", u8"HEXDIGIT",
u8"EXP", u8"PEXP", u8"FloatConst", u8"IntConst", u8"Ident", u8"WS", u8"LINE_COMMENT",
u8"BLOCK_COMMENT"
};
std::vector<std::string> SysYLexer::_channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
};
std::vector<std::string> SysYLexer::_modeNames = {
u8"DEFAULT_MODE"
};
std::vector<std::string> SysYLexer::_literalNames = {
"", u8"'const'", u8"','", u8"';'", u8"'int'", u8"'float'", u8"'['", u8"']'",
u8"'='", u8"'{'", u8"'}'", u8"'('", u8"')'", u8"'void'", u8"'if'", u8"'else'",
u8"'while'", u8"'break'", u8"'continue'", u8"'return'", u8"'+'", u8"'-'",
u8"'!'", u8"'*'", u8"'/'", u8"'%'", u8"'<'", u8"'>'", u8"'<='", u8"'>='",
u8"'=='", u8"'!='", u8"'&&'", u8"'||'"
};
std::vector<std::string> SysYLexer::_symbolicNames = {
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", u8"FloatConst",
u8"IntConst", u8"Ident", u8"WS", u8"LINE_COMMENT", u8"BLOCK_COMMENT"
};
dfa::Vocabulary SysYLexer::_vocabulary(_literalNames, _symbolicNames);
std::vector<std::string> SysYLexer::_tokenNames;
SysYLexer::Initializer::Initializer() {
// This code could be in a static initializer lambda, but VS doesn't allow access to private class members from there.
for (size_t i = 0; i < _symbolicNames.size(); ++i) {
std::string name = _vocabulary.getLiteralName(i);
if (name.empty()) {
name = _vocabulary.getSymbolicName(i);
}
if (name.empty()) {
_tokenNames.push_back("<INVALID>");
} else {
_tokenNames.push_back(name);
}
}
_serializedATN = {
0x3, 0x608b, 0xa72a, 0x8133, 0xb9ed, 0x417c, 0x3be7, 0x7786, 0x5964,
0x2, 0x29, 0x160, 0x8, 0x1, 0x4, 0x2, 0x9, 0x2, 0x4, 0x3, 0x9, 0x3,
0x4, 0x4, 0x9, 0x4, 0x4, 0x5, 0x9, 0x5, 0x4, 0x6, 0x9, 0x6, 0x4, 0x7,
0x9, 0x7, 0x4, 0x8, 0x9, 0x8, 0x4, 0x9, 0x9, 0x9, 0x4, 0xa, 0x9, 0xa,
0x4, 0xb, 0x9, 0xb, 0x4, 0xc, 0x9, 0xc, 0x4, 0xd, 0x9, 0xd, 0x4, 0xe,
0x9, 0xe, 0x4, 0xf, 0x9, 0xf, 0x4, 0x10, 0x9, 0x10, 0x4, 0x11, 0x9,
0x11, 0x4, 0x12, 0x9, 0x12, 0x4, 0x13, 0x9, 0x13, 0x4, 0x14, 0x9, 0x14,
0x4, 0x15, 0x9, 0x15, 0x4, 0x16, 0x9, 0x16, 0x4, 0x17, 0x9, 0x17, 0x4,
0x18, 0x9, 0x18, 0x4, 0x19, 0x9, 0x19, 0x4, 0x1a, 0x9, 0x1a, 0x4, 0x1b,
0x9, 0x1b, 0x4, 0x1c, 0x9, 0x1c, 0x4, 0x1d, 0x9, 0x1d, 0x4, 0x1e, 0x9,
0x1e, 0x4, 0x1f, 0x9, 0x1f, 0x4, 0x20, 0x9, 0x20, 0x4, 0x21, 0x9, 0x21,
0x4, 0x22, 0x9, 0x22, 0x4, 0x23, 0x9, 0x23, 0x4, 0x24, 0x9, 0x24, 0x4,
0x25, 0x9, 0x25, 0x4, 0x26, 0x9, 0x26, 0x4, 0x27, 0x9, 0x27, 0x4, 0x28,
0x9, 0x28, 0x4, 0x29, 0x9, 0x29, 0x4, 0x2a, 0x9, 0x2a, 0x4, 0x2b, 0x9,
0x2b, 0x4, 0x2c, 0x9, 0x2c, 0x3, 0x2, 0x3, 0x2, 0x3, 0x2, 0x3, 0x2,
0x3, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x4, 0x3, 0x5,
0x3, 0x5, 0x3, 0x5, 0x3, 0x5, 0x3, 0x6, 0x3, 0x6, 0x3, 0x6, 0x3, 0x6,
0x3, 0x6, 0x3, 0x6, 0x3, 0x7, 0x3, 0x7, 0x3, 0x8, 0x3, 0x8, 0x3, 0x9,
0x3, 0x9, 0x3, 0xa, 0x3, 0xa, 0x3, 0xb, 0x3, 0xb, 0x3, 0xc, 0x3, 0xc,
0x3, 0xd, 0x3, 0xd, 0x3, 0xe, 0x3, 0xe, 0x3, 0xe, 0x3, 0xe, 0x3, 0xe,
0x3, 0xf, 0x3, 0xf, 0x3, 0xf, 0x3, 0x10, 0x3, 0x10, 0x3, 0x10, 0x3,
0x10, 0x3, 0x10, 0x3, 0x11, 0x3, 0x11, 0x3, 0x11, 0x3, 0x11, 0x3, 0x11,
0x3, 0x11, 0x3, 0x12, 0x3, 0x12, 0x3, 0x12, 0x3, 0x12, 0x3, 0x12, 0x3,
0x12, 0x3, 0x13, 0x3, 0x13, 0x3, 0x13, 0x3, 0x13, 0x3, 0x13, 0x3, 0x13,
0x3, 0x13, 0x3, 0x13, 0x3, 0x13, 0x3, 0x14, 0x3, 0x14, 0x3, 0x14, 0x3,
0x14, 0x3, 0x14, 0x3, 0x14, 0x3, 0x14, 0x3, 0x15, 0x3, 0x15, 0x3, 0x16,
0x3, 0x16, 0x3, 0x17, 0x3, 0x17, 0x3, 0x18, 0x3, 0x18, 0x3, 0x19, 0x3,
0x19, 0x3, 0x1a, 0x3, 0x1a, 0x3, 0x1b, 0x3, 0x1b, 0x3, 0x1c, 0x3, 0x1c,
0x3, 0x1d, 0x3, 0x1d, 0x3, 0x1d, 0x3, 0x1e, 0x3, 0x1e, 0x3, 0x1e, 0x3,
0x1f, 0x3, 0x1f, 0x3, 0x1f, 0x3, 0x20, 0x3, 0x20, 0x3, 0x20, 0x3, 0x21,
0x3, 0x21, 0x3, 0x21, 0x3, 0x22, 0x3, 0x22, 0x3, 0x22, 0x3, 0x23, 0x3,
0x23, 0x3, 0x24, 0x3, 0x24, 0x3, 0x25, 0x3, 0x25, 0x5, 0x25, 0xcd, 0xa,
0x25, 0x3, 0x25, 0x6, 0x25, 0xd0, 0xa, 0x25, 0xd, 0x25, 0xe, 0x25, 0xd1,
0x3, 0x26, 0x3, 0x26, 0x5, 0x26, 0xd6, 0xa, 0x26, 0x3, 0x26, 0x6, 0x26,
0xd9, 0xa, 0x26, 0xd, 0x26, 0xe, 0x26, 0xda, 0x3, 0x27, 0x3, 0x27, 0x3,
0x27, 0x3, 0x27, 0x5, 0x27, 0xe1, 0xa, 0x27, 0x3, 0x27, 0x6, 0x27, 0xe4,
0xa, 0x27, 0xd, 0x27, 0xe, 0x27, 0xe5, 0x3, 0x27, 0x3, 0x27, 0x7, 0x27,
0xea, 0xa, 0x27, 0xc, 0x27, 0xe, 0x27, 0xed, 0xb, 0x27, 0x3, 0x27, 0x3,
0x27, 0x6, 0x27, 0xf1, 0xa, 0x27, 0xd, 0x27, 0xe, 0x27, 0xf2, 0x3, 0x27,
0x6, 0x27, 0xf6, 0xa, 0x27, 0xd, 0x27, 0xe, 0x27, 0xf7, 0x5, 0x27, 0xfa,
0xa, 0x27, 0x3, 0x27, 0x3, 0x27, 0x3, 0x27, 0x3, 0x27, 0x6, 0x27, 0x100,
0xa, 0x27, 0xd, 0x27, 0xe, 0x27, 0x101, 0x3, 0x27, 0x5, 0x27, 0x105,
0xa, 0x27, 0x3, 0x27, 0x6, 0x27, 0x108, 0xa, 0x27, 0xd, 0x27, 0xe, 0x27,
0x109, 0x3, 0x27, 0x3, 0x27, 0x7, 0x27, 0x10e, 0xa, 0x27, 0xc, 0x27,
0xe, 0x27, 0x111, 0xb, 0x27, 0x3, 0x27, 0x5, 0x27, 0x114, 0xa, 0x27,
0x3, 0x27, 0x6, 0x27, 0x117, 0xa, 0x27, 0xd, 0x27, 0xe, 0x27, 0x118,
0x3, 0x27, 0x3, 0x27, 0x5, 0x27, 0x11d, 0xa, 0x27, 0x3, 0x28, 0x3, 0x28,
0x3, 0x28, 0x7, 0x28, 0x122, 0xa, 0x28, 0xc, 0x28, 0xe, 0x28, 0x125,
0xb, 0x28, 0x3, 0x28, 0x3, 0x28, 0x6, 0x28, 0x129, 0xa, 0x28, 0xd, 0x28,
0xe, 0x28, 0x12a, 0x3, 0x28, 0x3, 0x28, 0x3, 0x28, 0x3, 0x28, 0x5, 0x28,
0x131, 0xa, 0x28, 0x3, 0x28, 0x6, 0x28, 0x134, 0xa, 0x28, 0xd, 0x28,
0xe, 0x28, 0x135, 0x5, 0x28, 0x138, 0xa, 0x28, 0x3, 0x29, 0x3, 0x29,
0x7, 0x29, 0x13c, 0xa, 0x29, 0xc, 0x29, 0xe, 0x29, 0x13f, 0xb, 0x29,
0x3, 0x2a, 0x6, 0x2a, 0x142, 0xa, 0x2a, 0xd, 0x2a, 0xe, 0x2a, 0x143,
0x3, 0x2a, 0x3, 0x2a, 0x3, 0x2b, 0x3, 0x2b, 0x3, 0x2b, 0x3, 0x2b, 0x7,
0x2b, 0x14c, 0xa, 0x2b, 0xc, 0x2b, 0xe, 0x2b, 0x14f, 0xb, 0x2b, 0x3,
0x2b, 0x3, 0x2b, 0x3, 0x2c, 0x3, 0x2c, 0x3, 0x2c, 0x3, 0x2c, 0x7, 0x2c,
0x157, 0xa, 0x2c, 0xc, 0x2c, 0xe, 0x2c, 0x15a, 0xb, 0x2c, 0x3, 0x2c,
0x3, 0x2c, 0x3, 0x2c, 0x3, 0x2c, 0x3, 0x2c, 0x3, 0x158, 0x2, 0x2d, 0x3,
0x3, 0x5, 0x4, 0x7, 0x5, 0x9, 0x6, 0xb, 0x7, 0xd, 0x8, 0xf, 0x9, 0x11,
0xa, 0x13, 0xb, 0x15, 0xc, 0x17, 0xd, 0x19, 0xe, 0x1b, 0xf, 0x1d, 0x10,
0x1f, 0x11, 0x21, 0x12, 0x23, 0x13, 0x25, 0x14, 0x27, 0x15, 0x29, 0x16,
0x2b, 0x17, 0x2d, 0x18, 0x2f, 0x19, 0x31, 0x1a, 0x33, 0x1b, 0x35, 0x1c,
0x37, 0x1d, 0x39, 0x1e, 0x3b, 0x1f, 0x3d, 0x20, 0x3f, 0x21, 0x41, 0x22,
0x43, 0x23, 0x45, 0x2, 0x47, 0x2, 0x49, 0x2, 0x4b, 0x2, 0x4d, 0x24,
0x4f, 0x25, 0x51, 0x26, 0x53, 0x27, 0x55, 0x28, 0x57, 0x29, 0x3, 0x2,
0xd, 0x3, 0x2, 0x32, 0x3b, 0x5, 0x2, 0x32, 0x3b, 0x43, 0x48, 0x63, 0x68,
0x4, 0x2, 0x47, 0x47, 0x67, 0x67, 0x4, 0x2, 0x2d, 0x2d, 0x2f, 0x2f,
0x4, 0x2, 0x52, 0x52, 0x72, 0x72, 0x3, 0x2, 0x33, 0x3b, 0x3, 0x2, 0x32,
0x39, 0x5, 0x2, 0x43, 0x5c, 0x61, 0x61, 0x63, 0x7c, 0x6, 0x2, 0x32,
0x3b, 0x43, 0x5c, 0x61, 0x61, 0x63, 0x7c, 0x5, 0x2, 0xb, 0xc, 0xf, 0xf,
0x22, 0x22, 0x4, 0x2, 0xc, 0xc, 0xf, 0xf, 0x2, 0x17a, 0x2, 0x3, 0x3,
0x2, 0x2, 0x2, 0x2, 0x5, 0x3, 0x2, 0x2, 0x2, 0x2, 0x7, 0x3, 0x2, 0x2,
0x2, 0x2, 0x9, 0x3, 0x2, 0x2, 0x2, 0x2, 0xb, 0x3, 0x2, 0x2, 0x2, 0x2,
0xd, 0x3, 0x2, 0x2, 0x2, 0x2, 0xf, 0x3, 0x2, 0x2, 0x2, 0x2, 0x11, 0x3,
0x2, 0x2, 0x2, 0x2, 0x13, 0x3, 0x2, 0x2, 0x2, 0x2, 0x15, 0x3, 0x2, 0x2,
0x2, 0x2, 0x17, 0x3, 0x2, 0x2, 0x2, 0x2, 0x19, 0x3, 0x2, 0x2, 0x2, 0x2,
0x1b, 0x3, 0x2, 0x2, 0x2, 0x2, 0x1d, 0x3, 0x2, 0x2, 0x2, 0x2, 0x1f,
0x3, 0x2, 0x2, 0x2, 0x2, 0x21, 0x3, 0x2, 0x2, 0x2, 0x2, 0x23, 0x3, 0x2,
0x2, 0x2, 0x2, 0x25, 0x3, 0x2, 0x2, 0x2, 0x2, 0x27, 0x3, 0x2, 0x2, 0x2,
0x2, 0x29, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2b, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2d,
0x3, 0x2, 0x2, 0x2, 0x2, 0x2f, 0x3, 0x2, 0x2, 0x2, 0x2, 0x31, 0x3, 0x2,
0x2, 0x2, 0x2, 0x33, 0x3, 0x2, 0x2, 0x2, 0x2, 0x35, 0x3, 0x2, 0x2, 0x2,
0x2, 0x37, 0x3, 0x2, 0x2, 0x2, 0x2, 0x39, 0x3, 0x2, 0x2, 0x2, 0x2, 0x3b,
0x3, 0x2, 0x2, 0x2, 0x2, 0x3d, 0x3, 0x2, 0x2, 0x2, 0x2, 0x3f, 0x3, 0x2,
0x2, 0x2, 0x2, 0x41, 0x3, 0x2, 0x2, 0x2, 0x2, 0x43, 0x3, 0x2, 0x2, 0x2,
0x2, 0x4d, 0x3, 0x2, 0x2, 0x2, 0x2, 0x4f, 0x3, 0x2, 0x2, 0x2, 0x2, 0x51,
0x3, 0x2, 0x2, 0x2, 0x2, 0x53, 0x3, 0x2, 0x2, 0x2, 0x2, 0x55, 0x3, 0x2,
0x2, 0x2, 0x2, 0x57, 0x3, 0x2, 0x2, 0x2, 0x3, 0x59, 0x3, 0x2, 0x2, 0x2,
0x5, 0x5f, 0x3, 0x2, 0x2, 0x2, 0x7, 0x61, 0x3, 0x2, 0x2, 0x2, 0x9, 0x63,
0x3, 0x2, 0x2, 0x2, 0xb, 0x67, 0x3, 0x2, 0x2, 0x2, 0xd, 0x6d, 0x3, 0x2,
0x2, 0x2, 0xf, 0x6f, 0x3, 0x2, 0x2, 0x2, 0x11, 0x71, 0x3, 0x2, 0x2,
0x2, 0x13, 0x73, 0x3, 0x2, 0x2, 0x2, 0x15, 0x75, 0x3, 0x2, 0x2, 0x2,
0x17, 0x77, 0x3, 0x2, 0x2, 0x2, 0x19, 0x79, 0x3, 0x2, 0x2, 0x2, 0x1b,
0x7b, 0x3, 0x2, 0x2, 0x2, 0x1d, 0x80, 0x3, 0x2, 0x2, 0x2, 0x1f, 0x83,
0x3, 0x2, 0x2, 0x2, 0x21, 0x88, 0x3, 0x2, 0x2, 0x2, 0x23, 0x8e, 0x3,
0x2, 0x2, 0x2, 0x25, 0x94, 0x3, 0x2, 0x2, 0x2, 0x27, 0x9d, 0x3, 0x2,
0x2, 0x2, 0x29, 0xa4, 0x3, 0x2, 0x2, 0x2, 0x2b, 0xa6, 0x3, 0x2, 0x2,
0x2, 0x2d, 0xa8, 0x3, 0x2, 0x2, 0x2, 0x2f, 0xaa, 0x3, 0x2, 0x2, 0x2,
0x31, 0xac, 0x3, 0x2, 0x2, 0x2, 0x33, 0xae, 0x3, 0x2, 0x2, 0x2, 0x35,
0xb0, 0x3, 0x2, 0x2, 0x2, 0x37, 0xb2, 0x3, 0x2, 0x2, 0x2, 0x39, 0xb4,
0x3, 0x2, 0x2, 0x2, 0x3b, 0xb7, 0x3, 0x2, 0x2, 0x2, 0x3d, 0xba, 0x3,
0x2, 0x2, 0x2, 0x3f, 0xbd, 0x3, 0x2, 0x2, 0x2, 0x41, 0xc0, 0x3, 0x2,
0x2, 0x2, 0x43, 0xc3, 0x3, 0x2, 0x2, 0x2, 0x45, 0xc6, 0x3, 0x2, 0x2,
0x2, 0x47, 0xc8, 0x3, 0x2, 0x2, 0x2, 0x49, 0xca, 0x3, 0x2, 0x2, 0x2,
0x4b, 0xd3, 0x3, 0x2, 0x2, 0x2, 0x4d, 0x11c, 0x3, 0x2, 0x2, 0x2, 0x4f,
0x137, 0x3, 0x2, 0x2, 0x2, 0x51, 0x139, 0x3, 0x2, 0x2, 0x2, 0x53, 0x141,
0x3, 0x2, 0x2, 0x2, 0x55, 0x147, 0x3, 0x2, 0x2, 0x2, 0x57, 0x152, 0x3,
0x2, 0x2, 0x2, 0x59, 0x5a, 0x7, 0x65, 0x2, 0x2, 0x5a, 0x5b, 0x7, 0x71,
0x2, 0x2, 0x5b, 0x5c, 0x7, 0x70, 0x2, 0x2, 0x5c, 0x5d, 0x7, 0x75, 0x2,
0x2, 0x5d, 0x5e, 0x7, 0x76, 0x2, 0x2, 0x5e, 0x4, 0x3, 0x2, 0x2, 0x2,
0x5f, 0x60, 0x7, 0x2e, 0x2, 0x2, 0x60, 0x6, 0x3, 0x2, 0x2, 0x2, 0x61,
0x62, 0x7, 0x3d, 0x2, 0x2, 0x62, 0x8, 0x3, 0x2, 0x2, 0x2, 0x63, 0x64,
0x7, 0x6b, 0x2, 0x2, 0x64, 0x65, 0x7, 0x70, 0x2, 0x2, 0x65, 0x66, 0x7,
0x76, 0x2, 0x2, 0x66, 0xa, 0x3, 0x2, 0x2, 0x2, 0x67, 0x68, 0x7, 0x68,
0x2, 0x2, 0x68, 0x69, 0x7, 0x6e, 0x2, 0x2, 0x69, 0x6a, 0x7, 0x71, 0x2,
0x2, 0x6a, 0x6b, 0x7, 0x63, 0x2, 0x2, 0x6b, 0x6c, 0x7, 0x76, 0x2, 0x2,
0x6c, 0xc, 0x3, 0x2, 0x2, 0x2, 0x6d, 0x6e, 0x7, 0x5d, 0x2, 0x2, 0x6e,
0xe, 0x3, 0x2, 0x2, 0x2, 0x6f, 0x70, 0x7, 0x5f, 0x2, 0x2, 0x70, 0x10,
0x3, 0x2, 0x2, 0x2, 0x71, 0x72, 0x7, 0x3f, 0x2, 0x2, 0x72, 0x12, 0x3,
0x2, 0x2, 0x2, 0x73, 0x74, 0x7, 0x7d, 0x2, 0x2, 0x74, 0x14, 0x3, 0x2,
0x2, 0x2, 0x75, 0x76, 0x7, 0x7f, 0x2, 0x2, 0x76, 0x16, 0x3, 0x2, 0x2,
0x2, 0x77, 0x78, 0x7, 0x2a, 0x2, 0x2, 0x78, 0x18, 0x3, 0x2, 0x2, 0x2,
0x79, 0x7a, 0x7, 0x2b, 0x2, 0x2, 0x7a, 0x1a, 0x3, 0x2, 0x2, 0x2, 0x7b,
0x7c, 0x7, 0x78, 0x2, 0x2, 0x7c, 0x7d, 0x7, 0x71, 0x2, 0x2, 0x7d, 0x7e,
0x7, 0x6b, 0x2, 0x2, 0x7e, 0x7f, 0x7, 0x66, 0x2, 0x2, 0x7f, 0x1c, 0x3,
0x2, 0x2, 0x2, 0x80, 0x81, 0x7, 0x6b, 0x2, 0x2, 0x81, 0x82, 0x7, 0x68,
0x2, 0x2, 0x82, 0x1e, 0x3, 0x2, 0x2, 0x2, 0x83, 0x84, 0x7, 0x67, 0x2,
0x2, 0x84, 0x85, 0x7, 0x6e, 0x2, 0x2, 0x85, 0x86, 0x7, 0x75, 0x2, 0x2,
0x86, 0x87, 0x7, 0x67, 0x2, 0x2, 0x87, 0x20, 0x3, 0x2, 0x2, 0x2, 0x88,
0x89, 0x7, 0x79, 0x2, 0x2, 0x89, 0x8a, 0x7, 0x6a, 0x2, 0x2, 0x8a, 0x8b,
0x7, 0x6b, 0x2, 0x2, 0x8b, 0x8c, 0x7, 0x6e, 0x2, 0x2, 0x8c, 0x8d, 0x7,
0x67, 0x2, 0x2, 0x8d, 0x22, 0x3, 0x2, 0x2, 0x2, 0x8e, 0x8f, 0x7, 0x64,
0x2, 0x2, 0x8f, 0x90, 0x7, 0x74, 0x2, 0x2, 0x90, 0x91, 0x7, 0x67, 0x2,
0x2, 0x91, 0x92, 0x7, 0x63, 0x2, 0x2, 0x92, 0x93, 0x7, 0x6d, 0x2, 0x2,
0x93, 0x24, 0x3, 0x2, 0x2, 0x2, 0x94, 0x95, 0x7, 0x65, 0x2, 0x2, 0x95,
0x96, 0x7, 0x71, 0x2, 0x2, 0x96, 0x97, 0x7, 0x70, 0x2, 0x2, 0x97, 0x98,
0x7, 0x76, 0x2, 0x2, 0x98, 0x99, 0x7, 0x6b, 0x2, 0x2, 0x99, 0x9a, 0x7,
0x70, 0x2, 0x2, 0x9a, 0x9b, 0x7, 0x77, 0x2, 0x2, 0x9b, 0x9c, 0x7, 0x67,
0x2, 0x2, 0x9c, 0x26, 0x3, 0x2, 0x2, 0x2, 0x9d, 0x9e, 0x7, 0x74, 0x2,
0x2, 0x9e, 0x9f, 0x7, 0x67, 0x2, 0x2, 0x9f, 0xa0, 0x7, 0x76, 0x2, 0x2,
0xa0, 0xa1, 0x7, 0x77, 0x2, 0x2, 0xa1, 0xa2, 0x7, 0x74, 0x2, 0x2, 0xa2,
0xa3, 0x7, 0x70, 0x2, 0x2, 0xa3, 0x28, 0x3, 0x2, 0x2, 0x2, 0xa4, 0xa5,
0x7, 0x2d, 0x2, 0x2, 0xa5, 0x2a, 0x3, 0x2, 0x2, 0x2, 0xa6, 0xa7, 0x7,
0x2f, 0x2, 0x2, 0xa7, 0x2c, 0x3, 0x2, 0x2, 0x2, 0xa8, 0xa9, 0x7, 0x23,
0x2, 0x2, 0xa9, 0x2e, 0x3, 0x2, 0x2, 0x2, 0xaa, 0xab, 0x7, 0x2c, 0x2,
0x2, 0xab, 0x30, 0x3, 0x2, 0x2, 0x2, 0xac, 0xad, 0x7, 0x31, 0x2, 0x2,
0xad, 0x32, 0x3, 0x2, 0x2, 0x2, 0xae, 0xaf, 0x7, 0x27, 0x2, 0x2, 0xaf,
0x34, 0x3, 0x2, 0x2, 0x2, 0xb0, 0xb1, 0x7, 0x3e, 0x2, 0x2, 0xb1, 0x36,
0x3, 0x2, 0x2, 0x2, 0xb2, 0xb3, 0x7, 0x40, 0x2, 0x2, 0xb3, 0x38, 0x3,
0x2, 0x2, 0x2, 0xb4, 0xb5, 0x7, 0x3e, 0x2, 0x2, 0xb5, 0xb6, 0x7, 0x3f,
0x2, 0x2, 0xb6, 0x3a, 0x3, 0x2, 0x2, 0x2, 0xb7, 0xb8, 0x7, 0x40, 0x2,
0x2, 0xb8, 0xb9, 0x7, 0x3f, 0x2, 0x2, 0xb9, 0x3c, 0x3, 0x2, 0x2, 0x2,
0xba, 0xbb, 0x7, 0x3f, 0x2, 0x2, 0xbb, 0xbc, 0x7, 0x3f, 0x2, 0x2, 0xbc,
0x3e, 0x3, 0x2, 0x2, 0x2, 0xbd, 0xbe, 0x7, 0x23, 0x2, 0x2, 0xbe, 0xbf,
0x7, 0x3f, 0x2, 0x2, 0xbf, 0x40, 0x3, 0x2, 0x2, 0x2, 0xc0, 0xc1, 0x7,
0x28, 0x2, 0x2, 0xc1, 0xc2, 0x7, 0x28, 0x2, 0x2, 0xc2, 0x42, 0x3, 0x2,
0x2, 0x2, 0xc3, 0xc4, 0x7, 0x7e, 0x2, 0x2, 0xc4, 0xc5, 0x7, 0x7e, 0x2,
0x2, 0xc5, 0x44, 0x3, 0x2, 0x2, 0x2, 0xc6, 0xc7, 0x9, 0x2, 0x2, 0x2,
0xc7, 0x46, 0x3, 0x2, 0x2, 0x2, 0xc8, 0xc9, 0x9, 0x3, 0x2, 0x2, 0xc9,
0x48, 0x3, 0x2, 0x2, 0x2, 0xca, 0xcc, 0x9, 0x4, 0x2, 0x2, 0xcb, 0xcd,
0x9, 0x5, 0x2, 0x2, 0xcc, 0xcb, 0x3, 0x2, 0x2, 0x2, 0xcc, 0xcd, 0x3,
0x2, 0x2, 0x2, 0xcd, 0xcf, 0x3, 0x2, 0x2, 0x2, 0xce, 0xd0, 0x5, 0x45,
0x23, 0x2, 0xcf, 0xce, 0x3, 0x2, 0x2, 0x2, 0xd0, 0xd1, 0x3, 0x2, 0x2,
0x2, 0xd1, 0xcf, 0x3, 0x2, 0x2, 0x2, 0xd1, 0xd2, 0x3, 0x2, 0x2, 0x2,
0xd2, 0x4a, 0x3, 0x2, 0x2, 0x2, 0xd3, 0xd5, 0x9, 0x6, 0x2, 0x2, 0xd4,
0xd6, 0x9, 0x5, 0x2, 0x2, 0xd5, 0xd4, 0x3, 0x2, 0x2, 0x2, 0xd5, 0xd6,
0x3, 0x2, 0x2, 0x2, 0xd6, 0xd8, 0x3, 0x2, 0x2, 0x2, 0xd7, 0xd9, 0x5,
0x45, 0x23, 0x2, 0xd8, 0xd7, 0x3, 0x2, 0x2, 0x2, 0xd9, 0xda, 0x3, 0x2,
0x2, 0x2, 0xda, 0xd8, 0x3, 0x2, 0x2, 0x2, 0xda, 0xdb, 0x3, 0x2, 0x2,
0x2, 0xdb, 0x4c, 0x3, 0x2, 0x2, 0x2, 0xdc, 0xdd, 0x7, 0x32, 0x2, 0x2,
0xdd, 0xe1, 0x7, 0x7a, 0x2, 0x2, 0xde, 0xdf, 0x7, 0x32, 0x2, 0x2, 0xdf,
0xe1, 0x7, 0x5a, 0x2, 0x2, 0xe0, 0xdc, 0x3, 0x2, 0x2, 0x2, 0xe0, 0xde,
0x3, 0x2, 0x2, 0x2, 0xe1, 0xf9, 0x3, 0x2, 0x2, 0x2, 0xe2, 0xe4, 0x5,
0x47, 0x24, 0x2, 0xe3, 0xe2, 0x3, 0x2, 0x2, 0x2, 0xe4, 0xe5, 0x3, 0x2,
0x2, 0x2, 0xe5, 0xe3, 0x3, 0x2, 0x2, 0x2, 0xe5, 0xe6, 0x3, 0x2, 0x2,
0x2, 0xe6, 0xe7, 0x3, 0x2, 0x2, 0x2, 0xe7, 0xeb, 0x7, 0x30, 0x2, 0x2,
0xe8, 0xea, 0x5, 0x47, 0x24, 0x2, 0xe9, 0xe8, 0x3, 0x2, 0x2, 0x2, 0xea,
0xed, 0x3, 0x2, 0x2, 0x2, 0xeb, 0xe9, 0x3, 0x2, 0x2, 0x2, 0xeb, 0xec,
0x3, 0x2, 0x2, 0x2, 0xec, 0xfa, 0x3, 0x2, 0x2, 0x2, 0xed, 0xeb, 0x3,
0x2, 0x2, 0x2, 0xee, 0xf0, 0x7, 0x30, 0x2, 0x2, 0xef, 0xf1, 0x5, 0x47,
0x24, 0x2, 0xf0, 0xef, 0x3, 0x2, 0x2, 0x2, 0xf1, 0xf2, 0x3, 0x2, 0x2,
0x2, 0xf2, 0xf0, 0x3, 0x2, 0x2, 0x2, 0xf2, 0xf3, 0x3, 0x2, 0x2, 0x2,
0xf3, 0xfa, 0x3, 0x2, 0x2, 0x2, 0xf4, 0xf6, 0x5, 0x47, 0x24, 0x2, 0xf5,
0xf4, 0x3, 0x2, 0x2, 0x2, 0xf6, 0xf7, 0x3, 0x2, 0x2, 0x2, 0xf7, 0xf5,
0x3, 0x2, 0x2, 0x2, 0xf7, 0xf8, 0x3, 0x2, 0x2, 0x2, 0xf8, 0xfa, 0x3,
0x2, 0x2, 0x2, 0xf9, 0xe3, 0x3, 0x2, 0x2, 0x2, 0xf9, 0xee, 0x3, 0x2,
0x2, 0x2, 0xf9, 0xf5, 0x3, 0x2, 0x2, 0x2, 0xfa, 0xfb, 0x3, 0x2, 0x2,
0x2, 0xfb, 0xfc, 0x5, 0x4b, 0x26, 0x2, 0xfc, 0x11d, 0x3, 0x2, 0x2, 0x2,
0xfd, 0xff, 0x7, 0x30, 0x2, 0x2, 0xfe, 0x100, 0x5, 0x45, 0x23, 0x2,
0xff, 0xfe, 0x3, 0x2, 0x2, 0x2, 0x100, 0x101, 0x3, 0x2, 0x2, 0x2, 0x101,
0xff, 0x3, 0x2, 0x2, 0x2, 0x101, 0x102, 0x3, 0x2, 0x2, 0x2, 0x102, 0x104,
0x3, 0x2, 0x2, 0x2, 0x103, 0x105, 0x5, 0x49, 0x25, 0x2, 0x104, 0x103,
0x3, 0x2, 0x2, 0x2, 0x104, 0x105, 0x3, 0x2, 0x2, 0x2, 0x105, 0x11d,
0x3, 0x2, 0x2, 0x2, 0x106, 0x108, 0x5, 0x45, 0x23, 0x2, 0x107, 0x106,
0x3, 0x2, 0x2, 0x2, 0x108, 0x109, 0x3, 0x2, 0x2, 0x2, 0x109, 0x107,
0x3, 0x2, 0x2, 0x2, 0x109, 0x10a, 0x3, 0x2, 0x2, 0x2, 0x10a, 0x10b,
0x3, 0x2, 0x2, 0x2, 0x10b, 0x10f, 0x7, 0x30, 0x2, 0x2, 0x10c, 0x10e,
0x5, 0x45, 0x23, 0x2, 0x10d, 0x10c, 0x3, 0x2, 0x2, 0x2, 0x10e, 0x111,
0x3, 0x2, 0x2, 0x2, 0x10f, 0x10d, 0x3, 0x2, 0x2, 0x2, 0x10f, 0x110,
0x3, 0x2, 0x2, 0x2, 0x110, 0x113, 0x3, 0x2, 0x2, 0x2, 0x111, 0x10f,
0x3, 0x2, 0x2, 0x2, 0x112, 0x114, 0x5, 0x49, 0x25, 0x2, 0x113, 0x112,
0x3, 0x2, 0x2, 0x2, 0x113, 0x114, 0x3, 0x2, 0x2, 0x2, 0x114, 0x11d,
0x3, 0x2, 0x2, 0x2, 0x115, 0x117, 0x5, 0x45, 0x23, 0x2, 0x116, 0x115,
0x3, 0x2, 0x2, 0x2, 0x117, 0x118, 0x3, 0x2, 0x2, 0x2, 0x118, 0x116,
0x3, 0x2, 0x2, 0x2, 0x118, 0x119, 0x3, 0x2, 0x2, 0x2, 0x119, 0x11a,
0x3, 0x2, 0x2, 0x2, 0x11a, 0x11b, 0x5, 0x49, 0x25, 0x2, 0x11b, 0x11d,
0x3, 0x2, 0x2, 0x2, 0x11c, 0xe0, 0x3, 0x2, 0x2, 0x2, 0x11c, 0xfd, 0x3,
0x2, 0x2, 0x2, 0x11c, 0x107, 0x3, 0x2, 0x2, 0x2, 0x11c, 0x116, 0x3,
0x2, 0x2, 0x2, 0x11d, 0x4e, 0x3, 0x2, 0x2, 0x2, 0x11e, 0x138, 0x7, 0x32,
0x2, 0x2, 0x11f, 0x123, 0x9, 0x7, 0x2, 0x2, 0x120, 0x122, 0x9, 0x2,
0x2, 0x2, 0x121, 0x120, 0x3, 0x2, 0x2, 0x2, 0x122, 0x125, 0x3, 0x2,
0x2, 0x2, 0x123, 0x121, 0x3, 0x2, 0x2, 0x2, 0x123, 0x124, 0x3, 0x2,
0x2, 0x2, 0x124, 0x138, 0x3, 0x2, 0x2, 0x2, 0x125, 0x123, 0x3, 0x2,
0x2, 0x2, 0x126, 0x128, 0x7, 0x32, 0x2, 0x2, 0x127, 0x129, 0x9, 0x8,
0x2, 0x2, 0x128, 0x127, 0x3, 0x2, 0x2, 0x2, 0x129, 0x12a, 0x3, 0x2,
0x2, 0x2, 0x12a, 0x128, 0x3, 0x2, 0x2, 0x2, 0x12a, 0x12b, 0x3, 0x2,
0x2, 0x2, 0x12b, 0x138, 0x3, 0x2, 0x2, 0x2, 0x12c, 0x12d, 0x7, 0x32,
0x2, 0x2, 0x12d, 0x131, 0x7, 0x7a, 0x2, 0x2, 0x12e, 0x12f, 0x7, 0x32,
0x2, 0x2, 0x12f, 0x131, 0x7, 0x5a, 0x2, 0x2, 0x130, 0x12c, 0x3, 0x2,
0x2, 0x2, 0x130, 0x12e, 0x3, 0x2, 0x2, 0x2, 0x131, 0x133, 0x3, 0x2,
0x2, 0x2, 0x132, 0x134, 0x9, 0x3, 0x2, 0x2, 0x133, 0x132, 0x3, 0x2,
0x2, 0x2, 0x134, 0x135, 0x3, 0x2, 0x2, 0x2, 0x135, 0x133, 0x3, 0x2,
0x2, 0x2, 0x135, 0x136, 0x3, 0x2, 0x2, 0x2, 0x136, 0x138, 0x3, 0x2,
0x2, 0x2, 0x137, 0x11e, 0x3, 0x2, 0x2, 0x2, 0x137, 0x11f, 0x3, 0x2,
0x2, 0x2, 0x137, 0x126, 0x3, 0x2, 0x2, 0x2, 0x137, 0x130, 0x3, 0x2,
0x2, 0x2, 0x138, 0x50, 0x3, 0x2, 0x2, 0x2, 0x139, 0x13d, 0x9, 0x9, 0x2,
0x2, 0x13a, 0x13c, 0x9, 0xa, 0x2, 0x2, 0x13b, 0x13a, 0x3, 0x2, 0x2,
0x2, 0x13c, 0x13f, 0x3, 0x2, 0x2, 0x2, 0x13d, 0x13b, 0x3, 0x2, 0x2,
0x2, 0x13d, 0x13e, 0x3, 0x2, 0x2, 0x2, 0x13e, 0x52, 0x3, 0x2, 0x2, 0x2,
0x13f, 0x13d, 0x3, 0x2, 0x2, 0x2, 0x140, 0x142, 0x9, 0xb, 0x2, 0x2,
0x141, 0x140, 0x3, 0x2, 0x2, 0x2, 0x142, 0x143, 0x3, 0x2, 0x2, 0x2,
0x143, 0x141, 0x3, 0x2, 0x2, 0x2, 0x143, 0x144, 0x3, 0x2, 0x2, 0x2,
0x144, 0x145, 0x3, 0x2, 0x2, 0x2, 0x145, 0x146, 0x8, 0x2a, 0x2, 0x2,
0x146, 0x54, 0x3, 0x2, 0x2, 0x2, 0x147, 0x148, 0x7, 0x31, 0x2, 0x2,
0x148, 0x149, 0x7, 0x31, 0x2, 0x2, 0x149, 0x14d, 0x3, 0x2, 0x2, 0x2,
0x14a, 0x14c, 0xa, 0xc, 0x2, 0x2, 0x14b, 0x14a, 0x3, 0x2, 0x2, 0x2,
0x14c, 0x14f, 0x3, 0x2, 0x2, 0x2, 0x14d, 0x14b, 0x3, 0x2, 0x2, 0x2,
0x14d, 0x14e, 0x3, 0x2, 0x2, 0x2, 0x14e, 0x150, 0x3, 0x2, 0x2, 0x2,
0x14f, 0x14d, 0x3, 0x2, 0x2, 0x2, 0x150, 0x151, 0x8, 0x2b, 0x2, 0x2,
0x151, 0x56, 0x3, 0x2, 0x2, 0x2, 0x152, 0x153, 0x7, 0x31, 0x2, 0x2,
0x153, 0x154, 0x7, 0x2c, 0x2, 0x2, 0x154, 0x158, 0x3, 0x2, 0x2, 0x2,
0x155, 0x157, 0xb, 0x2, 0x2, 0x2, 0x156, 0x155, 0x3, 0x2, 0x2, 0x2,
0x157, 0x15a, 0x3, 0x2, 0x2, 0x2, 0x158, 0x159, 0x3, 0x2, 0x2, 0x2,
0x158, 0x156, 0x3, 0x2, 0x2, 0x2, 0x159, 0x15b, 0x3, 0x2, 0x2, 0x2,
0x15a, 0x158, 0x3, 0x2, 0x2, 0x2, 0x15b, 0x15c, 0x7, 0x2c, 0x2, 0x2,
0x15c, 0x15d, 0x7, 0x31, 0x2, 0x2, 0x15d, 0x15e, 0x3, 0x2, 0x2, 0x2,
0x15e, 0x15f, 0x8, 0x2c, 0x2, 0x2, 0x15f, 0x58, 0x3, 0x2, 0x2, 0x2,
0x1d, 0x2, 0xcc, 0xd1, 0xd5, 0xda, 0xe0, 0xe5, 0xeb, 0xf2, 0xf7, 0xf9,
0x101, 0x104, 0x109, 0x10f, 0x113, 0x118, 0x11c, 0x123, 0x12a, 0x130,
0x135, 0x137, 0x13d, 0x143, 0x14d, 0x158, 0x3, 0x8, 0x2, 0x2,
};
atn::ATNDeserializer deserializer;
_atn = deserializer.deserialize(_serializedATN);
size_t count = _atn.getNumberOfDecisions();
_decisionToDFA.reserve(count);
for (size_t i = 0; i < count; i++) {
_decisionToDFA.emplace_back(_atn.getDecisionState(i), i);
}
}
SysYLexer::Initializer SysYLexer::_init;

@ -0,0 +1,62 @@
// Generated from SysY.g4 by ANTLR 4.7.2
#pragma once
#include "antlr4-runtime.h"
class SysYLexer : public antlr4::Lexer {
public:
enum {
T__0 = 1, T__1 = 2, T__2 = 3, T__3 = 4, T__4 = 5, T__5 = 6, T__6 = 7,
T__7 = 8, T__8 = 9, T__9 = 10, T__10 = 11, T__11 = 12, T__12 = 13, T__13 = 14,
T__14 = 15, T__15 = 16, T__16 = 17, T__17 = 18, T__18 = 19, T__19 = 20,
T__20 = 21, T__21 = 22, T__22 = 23, T__23 = 24, T__24 = 25, T__25 = 26,
T__26 = 27, T__27 = 28, T__28 = 29, T__29 = 30, T__30 = 31, T__31 = 32,
T__32 = 33, FloatConst = 34, IntConst = 35, Ident = 36, WS = 37, LINE_COMMENT = 38,
BLOCK_COMMENT = 39
};
SysYLexer(antlr4::CharStream *input);
~SysYLexer();
virtual std::string getGrammarFileName() const override;
virtual const std::vector<std::string>& getRuleNames() const override;
virtual const std::vector<std::string>& getChannelNames() const override;
virtual const std::vector<std::string>& getModeNames() const override;
virtual const std::vector<std::string>& getTokenNames() const override; // deprecated, use vocabulary instead
virtual antlr4::dfa::Vocabulary& getVocabulary() const override;
virtual const std::vector<uint16_t> getSerializedATN() const override;
virtual const antlr4::atn::ATN& getATN() const override;
private:
static std::vector<antlr4::dfa::DFA> _decisionToDFA;
static antlr4::atn::PredictionContextCache _sharedContextCache;
static std::vector<std::string> _ruleNames;
static std::vector<std::string> _tokenNames;
static std::vector<std::string> _channelNames;
static std::vector<std::string> _modeNames;
static std::vector<std::string> _literalNames;
static std::vector<std::string> _symbolicNames;
static antlr4::dfa::Vocabulary _vocabulary;
static antlr4::atn::ATN _atn;
static std::vector<uint16_t> _serializedATN;
// Individual action functions triggered by action() above.
// Individual semantic predicate functions triggered by sempred() above.
struct Initializer {
Initializer();
};
static Initializer _init;
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,513 @@
// Generated from SysY.g4 by ANTLR 4.7.2
#pragma once
#include "antlr4-runtime.h"
class SysYParser : public antlr4::Parser {
public:
enum {
T__0 = 1, T__1 = 2, T__2 = 3, T__3 = 4, T__4 = 5, T__5 = 6, T__6 = 7,
T__7 = 8, T__8 = 9, T__9 = 10, T__10 = 11, T__11 = 12, T__12 = 13, T__13 = 14,
T__14 = 15, T__15 = 16, T__16 = 17, T__17 = 18, T__18 = 19, T__19 = 20,
T__20 = 21, T__21 = 22, T__22 = 23, T__23 = 24, T__24 = 25, T__25 = 26,
T__26 = 27, T__27 = 28, T__28 = 29, T__29 = 30, T__30 = 31, T__31 = 32,
T__32 = 33, FloatConst = 34, IntConst = 35, Ident = 36, WS = 37, LINE_COMMENT = 38,
BLOCK_COMMENT = 39
};
enum {
RuleCompUnit = 0, RuleDecl = 1, RuleConstDecl = 2, RuleBType = 3, RuleConstDef = 4,
RuleConstInitVal = 5, RuleVarDecl = 6, RuleVarDef = 7, RuleInitVal = 8,
RuleFuncDef = 9, RuleFuncType = 10, RuleFuncFParams = 11, RuleFuncFParam = 12,
RuleBlock = 13, RuleBlockItem = 14, RuleStmt = 15, RuleExp = 16, RuleCond = 17,
RuleLVal = 18, RulePrimaryExp = 19, RuleNumber = 20, RuleUnaryExp = 21,
RuleUnaryOp = 22, RuleFuncRParams = 23, RuleMulExp = 24, RuleAddExp = 25,
RuleRelExp = 26, RuleEqExp = 27, RuleLAndExp = 28, RuleLOrExp = 29,
RuleConstExp = 30
};
SysYParser(antlr4::TokenStream *input);
~SysYParser();
virtual std::string getGrammarFileName() const override;
virtual const antlr4::atn::ATN& getATN() const override { return _atn; };
virtual const std::vector<std::string>& getTokenNames() const override { return _tokenNames; }; // deprecated: use vocabulary instead.
virtual const std::vector<std::string>& getRuleNames() const override;
virtual antlr4::dfa::Vocabulary& getVocabulary() const override;
class CompUnitContext;
class DeclContext;
class ConstDeclContext;
class BTypeContext;
class ConstDefContext;
class ConstInitValContext;
class VarDeclContext;
class VarDefContext;
class InitValContext;
class FuncDefContext;
class FuncTypeContext;
class FuncFParamsContext;
class FuncFParamContext;
class BlockContext;
class BlockItemContext;
class StmtContext;
class ExpContext;
class CondContext;
class LValContext;
class PrimaryExpContext;
class NumberContext;
class UnaryExpContext;
class UnaryOpContext;
class FuncRParamsContext;
class MulExpContext;
class AddExpContext;
class RelExpContext;
class EqExpContext;
class LAndExpContext;
class LOrExpContext;
class ConstExpContext;
class CompUnitContext : public antlr4::ParserRuleContext {
public:
CompUnitContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<DeclContext *> decl();
DeclContext* decl(size_t i);
std::vector<FuncDefContext *> funcDef();
FuncDefContext* funcDef(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
CompUnitContext* compUnit();
class DeclContext : public antlr4::ParserRuleContext {
public:
DeclContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
ConstDeclContext *constDecl();
VarDeclContext *varDecl();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
DeclContext* decl();
class ConstDeclContext : public antlr4::ParserRuleContext {
public:
ConstDeclContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
BTypeContext *bType();
std::vector<ConstDefContext *> constDef();
ConstDefContext* constDef(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
ConstDeclContext* constDecl();
class BTypeContext : public antlr4::ParserRuleContext {
public:
BTypeContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
BTypeContext* bType();
class ConstDefContext : public antlr4::ParserRuleContext {
public:
ConstDefContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
antlr4::tree::TerminalNode *Ident();
ConstInitValContext *constInitVal();
std::vector<ConstExpContext *> constExp();
ConstExpContext* constExp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
ConstDefContext* constDef();
class ConstInitValContext : public antlr4::ParserRuleContext {
public:
ConstInitValContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
ConstExpContext *constExp();
std::vector<ConstInitValContext *> constInitVal();
ConstInitValContext* constInitVal(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
ConstInitValContext* constInitVal();
class VarDeclContext : public antlr4::ParserRuleContext {
public:
VarDeclContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
BTypeContext *bType();
std::vector<VarDefContext *> varDef();
VarDefContext* varDef(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
VarDeclContext* varDecl();
class VarDefContext : public antlr4::ParserRuleContext {
public:
VarDefContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
antlr4::tree::TerminalNode *Ident();
std::vector<ConstExpContext *> constExp();
ConstExpContext* constExp(size_t i);
InitValContext *initVal();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
VarDefContext* varDef();
class InitValContext : public antlr4::ParserRuleContext {
public:
InitValContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
ExpContext *exp();
std::vector<InitValContext *> initVal();
InitValContext* initVal(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
InitValContext* initVal();
class FuncDefContext : public antlr4::ParserRuleContext {
public:
FuncDefContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
FuncTypeContext *funcType();
antlr4::tree::TerminalNode *Ident();
BlockContext *block();
FuncFParamsContext *funcFParams();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
FuncDefContext* funcDef();
class FuncTypeContext : public antlr4::ParserRuleContext {
public:
FuncTypeContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
FuncTypeContext* funcType();
class FuncFParamsContext : public antlr4::ParserRuleContext {
public:
FuncFParamsContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<FuncFParamContext *> funcFParam();
FuncFParamContext* funcFParam(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
FuncFParamsContext* funcFParams();
class FuncFParamContext : public antlr4::ParserRuleContext {
public:
FuncFParamContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
BTypeContext *bType();
antlr4::tree::TerminalNode *Ident();
std::vector<ExpContext *> exp();
ExpContext* exp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
FuncFParamContext* funcFParam();
class BlockContext : public antlr4::ParserRuleContext {
public:
BlockContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<BlockItemContext *> blockItem();
BlockItemContext* blockItem(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
BlockContext* block();
class BlockItemContext : public antlr4::ParserRuleContext {
public:
BlockItemContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
DeclContext *decl();
StmtContext *stmt();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
BlockItemContext* blockItem();
class StmtContext : public antlr4::ParserRuleContext {
public:
StmtContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
LValContext *lVal();
ExpContext *exp();
BlockContext *block();
CondContext *cond();
std::vector<StmtContext *> stmt();
StmtContext* stmt(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
StmtContext* stmt();
class ExpContext : public antlr4::ParserRuleContext {
public:
ExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
AddExpContext *addExp();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
ExpContext* exp();
class CondContext : public antlr4::ParserRuleContext {
public:
CondContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
LOrExpContext *lOrExp();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
CondContext* cond();
class LValContext : public antlr4::ParserRuleContext {
public:
LValContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
antlr4::tree::TerminalNode *Ident();
std::vector<ExpContext *> exp();
ExpContext* exp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
LValContext* lVal();
class PrimaryExpContext : public antlr4::ParserRuleContext {
public:
PrimaryExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
ExpContext *exp();
LValContext *lVal();
NumberContext *number();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
PrimaryExpContext* primaryExp();
class NumberContext : public antlr4::ParserRuleContext {
public:
NumberContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
antlr4::tree::TerminalNode *FloatConst();
antlr4::tree::TerminalNode *IntConst();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
NumberContext* number();
class UnaryExpContext : public antlr4::ParserRuleContext {
public:
UnaryExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
PrimaryExpContext *primaryExp();
antlr4::tree::TerminalNode *Ident();
FuncRParamsContext *funcRParams();
UnaryOpContext *unaryOp();
UnaryExpContext *unaryExp();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
UnaryExpContext* unaryExp();
class UnaryOpContext : public antlr4::ParserRuleContext {
public:
UnaryOpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
UnaryOpContext* unaryOp();
class FuncRParamsContext : public antlr4::ParserRuleContext {
public:
FuncRParamsContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<ExpContext *> exp();
ExpContext* exp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
FuncRParamsContext* funcRParams();
class MulExpContext : public antlr4::ParserRuleContext {
public:
MulExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<UnaryExpContext *> unaryExp();
UnaryExpContext* unaryExp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
MulExpContext* mulExp();
class AddExpContext : public antlr4::ParserRuleContext {
public:
AddExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<MulExpContext *> mulExp();
MulExpContext* mulExp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
AddExpContext* addExp();
class RelExpContext : public antlr4::ParserRuleContext {
public:
RelExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<AddExpContext *> addExp();
AddExpContext* addExp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
RelExpContext* relExp();
class EqExpContext : public antlr4::ParserRuleContext {
public:
EqExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<RelExpContext *> relExp();
RelExpContext* relExp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
EqExpContext* eqExp();
class LAndExpContext : public antlr4::ParserRuleContext {
public:
LAndExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<EqExpContext *> eqExp();
EqExpContext* eqExp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
LAndExpContext* lAndExp();
class LOrExpContext : public antlr4::ParserRuleContext {
public:
LOrExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
std::vector<LAndExpContext *> lAndExp();
LAndExpContext* lAndExp(size_t i);
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
LOrExpContext* lOrExp();
class ConstExpContext : public antlr4::ParserRuleContext {
public:
ConstExpContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
AddExpContext *addExp();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
ConstExpContext* constExp();
private:
static std::vector<antlr4::dfa::DFA> _decisionToDFA;
static antlr4::atn::PredictionContextCache _sharedContextCache;
static std::vector<std::string> _ruleNames;
static std::vector<std::string> _tokenNames;
static std::vector<std::string> _literalNames;
static std::vector<std::string> _symbolicNames;
static antlr4::dfa::Vocabulary _vocabulary;
static antlr4::atn::ATN _atn;
static std::vector<uint16_t> _serializedATN;
struct Initializer {
Initializer();
};
static Initializer _init;
};

@ -0,0 +1,7 @@
// Generated from SysY.g4 by ANTLR 4.7.2
#include "SysYVisitor.h"

@ -0,0 +1,86 @@
// Generated from SysY.g4 by ANTLR 4.7.2
#pragma once
#include "antlr4-runtime.h"
#include "SysYParser.h"
/**
* This class defines an abstract visitor for a parse tree
* produced by SysYParser.
*/
class SysYVisitor : public antlr4::tree::AbstractParseTreeVisitor {
public:
/**
* Visit parse trees produced by SysYParser.
*/
virtual antlrcpp::Any visitCompUnit(SysYParser::CompUnitContext *context) = 0;
virtual antlrcpp::Any visitDecl(SysYParser::DeclContext *context) = 0;
virtual antlrcpp::Any visitConstDecl(SysYParser::ConstDeclContext *context) = 0;
virtual antlrcpp::Any visitBType(SysYParser::BTypeContext *context) = 0;
virtual antlrcpp::Any visitConstDef(SysYParser::ConstDefContext *context) = 0;
virtual antlrcpp::Any visitConstInitVal(SysYParser::ConstInitValContext *context) = 0;
virtual antlrcpp::Any visitVarDecl(SysYParser::VarDeclContext *context) = 0;
virtual antlrcpp::Any visitVarDef(SysYParser::VarDefContext *context) = 0;
virtual antlrcpp::Any visitInitVal(SysYParser::InitValContext *context) = 0;
virtual antlrcpp::Any visitFuncDef(SysYParser::FuncDefContext *context) = 0;
virtual antlrcpp::Any visitFuncType(SysYParser::FuncTypeContext *context) = 0;
virtual antlrcpp::Any visitFuncFParams(SysYParser::FuncFParamsContext *context) = 0;
virtual antlrcpp::Any visitFuncFParam(SysYParser::FuncFParamContext *context) = 0;
virtual antlrcpp::Any visitBlock(SysYParser::BlockContext *context) = 0;
virtual antlrcpp::Any visitBlockItem(SysYParser::BlockItemContext *context) = 0;
virtual antlrcpp::Any visitStmt(SysYParser::StmtContext *context) = 0;
virtual antlrcpp::Any visitExp(SysYParser::ExpContext *context) = 0;
virtual antlrcpp::Any visitCond(SysYParser::CondContext *context) = 0;
virtual antlrcpp::Any visitLVal(SysYParser::LValContext *context) = 0;
virtual antlrcpp::Any visitPrimaryExp(SysYParser::PrimaryExpContext *context) = 0;
virtual antlrcpp::Any visitNumber(SysYParser::NumberContext *context) = 0;
virtual antlrcpp::Any visitUnaryExp(SysYParser::UnaryExpContext *context) = 0;
virtual antlrcpp::Any visitUnaryOp(SysYParser::UnaryOpContext *context) = 0;
virtual antlrcpp::Any visitFuncRParams(SysYParser::FuncRParamsContext *context) = 0;
virtual antlrcpp::Any visitMulExp(SysYParser::MulExpContext *context) = 0;
virtual antlrcpp::Any visitAddExp(SysYParser::AddExpContext *context) = 0;
virtual antlrcpp::Any visitRelExp(SysYParser::RelExpContext *context) = 0;
virtual antlrcpp::Any visitEqExp(SysYParser::EqExpContext *context) = 0;
virtual antlrcpp::Any visitLAndExp(SysYParser::LAndExpContext *context) = 0;
virtual antlrcpp::Any visitLOrExp(SysYParser::LOrExpContext *context) = 0;
virtual antlrcpp::Any visitConstExp(SysYParser::ConstExpContext *context) = 0;
};

@ -15,6 +15,14 @@ ConstantInt* Context::GetConstInt(int v) {
return inserted->second.get();
}
ConstantFloat* Context::GetConstFloat(float v) {
auto it = const_floats_.find(v);
if (it != const_floats_.end()) return it->second.get();
auto inserted =
const_floats_.emplace(v, std::make_unique<ConstantFloat>(Type::GetFloat32Type(), v)).first;
return inserted->second.get();
}
std::string Context::NextTemp() {
std::ostringstream oss;
oss << "%t" << ++temp_index_;

@ -7,9 +7,12 @@ namespace ir {
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name)
: User(std::move(ty), std::move(name)) {}
GlobalVariable::GlobalVariable(std::string name, int init_val, int count)
: GlobalValue(Type::GetPtrInt32Type(), std::move(name)),
GlobalVariable::GlobalVariable(std::string name, std::shared_ptr<Type> ptr_ty,
int init_val, int count,
std::vector<int> init_elems)
: GlobalValue(std::move(ptr_ty), std::move(name)),
init_val_(init_val),
count_(count) {}
count_(count),
init_elems_(std::move(init_elems)) {}
} // namespace ir

@ -75,6 +75,28 @@ CmpInst* IRBuilder::CreateCmp(CmpOp op, Value* lhs, Value* rhs,
name);
}
CastInst* IRBuilder::CreateSIToFP(Value* v, const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!v) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateSIToFP 缺少操作数"));
}
return insert_block_->Append<CastInst>(CastOp::IntToFloat, Type::GetFloat32Type(),
v, name);
}
CastInst* IRBuilder::CreateFPToSI(Value* v, const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!v) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateFPToSI 缺少操作数"));
}
return insert_block_->Append<CastInst>(CastOp::FloatToInt, Type::GetInt32Type(),
v, name);
}
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
@ -92,6 +114,23 @@ AllocaInst* IRBuilder::CreateAllocaArray(int count, const std::string& name) {
return insert_block_->Append<AllocaInst>(Type::GetPtrInt32Type(), name, count);
}
AllocaInst* IRBuilder::CreateAllocaF32(const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<AllocaInst>(Type::GetPtrFloat32Type(), name);
}
AllocaInst* IRBuilder::CreateAllocaF32Array(int count, const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (count <= 0) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateAllocaF32Array 数组大小必须为正数"));
}
return insert_block_->Append<AllocaInst>(Type::GetPtrFloat32Type(), name, count);
}
GepInst* IRBuilder::CreateGep(Value* base, Value* index, const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
@ -99,7 +138,11 @@ GepInst* IRBuilder::CreateGep(Value* base, Value* index, const std::string& name
if (!base || !index) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateGep 缺少操作数"));
}
return insert_block_->Append<GepInst>(Type::GetPtrInt32Type(), base, index, name);
std::shared_ptr<Type> ptr_ty = Type::GetPtrInt32Type();
if (base->GetType() && base->GetType()->IsPtrFloat32()) {
ptr_ty = Type::GetPtrFloat32Type();
}
return insert_block_->Append<GepInst>(ptr_ty, base, index, name);
}
LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
@ -110,7 +153,14 @@ LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateLoad 缺少 ptr"));
}
return insert_block_->Append<LoadInst>(Type::GetInt32Type(), ptr, name);
// 根据指针类型推断值类型
std::shared_ptr<Type> val_type;
if (ptr->GetType()->IsPtrFloat32()) {
val_type = Type::GetFloat32Type();
} else {
val_type = Type::GetInt32Type();
}
return insert_block_->Append<LoadInst>(val_type, ptr, name);
}
StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {

@ -4,6 +4,8 @@
#include "ir/IR.h"
#include <cstdint>
#include <cstring>
#include <ostream>
#include <stdexcept>
#include <string>
@ -20,6 +22,10 @@ static const char* TypeToString(const Type& ty) {
return "i32";
case Type::Kind::PtrInt32:
return "i32*";
case Type::Kind::Float32:
return "float";
case Type::Kind::PtrFloat32:
return "float*";
}
throw std::runtime_error(FormatError("ir", "未知类型"));
}
@ -38,6 +44,8 @@ static const char* OpcodeToString(Opcode op) {
return "srem";
case Opcode::Cmp:
return "icmp";
case Opcode::Cast:
return "cast";
case Opcode::Br:
return "br";
case Opcode::CondBr:
@ -96,11 +104,20 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
// 先打印全局变量
for (const auto& gv : module.GetGlobalVars()) {
if (!gv) continue;
const char* elem_ty = gv->IsFloat() ? "float" : "i32";
if (gv->IsArray()) {
os << "@" << gv->GetName() << " = global [" << gv->GetCount()
<< " x i32] zeroinitializer\n";
<< " x " << elem_ty << "] zeroinitializer\n";
} else {
os << "@" << gv->GetName() << " = global i32 " << gv->GetInitValue() << "\n";
if (gv->IsFloat()) {
std::int32_t bits = static_cast<std::int32_t>(gv->GetInitValue());
float fval = 0.0f;
std::memcpy(&fval, &bits, sizeof(fval));
os << "@" << gv->GetName() << " = global float " << fval << "\n";
} else {
os << "@" << gv->GetName() << " = global i32 " << gv->GetInitValue()
<< "\n";
}
}
}
if (!module.GetGlobalVars().empty()) os << "\n";
@ -159,26 +176,41 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
<< ValueToString(cmp->GetRhs()) << "\n";
break;
}
case Opcode::Cast: {
auto* cast = static_cast<const CastInst*>(inst);
const char* cast_name =
(cast->GetCastOp() == CastOp::IntToFloat) ? "sitofp" : "fptosi";
os << " " << cast->GetName() << " = " << cast_name << " "
<< TypeToString(*cast->GetValue()->GetType()) << " "
<< ValueToString(cast->GetValue()) << " to "
<< TypeToString(*cast->GetType()) << "\n";
break;
}
case Opcode::Alloca: {
auto* alloca = static_cast<const AllocaInst*>(inst);
const char* elem_ty = alloca->GetType()->IsPtrFloat32() ? "float" : "i32";
if (alloca->IsArray()) {
os << " " << alloca->GetName() << " = alloca i32, i32 "
os << " " << alloca->GetName() << " = alloca " << elem_ty << ", i32 "
<< alloca->GetCount() << "\n";
} else {
os << " " << alloca->GetName() << " = alloca i32\n";
os << " " << alloca->GetName() << " = alloca " << elem_ty << "\n";
}
break;
}
case Opcode::Load: {
auto* load = static_cast<const LoadInst*>(inst);
os << " " << load->GetName() << " = load i32, i32* "
os << " " << load->GetName() << " = load "
<< TypeToString(*load->GetType()) << ", "
<< TypeToString(*load->GetPtr()->GetType()) << " "
<< ValueToString(load->GetPtr()) << "\n";
break;
}
case Opcode::Store: {
auto* store = static_cast<const StoreInst*>(inst);
os << " store i32 " << ValueToString(store->GetValue())
<< ", i32* " << ValueToString(store->GetPtr()) << "\n";
os << " store " << TypeToString(*store->GetValue()->GetType())
<< " " << ValueToString(store->GetValue())
<< ", " << TypeToString(*store->GetPtr()->GetType())
<< " " << ValueToString(store->GetPtr()) << "\n";
break;
}
case Opcode::Br: {
@ -215,18 +247,20 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
case Opcode::Gep: {
auto* gep = static_cast<const GepInst*>(inst);
auto* base = gep->GetBase();
const char* elem_ty = base->GetType()->IsPtrFloat32() ? "float" : "i32";
// 全局数组用双下标 GEP局部 alloca 用平坦 GEP。
if (auto* gv = dynamic_cast<const GlobalVariable*>(base)) {
if (gv->IsArray()) {
os << " " << gep->GetName()
<< " = getelementptr [" << gv->GetCount() << " x i32], ["
<< gv->GetCount() << " x i32]* @" << gv->GetName()
<< " = getelementptr [" << gv->GetCount() << " x " << elem_ty << "], ["
<< gv->GetCount() << " x " << elem_ty << "]* @" << gv->GetName()
<< ", i32 0, i32 " << ValueToString(gep->GetIndex()) << "\n";
break;
}
}
os << " " << gep->GetName()
<< " = getelementptr i32, i32* " << ValueToString(base)
<< " = getelementptr " << elem_ty << ", "
<< TypeToString(*base->GetType()) << " " << ValueToString(base)
<< ", i32 " << ValueToString(gep->GetIndex()) << "\n";
break;
}

@ -21,6 +21,10 @@ const char* TypeKindToString(Type::Kind k) {
return "i32";
case Type::Kind::PtrInt32:
return "i32*";
case Type::Kind::Float32:
return "float";
case Type::Kind::PtrFloat32:
return "float*";
}
return "?";
}
@ -120,8 +124,13 @@ BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
type_->GetKind() != lhs->GetType()->GetKind()) {
throw std::runtime_error(FormatError("ir", "BinaryInst 类型不匹配"));
}
if (!type_->IsInt32()) {
throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 i32"));
const bool is_i32 = type_->IsInt32();
const bool is_f32 = type_->IsFloat32();
if (!is_i32 && !is_f32) {
throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 i32/float"));
}
if (op == Opcode::Mod && !is_i32) {
throw std::runtime_error(FormatError("ir", "BinaryInst 的 mod 仅支持 i32"));
}
AddOperand(lhs);
AddOperand(rhs);
@ -143,9 +152,11 @@ CmpInst::CmpInst(CmpOp op, std::shared_ptr<Type> ty, Value* lhs, Value* rhs,
if (!type_->IsInt32()) {
throw std::runtime_error(FormatError("ir", "CmpInst 结果类型必须为 i32"));
}
if (!lhs->GetType()->IsInt32() || !rhs->GetType()->IsInt32()) {
const bool is_int_cmp = lhs->GetType()->IsInt32() && rhs->GetType()->IsInt32();
const bool is_float_cmp = lhs->GetType()->IsFloat32() && rhs->GetType()->IsFloat32();
if (!is_int_cmp && !is_float_cmp) {
throw std::runtime_error(FormatError(
"ir", "CmpInst 当前只支持 i32 比较,实际为 " +
"ir", "CmpInst 当前只支持 i32/float 同类型比较,实际为 " +
std::string(TypeKindToString(lhs->GetType()->GetKind())) +
"" +
std::string(TypeKindToString(rhs->GetType()->GetKind()))));
@ -160,6 +171,28 @@ Value* CmpInst::GetLhs() const { return GetOperand(0); }
Value* CmpInst::GetRhs() const { return GetOperand(1); }
CastInst::CastInst(CastOp op, std::shared_ptr<Type> ty, Value* val,
std::string name)
: Instruction(Opcode::Cast, std::move(ty), std::move(name)), cast_op_(op) {
if (!val || !val->GetType() || !type_) {
throw std::runtime_error(FormatError("ir", "CastInst 缺少类型信息或操作数"));
}
if (cast_op_ == CastOp::IntToFloat) {
if (!val->GetType()->IsInt32() || !type_->IsFloat32()) {
throw std::runtime_error(FormatError("ir", "IntToFloat 需要 i32 -> float"));
}
} else {
if (!val->GetType()->IsFloat32() || !type_->IsInt32()) {
throw std::runtime_error(FormatError("ir", "FloatToInt 需要 float -> i32"));
}
}
AddOperand(val);
}
CastOp CastInst::GetCastOp() const { return cast_op_; }
Value* CastInst::GetValue() const { return GetOperand(0); }
ReturnInst::ReturnInst(std::shared_ptr<Type> void_ty, Value* val)
: Instruction(Opcode::Ret, std::move(void_ty), "") {
if (!type_ || !type_->IsVoid()) {
@ -176,15 +209,15 @@ Value* ReturnInst::GetValue() const {
AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name)
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)), count_(1) {
if (!type_ || !type_->IsPtrInt32()) {
throw std::runtime_error(FormatError("ir", "AllocaInst 当前只支持 i32*"));
if (!type_ || (!type_->IsPtrInt32() && !type_->IsPtrFloat32())) {
throw std::runtime_error(FormatError("ir", "AllocaInst 当前只支持 i32*/float*"));
}
}
AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name, int count)
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)), count_(count) {
if (!type_ || !type_->IsPtrInt32()) {
throw std::runtime_error(FormatError("ir", "AllocaInst 当前只支持 i32*"));
if (!type_ || (!type_->IsPtrInt32() && !type_->IsPtrFloat32())) {
throw std::runtime_error(FormatError("ir", "AllocaInst 当前只支持 i32*/float*"));
}
if (count_ <= 0) {
throw std::runtime_error(FormatError("ir", "AllocaInst 数组大小必须为正数"));
@ -196,12 +229,12 @@ LoadInst::LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name)
if (!ptr) {
throw std::runtime_error(FormatError("ir", "LoadInst 缺少 ptr"));
}
if (!type_ || !type_->IsInt32()) {
throw std::runtime_error(FormatError("ir", "LoadInst 当前只支持加载 i32"));
if (!type_ || (!type_->IsInt32() && !type_->IsFloat32())) {
throw std::runtime_error(FormatError("ir", "LoadInst 当前只支持加载 i32/float"));
}
if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) {
if (!ptr->GetType() || (!ptr->GetType()->IsPtrInt32() && !ptr->GetType()->IsPtrFloat32())) {
throw std::runtime_error(
FormatError("ir", "LoadInst 当前只支持从 i32* 加载"));
FormatError("ir", "LoadInst 当前只支持从 i32*/float* 加载"));
}
AddOperand(ptr);
}
@ -219,12 +252,12 @@ StoreInst::StoreInst(std::shared_ptr<Type> void_ty, Value* val, Value* ptr)
if (!type_ || !type_->IsVoid()) {
throw std::runtime_error(FormatError("ir", "StoreInst 返回类型必须为 void"));
}
if (!val->GetType() || !val->GetType()->IsInt32()) {
throw std::runtime_error(FormatError("ir", "StoreInst 当前只支持存储 i32"));
if (!val->GetType() || (!val->GetType()->IsInt32() && !val->GetType()->IsFloat32())) {
throw std::runtime_error(FormatError("ir", "StoreInst 当前只支持存储 i32/float"));
}
if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) {
if (!ptr->GetType() || (!ptr->GetType()->IsPtrInt32() && !ptr->GetType()->IsPtrFloat32())) {
throw std::runtime_error(
FormatError("ir", "StoreInst 当前只支持写入 i32*"));
FormatError("ir", "StoreInst 当前只支持写入 i32*/float*"));
}
AddOperand(val);
AddOperand(ptr);
@ -323,8 +356,9 @@ GepInst::GepInst(std::shared_ptr<Type> ptr_ty, Value* base, Value* index,
if (!base || !index) {
throw std::runtime_error(FormatError("ir", "GepInst 缺少操作数"));
}
if (!base->GetType() || !base->GetType()->IsPtrInt32()) {
throw std::runtime_error(FormatError("ir", "GepInst base 必须为 i32*"));
if (!base->GetType() ||
(!base->GetType()->IsPtrInt32() && !base->GetType()->IsPtrFloat32())) {
throw std::runtime_error(FormatError("ir", "GepInst base 必须为 i32*/float*"));
}
if (!index->GetType() || !index->GetType()->IsInt32()) {
throw std::runtime_error(FormatError("ir", "GepInst index 必须为 i32"));

@ -27,8 +27,12 @@ Function* Module::FindFunction(const std::string& name) const {
return nullptr;
}
GlobalVariable* Module::CreateGlobalVar(const std::string& name, int init_val, int count) {
global_vars_.push_back(std::make_unique<GlobalVariable>(name, init_val, count));
GlobalVariable* Module::CreateGlobalVar(const std::string& name, int init_val,
int count, std::shared_ptr<Type> ptr_ty,
std::vector<int> init_elems) {
global_vars_.push_back(
std::make_unique<GlobalVariable>(name, std::move(ptr_ty), init_val, count,
std::move(init_elems)));
return global_vars_.back().get();
}

@ -20,6 +20,16 @@ const std::shared_ptr<Type>& Type::GetPtrInt32Type() {
return type;
}
const std::shared_ptr<Type>& Type::GetFloat32Type() {
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Float32);
return type;
}
const std::shared_ptr<Type>& Type::GetPtrFloat32Type() {
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::PtrFloat32);
return type;
}
Type::Kind Type::GetKind() const { return kind_; }
bool Type::IsVoid() const { return kind_ == Kind::Void; }
@ -28,4 +38,8 @@ bool Type::IsInt32() const { return kind_ == Kind::Int32; }
bool Type::IsPtrInt32() const { return kind_ == Kind::PtrInt32; }
bool Type::IsFloat32() const { return kind_ == Kind::Float32; }
bool Type::IsPtrFloat32() const { return kind_ == Kind::PtrFloat32; }
} // namespace ir

@ -22,6 +22,10 @@ bool Value::IsInt32() const { return type_ && type_->IsInt32(); }
bool Value::IsPtrInt32() const { return type_ && type_->IsPtrInt32(); }
bool Value::IsFloat32() const { return type_ && type_->IsFloat32(); }
bool Value::IsPtrFloat32() const { return type_ && type_->IsPtrFloat32(); }
bool Value::IsConstant() const {
return dynamic_cast<const ConstantValue*>(this) != nullptr;
}
@ -80,4 +84,7 @@ ConstantValue::ConstantValue(std::shared_ptr<Type> ty, std::string name)
ConstantInt::ConstantInt(std::shared_ptr<Type> ty, int v)
: ConstantValue(std::move(ty), ""), value_(v) {}
ConstantFloat::ConstantFloat(std::shared_ptr<Type> ty, float v)
: ConstantValue(std::move(ty), ""), value_(v) {}
} // namespace ir

@ -1,5 +1,7 @@
#include "irgen/IRGen.h"
#include <cmath>
#include <cstdlib>
#include <stdexcept>
#include <string>
@ -9,75 +11,103 @@
// 内部辅助:不依赖类成员,只需 ConstEnv。
namespace {
int EvalAddExp(SysYParser::AddExpContext* ctx,
const IRGenImpl::ConstEnv& env);
int EvalMulExp(SysYParser::MulExpContext* ctx,
const IRGenImpl::ConstEnv& env);
int EvalUnaryExp(SysYParser::UnaryExpContext* ctx,
const IRGenImpl::ConstEnv& env);
double EvalAddExp(SysYParser::AddExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env);
double EvalMulExp(SysYParser::MulExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env);
double EvalUnaryExp(SysYParser::UnaryExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env);
int EvalPrimary(SysYParser::PrimaryExpContext* ctx,
const IRGenImpl::ConstEnv& env) {
int ParseIntLiteral(const std::string& text) {
if (text.size() >= 2 && text[0] == '0' &&
(text[1] == 'x' || text[1] == 'X')) {
return std::stoi(text, nullptr, 16);
}
if (text.size() > 1 && text[0] == '0') {
return std::stoi(text, nullptr, 8);
}
return std::stoi(text);
}
double EvalPrimary(SysYParser::PrimaryExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env) {
if (!ctx) throw std::runtime_error(FormatError("consteval", "空主表达式"));
if (ctx->number()) {
if (!ctx->number()->ILITERAL())
throw std::runtime_error(
FormatError("consteval", "constExp 不支持浮点字面量"));
return std::stoi(ctx->number()->getText());
if (ctx->number()->ILITERAL()) {
return static_cast<double>(ParseIntLiteral(ctx->number()->getText()));
}
if (ctx->number()->FLITERAL()) {
return static_cast<double>(std::strtof(ctx->number()->getText().c_str(), nullptr));
}
throw std::runtime_error(FormatError("consteval", "非法数字字面量"));
}
if (ctx->exp()) return EvalAddExp(ctx->exp()->addExp(), env);
if (ctx->exp()) return EvalAddExp(ctx->exp()->addExp(), int_env, float_env);
if (ctx->lValue()) {
if (!ctx->lValue()->ID())
throw std::runtime_error(FormatError("consteval", "非法 lValue"));
const std::string name = ctx->lValue()->ID()->getText();
auto it = env.find(name);
if (it == env.end())
throw std::runtime_error(
FormatError("consteval", "constExp 引用非 const 变量: " + name));
return it->second;
auto it_int = int_env.find(name);
if (it_int != int_env.end()) return static_cast<double>(it_int->second);
auto it_float = float_env.find(name);
if (it_float != float_env.end()) return static_cast<double>(it_float->second);
throw std::runtime_error(
FormatError("consteval", "constExp 引用非 const 变量: " + name));
}
throw std::runtime_error(FormatError("consteval", "不支持的主表达式形式"));
}
int EvalUnaryExp(SysYParser::UnaryExpContext* ctx,
const IRGenImpl::ConstEnv& env) {
double EvalUnaryExp(SysYParser::UnaryExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env) {
if (!ctx) throw std::runtime_error(FormatError("consteval", "空一元表达式"));
if (ctx->primaryExp()) return EvalPrimary(ctx->primaryExp(), env);
if (ctx->primaryExp()) return EvalPrimary(ctx->primaryExp(), int_env, float_env);
if (ctx->unaryOp() && ctx->unaryExp()) {
int v = EvalUnaryExp(ctx->unaryExp(), env);
double v = EvalUnaryExp(ctx->unaryExp(), int_env, float_env);
if (ctx->unaryOp()->SUB()) return -v;
if (ctx->unaryOp()->ADD()) return v;
if (ctx->unaryOp()->NOT()) return (v == 0) ? 1 : 0;
if (ctx->unaryOp()->NOT()) return (v == 0.0) ? 1.0 : 0.0;
}
throw std::runtime_error(
FormatError("consteval", "函数调用不能出现在 constExp 中"));
}
int EvalMulExp(SysYParser::MulExpContext* ctx,
const IRGenImpl::ConstEnv& env) {
double EvalMulExp(SysYParser::MulExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env) {
if (!ctx) throw std::runtime_error(FormatError("consteval", "空乘法表达式"));
if (ctx->mulExp()) {
int lhs = EvalMulExp(ctx->mulExp(), env);
int rhs = EvalUnaryExp(ctx->unaryExp(), env);
double lhs = EvalMulExp(ctx->mulExp(), int_env, float_env);
double rhs = EvalUnaryExp(ctx->unaryExp(), int_env, float_env);
if (ctx->MUL()) return lhs * rhs;
if (ctx->DIV()) { if (!rhs) throw std::runtime_error("除以零"); return lhs / rhs; }
if (ctx->MOD()) { if (!rhs) throw std::runtime_error("模零"); return lhs % rhs; }
if (ctx->DIV()) {
if (rhs == 0.0) throw std::runtime_error("除以零");
return lhs / rhs;
}
if (ctx->MOD()) {
if (rhs == 0.0) throw std::runtime_error("模零");
return std::fmod(lhs, rhs);
}
throw std::runtime_error(FormatError("consteval", "未知乘法运算符"));
}
return EvalUnaryExp(ctx->unaryExp(), env);
return EvalUnaryExp(ctx->unaryExp(), int_env, float_env);
}
int EvalAddExp(SysYParser::AddExpContext* ctx,
const IRGenImpl::ConstEnv& env) {
double EvalAddExp(SysYParser::AddExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env) {
if (!ctx) throw std::runtime_error(FormatError("consteval", "空加法表达式"));
if (ctx->addExp()) {
int lhs = EvalAddExp(ctx->addExp(), env);
int rhs = EvalMulExp(ctx->mulExp(), env);
double lhs = EvalAddExp(ctx->addExp(), int_env, float_env);
double rhs = EvalMulExp(ctx->mulExp(), int_env, float_env);
if (ctx->ADD()) return lhs + rhs;
if (ctx->SUB()) return lhs - rhs;
throw std::runtime_error(FormatError("consteval", "未知加法运算符"));
}
return EvalMulExp(ctx->mulExp(), env);
return EvalMulExp(ctx->mulExp(), int_env, float_env);
}
} // namespace
@ -85,11 +115,23 @@ int EvalAddExp(SysYParser::AddExpContext* ctx,
int IRGenImpl::EvalConstExpr(SysYParser::ConstExpContext* ctx) const {
if (!ctx || !ctx->addExp())
throw std::runtime_error(FormatError("consteval", "空 constExp"));
return EvalAddExp(ctx->addExp(), const_env_);
return static_cast<int>(EvalAddExp(ctx->addExp(), const_env_, const_float_env_));
}
float IRGenImpl::EvalConstExprAsFloat(SysYParser::ConstExpContext* ctx) const {
if (!ctx || !ctx->addExp())
throw std::runtime_error(FormatError("consteval", "空 constExp"));
return static_cast<float>(EvalAddExp(ctx->addExp(), const_env_, const_float_env_));
}
int IRGenImpl::EvalExpAsConst(SysYParser::ExpContext* ctx) const {
if (!ctx || !ctx->addExp())
throw std::runtime_error(FormatError("consteval", "空 exp"));
return EvalAddExp(ctx->addExp(), const_env_);
return static_cast<int>(EvalAddExp(ctx->addExp(), const_env_, const_float_env_));
}
float IRGenImpl::EvalExpAsConstFloat(SysYParser::ExpContext* ctx) const {
if (!ctx || !ctx->addExp())
throw std::runtime_error(FormatError("consteval", "空 exp"));
return static_cast<float>(EvalAddExp(ctx->addExp(), const_env_, const_float_env_));
}

@ -1,5 +1,7 @@
#include "irgen/IRGen.h"
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include "SysYParser.h"
@ -10,6 +12,8 @@ std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句块"));
}
const auto saved_const_env = const_env_;
const auto saved_const_float_env = const_float_env_;
for (auto* item : ctx->blockItem()) {
if (item) {
if (VisitBlockItemResult(*item) == BlockFlow::Terminated) {
@ -17,6 +21,8 @@ std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
}
}
}
const_env_ = saved_const_env;
const_float_env_ = saved_const_float_env;
return {};
}
@ -98,6 +104,40 @@ void IRGenImpl::FlattenConstInit(SysYParser::ConstInitValueContext* ctx,
while (pos < start + agg_size) out[pos++] = 0;
}
void IRGenImpl::FlattenConstInitFloat(SysYParser::ConstInitValueContext* ctx,
const std::vector<int>& dims, int dim_idx,
std::vector<float>& out, int& pos) {
if (!ctx) return;
if (ctx->constExp()) {
out[pos++] = EvalConstExprAsFloat(ctx->constExp());
return;
}
int sub_size = 1;
for (int i = dim_idx + 1; i < (int)dims.size(); i++) sub_size *= dims[i];
int agg_size = (dim_idx < (int)dims.size()) ? dims[dim_idx] * sub_size : 1;
int start = pos;
for (auto* item : ctx->constInitValue()) {
if (!item || pos >= start + agg_size) break;
if (item->constExp()) {
out[pos++] = EvalConstExprAsFloat(item->constExp());
} else {
if (sub_size > 1) {
int offset = pos - start;
int rem = offset % sub_size;
if (rem != 0) pos += sub_size - rem;
}
int sub_start = pos;
FlattenConstInitFloat(item, dims, dim_idx + 1, out, pos);
int sub_end = sub_start + sub_size;
while (pos < sub_end && pos < start + agg_size) out[pos++] = 0.0f;
}
}
while (pos < start + agg_size) out[pos++] = 0.0f;
}
// ─── 工具:扁平化 initValue ───────────────────────────────────────────────
void IRGenImpl::FlattenInit(SysYParser::InitValueContext* ctx,
const std::vector<int>& dims, int dim_idx,
@ -133,16 +173,93 @@ void IRGenImpl::FlattenInit(SysYParser::InitValueContext* ctx,
while (pos < start + agg_size) pos++; // zeros
}
void IRGenImpl::FlattenGlobalInitInt(SysYParser::InitValueContext* ctx,
const std::vector<int>& dims, int dim_idx,
std::vector<int>& out, int& pos) {
if (!ctx) return;
if (ctx->exp()) {
out[pos++] = EvalExpAsConst(ctx->exp());
return;
}
int sub_size = 1;
for (int i = dim_idx + 1; i < (int)dims.size(); i++) sub_size *= dims[i];
int agg_size = (dim_idx < (int)dims.size()) ? dims[dim_idx] * sub_size : 1;
int start = pos;
for (auto* item : ctx->initValue()) {
if (!item || pos >= start + agg_size) break;
if (item->exp()) {
out[pos++] = EvalExpAsConst(item->exp());
} else {
if (sub_size > 1) {
int offset = pos - start;
int rem = offset % sub_size;
if (rem != 0) pos += sub_size - rem;
}
int sub_start = pos;
FlattenGlobalInitInt(item, dims, dim_idx + 1, out, pos);
int sub_end = sub_start + sub_size;
while (pos < sub_end && pos < start + agg_size) out[pos++] = 0;
}
}
while (pos < start + agg_size) out[pos++] = 0;
}
void IRGenImpl::FlattenGlobalInitFloat(SysYParser::InitValueContext* ctx,
const std::vector<int>& dims,
int dim_idx, std::vector<float>& out,
int& pos) {
if (!ctx) return;
if (ctx->exp()) {
out[pos++] = EvalExpAsConstFloat(ctx->exp());
return;
}
int sub_size = 1;
for (int i = dim_idx + 1; i < (int)dims.size(); i++) sub_size *= dims[i];
int agg_size = (dim_idx < (int)dims.size()) ? dims[dim_idx] * sub_size : 1;
int start = pos;
for (auto* item : ctx->initValue()) {
if (!item || pos >= start + agg_size) break;
if (item->exp()) {
out[pos++] = EvalExpAsConstFloat(item->exp());
} else {
if (sub_size > 1) {
int offset = pos - start;
int rem = offset % sub_size;
if (rem != 0) pos += sub_size - rem;
}
int sub_start = pos;
FlattenGlobalInitFloat(item, dims, dim_idx + 1, out, pos);
int sub_end = sub_start + sub_size;
while (pos < sub_end && pos < start + agg_size) out[pos++] = 0.0f;
}
}
while (pos < start + agg_size) out[pos++] = 0.0f;
}
// ─── const 声明 ───────────────────────────────────────────────────────────
std::any IRGenImpl::visitConstDecl(SysYParser::ConstDeclContext* ctx) {
if (!ctx) return {};
if (!ctx->btype() || !ctx->btype()->INT()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持 int const 声明"));
if (!ctx->btype()) {
throw std::runtime_error(FormatError("irgen", "缺少类型声明"));
}
if (ctx->btype()->INT()) {
current_decl_type_ = ir::Type::GetInt32Type();
} else if (ctx->btype()->FLOAT()) {
current_decl_type_ = ir::Type::GetFloat32Type();
} else {
throw std::runtime_error(FormatError("irgen", "当前仅支持 int/float const 声明"));
}
for (auto* def : ctx->constDef()) {
if (def) def->accept(this);
}
current_decl_type_ = nullptr;
return {};
}
@ -155,16 +272,34 @@ std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) {
if (!ctx->constInitValue() || !ctx->constInitValue()->constExp()) {
throw std::runtime_error(FormatError("irgen", "const 标量声明缺少初始值"));
}
int ival = EvalConstExpr(ctx->constInitValue()->constExp());
const_env_[name] = ival; // 存入编译期环境
if (IsGlobalScope()) {
auto* gv = module_.CreateGlobalVar(name, ival);
global_storage_[name] = gv;
const bool is_float_const = current_decl_type_ && current_decl_type_->IsFloat32();
if (is_float_const) {
float fval = EvalConstExprAsFloat(ctx->constInitValue()->constExp());
const_float_env_[name] = fval;
if (IsGlobalScope()) {
std::int32_t bits = 0;
std::memcpy(&bits, &fval, sizeof(bits));
auto* gv = module_.CreateGlobalVar(
name, static_cast<int>(bits), 1, ir::Type::GetPtrFloat32Type());
global_storage_[name] = gv;
} else {
auto* slot = CreateEntryAllocaF32(module_.GetContext().NextTemp());
named_storage_[name] = slot;
builder_.CreateStore(module_.GetContext().GetConstFloat(fval), slot);
}
} else {
auto* slot = CreateEntryAllocaI32(module_.GetContext().NextTemp());
named_storage_[name] = slot;
builder_.CreateStore(builder_.CreateConstInt(ival), slot);
int ival = EvalConstExpr(ctx->constInitValue()->constExp());
const_env_[name] = ival; // 存入编译期环境
if (IsGlobalScope()) {
auto* gv = module_.CreateGlobalVar(name, ival);
global_storage_[name] = gv;
} else {
auto* slot = CreateEntryAllocaI32(module_.GetContext().NextTemp());
named_storage_[name] = slot;
builder_.CreateStore(builder_.CreateConstInt(ival), slot);
}
}
return {};
}
@ -177,6 +312,40 @@ std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) {
int total = 1;
for (int d : dims) total *= d;
const bool is_float_const = current_decl_type_ && current_decl_type_->IsFloat32();
if (is_float_const) {
std::vector<float> flat(total, 0.0f);
if (ctx->constInitValue()) {
int pos = 0;
FlattenConstInitFloat(ctx->constInitValue(), dims, 0, flat, pos);
}
std::vector<int> init_bits;
init_bits.reserve(flat.size());
for (float v : flat) {
std::int32_t bits = 0;
std::memcpy(&bits, &v, sizeof(bits));
init_bits.push_back(static_cast<int>(bits));
}
if (IsGlobalScope()) {
auto* gv = module_.CreateGlobalVar(
name, 0, total, ir::Type::GetPtrFloat32Type(), std::move(init_bits));
global_storage_[name] = gv;
global_array_dims_[name] = dims;
} else {
auto* slot = CreateEntryAllocaF32Array(total, module_.GetContext().NextTemp());
named_storage_[name] = slot;
local_array_dims_[name] = dims;
for (int i = 0; i < total; i++) {
auto* idx = builder_.CreateConstInt(i);
auto* ptr = builder_.CreateGep(slot, idx, module_.GetContext().NextTemp());
builder_.CreateStore(module_.GetContext().GetConstFloat(flat[i]), ptr);
}
}
return {};
}
// 扁平化初始化值
std::vector<int> flat(total, 0);
if (ctx->constInitValue()) {
@ -185,9 +354,9 @@ std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) {
}
if (IsGlobalScope()) {
// 全局 const 数组:创建全局数组变量(仅支持零初始化;非零初始化暂用零)
// TODO: 支持全局 const 数组的非零初始化
auto* gv = module_.CreateGlobalVar(name, 0, total);
auto* gv = module_.CreateGlobalVar(name, 0, total,
ir::Type::GetPtrInt32Type(),
std::move(flat));
global_storage_[name] = gv;
global_array_dims_[name] = dims;
} else {
@ -210,15 +379,25 @@ std::any IRGenImpl::visitVarDecl(SysYParser::VarDeclContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少变量声明"));
}
if (!ctx->btype() || !ctx->btype()->INT()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持 int 变量声明"));
if (!ctx->btype()) {
throw std::runtime_error(FormatError("irgen", "缺少类型声明"));
}
// 设置当前声明类型
if (ctx->btype()->INT()) {
current_decl_type_ = ir::Type::GetInt32Type();
} else if (ctx->btype()->FLOAT()) {
current_decl_type_ = ir::Type::GetFloat32Type();
} else {
throw std::runtime_error(FormatError("irgen", "当前仅支持 int/float 变量声明"));
}
for (auto* var_def : ctx->varDef()) {
if (!var_def) {
throw std::runtime_error(FormatError("irgen", "非法变量声明"));
}
var_def->accept(this);
}
current_decl_type_ = nullptr; // 清理
return {};
}
@ -238,22 +417,66 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
for (int d : dims) total *= d;
if (IsGlobalScope()) {
auto* gv = module_.CreateGlobalVar(name, 0, total);
std::vector<int> init_elems;
if (auto* init_val = ctx->initValue()) {
if (current_decl_type_->IsFloat32()) {
std::vector<float> flat(total, 0.0f);
int pos = 0;
FlattenGlobalInitFloat(init_val, dims, 0, flat, pos);
init_elems.reserve(flat.size());
for (float v : flat) {
std::int32_t bits = 0;
std::memcpy(&bits, &v, sizeof(bits));
init_elems.push_back(static_cast<int>(bits));
}
} else {
init_elems.assign(total, 0);
int pos = 0;
FlattenGlobalInitInt(init_val, dims, 0, init_elems, pos);
}
}
auto* gv = module_.CreateGlobalVar(
name, 0, total,
current_decl_type_->IsFloat32() ? ir::Type::GetPtrFloat32Type()
: ir::Type::GetPtrInt32Type(),
std::move(init_elems));
storage_map_[ctx] = gv;
global_storage_[name] = gv;
global_array_dims_[name] = dims;
// 全局数组:不支持运行时初始化(全零已足够)
} else {
auto* slot = CreateEntryAllocaArray(total, module_.GetContext().NextTemp());
// 根据当前声明类型创建数组alloca
ir::AllocaInst* slot;
if (current_decl_type_->IsFloat32()) {
slot = CreateEntryAllocaF32Array(total, module_.GetContext().NextTemp());
} else {
slot = CreateEntryAllocaArray(total, module_.GetContext().NextTemp());
}
storage_map_[ctx] = slot;
named_storage_[name] = slot;
local_array_dims_[name] = dims;
// 先零初始化
for (int i = 0; i < total; i++) {
auto* idx = builder_.CreateConstInt(i);
auto* ptr = builder_.CreateGep(slot, idx, module_.GetContext().NextTemp());
builder_.CreateStore(builder_.CreateConstInt(0), ptr);
// 先零初始化float 数组走 memsetint 数组维持逐元素 store。
if (current_decl_type_->IsFloat32()) {
if (total > 0) {
auto* memset_fn = module_.FindFunction("memset");
if (!memset_fn) {
memset_fn = module_.CreateFunction(
"memset", ir::Type::GetVoidType(),
{ir::Type::GetPtrFloat32Type(), ir::Type::GetInt32Type(),
ir::Type::GetInt32Type()});
memset_fn->SetExternal(true);
}
builder_.CreateCall(
memset_fn,
{slot, builder_.CreateConstInt(0), builder_.CreateConstInt(total * 4)},
module_.GetContext().NextTemp());
}
} else {
for (int i = 0; i < total; i++) {
auto* idx = builder_.CreateConstInt(i);
auto* ptr = builder_.CreateGep(slot, idx, module_.GetContext().NextTemp());
builder_.CreateStore(builder_.CreateConstInt(0), ptr);
}
}
// 如果有初始化列表,覆盖零
if (auto* init_val = ctx->initValue()) {
@ -264,7 +487,13 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
if (flat[i] != nullptr) {
auto* idx = builder_.CreateConstInt(i);
auto* ptr = builder_.CreateGep(slot, idx, module_.GetContext().NextTemp());
builder_.CreateStore(flat[i], ptr);
ir::Value* val = flat[i];
if (ptr->GetType()->IsPtrFloat32()) {
val = CastToFloat(val);
} else {
val = CastToInt(val);
}
builder_.CreateStore(val, ptr);
}
}
}
@ -274,15 +503,32 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
// ── 标量变量 ──────────────────────────────────────────────────────────
if (IsGlobalScope()) {
int ival = 0;
if (auto* init_value = ctx->initValue()) {
if (!init_value->exp()) {
throw std::runtime_error(
FormatError("irgen", "全局标量变量仅支持表达式初始化"));
int init_bits_or_int = 0;
if (current_decl_type_->IsFloat32()) {
float fval = 0.0f;
if (auto* init_value = ctx->initValue()) {
if (!init_value->exp()) {
throw std::runtime_error(
FormatError("irgen", "全局标量变量仅支持表达式初始化"));
}
fval = EvalExpAsConstFloat(init_value->exp());
}
std::int32_t bits = 0;
std::memcpy(&bits, &fval, sizeof(bits));
init_bits_or_int = static_cast<int>(bits);
} else {
if (auto* init_value = ctx->initValue()) {
if (!init_value->exp()) {
throw std::runtime_error(
FormatError("irgen", "全局标量变量仅支持表达式初始化"));
}
init_bits_or_int = EvalExpAsConst(init_value->exp());
}
ival = EvalExpAsConst(init_value->exp());
}
auto* gv = module_.CreateGlobalVar(name, ival);
auto* gv = module_.CreateGlobalVar(
name, init_bits_or_int, 1,
current_decl_type_->IsFloat32() ? ir::Type::GetPtrFloat32Type()
: ir::Type::GetPtrInt32Type());
storage_map_[ctx] = gv;
global_storage_[name] = gv;
return {};
@ -292,7 +538,14 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
if (storage_map_.find(ctx) != storage_map_.end()) {
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
}
auto* slot = CreateEntryAllocaI32(module_.GetContext().NextTemp());
// 根据当前声明类型创建alloca
ir::AllocaInst* slot;
if (current_decl_type_->IsFloat32()) {
slot = CreateEntryAllocaF32(module_.GetContext().NextTemp());
} else {
slot = CreateEntryAllocaI32(module_.GetContext().NextTemp());
}
storage_map_[ctx] = slot;
named_storage_[name] = slot;
@ -303,7 +556,16 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
}
init = EvalExpr(*init_value->exp());
} else {
init = builder_.CreateConstInt(0);
if (current_decl_type_->IsFloat32()) {
init = module_.GetContext().GetConstFloat(0.0f);
} else {
init = builder_.CreateConstInt(0);
}
}
if (current_decl_type_->IsFloat32()) {
init = CastToFloat(init);
} else {
init = CastToInt(init);
}
builder_.CreateStore(init, slot);
return {};

@ -14,18 +14,42 @@ ir::Value* IRGenImpl::EvalCond(SysYParser::CondContext& cond) {
return std::any_cast<ir::Value*>(cond.accept(this));
}
ir::Value* IRGenImpl::CastToFloat(ir::Value* v) {
if (!v || !v->GetType()) {
throw std::runtime_error(FormatError("irgen", "CastToFloat 输入为空"));
}
if (v->GetType()->IsFloat32()) return v;
if (v->GetType()->IsInt32()) {
return builder_.CreateSIToFP(v, module_.GetContext().NextTemp());
}
throw std::runtime_error(FormatError("irgen", "不支持转换到 float 的类型"));
}
ir::Value* IRGenImpl::CastToInt(ir::Value* v) {
if (!v || !v->GetType()) {
throw std::runtime_error(FormatError("irgen", "CastToInt 输入为空"));
}
if (v->GetType()->IsInt32()) return v;
if (v->GetType()->IsFloat32()) {
return builder_.CreateFPToSI(v, module_.GetContext().NextTemp());
}
throw std::runtime_error(FormatError("irgen", "不支持转换到 i32 的类型"));
}
ir::Value* IRGenImpl::ToBoolValue(ir::Value* v) {
if (!v) {
throw std::runtime_error(FormatError("irgen", "条件值为空"));
}
if (v->GetType() && v->GetType()->IsPtrInt32()) {
if (v->GetType() && (v->GetType()->IsPtrInt32() || v->GetType()->IsPtrFloat32())) {
// SysY 中数组名退化得到的指针在当前实现里总是非空。
return builder_.CreateConstInt(1);
}
if (dynamic_cast<ir::CmpInst*>(v) != nullptr) {
return v;
}
auto* zero = builder_.CreateConstInt(0);
ir::Value* zero = v->GetType()->IsFloat32()
? static_cast<ir::Value*>(module_.GetContext().GetConstFloat(0.0f))
: static_cast<ir::Value*>(builder_.CreateConstInt(0));
return builder_.CreateCmp(ir::CmpOp::Ne, v, zero, module_.GetContext().NextTemp());
}
@ -60,7 +84,7 @@ ir::Value* IRGenImpl::ComputeLinearIndex(
int stride = 1;
for (int j = k + 1; j < (int)dims.size(); j++) stride *= dims[j];
ir::Value* idx = EvalExpr(*subs[k]);
ir::Value* idx = CastToInt(EvalExpr(*subs[k]));
if (stride != 1) {
auto* sv = builder_.CreateConstInt(stride);
idx = builder_.CreateMul(idx, sv, module_.GetContext().NextTemp());
@ -105,8 +129,20 @@ std::any IRGenImpl::visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) {
}
std::any IRGenImpl::visitNumber(SysYParser::NumberContext* ctx) {
if (!ctx || !ctx->ILITERAL()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量"));
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少数字字面量"));
}
// 浮点字面量
if (ctx->FLITERAL()) {
const std::string text = ctx->getText();
float val = std::stof(text);
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(val));
}
// 整数字面量
if (!ctx->ILITERAL()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持整数和浮点字面量"));
}
// 支持十六进制和八进制字面量
const std::string text = ctx->getText();
@ -172,6 +208,15 @@ std::any IRGenImpl::visitLValue(SysYParser::LValueContext* ctx) {
const std::string name = ctx->ID()->getText();
if (ctx->exp().empty()) {
auto itf = const_float_env_.find(name);
if (itf != const_float_env_.end()) {
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(itf->second));
}
auto iti = const_env_.find(name);
if (iti != const_env_.end()) {
return static_cast<ir::Value*>(builder_.CreateConstInt(iti->second));
}
// 无下标:标量读取 或 数组基址引用
ir::Value* slot = ResolveStorage(ctx);
if (!slot) {
@ -218,7 +263,9 @@ std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
if (ctx->unaryOp() && ctx->unaryExp()) {
ir::Value* v = std::any_cast<ir::Value*>(ctx->unaryExp()->accept(this));
if (ctx->unaryOp()->SUB()) {
auto* zero = builder_.CreateConstInt(0);
ir::Value* zero = v->GetType()->IsFloat32()
? static_cast<ir::Value*>(module_.GetContext().GetConstFloat(0.0f))
: static_cast<ir::Value*>(builder_.CreateConstInt(0));
return static_cast<ir::Value*>(builder_.CreateSub(
zero, v, module_.GetContext().NextTemp()));
}
@ -227,7 +274,9 @@ std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
}
if (ctx->unaryOp()->NOT()) {
// !v ≡ (v == 0)
auto* zero = builder_.CreateConstInt(0);
ir::Value* zero = v->GetType()->IsFloat32()
? static_cast<ir::Value*>(module_.GetContext().GetConstFloat(0.0f))
: static_cast<ir::Value*>(builder_.CreateConstInt(0));
return static_cast<ir::Value*>(builder_.CreateCmp(
ir::CmpOp::Eq, v, zero, module_.GetContext().NextTemp()));
}
@ -243,8 +292,19 @@ std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
}
std::vector<ir::Value*> args;
if (auto* rparams = ctx->funcRParams()) {
const auto& param_types = callee->GetParamTypes();
size_t i = 0;
for (auto* ep : rparams->exp()) {
args.push_back(EvalExpr(*ep));
ir::Value* arg = EvalExpr(*ep);
if (i < param_types.size()) {
if (param_types[i]->IsFloat32()) {
arg = CastToFloat(arg);
} else if (param_types[i]->IsInt32()) {
arg = CastToInt(arg);
}
}
args.push_back(arg);
++i;
}
}
const std::string name =
@ -265,6 +325,11 @@ std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) {
}
ir::Value* lhs = std::any_cast<ir::Value*>(ctx->mulExp()->accept(this));
ir::Value* rhs = std::any_cast<ir::Value*>(ctx->unaryExp()->accept(this));
const bool has_float = lhs->GetType()->IsFloat32() || rhs->GetType()->IsFloat32();
if (has_float) {
lhs = CastToFloat(lhs);
rhs = CastToFloat(rhs);
}
if (ctx->MUL()) {
return static_cast<ir::Value*>(
builder_.CreateMul(lhs, rhs, module_.GetContext().NextTemp()));
@ -274,6 +339,8 @@ std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) {
builder_.CreateDiv(lhs, rhs, module_.GetContext().NextTemp()));
}
if (ctx->MOD()) {
lhs = CastToInt(lhs);
rhs = CastToInt(rhs);
return static_cast<ir::Value*>(
builder_.CreateMod(lhs, rhs, module_.GetContext().NextTemp()));
}
@ -295,6 +362,10 @@ std::any IRGenImpl::visitAddExp(SysYParser::AddExpContext* ctx) {
}
ir::Value* lhs = std::any_cast<ir::Value*>(ctx->addExp()->accept(this));
ir::Value* rhs = std::any_cast<ir::Value*>(ctx->mulExp()->accept(this));
if (lhs->GetType()->IsFloat32() || rhs->GetType()->IsFloat32()) {
lhs = CastToFloat(lhs);
rhs = CastToFloat(rhs);
}
if (ctx->ADD()) {
return static_cast<ir::Value*>(
builder_.CreateAdd(lhs, rhs, module_.GetContext().NextTemp()));
@ -321,6 +392,10 @@ std::any IRGenImpl::visitRelExp(SysYParser::RelExpContext* ctx) {
}
ir::Value* lhs = std::any_cast<ir::Value*>(ctx->relExp()->accept(this));
ir::Value* rhs = std::any_cast<ir::Value*>(ctx->addExp()->accept(this));
if (lhs->GetType()->IsFloat32() || rhs->GetType()->IsFloat32()) {
lhs = CastToFloat(lhs);
rhs = CastToFloat(rhs);
}
if (ctx->LT()) {
return static_cast<ir::Value*>(builder_.CreateCmp(
ir::CmpOp::Lt, lhs, rhs, module_.GetContext().NextTemp()));
@ -355,6 +430,10 @@ std::any IRGenImpl::visitEqExp(SysYParser::EqExpContext* ctx) {
}
ir::Value* lhs = std::any_cast<ir::Value*>(ctx->eqExp()->accept(this));
ir::Value* rhs = std::any_cast<ir::Value*>(ctx->relExp()->accept(this));
if (lhs->GetType()->IsFloat32() || rhs->GetType()->IsFloat32()) {
lhs = CastToFloat(lhs);
rhs = CastToFloat(rhs);
}
if (ctx->EQ()) {
return static_cast<ir::Value*>(builder_.CreateCmp(
ir::CmpOp::Eq, lhs, rhs, module_.GetContext().NextTemp()));

@ -49,6 +49,28 @@ ir::AllocaInst* IRGenImpl::CreateEntryAllocaArray(int count, const std::string&
return slot;
}
ir::AllocaInst* IRGenImpl::CreateEntryAllocaF32(const std::string& name) {
if (!func_) {
throw std::runtime_error(FormatError("irgen", "局部 alloca 必须位于函数内"));
}
auto* saved = builder_.GetInsertBlock();
builder_.SetInsertPoint(func_->GetEntry());
auto* slot = builder_.CreateAllocaF32(name);
builder_.SetInsertPoint(saved);
return slot;
}
ir::AllocaInst* IRGenImpl::CreateEntryAllocaF32Array(int count, const std::string& name) {
if (!func_) {
throw std::runtime_error(FormatError("irgen", "局部 alloca 必须位于函数内"));
}
auto* saved = builder_.GetInsertBlock();
builder_.SetInsertPoint(func_->GetEntry());
auto* slot = builder_.CreateAllocaF32Array(count, name);
builder_.SetInsertPoint(saved);
return slot;
}
// 预声明 SysY 运行时外部函数putint / putch / getint / getch 等)。
void IRGenImpl::DeclareRuntimeFunctions() {
auto i32 = ir::Type::GetInt32Type();
@ -71,9 +93,16 @@ void IRGenImpl::DeclareRuntimeFunctions() {
// 数组 I/O
decl("getarray", i32, {ir::Type::GetPtrInt32Type()});
decl("putarray", void_, {i32, ir::Type::GetPtrInt32Type()});
// 浮点 I/O
decl("getfloat", ir::Type::GetFloat32Type(), {});
decl("getfarray", i32, {ir::Type::GetPtrFloat32Type()});
decl("putfloat", void_, {ir::Type::GetFloat32Type()});
decl("putfarray", void_, {i32, ir::Type::GetPtrFloat32Type()});
// 时间
decl("starttime", void_, {});
decl("stoptime", void_, {});
// 通用内存清零(用于局部 float 大数组初始化)
decl("memset", void_, {ir::Type::GetPtrFloat32Type(), i32, i32});
}
// 编译单元 IR 生成:
@ -130,8 +159,10 @@ std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
ret_type = ir::Type::GetInt32Type();
} else if (ctx->funcType()->VOID()) {
ret_type = ir::Type::GetVoidType();
} else if (ctx->funcType()->FLOAT()) {
ret_type = ir::Type::GetFloat32Type();
} else {
throw std::runtime_error(FormatError("irgen", "当前仅支持 int/void 返回类型"));
throw std::runtime_error(FormatError("irgen", "当前仅支持 int/void/float 返回类型"));
}
// 收集形参类型(支持 int 标量和 int 数组参数)。
@ -141,14 +172,25 @@ std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
if (auto* fparams = ctx->funcFParams()) {
for (auto* fp : fparams->funcFParam()) {
if (!fp || !fp->btype() || !fp->btype()->INT()) {
if (!fp || !fp->btype()) {
throw std::runtime_error(
FormatError("irgen", "缺少参数类型"));
}
bool is_int = fp->btype()->INT() != nullptr;
bool is_float = fp->btype()->FLOAT() != nullptr;
if (!is_int && !is_float) {
throw std::runtime_error(
FormatError("irgen", "当前仅支持 int 类型形参"));
FormatError("irgen", "当前仅支持 int/float 类型形参"));
}
bool is_arr = !fp->LBRACK().empty();
param_is_array.push_back(is_arr);
param_types.push_back(is_arr ? ir::Type::GetPtrInt32Type()
: ir::Type::GetInt32Type());
if (is_arr) {
param_types.push_back(is_int ? ir::Type::GetPtrInt32Type()
: ir::Type::GetPtrFloat32Type());
} else {
param_types.push_back(is_int ? ir::Type::GetInt32Type()
: ir::Type::GetFloat32Type());
}
param_names.push_back(fp->ID() ? fp->ID()->getText() : "");
}
}
@ -181,7 +223,12 @@ std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
}
} else {
// 标量参数alloca + store
auto* slot = CreateEntryAllocaI32(module_.GetContext().NextTemp());
ir::AllocaInst* slot = nullptr;
if (arg->GetType()->IsFloat32()) {
slot = CreateEntryAllocaF32(module_.GetContext().NextTemp());
} else {
slot = CreateEntryAllocaI32(module_.GetContext().NextTemp());
}
builder_.CreateStore(arg, slot);
if (!param_names[i].empty()) {
named_storage_[param_names[i]] = slot;

@ -29,6 +29,11 @@ std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
? ctx->lValue()->ID()->getText()
: "?")));
}
if (slot->GetType() && slot->GetType()->IsPtrFloat32()) {
rhs = CastToFloat(rhs);
} else if (slot->GetType() && slot->GetType()->IsPtrInt32()) {
rhs = CastToInt(rhs);
}
builder_.CreateStore(rhs, slot);
return BlockFlow::Continue;
}
@ -138,6 +143,13 @@ std::any IRGenImpl::visitReturnStmt(SysYParser::ReturnStmtContext* ctx) {
return BlockFlow::Terminated;
}
ir::Value* v = EvalExpr(*ctx->exp());
if (func_ && func_->GetType()) {
if (func_->GetType()->IsFloat32()) {
v = CastToFloat(v);
} else if (func_->GetType()->IsInt32()) {
v = CastToInt(v);
}
}
builder_.CreateRet(v);
return BlockFlow::Terminated;
}

@ -149,13 +149,16 @@ int main(int argc, char** argv) {
}
if (opts.emit_asm) {
auto machine_func = mir::LowerToMIR(*module);
mir::RunRegAlloc(*machine_func);
mir::RunFrameLowering(*machine_func);
auto machine_module = mir::LowerToMIR(*module);
for (const auto& func_ptr : machine_module->GetFunctions()) {
mir::RunPeephole(*func_ptr);
mir::RunRegAlloc(*func_ptr);
mir::RunFrameLowering(*func_ptr);
}
if (need_blank_line) {
std::cout << "\n";
}
mir::PrintAsm(*machine_func, std::cout);
mir::PrintAsm(*machine_module, std::cout);
}
#else
if (opts.emit_ir || opts.emit_asm) {

@ -1,8 +1,10 @@
#include "mir/MIR.h"
#include <cstdint>
#include <ostream>
#include <stdexcept>
#include "ir/IR.h"
#include "utils/Log.h"
namespace mir {
@ -16,63 +18,394 @@ const FrameSlot& GetFrameSlot(const MachineFunction& function,
return function.GetFrameSlot(operand.GetFrameIndex());
}
void PrintMoveImm32(std::ostream& os, PhysReg reg, int imm) {
std::uint32_t u = static_cast<std::uint32_t>(imm);
std::uint32_t lo = u & 0xFFFFu;
std::uint32_t hi = (u >> 16) & 0xFFFFu;
os << " movz " << PhysRegName(reg) << ", #" << lo << "\n";
if (hi != 0) {
os << " movk " << PhysRegName(reg) << ", #" << hi << ", lsl #16\n";
}
}
void PrintStackAdjust(std::ostream& os, const char* mnemonic, int size) {
if (size >= 0 && size <= 4095) {
os << " " << mnemonic << " sp, sp, #" << size << "\n";
return;
}
PrintMoveImm32(os, PhysReg::X10, size);
os << " " << mnemonic << " sp, sp, x10\n";
}
void PrintAddrFromX29(std::ostream& os, PhysReg dst, int offset) {
if (offset >= -4095 && offset <= 4095) {
if (offset >= 0) {
os << " add " << PhysRegName(dst) << ", x29, #" << offset << "\n";
} else {
os << " sub " << PhysRegName(dst) << ", x29, #" << (-offset) << "\n";
}
return;
}
// 使用 X11 而不是 X10避免与数组索引偏移量冲突
PrintMoveImm32(os, PhysReg::X11, offset < 0 ? -offset : offset);
if (offset >= 0) {
os << " add " << PhysRegName(dst) << ", x29, x11\n";
} else {
os << " sub " << PhysRegName(dst) << ", x29, x11\n";
}
}
void PrintStackAccess(std::ostream& os, const char* mnemonic, PhysReg reg,
int offset) {
os << " " << mnemonic << " " << PhysRegName(reg) << ", [x29, #" << offset
<< "]\n";
// AArch64 ldur/stur 只支持 -256..255 的立即数偏移
if (offset >= -256 && offset <= 255) {
os << " " << mnemonic << " " << PhysRegName(reg) << ", [x29, #" << offset
<< "]\n";
} else {
// 大偏移:使用 x11 作为临时寄存器X10 用于数组索引)
bool is_load = (mnemonic[0] == 'l'); // ldur -> ldr
const char* base_mnemonic = is_load ? "ldr" : "str";
PrintAddrFromX29(os, PhysReg::X11, offset);
os << " " << base_mnemonic << " " << PhysRegName(reg) << ", [x11]\n";
}
}
const char* CondSuffix(ir::CmpOp cmp_op) {
switch (cmp_op) {
case ir::CmpOp::Eq:
return "eq";
case ir::CmpOp::Ne:
return "ne";
case ir::CmpOp::Lt:
return "lt";
case ir::CmpOp::Le:
return "le";
case ir::CmpOp::Gt:
return "gt";
case ir::CmpOp::Ge:
return "ge";
}
return "eq";
}
// 浮点比较使用 IEEE 754 兼容的条件码(正确处理 NaN
const char* FloatCondSuffix(ir::CmpOp cmp_op) {
switch (cmp_op) {
case ir::CmpOp::Eq:
return "eq"; // Z==1
case ir::CmpOp::Ne:
return "ne"; // Z==0
case ir::CmpOp::Lt:
return "mi"; // N==1 (minus, 正确处理 NaN)
case ir::CmpOp::Le:
return "ls"; // !(C==1 && Z==0) (lower or same, 正确处理 NaN)
case ir::CmpOp::Gt:
return "gt"; // Z==0 && N==V (已正确处理 NaN)
case ir::CmpOp::Ge:
return "ge"; // N==V (已正确处理 NaN)
}
return "eq";
}
} // namespace
void PrintAsm(const MachineFunction& function, std::ostream& os) {
os << ".text\n";
os << ".global " << function.GetName() << "\n";
os << ".type " << function.GetName() << ", %function\n";
os << function.GetName() << ":\n";
for (const auto& inst : function.GetEntry().GetInstructions()) {
const auto& ops = inst.GetOperands();
switch (inst.GetOpcode()) {
case Opcode::Prologue:
os << " stp x29, x30, [sp, #-16]!\n";
os << " mov x29, sp\n";
if (function.GetFrameSize() > 0) {
os << " sub sp, sp, #" << function.GetFrameSize() << "\n";
void PrintAsm(const MachineModule& module, std::ostream& os) {
// 输出全局变量定义
if (!module.GetGlobalVars().empty()) {
os << ".data\n";
for (const auto& [name, init_val, count, is_float, init_elems] :
module.GetGlobalVars()) {
(void)is_float;
os << ".global " << name << "\n";
os << ".type " << name << ", %object\n";
os << name << ":\n";
if (count == 1) {
// 标量全局变量
os << " .word " << init_val << "\n";
} else {
// 数组全局变量:优先输出显式初始化元素,剩余部分补零。
int emitted = 0;
for (int elem : init_elems) {
if (emitted >= count) {
break;
}
os << " .word " << elem << "\n";
++emitted;
}
break;
case Opcode::Epilogue:
if (function.GetFrameSize() > 0) {
os << " add sp, sp, #" << function.GetFrameSize() << "\n";
if (emitted == 0) {
os << " .zero " << (count * 4) << "\n";
} else if (emitted < count) {
os << " .zero " << ((count - emitted) * 4) << "\n";
}
os << " ldp x29, x30, [sp], #16\n";
break;
case Opcode::MovImm:
os << " mov " << PhysRegName(ops.at(0).GetReg()) << ", #"
<< ops.at(1).GetImm() << "\n";
break;
case Opcode::LoadStack: {
const auto& slot = GetFrameSlot(function, ops.at(1));
PrintStackAccess(os, "ldur", ops.at(0).GetReg(), slot.offset);
break;
}
case Opcode::StoreStack: {
const auto& slot = GetFrameSlot(function, ops.at(1));
PrintStackAccess(os, "stur", ops.at(0).GetReg(), slot.offset);
break;
}
os << "\n";
}
os << ".text\n";
for (const auto& func_ptr : module.GetFunctions()) {
const auto& function = *func_ptr;
os << ".global " << function.GetName() << "\n";
os << ".type " << function.GetName() << ", %function\n";
os << function.GetName() << ":\n";
// 遍历所有基本块
for (const auto& bb_ptr : function.GetBlocks()) {
const auto& bb = *bb_ptr;
// 打印块标签entry 块不需要标签,因为函数名已经是标签了)
if (bb.GetName() != "entry") {
os << "." << bb.GetName() << ":\n";
}
for (const auto& inst : bb.GetInstructions()) {
const auto& ops = inst.GetOperands();
switch (inst.GetOpcode()) {
case Opcode::Prologue:
os << " stp x29, x30, [sp, #-16]!\n";
os << " mov x29, sp\n";
if (function.GetFrameSize() > 0) {
PrintStackAdjust(os, "sub", function.GetFrameSize());
}
break;
case Opcode::Epilogue:
if (function.GetFrameSize() > 0) {
PrintStackAdjust(os, "add", function.GetFrameSize());
}
os << " ldp x29, x30, [sp], #16\n";
break;
case Opcode::MovImm:
PrintMoveImm32(os, ops.at(0).GetReg(), ops.at(1).GetImm());
break;
case Opcode::MovReg:
os << " mov " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << "\n";
break;
case Opcode::FMovImm:
// 通用浮点立即数:先装载 bit pattern再位级移动到 s 寄存器。
PrintMoveImm32(os, PhysReg::W10, ops.at(1).GetImm());
os << " fmov " << PhysRegName(ops.at(0).GetReg()) << ", w10\n";
break;
case Opcode::FMovReg:
os << " fmov " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << "\n";
break;
case Opcode::LoadStack: {
const auto& slot = GetFrameSlot(function, ops.at(1));
PrintStackAccess(os, "ldur", ops.at(0).GetReg(), slot.offset);
break;
}
case Opcode::StoreStack: {
const auto& slot = GetFrameSlot(function, ops.at(1));
PrintStackAccess(os, "stur", ops.at(0).GetReg(), slot.offset);
break;
}
case Opcode::LoadStackOffset: {
// ops: reg, frame_index, imm_offset
const auto& slot = GetFrameSlot(function, ops.at(1));
int final_offset = slot.offset + ops.at(2).GetImm();
PrintStackAccess(os, "ldur", ops.at(0).GetReg(), final_offset);
break;
}
case Opcode::StoreStackOffset: {
// ops: reg, frame_index, imm_offset
const auto& slot = GetFrameSlot(function, ops.at(1));
int final_offset = slot.offset + ops.at(2).GetImm();
PrintStackAccess(os, "stur", ops.at(0).GetReg(), final_offset);
break;
}
case Opcode::LoadStackAddr: {
// ops: xN, frame_index
// add xN, x29, #offset
const auto& slot = GetFrameSlot(function, ops.at(1));
PrintAddrFromX29(os, ops.at(0).GetReg(), slot.offset);
break;
}
case Opcode::LoadIndirect: {
// ops: wN, xM
// ldr wN, [xM]
os << " ldr " << PhysRegName(ops.at(0).GetReg()) << ", ["
<< PhysRegName(ops.at(1).GetReg()) << "]\n";
break;
}
case Opcode::StoreIndirect: {
// ops: wN, xM
// str wN, [xM]
os << " str " << PhysRegName(ops.at(0).GetReg()) << ", ["
<< PhysRegName(ops.at(1).GetReg()) << "]\n";
break;
}
case Opcode::LoadGlobal: {
// adrp x9, global_var
// add x9, x9, :lo12:global_var
// ldr wN, [x9]
const std::string& name = ops.at(1).GetSymbol();
os << " adrp x9, " << name << "\n";
os << " add x9, x9, :lo12:" << name << "\n";
os << " ldr " << PhysRegName(ops.at(0).GetReg()) << ", [x9]\n";
break;
}
case Opcode::StoreGlobal: {
// adrp x9, global_var
// add x9, x9, :lo12:global_var
// str wN, [x9]
const std::string& name = ops.at(1).GetSymbol();
os << " adrp x9, " << name << "\n";
os << " add x9, x9, :lo12:" << name << "\n";
os << " str " << PhysRegName(ops.at(0).GetReg()) << ", [x9]\n";
break;
}
case Opcode::LoadGlobalAddr: {
// adrp xN, global_var
// add xN, xN, :lo12:global_var
const std::string& name = ops.at(1).GetSymbol();
os << " adrp " << PhysRegName(ops.at(0).GetReg()) << ", " << name << "\n";
os << " add " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(0).GetReg()) << ", :lo12:" << name << "\n";
break;
}
case Opcode::AddRI:
os << " add " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", #"
<< ops.at(2).GetImm() << "\n";
break;
case Opcode::SubRI:
os << " sub " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", #"
<< ops.at(2).GetImm() << "\n";
break;
case Opcode::AddRR:
os << " add " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::SubRR:
os << " sub " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::MulRR:
os << " mul " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::DivRR:
os << " sdiv " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::FAddRR:
os << " fadd " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::FSubRR:
os << " fsub " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::FMulRR:
os << " fmul " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::FDivRR:
os << " fdiv " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::FSqrtRR:
os << " fsqrt " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << "\n";
break;
case Opcode::SIToFP:
os << " scvtf " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << "\n";
break;
case Opcode::FPToSI:
os << " fcvtzs " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << "\n";
break;
case Opcode::ModRR:
// 不应该出现Mod 在 lowering 时已展开为 div+mul+sub
throw std::runtime_error(FormatError("mir", "ModRR 不应被打印"));
case Opcode::LsrRI:
os << " lsr " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", #"
<< ops.at(2).GetImm() << "\n";
break;
case Opcode::LslRI:
os << " lsl " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", #"
<< ops.at(2).GetImm() << "\n";
break;
case Opcode::LslRR:
os << " lsl " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::CmpOnlyRR:
os << " cmp " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << "\n";
break;
case Opcode::FCmpOnlyRR:
os << " fcmp " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << "\n";
break;
case Opcode::CmpRR: {
// ops: dst, lhs, rhs, cmpop(imm)
auto cmp_op = static_cast<ir::CmpOp>(ops.at(3).GetImm());
os << " cmp " << PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
os << " cset " << PhysRegName(ops.at(0).GetReg()) << ", "
<< CondSuffix(cmp_op) << "\n";
break;
}
case Opcode::FCmpRR: {
// ops: dst(wN), lhs(sN), rhs(sN), cmpop(imm)
auto cmp_op = static_cast<ir::CmpOp>(ops.at(3).GetImm());
os << " fcmp " << PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
os << " cset " << PhysRegName(ops.at(0).GetReg()) << ", "
<< FloatCondSuffix(cmp_op) << "\n";
break;
}
case Opcode::Bl:
os << " bl " << ops.at(0).GetSymbol() << "\n";
break;
case Opcode::B:
os << " b ." << ops.at(0).GetSymbol() << "\n";
break;
case Opcode::Cbnz:
os << " cbnz " << PhysRegName(ops.at(0).GetReg())
<< ", ." << ops.at(1).GetSymbol() << "\n";
break;
case Opcode::Cbz:
os << " cbz " << PhysRegName(ops.at(0).GetReg())
<< ", ." << ops.at(1).GetSymbol() << "\n";
break;
case Opcode::Bcond:
// ops: symbol, cmpop(imm)
os << " b." << CondSuffix(static_cast<ir::CmpOp>(ops.at(1).GetImm()))
<< " ." << ops.at(0).GetSymbol() << "\n";
break;
case Opcode::FBcond:
// ops: symbol, cmpop(imm) - 浮点条件分支
os << " b." << FloatCondSuffix(static_cast<ir::CmpOp>(ops.at(1).GetImm()))
<< " ." << ops.at(0).GetSymbol() << "\n";
break;
case Opcode::Ret:
os << " ret\n";
break;
}
case Opcode::AddRR:
os << " add " << PhysRegName(ops.at(0).GetReg()) << ", "
<< PhysRegName(ops.at(1).GetReg()) << ", "
<< PhysRegName(ops.at(2).GetReg()) << "\n";
break;
case Opcode::Ret:
os << " ret\n";
break;
}
}
os << ".size " << function.GetName() << ", .-" << function.GetName()
<< "\n";
os << ".size " << function.GetName() << ", .-" << function.GetName()
<< "\n\n";
}
}
} // namespace mir

@ -18,9 +18,6 @@ void RunFrameLowering(MachineFunction& function) {
int cursor = 0;
for (const auto& slot : function.GetFrameSlots()) {
cursor += slot.size;
if (-cursor < -256) {
throw std::runtime_error(FormatError("mir", "暂不支持过大的栈帧"));
}
}
cursor = 0;
@ -30,16 +27,25 @@ void RunFrameLowering(MachineFunction& function) {
}
function.SetFrameSize(AlignTo(cursor, 16));
auto& insts = function.GetEntry().GetInstructions();
std::vector<MachineInstr> lowered;
lowered.emplace_back(Opcode::Prologue);
for (const auto& inst : insts) {
if (inst.GetOpcode() == Opcode::Ret) {
lowered.emplace_back(Opcode::Epilogue);
// 在每个基本块的开头和结尾插入 prologue/epilogue
for (const auto& bb_ptr : function.GetBlocks()) {
auto& bb = *bb_ptr;
auto& insts = bb.GetInstructions();
std::vector<MachineInstr> lowered;
// 只在入口块插入 prologue
if (bb.GetName() == "entry") {
lowered.emplace_back(Opcode::Prologue);
}
for (const auto& inst : insts) {
if (inst.GetOpcode() == Opcode::Ret) {
lowered.emplace_back(Opcode::Epilogue);
}
lowered.push_back(inst);
}
lowered.push_back(inst);
insts = std::move(lowered);
}
insts = std::move(lowered);
}
} // namespace mir

File diff suppressed because it is too large Load Diff

@ -8,7 +8,24 @@
namespace mir {
MachineFunction::MachineFunction(std::string name)
: name_(std::move(name)), entry_("entry") {}
: name_(std::move(name)) {
// 创建入口块
blocks_.push_back(std::make_unique<MachineBasicBlock>("entry"));
}
MachineBasicBlock* MachineFunction::CreateBlock(std::string name) {
blocks_.push_back(std::make_unique<MachineBasicBlock>(std::move(name)));
return blocks_.back().get();
}
MachineBasicBlock* MachineFunction::FindBlock(const std::string& name) {
for (auto& block : blocks_) {
if (block->GetName() == name) {
return block.get();
}
}
return nullptr;
}
int MachineFunction::CreateFrameIndex(int size) {
int index = static_cast<int>(frame_slots_.size());
@ -30,4 +47,15 @@ const FrameSlot& MachineFunction::GetFrameSlot(int index) const {
return frame_slots_[index];
}
MachineFunction* MachineModule::CreateFunction(std::string name) {
functions_.push_back(std::make_unique<MachineFunction>(std::move(name)));
return functions_.back().get();
}
void MachineModule::AddGlobalVar(std::string name, int init_val, int count,
bool is_float, std::vector<int> init_elems) {
global_vars_.emplace_back(std::move(name), init_val, count, is_float,
std::move(init_elems));
}
} // namespace mir

@ -4,8 +4,8 @@
namespace mir {
Operand::Operand(Kind kind, PhysReg reg, int imm)
: kind_(kind), reg_(reg), imm_(imm) {}
Operand::Operand(Kind kind, PhysReg reg, int imm, std::string symbol)
: kind_(kind), reg_(reg), imm_(imm), symbol_(std::move(symbol)) {}
Operand Operand::Reg(PhysReg reg) { return Operand(Kind::Reg, reg, 0); }
@ -17,6 +17,10 @@ Operand Operand::FrameIndex(int index) {
return Operand(Kind::FrameIndex, PhysReg::W0, index);
}
Operand Operand::Symbol(std::string name) {
return Operand(Kind::Symbol, PhysReg::W0, 0, std::move(name));
}
MachineInstr::MachineInstr(Opcode opcode, std::vector<Operand> operands)
: opcode_(opcode), operands_(std::move(operands)) {}

@ -10,11 +10,41 @@ namespace {
bool IsAllowedReg(PhysReg reg) {
switch (reg) {
case PhysReg::W0:
case PhysReg::W1:
case PhysReg::W2:
case PhysReg::W3:
case PhysReg::W4:
case PhysReg::W5:
case PhysReg::W6:
case PhysReg::W7:
case PhysReg::W8:
case PhysReg::W9:
case PhysReg::W10:
case PhysReg::X0:
case PhysReg::X1:
case PhysReg::X2:
case PhysReg::X3:
case PhysReg::X4:
case PhysReg::X5:
case PhysReg::X6:
case PhysReg::X7:
case PhysReg::X8:
case PhysReg::X9:
case PhysReg::X10:
case PhysReg::X29:
case PhysReg::X30:
case PhysReg::SP:
case PhysReg::S0:
case PhysReg::S1:
case PhysReg::S2:
case PhysReg::S3:
case PhysReg::S4:
case PhysReg::S5:
case PhysReg::S6:
case PhysReg::S7:
case PhysReg::S8:
case PhysReg::S9:
case PhysReg::S10:
return true;
}
return false;
@ -23,11 +53,13 @@ bool IsAllowedReg(PhysReg reg) {
} // namespace
void RunRegAlloc(MachineFunction& function) {
for (const auto& inst : function.GetEntry().GetInstructions()) {
for (const auto& operand : inst.GetOperands()) {
if (operand.GetKind() == Operand::Kind::Reg &&
!IsAllowedReg(operand.GetReg())) {
throw std::runtime_error(FormatError("mir", "寄存器分配失败"));
for (const auto& bb_ptr : function.GetBlocks()) {
for (const auto& inst : bb_ptr->GetInstructions()) {
for (const auto& operand : inst.GetOperands()) {
if (operand.GetKind() == Operand::Kind::Reg &&
!IsAllowedReg(operand.GetReg())) {
throw std::runtime_error(FormatError("mir", "寄存器分配失败"));
}
}
}
}

@ -8,18 +8,44 @@ namespace mir {
const char* PhysRegName(PhysReg reg) {
switch (reg) {
case PhysReg::W0:
return "w0";
case PhysReg::W8:
return "w8";
case PhysReg::W9:
return "w9";
case PhysReg::X29:
return "x29";
case PhysReg::X30:
return "x30";
case PhysReg::SP:
return "sp";
case PhysReg::W0: return "w0";
case PhysReg::W1: return "w1";
case PhysReg::W2: return "w2";
case PhysReg::W3: return "w3";
case PhysReg::W4: return "w4";
case PhysReg::W5: return "w5";
case PhysReg::W6: return "w6";
case PhysReg::W7: return "w7";
case PhysReg::W8: return "w8";
case PhysReg::W9: return "w9";
case PhysReg::W10: return "w10";
case PhysReg::W11: return "w11";
case PhysReg::X0: return "x0";
case PhysReg::X1: return "x1";
case PhysReg::X2: return "x2";
case PhysReg::X3: return "x3";
case PhysReg::X4: return "x4";
case PhysReg::X5: return "x5";
case PhysReg::X6: return "x6";
case PhysReg::X7: return "x7";
case PhysReg::X8: return "x8";
case PhysReg::X9: return "x9";
case PhysReg::X10: return "x10";
case PhysReg::X11: return "x11";
case PhysReg::X29: return "x29";
case PhysReg::X30: return "x30";
case PhysReg::SP: return "sp";
case PhysReg::S0: return "s0";
case PhysReg::S1: return "s1";
case PhysReg::S2: return "s2";
case PhysReg::S3: return "s3";
case PhysReg::S4: return "s4";
case PhysReg::S5: return "s5";
case PhysReg::S6: return "s6";
case PhysReg::S7: return "s7";
case PhysReg::S8: return "s8";
case PhysReg::S9: return "s9";
case PhysReg::S10: return "s10";
}
throw std::runtime_error(FormatError("mir", "未知物理寄存器"));
}

@ -1,4 +1,290 @@
// 窥孔优化Peephole
// - 删除冗余 move、合并常见指令模式
// - 提升最终汇编质量(按实现范围裁剪)
#include "mir/MIR.h"
#include <optional>
#include <unordered_map>
#include <vector>
namespace mir {
namespace {
bool IsLoadStack(const MachineInstr& inst) { return inst.GetOpcode() == Opcode::LoadStack; }
bool IsStoreStack(const MachineInstr& inst) { return inst.GetOpcode() == Opcode::StoreStack; }
bool IsMovLike(Opcode opcode) { return opcode == Opcode::MovReg || opcode == Opcode::FMovReg; }
bool IsFloatReg(PhysReg reg) { return reg >= PhysReg::S0 && reg <= PhysReg::S10; }
bool IsWxReg(PhysReg reg) {
return (reg >= PhysReg::W0 && reg <= PhysReg::W10) ||
(reg >= PhysReg::X0 && reg <= PhysReg::X10);
}
int WxIndex(PhysReg reg) {
if (reg >= PhysReg::W0 && reg <= PhysReg::W10) {
return static_cast<int>(reg) - static_cast<int>(PhysReg::W0);
}
if (reg >= PhysReg::X0 && reg <= PhysReg::X10) {
return static_cast<int>(reg) - static_cast<int>(PhysReg::X0);
}
return -1;
}
bool RegAlias(PhysReg a, PhysReg b) {
if (a == b) return true;
if (IsFloatReg(a) || IsFloatReg(b)) return false;
if (IsWxReg(a) && IsWxReg(b)) {
return WxIndex(a) >= 0 && WxIndex(a) == WxIndex(b);
}
return false;
}
bool IsSameFrameIndex(const MachineInstr& a, const MachineInstr& b) {
const auto& a_ops = a.GetOperands();
const auto& b_ops = b.GetOperands();
if (a_ops.size() < 2 || b_ops.size() < 2) {
return false;
}
if (a_ops[1].GetKind() != Operand::Kind::FrameIndex ||
b_ops[1].GetKind() != Operand::Kind::FrameIndex) {
return false;
}
return a_ops[1].GetFrameIndex() == b_ops[1].GetFrameIndex();
}
std::optional<PhysReg> GetWrittenReg(const MachineInstr& inst) {
const auto& ops = inst.GetOperands();
if (ops.empty() || ops[0].GetKind() != Operand::Kind::Reg) {
return std::nullopt;
}
switch (inst.GetOpcode()) {
case Opcode::MovImm:
case Opcode::MovReg:
case Opcode::FMovImm:
case Opcode::FMovReg:
case Opcode::LoadStack:
case Opcode::LoadStackOffset:
case Opcode::LoadStackAddr:
case Opcode::LoadIndirect:
case Opcode::LoadGlobal:
case Opcode::LoadGlobalAddr:
case Opcode::AddRI:
case Opcode::SubRI:
case Opcode::AddRR:
case Opcode::SubRR:
case Opcode::MulRR:
case Opcode::DivRR:
case Opcode::LslRI:
case Opcode::LslRR:
case Opcode::FAddRR:
case Opcode::FSubRR:
case Opcode::FMulRR:
case Opcode::FDivRR:
case Opcode::SIToFP:
case Opcode::FPToSI:
case Opcode::CmpRR:
case Opcode::FCmpRR:
return ops[0].GetReg();
default:
return std::nullopt;
}
}
bool IsMemoryClobber(const MachineInstr& inst) {
switch (inst.GetOpcode()) {
case Opcode::StoreIndirect:
case Opcode::StoreGlobal:
case Opcode::Bl:
return true;
default:
return false;
}
}
void InvalidateByReg(std::unordered_map<int, PhysReg>& slot_to_reg, PhysReg reg) {
std::vector<int> dead;
dead.reserve(slot_to_reg.size());
for (const auto& [slot, src] : slot_to_reg) {
if (RegAlias(src, reg)) {
dead.push_back(slot);
}
}
for (int slot : dead) {
slot_to_reg.erase(slot);
}
}
void RecordStore(std::unordered_map<int, PhysReg>& slot_to_reg,
const MachineInstr& store) {
const auto& ops = store.GetOperands();
if (ops.size() < 2 || ops[0].GetKind() != Operand::Kind::Reg ||
ops[1].GetKind() != Operand::Kind::FrameIndex) {
return;
}
slot_to_reg[ops[1].GetFrameIndex()] = ops[0].GetReg();
}
bool TryForwardLoad(std::vector<MachineInstr>& out,
std::unordered_map<int, PhysReg>& slot_to_reg,
const MachineInstr& load) {
const auto& ops = load.GetOperands();
if (ops.size() < 2 || ops[0].GetKind() != Operand::Kind::Reg ||
ops[1].GetKind() != Operand::Kind::FrameIndex) {
return false;
}
const int slot = ops[1].GetFrameIndex();
const PhysReg dst = ops[0].GetReg();
auto it = slot_to_reg.find(slot);
if (it == slot_to_reg.end()) {
return false;
}
const PhysReg src = it->second;
if (RegAlias(src, dst)) {
slot_to_reg[slot] = dst;
return true;
}
const Opcode mv_op = (IsFloatReg(src) && IsFloatReg(dst)) ? Opcode::FMovReg : Opcode::MovReg;
out.emplace_back(mv_op, std::vector<Operand>{Operand::Reg(dst), Operand::Reg(src)});
slot_to_reg[slot] = dst;
return true;
}
bool IsImm2(const MachineInstr& inst, PhysReg* dst_reg) {
if (inst.GetOpcode() != Opcode::MovImm) return false;
const auto& ops = inst.GetOperands();
if (ops.size() != 2 || ops[0].GetKind() != Operand::Kind::Reg ||
ops[1].GetKind() != Operand::Kind::Imm || ops[1].GetImm() != 2) {
return false;
}
*dst_reg = ops[0].GetReg();
return true;
}
bool IsNoopImmArithmetic(const MachineInstr& inst) {
if (inst.GetOpcode() != Opcode::AddRI && inst.GetOpcode() != Opcode::SubRI) {
return false;
}
const auto& ops = inst.GetOperands();
if (ops.size() != 3 || ops[0].GetKind() != Operand::Kind::Reg ||
ops[1].GetKind() != Operand::Kind::Reg || ops[2].GetKind() != Operand::Kind::Imm) {
return false;
}
return ops[2].GetImm() == 0 && RegAlias(ops[0].GetReg(), ops[1].GetReg());
}
} // namespace
void RunPeephole(MachineFunction& function) {
for (const auto& bb_ptr : function.GetBlocks()) {
auto& insts = bb_ptr->GetInstructions();
if (insts.empty()) {
continue;
}
std::vector<MachineInstr> optimized;
optimized.reserve(insts.size());
std::unordered_map<int, PhysReg> slot_to_reg;
for (size_t i = 0; i < insts.size(); ++i) {
const auto& cur = insts[i];
if (IsNoopImmArithmetic(cur)) {
continue;
}
// mov #2 + lsl reg, reg, mov_reg -> lsl reg, reg, #2
if (i + 1 < insts.size()) {
PhysReg imm_reg = PhysReg::W0;
if (IsImm2(cur, &imm_reg) && insts[i + 1].GetOpcode() == Opcode::LslRR) {
const auto& nops = insts[i + 1].GetOperands();
if (nops.size() == 3 && nops[0].GetKind() == Operand::Kind::Reg &&
nops[1].GetKind() == Operand::Kind::Reg &&
nops[2].GetKind() == Operand::Kind::Reg &&
RegAlias(nops[2].GetReg(), imm_reg)) {
optimized.emplace_back(
Opcode::LslRI,
std::vector<Operand>{Operand::Reg(nops[0].GetReg()),
Operand::Reg(nops[1].GetReg()),
Operand::Imm(2)});
if (auto wr = GetWrittenReg(insts[i + 1]); wr.has_value()) {
InvalidateByReg(slot_to_reg, *wr);
}
++i;
continue;
}
}
}
if (IsMemoryClobber(cur)) {
slot_to_reg.clear();
}
if (auto wr = GetWrittenReg(cur); wr.has_value()) {
InvalidateByReg(slot_to_reg, *wr);
}
// 删除 no-op move/fmov
if (IsMovLike(cur.GetOpcode())) {
const auto& ops = cur.GetOperands();
if (ops.size() == 2 && ops[0].GetKind() == Operand::Kind::Reg &&
ops[1].GetKind() == Operand::Kind::Reg &&
RegAlias(ops[0].GetReg(), ops[1].GetReg())) {
continue;
}
}
// store -> load 同槽load 改为 mov/fmov或直接删除 no-op
if (i + 1 < insts.size() && IsStoreStack(cur) &&
IsLoadStack(insts[i + 1]) && IsSameFrameIndex(cur, insts[i + 1])) {
optimized.push_back(cur);
RecordStore(slot_to_reg, cur);
TryForwardLoad(optimized, slot_to_reg, insts[i + 1]);
++i;
continue;
}
// 单条 load 的槽位转发
if (IsLoadStack(cur) && TryForwardLoad(optimized, slot_to_reg, cur)) {
continue;
}
// load -> store 同槽同寄存器:删除 store
if (i + 1 < insts.size() && IsLoadStack(cur) &&
IsStoreStack(insts[i + 1]) && IsSameFrameIndex(cur, insts[i + 1])) {
const auto& cur_ops = cur.GetOperands();
const auto& next_ops = insts[i + 1].GetOperands();
if (cur_ops.size() >= 2 && next_ops.size() >= 2 &&
cur_ops[0].GetKind() == Operand::Kind::Reg &&
next_ops[0].GetKind() == Operand::Kind::Reg &&
RegAlias(cur_ops[0].GetReg(), next_ops[0].GetReg())) {
optimized.push_back(cur);
++i;
continue;
}
}
// 连续 store 同槽:前一条一定死,删掉前一条
if (!optimized.empty() && IsStoreStack(cur) &&
IsStoreStack(optimized.back()) &&
IsSameFrameIndex(cur, optimized.back())) {
optimized.pop_back();
optimized.push_back(cur);
continue;
}
optimized.push_back(cur);
if (IsStoreStack(cur)) {
RecordStore(slot_to_reg, cur);
}
}
insts = std::move(optimized);
}
}
} // namespace mir

@ -0,0 +1,143 @@
开始批量测试...
测试时间: 2026年 04月 24日 星期五 10:53:20 CST
========================================
测试目录: test/test_case/functional
----------------------------------------
运行 test/test_result/function/asm/05_arr_defn4 ...
退出码: 21
输出匹配: test/test_case/functional/05_arr_defn4.out
运行 test/test_result/function/asm/09_func_defn ...
退出码: 9
输出匹配: test/test_case/functional/09_func_defn.out
运行 test/test_result/function/asm/11_add2 ...
退出码: 9
输出匹配: test/test_case/functional/11_add2.out
运行 test/test_result/function/asm/13_sub2 ...
退出码: 248
输出匹配: test/test_case/functional/13_sub2.out
运行 test/test_result/function/asm/15_graph_coloring ...
退出码: 0
输出匹配: test/test_case/functional/15_graph_coloring.out
运行 test/test_result/function/asm/22_matrix_multiply ...
退出码: 0
输出匹配: test/test_case/functional/22_matrix_multiply.out
运行 test/test_result/function/asm/25_scope3 ...
退出码: 46
输出匹配: test/test_case/functional/25_scope3.out
运行 test/test_result/function/asm/29_break ...
退出码: 201
输出匹配: test/test_case/functional/29_break.out
运行 test/test_result/function/asm/36_op_priority2 ...
退出码: 24
输出匹配: test/test_case/functional/36_op_priority2.out
运行 test/test_result/function/asm/95_float ...
退出码: 0
输出匹配: test/test_case/functional/95_float.out
运行 test/test_result/function/asm/simple_add ...
退出码: 3
输出匹配: test/test_case/functional/simple_add.out
测试目录: test/test_case/performance
----------------------------------------
运行 test/test_result/performance/asm/01_mm2 ...
退出码: 0
输出匹配: test/test_case/performance/01_mm2.out
运行 test/test_result/performance/asm/02_mv3 ...
退出码: 0
输出匹配: test/test_case/performance/02_mv3.out
运行 test/test_result/performance/asm/03_sort1 ...
退出码: 0
输出匹配: test/test_case/performance/03_sort1.out
运行 test/test_result/performance/asm/2025-MYO-20 ...
退出码: 0
输出匹配: test/test_case/performance/2025-MYO-20.out
运行 test/test_result/performance/asm/fft0 ...
退出码: 0
输出匹配: test/test_case/performance/fft0.out
运行 test/test_result/performance/asm/gameoflife-oscillator ...
退出码: 0
输出匹配: test/test_case/performance/gameoflife-oscillator.out
运行 test/test_result/performance/asm/if-combine3 ...
退出码: 0
输出匹配: test/test_case/performance/if-combine3.out
运行 test/test_result/performance/asm/large_loop_array_2 ...
0退出码: 0
输出匹配: test/test_case/performance/large_loop_array_2.out
运行 test/test_result/performance/asm/transpose0 ...
退出码: 0
输出匹配: test/test_case/performance/transpose0.out
运行 test/test_result/performance/asm/vector_mul3 ...
退出码: 0
输出匹配: test/test_case/performance/vector_mul3.out
========================================
测试统计:
总计: 21
通过: 21
失败: 0
跳过: 0
通过率: 100.0%

@ -0,0 +1,14 @@
批量测试示例
========================================
运行 test/test_result/performance/asm/vector_mul3 ...
退出码: 0
输出匹配: test/test_case/performance/vector_mul3.out
运行 test/test_result/functional/asm/95_float ...
退出码: 0
输出匹配: test/test_case/functional/95_float.out
运行 test/test_result/functional/asm/22_matrix_multiply ...
退出码: 0
输出匹配: test/test_case/functional/22_matrix_multiply.out
Loading…
Cancel
Save