Compare commits
20 Commits
deploy-202
...
midend-llv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1cca3c95a | ||
|
|
1361156b0d | ||
|
|
46179e3866 | ||
|
|
038552f58b | ||
|
|
4d0e2d73ea | ||
|
|
ad19a6715f | ||
|
|
d1ba140657 | ||
|
|
2c5e4cead1 | ||
|
|
6b92020bc4 | ||
|
|
c867bda9b4 | ||
|
|
6b9ad0566d | ||
|
|
c507b98199 | ||
|
|
ba21bb3203 | ||
|
|
8aa5ba692f | ||
|
|
d732800149 | ||
|
|
37f2a01783 | ||
|
|
5d343f42a5 | ||
|
|
a4406e0112 | ||
|
|
08fcda939b | ||
|
|
5f63554ca3 |
2732
doc/Doxyfile
Normal file
2732
doc/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
BIN
doc/The Definitive ANTLR 4 Reference.pdf
Normal file
BIN
doc/The Definitive ANTLR 4 Reference.pdf
Normal file
Binary file not shown.
BIN
doc/arm/ARM_calling_convention.pdf
Executable file
BIN
doc/arm/ARM_calling_convention.pdf
Executable file
Binary file not shown.
BIN
doc/arm/DDI0403E_e_armv7m_arm.pdf
Executable file
BIN
doc/arm/DDI0403E_e_armv7m_arm.pdf
Executable file
Binary file not shown.
BIN
doc/arm/DDI0406C_d_armv7ar_arm.pdf
Executable file
BIN
doc/arm/DDI0406C_d_armv7ar_arm.pdf
Executable file
Binary file not shown.
27078
doc/arm/DEN0013D_cortex_a_series_PG.pdf
Executable file
27078
doc/arm/DEN0013D_cortex_a_series_PG.pdf
Executable file
File diff suppressed because one or more lines are too long
BIN
doc/arm/GNU_Assembler_Directives.pdf
Executable file
BIN
doc/arm/GNU_Assembler_Directives.pdf
Executable file
Binary file not shown.
BIN
doc/arm/ISA_AArch32_xml_A_profile-2023-03.pdf
Executable file
BIN
doc/arm/ISA_AArch32_xml_A_profile-2023-03.pdf
Executable file
Binary file not shown.
BIN
doc/arm/Raspberry.pdf
Executable file
BIN
doc/arm/Raspberry.pdf
Executable file
Binary file not shown.
BIN
doc/arm/cheatsheetv1.3-1920x1080.png
Executable file
BIN
doc/arm/cheatsheetv1.3-1920x1080.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 346 KiB |
169
doc/markdowns/IR.md
Normal file
169
doc/markdowns/IR.md
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
这个头文件定义了一个用于生成中间表示(IR)的数据结构,主要用于编译器前端将抽象语法树(AST)转换为中间代码。以下是文件中定义的主要类和功能的整理和解释:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1. 类型系统(Type System)**
|
||||||
|
#### **1.1 `Type` 类**
|
||||||
|
- **作用**:表示所有基本标量类型(如 `int`、`float`、`void` 等)以及指针类型和函数类型。
|
||||||
|
- **成员**:
|
||||||
|
- `Kind` 枚举:表示类型的种类(如 `kInt`、`kFloat`、`kPointer` 等)。
|
||||||
|
- `kind`:当前类型的种类。
|
||||||
|
- 构造函数:`Type(Kind kind)`,用于初始化类型。
|
||||||
|
- 静态方法:如 `getIntType()`、`getFloatType()` 等,用于获取特定类型的单例对象。
|
||||||
|
- 类型检查方法:如 `isInt()`、`isFloat()` 等,用于检查当前类型是否为某种类型。
|
||||||
|
- `getSize()`:获取类型的大小。
|
||||||
|
- `as<T>()`:将当前类型动态转换为派生类(如 `PointerType` 或 `FunctionType`)。
|
||||||
|
|
||||||
|
#### **1.2 `PointerType` 类**
|
||||||
|
- **作用**:表示指针类型,派生自 `Type`。
|
||||||
|
- **成员**:
|
||||||
|
- `baseType`:指针指向的基础类型。
|
||||||
|
- 静态方法:`get(Type *baseType)`,用于获取指向 `baseType` 的指针类型。
|
||||||
|
- `getBaseType()`:获取指针指向的基础类型。
|
||||||
|
|
||||||
|
#### **1.3 `FunctionType` 类**
|
||||||
|
- **作用**:表示函数类型,派生自 `Type`。
|
||||||
|
- **成员**:
|
||||||
|
- `returnType`:函数的返回类型。
|
||||||
|
- `paramTypes`:函数的参数类型列表。
|
||||||
|
- 静态方法:`get(Type *returnType, const std::vector<Type *> ¶mTypes)`,用于获取函数类型。
|
||||||
|
- `getReturnType()`:获取函数的返回类型。
|
||||||
|
- `getParamTypes()`:获取函数的参数类型列表。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **2. 中间表示(IR)**
|
||||||
|
#### **2.1 `Value` 类**
|
||||||
|
- **作用**:表示 IR 中的所有值(如指令、常量、参数等)。
|
||||||
|
- **成员**:
|
||||||
|
- `Kind` 枚举:表示值的种类(如 `kAdd`、`kSub`、`kConstant` 等)。
|
||||||
|
- `kind`:当前值的种类。
|
||||||
|
- `type`:值的类型。
|
||||||
|
- `name`:值的名称。
|
||||||
|
- `uses`:值的用途列表(表示哪些指令使用了该值)。
|
||||||
|
- 构造函数:`Value(Kind kind, Type *type, const std::string &name)`。
|
||||||
|
- 类型检查方法:如 `isInt()`、`isFloat()` 等。
|
||||||
|
- `getUses()`:获取值的用途列表。
|
||||||
|
- `replaceAllUsesWith(Value *value)`:将该值的所有用途替换为另一个值。
|
||||||
|
- `print(std::ostream &os)`:打印值的表示。
|
||||||
|
|
||||||
|
#### **2.2 `ConstantValue` 类**
|
||||||
|
- **作用**:表示编译时常量(如整数常量、浮点数常量)。
|
||||||
|
- **成员**:
|
||||||
|
- `iScalar` 和 `fScalar`:分别存储整数和浮点数常量的值。
|
||||||
|
- 静态方法:`get(int value)` 和 `get(float value)`,用于获取常量值。
|
||||||
|
- `getInt()` 和 `getFloat()`:获取常量的值。
|
||||||
|
|
||||||
|
#### **2.3 `Argument` 类**
|
||||||
|
- **作用**:表示函数或基本块的参数。
|
||||||
|
- **成员**:
|
||||||
|
- `block`:参数所属的基本块。
|
||||||
|
- `index`:参数的索引。
|
||||||
|
- 构造函数:`Argument(Type *type, BasicBlock *block, int index, const std::string &name)`。
|
||||||
|
- `getParent()`:获取参数所属的基本块。
|
||||||
|
- `getIndex()`:获取参数的索引。
|
||||||
|
|
||||||
|
#### **2.4 `BasicBlock` 类**
|
||||||
|
- **作用**:表示基本块,包含一系列指令。
|
||||||
|
- **成员**:
|
||||||
|
- `parent`:基本块所属的函数。
|
||||||
|
- `instructions`:基本块中的指令列表。
|
||||||
|
- `arguments`:基本块的参数列表。
|
||||||
|
- `successors` 和 `predecessors`:基本块的后继和前驱列表。
|
||||||
|
- 构造函数:`BasicBlock(Function *parent, const std::string &name)`。
|
||||||
|
- `getParent()`:获取基本块所属的函数。
|
||||||
|
- `getInstructions()`:获取基本块中的指令列表。
|
||||||
|
- `createArgument()`:为基本块创建一个参数。
|
||||||
|
|
||||||
|
#### **2.5 `Instruction` 类**
|
||||||
|
- **作用**:表示 IR 中的指令,派生自 `User`。
|
||||||
|
- **成员**:
|
||||||
|
- `Kind` 枚举:表示指令的种类(如 `kAdd`、`kSub`、`kLoad` 等)。
|
||||||
|
- `kind`:当前指令的种类。
|
||||||
|
- `parent`:指令所属的基本块。
|
||||||
|
- 构造函数:`Instruction(Kind kind, Type *type, BasicBlock *parent, const std::string &name)`。
|
||||||
|
- `getParent()`:获取指令所属的基本块。
|
||||||
|
- `getFunction()`:获取指令所属的函数。
|
||||||
|
- 指令分类方法:如 `isBinary()`、`isUnary()`、`isMemory()` 等。
|
||||||
|
|
||||||
|
#### **2.6 `User` 类**
|
||||||
|
- **作用**:表示使用其他值的指令或全局值,派生自 `Value`。
|
||||||
|
- **成员**:
|
||||||
|
- `operands`:指令的操作数列表。
|
||||||
|
- 构造函数:`User(Kind kind, Type *type, const std::string &name)`。
|
||||||
|
- `getOperand(int index)`:获取指定索引的操作数。
|
||||||
|
- `addOperand(Value *value)`:添加一个操作数。
|
||||||
|
- `replaceOperand(int index, Value *value)`:替换指定索引的操作数。
|
||||||
|
|
||||||
|
#### **2.7 具体指令类**
|
||||||
|
- **`CallInst`**:表示函数调用指令。
|
||||||
|
- **`UnaryInst`**:表示一元操作指令(如取反、类型转换)。
|
||||||
|
- **`BinaryInst`**:表示二元操作指令(如加法、减法)。
|
||||||
|
- **`ReturnInst`**:表示返回指令。
|
||||||
|
- **`UncondBrInst`**:表示无条件跳转指令。
|
||||||
|
- **`CondBrInst`**:表示条件跳转指令。
|
||||||
|
- **`AllocaInst`**:表示栈内存分配指令。
|
||||||
|
- **`LoadInst`**:表示从内存加载值的指令。
|
||||||
|
- **`StoreInst`**:表示将值存储到内存的指令。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **3. 模块和函数**
|
||||||
|
#### **3.1 `Function` 类**
|
||||||
|
- **作用**:表示函数,包含多个基本块。
|
||||||
|
- **成员**:
|
||||||
|
- `parent`:函数所属的模块。
|
||||||
|
- `blocks`:函数中的基本块列表。
|
||||||
|
- 构造函数:`Function(Module *parent, Type *type, const std::string &name)`。
|
||||||
|
- `getReturnType()`:获取函数的返回类型。
|
||||||
|
- `getParamTypes()`:获取函数的参数类型列表。
|
||||||
|
- `addBasicBlock()`:为函数添加一个基本块。
|
||||||
|
|
||||||
|
#### **3.2 `GlobalValue` 类**
|
||||||
|
- **作用**:表示全局变量或常量。
|
||||||
|
- **成员**:
|
||||||
|
- `parent`:全局值所属的模块。
|
||||||
|
- `hasInit`:是否有初始化值。
|
||||||
|
- `isConst`:是否是常量。
|
||||||
|
- 构造函数:`GlobalValue(Module *parent, Type *type, const std::string &name, const std::vector<Value *> &dims, Value *init)`。
|
||||||
|
- `init()`:获取全局值的初始化值。
|
||||||
|
|
||||||
|
#### **3.3 `Module` 类**
|
||||||
|
- **作用**:表示整个编译单元(如一个源文件)。
|
||||||
|
- **成员**:
|
||||||
|
- `children`:模块中的所有值(如函数、全局变量)。
|
||||||
|
- `functions`:模块中的函数列表。
|
||||||
|
- `globals`:模块中的全局变量列表。
|
||||||
|
- `createFunction()`:创建一个函数。
|
||||||
|
- `createGlobalValue()`:创建一个全局变量。
|
||||||
|
- `getFunction()`:获取指定名称的函数。
|
||||||
|
- `getGlobalValue()`:获取指定名称的全局变量。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **4. 工具类**
|
||||||
|
#### **4.1 `Use` 类**
|
||||||
|
- **作用**:表示值与其使用者之间的关系。
|
||||||
|
- **成员**:
|
||||||
|
- `index`:值在使用者操作数列表中的索引。
|
||||||
|
- `user`:使用者。
|
||||||
|
- `value`:被使用的值。
|
||||||
|
- 构造函数:`Use(int index, User *user, Value *value)`。
|
||||||
|
- `getValue()`:获取被使用的值。
|
||||||
|
|
||||||
|
#### **4.2 `range` 类**
|
||||||
|
- **作用**:封装迭代器对 `[begin, end)`,用于遍历容器。
|
||||||
|
- **成员**:
|
||||||
|
- `begin()` 和 `end()`:返回范围的起始和结束迭代器。
|
||||||
|
- `size()`:返回范围的大小。
|
||||||
|
- `empty()`:判断范围是否为空。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **5. 总结**
|
||||||
|
- **类型系统**:`Type`、`PointerType`、`FunctionType` 用于表示 IR 中的类型。
|
||||||
|
- **中间表示**:`Value`、`ConstantValue`、`Instruction` 等用于表示 IR 中的值和指令。
|
||||||
|
- **模块和函数**:`Module`、`Function`、`GlobalValue` 用于组织 IR 的结构。
|
||||||
|
- **工具类**:`Use` 和 `range` 用于辅助实现 IR 的数据结构和遍历。
|
||||||
|
|
||||||
|
这个头文件定义了一个完整的 IR 数据结构,适用于编译器前端将 AST 转换为中间代码,并支持后续的优化和目标代码生成。
|
||||||
156
doc/markdowns/IRbuilder.md
Normal file
156
doc/markdowns/IRbuilder.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
`IRBuilder.h` 文件定义了一个 `IRBuilder` 类,用于简化中间表示(IR)的构建过程。`IRBuilder` 提供了创建各种 IR 指令的便捷方法,并将这些指令插入到指定的基本块中。以下是对文件中主要内容的整理和解释:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1. `IRBuilder` 类的作用**
|
||||||
|
`IRBuilder` 是一个工具类,用于在生成中间表示(IR)时简化指令的创建和插入操作。它的主要功能包括:
|
||||||
|
- 提供创建各种 IR 指令的工厂方法。
|
||||||
|
- 将创建的指令插入到指定的基本块中。
|
||||||
|
- 支持在基本块的任意位置插入指令。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **2. 主要成员**
|
||||||
|
|
||||||
|
#### **2.1 成员变量**
|
||||||
|
- **`block`**:当前操作的基本块。
|
||||||
|
- **`position`**:当前操作的插入位置(基本块中的迭代器)。
|
||||||
|
|
||||||
|
#### **2.2 构造函数**
|
||||||
|
- **默认构造函数**:`IRBuilder()`。
|
||||||
|
- **带参数的构造函数**:
|
||||||
|
- `IRBuilder(BasicBlock *block)`:初始化 `IRBuilder`,并设置当前基本块和插入位置(默认在基本块末尾)。
|
||||||
|
- `IRBuilder(BasicBlock *block, BasicBlock::iterator position)`:初始化 `IRBuilder`,并设置当前基本块和插入位置。
|
||||||
|
|
||||||
|
#### **2.3 设置方法**
|
||||||
|
- **`setPosition(BasicBlock *block, BasicBlock::iterator position)`**:设置当前基本块和插入位置。
|
||||||
|
- **`setPosition(BasicBlock::iterator position)`**:设置当前插入位置。
|
||||||
|
|
||||||
|
#### **2.4 获取方法**
|
||||||
|
- **`getBasicBlock()`**:获取当前基本块。
|
||||||
|
- **`getPosition()`**:获取当前插入位置。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **3. 指令创建方法**
|
||||||
|
`IRBuilder` 提供了多种工厂方法,用于创建不同类型的 IR 指令。这些方法会将创建的指令插入到当前基本块的指定位置。
|
||||||
|
|
||||||
|
#### **3.1 函数调用指令**
|
||||||
|
- **`createCallInst(Function *callee, const std::vector<Value *> &args, const std::string &name)`**:
|
||||||
|
- 创建一个函数调用指令。
|
||||||
|
- 参数:
|
||||||
|
- `callee`:被调用的函数。
|
||||||
|
- `args`:函数参数列表。
|
||||||
|
- `name`:指令的名称(可选)。
|
||||||
|
- 返回:`CallInst*`。
|
||||||
|
|
||||||
|
#### **3.2 一元操作指令**
|
||||||
|
- **`createUnaryInst(Instruction::Kind kind, Type *type, Value *operand, const std::string &name)`**:
|
||||||
|
- 创建一个一元操作指令(如取反、类型转换)。
|
||||||
|
- 参数:
|
||||||
|
- `kind`:指令的类型(如 `kNeg`、`kFtoI` 等)。
|
||||||
|
- `type`:指令的结果类型。
|
||||||
|
- `operand`:操作数。
|
||||||
|
- `name`:指令的名称(可选)。
|
||||||
|
- 返回:`UnaryInst*`。
|
||||||
|
|
||||||
|
- **具体一元操作指令**:
|
||||||
|
- `createNegInst(Value *operand, const std::string &name)`:创建整数取反指令。
|
||||||
|
- `createNotInst(Value *operand, const std::string &name)`:创建逻辑取反指令。
|
||||||
|
- `createFtoIInst(Value *operand, const std::string &name)`:创建浮点数转整数指令。
|
||||||
|
- `createFNegInst(Value *operand, const std::string &name)`:创建浮点数取反指令。
|
||||||
|
- `createIToFInst(Value *operand, const std::string &name)`:创建整数转浮点数指令。
|
||||||
|
|
||||||
|
#### **3.3 二元操作指令**
|
||||||
|
- **`createBinaryInst(Instruction::Kind kind, Type *type, Value *lhs, Value *rhs, const std::string &name)`**:
|
||||||
|
- 创建一个二元操作指令(如加法、减法)。
|
||||||
|
- 参数:
|
||||||
|
- `kind`:指令的类型(如 `kAdd`、`kSub` 等)。
|
||||||
|
- `type`:指令的结果类型。
|
||||||
|
- `lhs` 和 `rhs`:左操作数和右操作数。
|
||||||
|
- `name`:指令的名称(可选)。
|
||||||
|
- 返回:`BinaryInst*`。
|
||||||
|
|
||||||
|
- **具体二元操作指令**:
|
||||||
|
- 整数运算:
|
||||||
|
- `createAddInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数加法指令。
|
||||||
|
- `createSubInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数减法指令。
|
||||||
|
- `createMulInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数乘法指令。
|
||||||
|
- `createDivInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数除法指令。
|
||||||
|
- `createRemInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数取余指令。
|
||||||
|
- 整数比较:
|
||||||
|
- `createICmpEQInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数相等比较指令。
|
||||||
|
- `createICmpNEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数不等比较指令。
|
||||||
|
- `createICmpLTInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数小于比较指令。
|
||||||
|
- `createICmpLEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数小于等于比较指令。
|
||||||
|
- `createICmpGTInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数大于比较指令。
|
||||||
|
- `createICmpGEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数大于等于比较指令。
|
||||||
|
- 浮点数运算:
|
||||||
|
- `createFAddInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数加法指令。
|
||||||
|
- `createFSubInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数减法指令。
|
||||||
|
- `createFMulInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数乘法指令。
|
||||||
|
- `createFDivInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数除法指令。
|
||||||
|
- `createFRemInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数取余指令。
|
||||||
|
- 浮点数比较:
|
||||||
|
- `createFCmpEQInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数相等比较指令。
|
||||||
|
- `createFCmpNEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数不等比较指令。
|
||||||
|
- `createFCmpLTInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数小于比较指令。
|
||||||
|
- `createFCmpLEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数小于等于比较指令。
|
||||||
|
- `createFCmpGTInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数大于比较指令。
|
||||||
|
- `createFCmpGEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数大于等于比较指令。
|
||||||
|
|
||||||
|
#### **3.4 控制流指令**
|
||||||
|
- **`createReturnInst(Value *value)`**:
|
||||||
|
- 创建返回指令。
|
||||||
|
- 参数:
|
||||||
|
- `value`:返回值(可选)。
|
||||||
|
- 返回:`ReturnInst*`。
|
||||||
|
|
||||||
|
- **`createUncondBrInst(BasicBlock *block, std::vector<Value *> args)`**:
|
||||||
|
- 创建无条件跳转指令。
|
||||||
|
- 参数:
|
||||||
|
- `block`:目标基本块。
|
||||||
|
- `args`:跳转参数(可选)。
|
||||||
|
- 返回:`UncondBrInst*`。
|
||||||
|
|
||||||
|
- **`createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock, const std::vector<Value *> &thenArgs, const std::vector<Value *> &elseArgs)`**:
|
||||||
|
- 创建条件跳转指令。
|
||||||
|
- 参数:
|
||||||
|
- `condition`:跳转条件。
|
||||||
|
- `thenBlock`:条件为真时的目标基本块。
|
||||||
|
- `elseBlock`:条件为假时的目标基本块。
|
||||||
|
- `thenArgs` 和 `elseArgs`:跳转参数(可选)。
|
||||||
|
- 返回:`CondBrInst*`。
|
||||||
|
|
||||||
|
#### **3.5 内存操作指令**
|
||||||
|
- **`createAllocaInst(Type *type, const std::vector<Value *> &dims, const std::string &name)`**:
|
||||||
|
- 创建栈内存分配指令。
|
||||||
|
- 参数:
|
||||||
|
- `type`:分配的类型。
|
||||||
|
- `dims`:数组维度(可选)。
|
||||||
|
- `name`:指令的名称(可选)。
|
||||||
|
- 返回:`AllocaInst*`。
|
||||||
|
|
||||||
|
- **`createLoadInst(Value *pointer, const std::vector<Value *> &indices, const std::string &name)`**:
|
||||||
|
- 创建加载指令。
|
||||||
|
- 参数:
|
||||||
|
- `pointer`:指针值。
|
||||||
|
- `indices`:数组索引(可选)。
|
||||||
|
- `name`:指令的名称(可选)。
|
||||||
|
- 返回:`LoadInst*`。
|
||||||
|
|
||||||
|
- **`createStoreInst(Value *value, Value *pointer, const std::vector<Value *> &indices, const std::string &name)`**:
|
||||||
|
- 创建存储指令。
|
||||||
|
- 参数:
|
||||||
|
- `value`:要存储的值。
|
||||||
|
- `pointer`:指针值。
|
||||||
|
- `indices`:数组索引(可选)。
|
||||||
|
- `name`:指令的名称(可选)。
|
||||||
|
- 返回:`StoreInst*`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **4. 总结**
|
||||||
|
- `IRBuilder` 是一个用于简化 IR 构建的工具类,提供了创建各种 IR 指令的工厂方法。
|
||||||
|
- 通过 `IRBuilder`,可以方便地在指定基本块的任意位置插入指令。
|
||||||
|
- 该类的设计使得 IR 的生成更加模块化和易于维护。
|
||||||
121
doc/markdowns/IRcpp.md
Normal file
121
doc/markdowns/IRcpp.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
这个 `IR.cpp` 文件实现了 `IR.h` 中定义的中间表示(IR)数据结构的功能。它包含了类型系统、值、指令、基本块、函数和模块的具体实现,以及一些辅助函数用于打印 IR 的内容。以下是对文件中主要内容的整理和解释:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1. 辅助函数**
|
||||||
|
#### **1.1 `interleave` 函数**
|
||||||
|
- **作用**:用于在输出流中插入分隔符(如逗号)来打印容器中的元素。
|
||||||
|
- **示例**:
|
||||||
|
```cpp
|
||||||
|
interleave(os, container, ", ");
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **1.2 打印函数**
|
||||||
|
- **`printVarName`**:打印变量名,全局变量以 `@` 开头,局部变量以 `%` 开头。
|
||||||
|
- **`printBlockName`**:打印基本块名,以 `^` 开头。
|
||||||
|
- **`printFunctionName`**:打印函数名,以 `@` 开头。
|
||||||
|
- **`printOperand`**:打印操作数,如果是常量则直接打印值,否则打印变量名。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **2. 类型系统**
|
||||||
|
#### **2.1 `Type` 类的实现**
|
||||||
|
- **静态方法**:
|
||||||
|
- `getIntType()`、`getFloatType()`、`getVoidType()`、`getLabelType()`:返回对应类型的单例对象。
|
||||||
|
- `getPointerType(Type *baseType)`:返回指向 `baseType` 的指针类型。
|
||||||
|
- `getFunctionType(Type *returnType, const vector<Type *> ¶mTypes)`:返回函数类型。
|
||||||
|
- **`getSize()`**:返回类型的大小(如 `int` 和 `float` 为 4 字节,指针为 8 字节)。
|
||||||
|
- **`print()`**:打印类型的表示。
|
||||||
|
|
||||||
|
#### **2.2 `PointerType` 类的实现**
|
||||||
|
- **静态方法**:
|
||||||
|
- `get(Type *baseType)`:返回指向 `baseType` 的指针类型,使用 `std::map` 缓存已创建的指针类型。
|
||||||
|
- **`getBaseType()`**:返回指针指向的基础类型。
|
||||||
|
|
||||||
|
#### **2.3 `FunctionType` 类的实现**
|
||||||
|
- **静态方法**:
|
||||||
|
- `get(Type *returnType, const vector<Type *> ¶mTypes)`:返回函数类型,使用 `std::set` 缓存已创建的函数类型。
|
||||||
|
- **`getReturnType()`** 和 `getParamTypes()`:分别返回函数的返回类型和参数类型列表。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **3. 值(Value)**
|
||||||
|
#### **3.1 `Value` 类的实现**
|
||||||
|
- **`replaceAllUsesWith(Value *value)`**:将该值的所有用途替换为另一个值。
|
||||||
|
- **`isConstant()`**:判断值是否为常量(包括常量值、全局值和函数)。
|
||||||
|
|
||||||
|
#### **3.2 `ConstantValue` 类的实现**
|
||||||
|
- **静态方法**:
|
||||||
|
- `get(int value)` 和 `get(float value)`:返回整数或浮点数常量,使用 `std::map` 缓存已创建的常量。
|
||||||
|
- **`getInt()` 和 `getFloat()`**:返回常量的值。
|
||||||
|
- **`print()`**:打印常量的值。
|
||||||
|
|
||||||
|
#### **3.3 `Argument` 类的实现**
|
||||||
|
- **构造函数**:初始化参数的类型、所属基本块和索引。
|
||||||
|
- **`print()`**:打印参数的表示。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **4. 基本块(BasicBlock)**
|
||||||
|
#### **4.1 `BasicBlock` 类的实现**
|
||||||
|
- **构造函数**:初始化基本块的名称和所属函数。
|
||||||
|
- **`print()`**:打印基本块的表示,包括参数和指令。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **5. 指令(Instruction)**
|
||||||
|
#### **5.1 `Instruction` 类的实现**
|
||||||
|
- **构造函数**:初始化指令的类型、所属基本块和名称。
|
||||||
|
- **`print()`**:由具体指令类实现。
|
||||||
|
|
||||||
|
#### **5.2 具体指令类的实现**
|
||||||
|
- **`CallInst`**:表示函数调用指令。
|
||||||
|
- **`print()`**:打印函数调用的表示。
|
||||||
|
- **`UnaryInst`**:表示一元操作指令(如取反、类型转换)。
|
||||||
|
- **`print()`**:打印一元操作的表示。
|
||||||
|
- **`BinaryInst`**:表示二元操作指令(如加法、减法)。
|
||||||
|
- **`print()`**:打印二元操作的表示。
|
||||||
|
- **`ReturnInst`**:表示返回指令。
|
||||||
|
- **`print()`**:打印返回指令的表示。
|
||||||
|
- **`UncondBrInst`**:表示无条件跳转指令。
|
||||||
|
- **`print()`**:打印无条件跳转的表示。
|
||||||
|
- **`CondBrInst`**:表示条件跳转指令。
|
||||||
|
- **`print()`**:打印条件跳转的表示。
|
||||||
|
- **`AllocaInst`**:表示栈内存分配指令。
|
||||||
|
- **`print()`**:打印内存分配的表示。
|
||||||
|
- **`LoadInst`**:表示从内存加载值的指令。
|
||||||
|
- **`print()`**:打印加载指令的表示。
|
||||||
|
- **`StoreInst`**:表示将值存储到内存的指令。
|
||||||
|
- **`print()`**:打印存储指令的表示。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **6. 函数(Function)**
|
||||||
|
#### **6.1 `Function` 类的实现**
|
||||||
|
- **构造函数**:初始化函数的名称、返回类型和参数类型。
|
||||||
|
- **`print()`**:打印函数的表示,包括基本块和指令。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **7. 模块(Module)**
|
||||||
|
#### **7.1 `Module` 类的实现**
|
||||||
|
- **`print()`**:打印模块的表示,包括所有函数和全局变量。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **8. 用户(User)**
|
||||||
|
#### **8.1 `User` 类的实现**
|
||||||
|
- **`setOperand(int index, Value *value)`**:设置指定索引的操作数。
|
||||||
|
- **`replaceOperand(int index, Value *value)`**:替换指定索引的操作数,并更新用途列表。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **9. 总结**
|
||||||
|
- **类型系统**:实现了 `Type`、`PointerType` 和 `FunctionType`,用于表示 IR 中的类型。
|
||||||
|
- **值**:实现了 `Value`、`ConstantValue` 和 `Argument`,用于表示 IR 中的值和参数。
|
||||||
|
- **基本块**:实现了 `BasicBlock`,用于组织指令。
|
||||||
|
- **指令**:实现了多种具体指令类(如 `CallInst`、`BinaryInst` 等),用于表示 IR 中的操作。
|
||||||
|
- **函数和模块**:实现了 `Function` 和 `Module`,用于组织 IR 的结构。
|
||||||
|
- **打印功能**:通过 `print()` 方法,可以将 IR 的内容输出为可读的文本格式。
|
||||||
|
|
||||||
|
这个文件是编译器中间表示的核心实现,能够将抽象语法树(AST)转换为中间代码,并支持后续的优化和目标代码生成。
|
||||||
20878
doc/n1124.pdf
Normal file
20878
doc/n1124.pdf
Normal file
File diff suppressed because one or more lines are too long
BIN
doc/riscv/RISC-V-Reader-Chinese-v1.pdf
Executable file
BIN
doc/riscv/RISC-V-Reader-Chinese-v1.pdf
Executable file
Binary file not shown.
BIN
doc/riscv/riscv-spec-20191213.pdf
Executable file
BIN
doc/riscv/riscv-spec-20191213.pdf
Executable file
Binary file not shown.
BIN
doc/slides/exp01-antlr.pdf
Executable file
BIN
doc/slides/exp01-antlr.pdf
Executable file
Binary file not shown.
BIN
doc/slides/exp02-ir.pdf
Executable file
BIN
doc/slides/exp02-ir.pdf
Executable file
Binary file not shown.
BIN
doc/slides/lab03-code generation.pdf
Executable file
BIN
doc/slides/lab03-code generation.pdf
Executable file
Binary file not shown.
BIN
doc/slides/lab04-scalar optimization.pdf
Executable file
BIN
doc/slides/lab04-scalar optimization.pdf
Executable file
Binary file not shown.
BIN
doc/slides/lab05-register allocation.pdf
Normal file
BIN
doc/slides/lab05-register allocation.pdf
Normal file
Binary file not shown.
BIN
doc/sysy-2022-runtime.pdf
Normal file
BIN
doc/sysy-2022-runtime.pdf
Normal file
Binary file not shown.
BIN
doc/sysy-2022-spec.pdf
Normal file
BIN
doc/sysy-2022-spec.pdf
Normal file
Binary file not shown.
@@ -2,66 +2,67 @@
|
|||||||
|
|
||||||
# runit-single.sh - 用于编译和测试单个或少量 SysY 程序的脚本
|
# runit-single.sh - 用于编译和测试单个或少量 SysY 程序的脚本
|
||||||
# 模仿 runit.sh 的功能,但以具体文件路径作为输入。
|
# 模仿 runit.sh 的功能,但以具体文件路径作为输入。
|
||||||
|
# 此脚本应该位于 mysysy/script/
|
||||||
|
|
||||||
|
export ASAN_OPTIONS=detect_leaks=0
|
||||||
|
|
||||||
# --- 配置区 ---
|
# --- 配置区 ---
|
||||||
# 请根据你的环境修改这些路径
|
|
||||||
# 假设此脚本位于你的项目根目录或一个脚本目录中
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||||
# 默认寻找项目根目录下的 build 和 lib
|
|
||||||
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
|
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
|
||||||
LIB_DIR="${SCRIPT_DIR}/../lib"
|
LIB_DIR="${SCRIPT_DIR}/../lib"
|
||||||
# 临时文件会存储在脚本所在目录的 tmp 子目录中
|
|
||||||
TMP_DIR="${SCRIPT_DIR}/tmp"
|
TMP_DIR="${SCRIPT_DIR}/tmp"
|
||||||
|
|
||||||
# 定义编译器和模拟器
|
# 定义编译器和模拟器
|
||||||
SYSYC="${BUILD_BIN_DIR}/sysyc"
|
SYSYC="${BUILD_BIN_DIR}/sysyc"
|
||||||
|
LLC_CMD="llc-19" # 新增
|
||||||
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
||||||
QEMU_RISCV64="qemu-riscv64"
|
QEMU_RISCV64="qemu-riscv64"
|
||||||
|
|
||||||
# --- 初始化变量 ---
|
# --- 初始化变量 ---
|
||||||
EXECUTE_MODE=false
|
EXECUTE_MODE=false
|
||||||
|
IR_EXECUTE_MODE=false # 新增
|
||||||
CLEAN_MODE=false
|
CLEAN_MODE=false
|
||||||
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
|
OPTIMIZE_FLAG=""
|
||||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
SYSYC_TIMEOUT=30
|
||||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
LLC_TIMEOUT=10 # 新增
|
||||||
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
|
GCC_TIMEOUT=10
|
||||||
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
EXEC_TIMEOUT=30
|
||||||
SY_FILES=() # 存储用户提供的 .sy 文件列表
|
MAX_OUTPUT_LINES=20
|
||||||
|
SY_FILES=()
|
||||||
PASSED_CASES=0
|
PASSED_CASES=0
|
||||||
FAILED_CASES_LIST=""
|
FAILED_CASES_LIST=""
|
||||||
|
INTERRUPTED=false # 新增
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
# --- 函数定义 ---
|
# --- 函数定义 ---
|
||||||
|
# =================================================================
|
||||||
show_help() {
|
show_help() {
|
||||||
echo "用法: $0 [文件1.sy] [文件2.sy] ... [选项]"
|
echo "用法: $0 [文件1.sy] [文件2.sy] ... [选项]"
|
||||||
echo "编译并测试指定的 .sy 文件。"
|
echo "编译并测试指定的 .sy 文件。必须提供 -e 或 -eir 之一。"
|
||||||
echo ""
|
|
||||||
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "选项:"
|
echo "选项:"
|
||||||
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
|
echo " -e 通过汇编运行测试 (sysyc -> gcc -> qemu)。"
|
||||||
|
echo " -eir 通过IR运行测试 (sysyc -> llc -> gcc -> qemu)。"
|
||||||
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
|
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
|
||||||
echo " -O1 启用 sysyc 的 -O1 优化。"
|
echo " -O1 启用 sysyc 的 -O1 优化。"
|
||||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
|
||||||
|
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
|
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
|
||||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
||||||
echo " -h, --help 显示此帮助信息并退出。"
|
echo " -h, --help 显示此帮助信息并退出。"
|
||||||
|
echo ""
|
||||||
|
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- 新增功能: 显示文件内容并根据行数截断 ---
|
|
||||||
display_file_content() {
|
display_file_content() {
|
||||||
local file_path="$1"
|
local file_path="$1"
|
||||||
local title="$2"
|
local title="$2"
|
||||||
local max_lines="$3"
|
local max_lines="$3"
|
||||||
|
if [ ! -f "$file_path" ]; then return; fi
|
||||||
if [ ! -f "$file_path" ]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "$title"
|
echo -e "$title"
|
||||||
local line_count
|
local line_count
|
||||||
line_count=$(wc -l < "$file_path")
|
line_count=$(wc -l < "$file_path")
|
||||||
|
|
||||||
if [ "$line_count" -gt "$max_lines" ]; then
|
if [ "$line_count" -gt "$max_lines" ]; then
|
||||||
head -n "$max_lines" "$file_path"
|
head -n "$max_lines" "$file_path"
|
||||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||||
@@ -70,55 +71,79 @@ display_file_content() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# --- 新增:总结报告函数 ---
|
||||||
|
print_summary() {
|
||||||
|
local total_cases=${#SY_FILES[@]}
|
||||||
|
echo ""
|
||||||
|
echo "======================================================================"
|
||||||
|
if [ "$INTERRUPTED" = true ]; then
|
||||||
|
echo -e "\e[33m测试被中断。正在汇总已完成的结果...\e[0m"
|
||||||
|
else
|
||||||
|
echo "所有测试完成"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local failed_count
|
||||||
|
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||||
|
failed_count=$(echo -e -n "${FAILED_CASES_LIST}" | wc -l)
|
||||||
|
else
|
||||||
|
failed_count=0
|
||||||
|
fi
|
||||||
|
local executed_count=$((PASSED_CASES + failed_count))
|
||||||
|
|
||||||
|
echo "测试结果: [通过: ${PASSED_CASES}, 失败: ${failed_count}, 已执行: ${executed_count}/${total_cases}]"
|
||||||
|
|
||||||
|
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||||
|
echo ""
|
||||||
|
echo -e "\e[31m未通过的测例:\e[0m"
|
||||||
|
printf "%b" "${FAILED_CASES_LIST}"
|
||||||
|
fi
|
||||||
|
echo "======================================================================"
|
||||||
|
|
||||||
|
if [ "$failed_count" -gt 0 ]; then
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 新增:SIGINT 信号处理函数 ---
|
||||||
|
handle_sigint() {
|
||||||
|
INTERRUPTED=true
|
||||||
|
print_summary
|
||||||
|
}
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# --- 主逻辑开始 ---
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
# --- 新增:设置 trap 来捕获 SIGINT ---
|
||||||
|
trap handle_sigint SIGINT
|
||||||
|
|
||||||
# --- 参数解析 ---
|
# --- 参数解析 ---
|
||||||
# 使用标准的 while 循环来健壮地处理任意顺序的参数
|
|
||||||
while [[ "$#" -gt 0 ]]; do
|
while [[ "$#" -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-e|--executable)
|
-e|--executable) EXECUTE_MODE=true; shift ;;
|
||||||
EXECUTE_MODE=true
|
-eir) IR_EXECUTE_MODE=true; shift ;; # 新增
|
||||||
shift # 消耗选项
|
-c|--clean) CLEAN_MODE=true; shift ;;
|
||||||
;;
|
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
|
||||||
-c|--clean)
|
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;; # 新增
|
||||||
CLEAN_MODE=true
|
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
shift # 消耗选项
|
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
;;
|
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
-O1)
|
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
OPTIMIZE_FLAG="-O1"
|
-h|--help) show_help; exit 0 ;;
|
||||||
shift # 消耗选项
|
-*) echo "未知选项: $1"; show_help; exit 1 ;;
|
||||||
;;
|
*)
|
||||||
-sct)
|
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
|
||||||
;;
|
|
||||||
-gct)
|
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
|
|
||||||
;;
|
|
||||||
-et)
|
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
|
|
||||||
;;
|
|
||||||
-ml|--max-lines)
|
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
|
|
||||||
;;
|
|
||||||
-h|--help)
|
|
||||||
show_help
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
-*) # 未知选项
|
|
||||||
echo "未知选项: $1"
|
|
||||||
show_help
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*) # 其他参数被视为文件路径
|
|
||||||
if [[ -f "$1" && "$1" == *.sy ]]; then
|
if [[ -f "$1" && "$1" == *.sy ]]; then
|
||||||
SY_FILES+=("$1")
|
SY_FILES+=("$1")
|
||||||
else
|
else
|
||||||
echo "警告: 无效文件或不是 .sy 文件,已忽略: $1"
|
echo "警告: 无效文件或不是 .sy 文件,已忽略: $1"
|
||||||
fi
|
fi
|
||||||
shift # 消耗文件参数
|
shift
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
if ${CLEAN_MODE}; then
|
if ${CLEAN_MODE}; then
|
||||||
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
|
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
|
||||||
if [ -d "${TMP_DIR}" ]; then
|
if [ -d "${TMP_DIR}" ]; then
|
||||||
@@ -127,19 +152,22 @@ if ${CLEAN_MODE}; then
|
|||||||
else
|
else
|
||||||
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
|
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
|
||||||
fi
|
fi
|
||||||
|
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
|
||||||
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE}; then
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 主逻辑开始 ---
|
if ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
|
||||||
if ! ${EXECUTE_MODE}; then
|
echo "错误: 请提供 -e 或 -eir 选项来运行测试。"
|
||||||
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
|
|
||||||
show_help
|
show_help
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
|
||||||
|
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ ${#SY_FILES[@]} -eq 0 ]; then
|
if [ ${#SY_FILES[@]} -eq 0 ]; then
|
||||||
echo "错误: 未提供任何 .sy 文件作为输入。"
|
echo "错误: 未提供任何 .sy 文件作为输入。"
|
||||||
show_help
|
show_help
|
||||||
@@ -151,18 +179,17 @@ TOTAL_CASES=${#SY_FILES[@]}
|
|||||||
|
|
||||||
echo "SysY 单例测试运行器启动..."
|
echo "SysY 单例测试运行器启动..."
|
||||||
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
for sy_file in "${SY_FILES[@]}"; do
|
for sy_file in "${SY_FILES[@]}"; do
|
||||||
is_passed=1
|
is_passed=1
|
||||||
|
compilation_ok=1
|
||||||
base_name=$(basename "${sy_file}" .sy)
|
base_name=$(basename "${sy_file}" .sy)
|
||||||
source_dir=$(dirname "${sy_file}")
|
source_dir=$(dirname "${sy_file}")
|
||||||
|
|
||||||
ir_file="${TMP_DIR}/${base_name}_sysyc_riscv64.ll"
|
ir_file="${TMP_DIR}/${base_name}.ll"
|
||||||
assembly_file="${TMP_DIR}/${base_name}.s"
|
assembly_file="${TMP_DIR}/${base_name}.s"
|
||||||
assembly_debug_file="${TMP_DIR}/${base_name}_d.s"
|
|
||||||
executable_file="${TMP_DIR}/${base_name}"
|
executable_file="${TMP_DIR}/${base_name}"
|
||||||
input_file="${source_dir}/${base_name}.in"
|
input_file="${source_dir}/${base_name}.in"
|
||||||
output_reference_file="${source_dir}/${base_name}.out"
|
output_reference_file="${source_dir}/${base_name}.out"
|
||||||
@@ -171,47 +198,39 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
echo "======================================================================"
|
echo "======================================================================"
|
||||||
echo "正在处理: ${sy_file}"
|
echo "正在处理: ${sy_file}"
|
||||||
|
|
||||||
# --- 本次修改点: 拷贝源文件到 tmp 目录 ---
|
# --- 编译阶段 ---
|
||||||
echo " 拷贝源文件到 ${TMP_DIR}..."
|
if ${IR_EXECUTE_MODE}; then
|
||||||
cp "${sy_file}" "${TMP_DIR}/$(basename "${sy_file}")"
|
# 路径1: sysyc -> llc -> gcc
|
||||||
if [ -f "${input_file}" ]; then
|
echo " [1/3] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
cp "${input_file}" "${TMP_DIR}/$(basename "${input_file}")"
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} -o "${ir_file}"
|
||||||
fi
|
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (IR) 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||||
if [ -f "${output_reference_file}" ]; then
|
|
||||||
cp "${output_reference_file}" "${TMP_DIR}/$(basename "${output_reference_file}")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 步骤 1: sysyc 编译
|
if [ "$compilation_ok" -eq 1 ]; then
|
||||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
echo " [2/3] 使用 llc 编译为汇编 (超时 ${LLC_TIMEOUT}s)..."
|
||||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
|
timeout -s KILL ${LLC_TIMEOUT} "${LLC_CMD}" -march=riscv64 -mcpu=generic-rv64 -mattr=+m,+a,+f,+d,+c -filetype=asm "${ir_file}" -o "${assembly_file}"
|
||||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} > "${ir_file}"
|
if [ $? -ne 0 ]; then echo -e "\e[31m错误: llc 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||||
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
|
fi
|
||||||
SYSYC_STATUS=$?
|
|
||||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
|
||||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR超时\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
elif [ $SYSYC_STATUS -ne 0 ]; then
|
|
||||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR失败,退出码: ${SYSYC_STATUS}\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
fi
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 步骤 2: GCC 编译
|
if [ "$compilation_ok" -eq 1 ]; then
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
echo " [3/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||||
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||||
if [ $? -ne 0 ]; then
|
fi
|
||||||
echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"
|
else # EXECUTE_MODE
|
||||||
is_passed=0
|
# 路径2: sysyc -> gcc
|
||||||
|
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
|
||||||
|
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (汇编) 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||||
|
|
||||||
|
if [ "$compilation_ok" -eq 1 ]; then
|
||||||
|
echo " [2/2] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||||
|
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 步骤 3: 执行与测试
|
# --- 执行与测试阶段 (公共逻辑) ---
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$compilation_ok" -eq 1 ]; then
|
||||||
# 检查是自动化测试还是交互模式
|
|
||||||
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
|
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
|
||||||
# --- 自动化测试模式 ---
|
# --- 自动化测试模式 ---
|
||||||
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
|
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
|
||||||
@@ -234,24 +253,26 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name}.expected_stdout"
|
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name}.expected_stdout"
|
||||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||||
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; is_passed=0; fi
|
|
||||||
|
|
||||||
|
ret_ok=1
|
||||||
|
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; ret_ok=0; fi
|
||||||
|
|
||||||
|
out_ok=1
|
||||||
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||||
echo -e "\e[31m 标准输出测试失败。\e[0m"
|
echo -e "\e[31m 标准输出测试失败。\e[0m"; out_ok=0
|
||||||
is_passed=0
|
|
||||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
echo -e " \e[36m----------------\e[0m"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
|
||||||
|
|
||||||
else
|
else
|
||||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||||
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 标准输出测试失败。\e[0m"
|
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
||||||
is_passed=0
|
|
||||||
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
echo -e " \e[36m----------------\e[0m"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -260,20 +281,16 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# --- 交互模式 ---
|
# --- 交互模式 ---
|
||||||
echo -e "\e[33m"
|
echo -e "\e[33m\n 未找到 .in 或 .out 文件,进入交互模式...\e[0m"
|
||||||
echo " **********************************************************"
|
|
||||||
echo " ** 未找到 .in 或 .out 文件,进入交互模式。 **"
|
|
||||||
echo " ** 程序即将运行,你可以直接在终端中输入。 **"
|
|
||||||
echo " ** 按下 Ctrl+D (EOF) 或以其他方式结束程序以继续。 **"
|
|
||||||
echo " **********************************************************"
|
|
||||||
echo -e "\e[0m"
|
|
||||||
"${QEMU_RISCV64}" "${executable_file}"
|
"${QEMU_RISCV64}" "${executable_file}"
|
||||||
INTERACTIVE_RET_CODE=$?
|
INTERACTIVE_RET_CODE=$?
|
||||||
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE}\e[0m"
|
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE} (此结果未经验证)\e[0m"
|
||||||
echo " 注意: 交互模式的结果未经验证。"
|
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
is_passed=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --- 状态总结 ---
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
echo -e "\e[32m状态: 通过\e[0m"
|
echo -e "\e[32m状态: 通过\e[0m"
|
||||||
((PASSED_CASES++))
|
((PASSED_CASES++))
|
||||||
@@ -284,20 +301,4 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# --- 打印最终总结 ---
|
# --- 打印最终总结 ---
|
||||||
echo "======================================================================"
|
print_summary
|
||||||
echo "所有测试完成"
|
|
||||||
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
|
||||||
|
|
||||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
|
||||||
echo ""
|
|
||||||
echo -e "\e[31m未通过的测例:\e[0m"
|
|
||||||
echo -e "${FAILED_CASES_LIST}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "======================================================================"
|
|
||||||
|
|
||||||
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
484
script/runit.sh
484
script/runit.sh
@@ -1,31 +1,41 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# runit.sh - 用于编译和测试 SysY 程序的脚本
|
# runit.sh - 用于编译和测试 SysY 程序的脚本
|
||||||
# 此脚本应该位于 mysysy/test_script/
|
# 此脚本应该位于 mysysy/script/
|
||||||
|
|
||||||
|
export ASAN_OPTIONS=detect_leaks=0
|
||||||
|
|
||||||
# 定义相对于脚本位置的目录
|
# 定义相对于脚本位置的目录
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||||
TESTDATA_DIR="${SCRIPT_DIR}/../testdata"
|
TESTDATA_DIR="${SCRIPT_DIR}/../testdata"
|
||||||
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
|
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
|
||||||
LIB_DIR="${SCRIPT_DIR}/../lib"
|
LIB_DIR="${SCRIPT_DIR}/../lib"
|
||||||
# TMP_DIR="${SCRIPT_DIR}/tmp"
|
|
||||||
TMP_DIR="${SCRIPT_DIR}/tmp"
|
TMP_DIR="${SCRIPT_DIR}/tmp"
|
||||||
|
|
||||||
# 定义编译器和模拟器
|
# 定义编译器和模拟器
|
||||||
SYSYC="${BUILD_BIN_DIR}/sysyc"
|
SYSYC="${BUILD_BIN_DIR}/sysyc"
|
||||||
|
LLC_CMD="llc-19"
|
||||||
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
||||||
QEMU_RISCV64="qemu-riscv64"
|
QEMU_RISCV64="qemu-riscv64"
|
||||||
|
|
||||||
|
# --- 状态变量 ---
|
||||||
EXECUTE_MODE=false
|
EXECUTE_MODE=false
|
||||||
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
|
IR_EXECUTE_MODE=false
|
||||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
OPTIMIZE_FLAG=""
|
||||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
SYSYC_TIMEOUT=30
|
||||||
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
|
LLC_TIMEOUT=10
|
||||||
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
GCC_TIMEOUT=10
|
||||||
TEST_SETS=() # 用于存储要运行的测试集
|
EXEC_TIMEOUT=30
|
||||||
|
MAX_OUTPUT_LINES=20
|
||||||
|
TEST_SETS=()
|
||||||
TOTAL_CASES=0
|
TOTAL_CASES=0
|
||||||
PASSED_CASES=0
|
PASSED_CASES=0
|
||||||
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
|
FAILED_CASES_LIST=""
|
||||||
|
INTERRUPTED=false # 新增:用于标记是否被中断
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# --- 函数定义 ---
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
# 显示帮助信息的函数
|
# 显示帮助信息的函数
|
||||||
show_help() {
|
show_help() {
|
||||||
@@ -33,31 +43,32 @@ show_help() {
|
|||||||
echo "此脚本用于按文件名前缀数字升序编译和测试 .sy 文件。"
|
echo "此脚本用于按文件名前缀数字升序编译和测试 .sy 文件。"
|
||||||
echo ""
|
echo ""
|
||||||
echo "选项:"
|
echo "选项:"
|
||||||
echo " -e, --executable 编译为可执行文件并运行测试。"
|
echo " -e, --executable 编译为汇编并运行测试 (sysyc -> gcc -> qemu)。"
|
||||||
|
echo " -eir 通过IR编译为可执行文件并运行测试 (sysyc -> llc -> gcc -> qemu)。"
|
||||||
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
||||||
echo " -O1 启用 sysyc 的 -O1 优化。"
|
echo " -O1 启用 sysyc 的 -O1 优化。"
|
||||||
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
|
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
|
||||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
|
||||||
|
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 5)。"
|
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
|
||||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
||||||
echo " -h, --help 显示此帮助信息并退出。"
|
echo " -h, --help 显示此帮助信息并退出。"
|
||||||
|
echo ""
|
||||||
|
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
|
||||||
|
echo " 可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# 显示文件内容并根据行数截断的函数
|
# 显示文件内容并根据行数截断的函数
|
||||||
display_file_content() {
|
display_file_content() {
|
||||||
local file_path="$1"
|
local file_path="$1"
|
||||||
local title="$2"
|
local title="$2"
|
||||||
local max_lines="$3"
|
local max_lines="$3"
|
||||||
|
if [ ! -f "$file_path" ]; then return; fi
|
||||||
if [ ! -f "$file_path" ]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "$title"
|
echo -e "$title"
|
||||||
local line_count
|
local line_count
|
||||||
line_count=$(wc -l < "$file_path")
|
line_count=$(wc -l < "$file_path")
|
||||||
|
|
||||||
if [ "$line_count" -gt "$max_lines" ]; then
|
if [ "$line_count" -gt "$max_lines" ]; then
|
||||||
head -n "$max_lines" "$file_path"
|
head -n "$max_lines" "$file_path"
|
||||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||||
@@ -72,63 +83,90 @@ clean_tmp() {
|
|||||||
rm -rf "${TMP_DIR}"/*
|
rm -rf "${TMP_DIR}"/*
|
||||||
}
|
}
|
||||||
|
|
||||||
# 如果临时目录不存在,则创建它
|
# --- 新增:总结报告函数 ---
|
||||||
|
print_summary() {
|
||||||
|
echo "" # 确保从新的一行开始
|
||||||
|
echo "========================================"
|
||||||
|
if [ "$INTERRUPTED" = true ]; then
|
||||||
|
echo -e "\e[33m测试被中断。正在汇总已完成的结果...\e[0m"
|
||||||
|
else
|
||||||
|
echo "测试完成"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local failed_count
|
||||||
|
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||||
|
# `wc -l` 计算由换行符分隔的列表项数
|
||||||
|
failed_count=$(echo -e -n "${FAILED_CASES_LIST}" | wc -l)
|
||||||
|
else
|
||||||
|
failed_count=0
|
||||||
|
fi
|
||||||
|
local executed_count=$((PASSED_CASES + failed_count))
|
||||||
|
|
||||||
|
echo "测试结果: [通过: ${PASSED_CASES}, 失败: ${failed_count}, 已执行: ${executed_count}/${TOTAL_CASES}]"
|
||||||
|
|
||||||
|
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||||
|
echo ""
|
||||||
|
echo -e "\e[31m未通过的测例:\e[0m"
|
||||||
|
# 使用 printf 保证原样输出
|
||||||
|
printf "%b" "${FAILED_CASES_LIST}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
|
||||||
|
if [ "$failed_count" -gt 0 ]; then
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 新增:SIGINT 信号处理函数 ---
|
||||||
|
handle_sigint() {
|
||||||
|
INTERRUPTED=true
|
||||||
|
print_summary
|
||||||
|
}
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# --- 主逻辑开始 ---
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
# --- 新增:设置 trap 来捕获 SIGINT ---
|
||||||
|
trap handle_sigint SIGINT
|
||||||
|
|
||||||
mkdir -p "${TMP_DIR}"
|
mkdir -p "${TMP_DIR}"
|
||||||
|
|
||||||
# 解析命令行参数
|
# 解析命令行参数
|
||||||
while [[ "$#" -gt 0 ]]; do
|
while [[ "$#" -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-e|--executable)
|
-e|--executable) EXECUTE_MODE=true; shift ;;
|
||||||
EXECUTE_MODE=true
|
-eir) IR_EXECUTE_MODE=true; shift ;;
|
||||||
shift
|
-c|--clean) clean_tmp; exit 0 ;;
|
||||||
;;
|
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
|
||||||
-c|--clean)
|
|
||||||
clean_tmp
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
-O1)
|
|
||||||
OPTIMIZE_FLAG="-O1"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-set)
|
-set)
|
||||||
shift # 移过 '-set'
|
shift
|
||||||
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do
|
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do TEST_SETS+=("$1"); shift; done
|
||||||
TEST_SETS+=("$1")
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
-sct)
|
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
|
||||||
;;
|
|
||||||
-gct)
|
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
|
|
||||||
;;
|
|
||||||
-et)
|
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
|
|
||||||
;;
|
|
||||||
-ml|--max-lines)
|
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
|
|
||||||
;;
|
|
||||||
-h|--help)
|
|
||||||
show_help
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "未知选项: $1"
|
|
||||||
show_help
|
|
||||||
exit 1
|
|
||||||
;;
|
;;
|
||||||
|
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-h|--help) show_help; exit 0 ;;
|
||||||
|
*) echo "未知选项: $1"; show_help; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# --- 本次修改点: 根据 -set 参数构建查找路径 ---
|
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
|
||||||
|
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
declare -A SET_MAP
|
declare -A SET_MAP
|
||||||
SET_MAP[f]="functional"
|
SET_MAP[f]="functional"
|
||||||
SET_MAP[h]="h_functional"
|
SET_MAP[h]="h_functional"
|
||||||
SET_MAP[p]="performance"
|
SET_MAP[p]="performance"
|
||||||
|
|
||||||
SEARCH_PATHS=()
|
SEARCH_PATHS=()
|
||||||
|
|
||||||
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
|
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
|
||||||
SEARCH_PATHS+=("${TESTDATA_DIR}")
|
SEARCH_PATHS+=("${TESTDATA_DIR}")
|
||||||
else
|
else
|
||||||
@@ -150,9 +188,21 @@ echo "SysY 测试运行器启动..."
|
|||||||
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||||
echo "输入目录: ${SEARCH_PATHS[@]}"
|
echo "输入目录: ${SEARCH_PATHS[@]}"
|
||||||
echo "临时目录: ${TMP_DIR}"
|
echo "临时目录: ${TMP_DIR}"
|
||||||
echo "执行模式: ${EXECUTE_MODE}"
|
|
||||||
if ${EXECUTE_MODE}; then
|
RUN_MODE_INFO=""
|
||||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
if ${IR_EXECUTE_MODE}; then
|
||||||
|
RUN_MODE_INFO="IR执行模式 (-eir)"
|
||||||
|
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||||
|
elif ${EXECUTE_MODE}; then
|
||||||
|
RUN_MODE_INFO="直接执行模式 (-e)"
|
||||||
|
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||||
|
else
|
||||||
|
RUN_MODE_INFO="编译模式 (默认)"
|
||||||
|
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s"
|
||||||
|
fi
|
||||||
|
echo "运行模式: ${RUN_MODE_INFO}"
|
||||||
|
echo "${TIMEOUT_INFO}"
|
||||||
|
if ${EXECUTE_MODE} || ${IR_EXECUTE_MODE}; then
|
||||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
@@ -165,132 +215,228 @@ fi
|
|||||||
TOTAL_CASES=$(echo "$sy_files" | wc -w)
|
TOTAL_CASES=$(echo "$sy_files" | wc -w)
|
||||||
|
|
||||||
while IFS= read -r sy_file; do
|
while IFS= read -r sy_file; do
|
||||||
is_passed=1 # 1 表示通过, 0 表示失败
|
is_passed=0 # 0 表示失败, 1 表示通过
|
||||||
|
|
||||||
relative_path_no_ext=$(realpath --relative-to="${TESTDATA_DIR}" "${sy_file%.*}")
|
relative_path_no_ext=$(realpath --relative-to="${TESTDATA_DIR}" "${sy_file%.*}")
|
||||||
output_base_name=$(echo "${relative_path_no_ext}" | tr '/' '_')
|
output_base_name=$(echo "${relative_path_no_ext}" | tr '/' '_')
|
||||||
|
|
||||||
assembly_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.s"
|
assembly_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.s"
|
||||||
executable_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64"
|
executable_file_S="${TMP_DIR}/${output_base_name}_sysyc_S"
|
||||||
|
output_actual_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.actual_out"
|
||||||
|
|
||||||
|
ir_file="${TMP_DIR}/${output_base_name}_sysyc_ir.ll"
|
||||||
|
assembly_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir.s"
|
||||||
|
executable_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir"
|
||||||
|
output_actual_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir.actual_out"
|
||||||
|
|
||||||
input_file="${sy_file%.*}.in"
|
input_file="${sy_file%.*}.in"
|
||||||
output_reference_file="${sy_file%.*}.out"
|
output_reference_file="${sy_file%.*}.out"
|
||||||
output_actual_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.actual_out"
|
|
||||||
|
|
||||||
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
|
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
|
||||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
|
||||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}" ${OPTIMIZE_FLAG}
|
|
||||||
SYSYC_STATUS=$?
|
|
||||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
|
||||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
elif [ $SYSYC_STATUS -ne 0 ]; then
|
|
||||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} 失败,退出码: ${SYSYC_STATUS}\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
|
# --- 模式 1: IR 执行模式 (-eir) ---
|
||||||
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
if ${IR_EXECUTE_MODE}; then
|
||||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
step_failed=0
|
||||||
GCC_STATUS=$?
|
test_logic_passed=0
|
||||||
if [ $GCC_STATUS -eq 124 ]; then
|
|
||||||
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 超时\e[0m"
|
echo " [1/4] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
is_passed=0
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
|
||||||
elif [ $GCC_STATUS -ne 0 ]; then
|
SYSYC_STATUS=$?
|
||||||
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 失败,退出码: ${GCC_STATUS}\e[0m"
|
if [ $SYSYC_STATUS -ne 0 ]; then
|
||||||
is_passed=0
|
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (IR) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (IR) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
|
||||||
|
step_failed=1
|
||||||
fi
|
fi
|
||||||
elif ! ${EXECUTE_MODE}; then
|
|
||||||
echo " 跳过执行模式。仅生成汇编文件。"
|
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
|
||||||
((PASSED_CASES++))
|
|
||||||
else
|
|
||||||
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$step_failed" -eq 0 ]; then
|
||||||
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
echo " [2/4] 使用 llc-19 编译为汇编 (超时 ${LLC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${LLC_TIMEOUT} "${LLC_CMD}" -march=riscv64 -mcpu=generic-rv64 -mattr=+m,+a,+f,+d,+c -filetype=asm "${ir_file}" -o "${assembly_file_from_ir}"
|
||||||
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
|
LLC_STATUS=$?
|
||||||
if [ -f "${input_file}" ]; then
|
if [ $LLC_STATUS -ne 0 ]; then
|
||||||
exec_cmd+=" < \"${input_file}\""
|
[ $LLC_STATUS -eq 124 ] && echo -e "\e[31m错误: llc-19 编译超时\e[0m" || echo -e "\e[31m错误: llc-19 编译失败,退出码: ${LLC_STATUS}\e[0m"
|
||||||
fi
|
step_failed=1
|
||||||
exec_cmd+=" > \"${output_actual_file}\""
|
|
||||||
|
|
||||||
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
|
||||||
ACTUAL_RETURN_CODE=$?
|
|
||||||
|
|
||||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
|
||||||
echo -e "\e[31m 执行超时: ${sy_file} 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
else
|
|
||||||
if [ -f "${output_reference_file}" ]; then
|
|
||||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
|
||||||
|
|
||||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
|
||||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
|
||||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_riscv64.expected_stdout"
|
|
||||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
|
||||||
|
|
||||||
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
|
||||||
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
|
||||||
else
|
|
||||||
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
|
||||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
|
||||||
display_file_content "${output_actual_file}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
|
||||||
echo -e " \e[36m------------------------------\e[0m"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
|
|
||||||
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
|
||||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
|
||||||
else
|
|
||||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
|
||||||
display_file_content "${output_actual_file}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
|
||||||
echo -e " \e[36m------------------------------\e[0m"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$step_failed" -eq 0 ]; then
|
||||||
|
echo " [3/4] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_from_ir}" -o "${executable_file_from_ir}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||||
|
GCC_STATUS=$?
|
||||||
|
if [ $GCC_STATUS -ne 0 ]; then
|
||||||
|
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
|
||||||
|
step_failed=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$step_failed" -eq 0 ]; then
|
||||||
|
echo " [4/4] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||||
|
exec_cmd="${QEMU_RISCV64} \"${executable_file_from_ir}\""
|
||||||
|
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||||
|
exec_cmd+=" > \"${output_actual_file_from_ir}\""
|
||||||
|
|
||||||
|
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||||
|
ACTUAL_RETURN_CODE=$?
|
||||||
|
|
||||||
|
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||||
|
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||||
|
else
|
||||||
|
if [ -f "${output_reference_file}" ]; then
|
||||||
|
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||||
|
test_logic_passed=1
|
||||||
|
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||||
|
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||||
|
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_from_ir.expected_stdout"
|
||||||
|
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||||
|
|
||||||
|
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||||
|
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
||||||
|
test_logic_passed=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||||
|
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||||
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
test_logic_passed=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
|
||||||
|
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||||
|
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||||
|
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
test_logic_passed=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||||
|
test_logic_passed=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
|
||||||
|
|
||||||
|
# --- 模式 2: 直接执行模式 (-e) ---
|
||||||
|
elif ${EXECUTE_MODE}; then
|
||||||
|
step_failed=0
|
||||||
|
test_logic_passed=0
|
||||||
|
|
||||||
|
echo " [1/3] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
|
||||||
|
SYSYC_STATUS=$?
|
||||||
|
if [ $SYSYC_STATUS -ne 0 ]; then
|
||||||
|
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (汇编) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (汇编) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
|
||||||
|
step_failed=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$step_failed" -eq 0 ]; then
|
||||||
|
echo " [2/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_S}" -o "${executable_file_S}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||||
|
GCC_STATUS=$?
|
||||||
|
if [ $GCC_STATUS -ne 0 ]; then
|
||||||
|
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
|
||||||
|
step_failed=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$step_failed" -eq 0 ]; then
|
||||||
|
echo " [3/3] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||||
|
exec_cmd="${QEMU_RISCV64} \"${executable_file_S}\""
|
||||||
|
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||||
|
exec_cmd+=" > \"${output_actual_file_S}\""
|
||||||
|
|
||||||
|
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||||
|
ACTUAL_RETURN_CODE=$?
|
||||||
|
|
||||||
|
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||||
|
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||||
|
else
|
||||||
|
if [ -f "${output_reference_file}" ]; then
|
||||||
|
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||||
|
test_logic_passed=1
|
||||||
|
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||||
|
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||||
|
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_S.expected_stdout"
|
||||||
|
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||||
|
|
||||||
|
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||||
|
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
||||||
|
test_logic_passed=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||||
|
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||||
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
test_logic_passed=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
|
||||||
|
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||||
|
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||||
|
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
test_logic_passed=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||||
|
test_logic_passed=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
|
||||||
|
|
||||||
|
# --- 模式 3: 默认编译模式 ---
|
||||||
|
else
|
||||||
|
s_compile_ok=0
|
||||||
|
ir_compile_ok=0
|
||||||
|
|
||||||
|
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
|
||||||
|
SYSYC_S_STATUS=$?
|
||||||
|
if [ $SYSYC_S_STATUS -eq 0 ]; then
|
||||||
|
s_compile_ok=1
|
||||||
|
echo -e " \e[32m-> ${assembly_file_S} [成功]\e[0m"
|
||||||
|
else
|
||||||
|
[ $SYSYC_S_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_S_STATUS}]\e[0m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " [2/2] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
|
||||||
|
SYSYC_IR_STATUS=$?
|
||||||
|
if [ $SYSYC_IR_STATUS -eq 0 ]; then
|
||||||
|
ir_compile_ok=1
|
||||||
|
echo -e " \e[32m-> ${ir_file} [成功]\e[0m"
|
||||||
|
else
|
||||||
|
[ $SYSYC_IR_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_IR_STATUS}]\e[0m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$s_compile_ok" -eq 1 ] && [ "$ir_compile_ok" -eq 1 ]; then
|
||||||
|
is_passed=1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --- 统计结果 ---
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
((PASSED_CASES++))
|
((PASSED_CASES++))
|
||||||
else
|
else
|
||||||
|
# 确保 FAILED_CASES_LIST 的每一项都以换行符结尾
|
||||||
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
done <<< "$sy_files"
|
done <<< "$sy_files"
|
||||||
|
|
||||||
echo "========================================"
|
# --- 修改:调用总结函数 ---
|
||||||
echo "测试完成"
|
print_summary
|
||||||
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
|
||||||
|
|
||||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
|
||||||
echo ""
|
|
||||||
echo -e "\e[31m未通过的测例:\e[0m"
|
|
||||||
echo -e "${FAILED_CASES_LIST}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "========================================"
|
|
||||||
|
|
||||||
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -5,7 +5,6 @@ add_library(riscv64_backend_lib STATIC
|
|||||||
RISCv64ISel.cpp
|
RISCv64ISel.cpp
|
||||||
RISCv64LLIR.cpp
|
RISCv64LLIR.cpp
|
||||||
RISCv64RegAlloc.cpp
|
RISCv64RegAlloc.cpp
|
||||||
RISCv64LinearScan.cpp
|
|
||||||
Handler/CalleeSavedHandler.cpp
|
Handler/CalleeSavedHandler.cpp
|
||||||
Handler/LegalizeImmediates.cpp
|
Handler/LegalizeImmediates.cpp
|
||||||
Handler/PrologueEpilogueInsertion.cpp
|
Handler/PrologueEpilogueInsertion.cpp
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
|||||||
case RVOpcodes::FLE_S: *OS << "fle.s "; break;
|
case RVOpcodes::FLE_S: *OS << "fle.s "; break;
|
||||||
case RVOpcodes::FCVT_S_W: *OS << "fcvt.s.w "; break;
|
case RVOpcodes::FCVT_S_W: *OS << "fcvt.s.w "; break;
|
||||||
case RVOpcodes::FCVT_W_S: *OS << "fcvt.w.s "; break;
|
case RVOpcodes::FCVT_W_S: *OS << "fcvt.w.s "; break;
|
||||||
case RVOpcodes::FCVT_W_S_RTZ: *OS << "fcvt.w.s "; break;
|
|
||||||
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
|
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
|
||||||
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
|
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
|
||||||
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;
|
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
#include "RISCv64Backend.h"
|
#include "RISCv64Backend.h"
|
||||||
#include "RISCv64ISel.h"
|
#include "RISCv64ISel.h"
|
||||||
#include "RISCv64RegAlloc.h"
|
#include "RISCv64RegAlloc.h"
|
||||||
#include "RISCv64LinearScan.h" // <--- 新增此行
|
|
||||||
#include "RISCv64AsmPrinter.h"
|
#include "RISCv64AsmPrinter.h"
|
||||||
#include "RISCv64Passes.h"
|
#include "RISCv64Passes.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <future> // <--- 新增此行
|
|
||||||
#include <chrono> // <--- 新增此行
|
|
||||||
#include <iostream> // <--- 新增此行,用于打印超时警告
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
// 顶层入口
|
// 顶层入口
|
||||||
@@ -199,6 +196,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
// === 完整的后端处理流水线 ===
|
// === 完整的后端处理流水线 ===
|
||||||
|
|
||||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||||
|
DEBUG = 0;
|
||||||
|
DEEPDEBUG = 0;
|
||||||
|
|
||||||
RISCv64ISel isel;
|
RISCv64ISel isel;
|
||||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||||
|
|
||||||
@@ -206,7 +206,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
std::stringstream ss_after_isel;
|
std::stringstream ss_after_isel;
|
||||||
RISCv64AsmPrinter printer_isel(mfunc.get());
|
RISCv64AsmPrinter printer_isel(mfunc.get());
|
||||||
printer_isel.run(ss_after_isel, true);
|
printer_isel.run(ss_after_isel, true);
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << ss_after_isel.str();
|
||||||
|
}
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
||||||
<< ss_after_isel.str();
|
<< ss_after_isel.str();
|
||||||
@@ -226,13 +228,13 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
<< ss_after_eli.str();
|
<< ss_after_eli.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
|
// 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
|
||||||
// DivStrengthReduction div_strength_reduction;
|
DivStrengthReduction div_strength_reduction;
|
||||||
// div_strength_reduction.runOnMachineFunction(mfunc.get());
|
div_strength_reduction.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
// // 阶段 2.1: 指令调度 (Instruction Scheduling)
|
// 阶段 2.1: 指令调度 (Instruction Scheduling)
|
||||||
// PreRA_Scheduler scheduler;
|
PreRA_Scheduler scheduler;
|
||||||
// scheduler.runOnMachineFunction(mfunc.get());
|
scheduler.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||||
@@ -252,9 +254,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
mfunc->dumpStackFrameInfo(std::cerr);
|
mfunc->dumpStackFrameInfo(std::cerr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 阶段 4: 窥孔优化 (Peephole Optimization)
|
// 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||||
// PeepholeOptimizer peephole;
|
PeepholeOptimizer peephole;
|
||||||
// peephole.runOnMachineFunction(mfunc.get());
|
peephole.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
// 阶段 5: 局部指令调度 (Local Scheduling)
|
// 阶段 5: 局部指令调度 (Local Scheduling)
|
||||||
PostRA_Scheduler local_scheduler;
|
PostRA_Scheduler local_scheduler;
|
||||||
@@ -274,6 +276,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
printer.run(ss);
|
printer.run(ss);
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
@@ -745,12 +745,83 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(instr));
|
CurMBB->addInstruction(std::move(instr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Instruction::kFtoI: { // 浮点 to 整数 (使用硬件指令进行向零截断)
|
case Instruction::kFtoI: { // 浮点 to 整数 (带向下取整)
|
||||||
// 直接生成一条带有 rtz 舍入模式的转换指令
|
// 目标:实现 floor(x) 的效果, C/C++中浮点转整数是截断(truncate)
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S_RTZ);
|
// 对于正数,floor(x) == truncate(x)
|
||||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
|
// RISC-V的 fcvt.w.s 默认是“四舍五入到偶数”
|
||||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
|
// 我们需要手动实现截断逻辑
|
||||||
CurMBB->addInstruction(std::move(instr));
|
// 逻辑:
|
||||||
|
// temp_i = fcvt.w.s(x) // 四舍五入
|
||||||
|
// temp_f = fcvt.s.w(temp_i) // 转回浮点
|
||||||
|
// if (x < temp_f) { // 如果原数更小,说明被“五入”了
|
||||||
|
// result = temp_i - 1
|
||||||
|
// } else {
|
||||||
|
// result = temp_i
|
||||||
|
// }
|
||||||
|
|
||||||
|
auto temp_i_vreg = getNewVReg(Type::getIntType());
|
||||||
|
auto temp_f_vreg = getNewVReg(Type::getFloatType());
|
||||||
|
auto cmp_vreg = getNewVReg(Type::getIntType());
|
||||||
|
|
||||||
|
// 1. fcvt.w.s temp_i_vreg, src_vreg
|
||||||
|
auto fcvt_w = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
|
||||||
|
fcvt_w->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
|
||||||
|
fcvt_w->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||||
|
CurMBB->addInstruction(std::move(fcvt_w));
|
||||||
|
|
||||||
|
// 2. fcvt.s.w temp_f_vreg, temp_i_vreg
|
||||||
|
auto fcvt_s = std::make_unique<MachineInstr>(RVOpcodes::FCVT_S_W);
|
||||||
|
fcvt_s->addOperand(std::make_unique<RegOperand>(temp_f_vreg));
|
||||||
|
fcvt_s->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
|
||||||
|
CurMBB->addInstruction(std::move(fcvt_s));
|
||||||
|
|
||||||
|
// 3. flt.s cmp_vreg, src_vreg, temp_f_vreg
|
||||||
|
auto flt = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
|
||||||
|
flt->addOperand(std::make_unique<RegOperand>(cmp_vreg));
|
||||||
|
flt->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||||
|
flt->addOperand(std::make_unique<RegOperand>(temp_f_vreg));
|
||||||
|
CurMBB->addInstruction(std::move(flt));
|
||||||
|
|
||||||
|
// 创建标签
|
||||||
|
int unique_id = this->local_label_counter++;
|
||||||
|
std::string rounded_up_label = MFunc->getName() + "_ftoi_rounded_up_" + std::to_string(unique_id);
|
||||||
|
std::string done_label = MFunc->getName() + "_ftoi_done_" + std::to_string(unique_id);
|
||||||
|
|
||||||
|
// 4. bne cmp_vreg, x0, rounded_up_label
|
||||||
|
auto bne = std::make_unique<MachineInstr>(RVOpcodes::BNE);
|
||||||
|
bne->addOperand(std::make_unique<RegOperand>(cmp_vreg));
|
||||||
|
bne->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
|
bne->addOperand(std::make_unique<LabelOperand>(rounded_up_label));
|
||||||
|
CurMBB->addInstruction(std::move(bne));
|
||||||
|
|
||||||
|
// 5. else 分支: mv dest_vreg, temp_i_vreg
|
||||||
|
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||||
|
mv->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
|
mv->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
|
||||||
|
CurMBB->addInstruction(std::move(mv));
|
||||||
|
|
||||||
|
// 6. j done_label
|
||||||
|
auto j = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||||
|
j->addOperand(std::make_unique<LabelOperand>(done_label));
|
||||||
|
CurMBB->addInstruction(std::move(j));
|
||||||
|
|
||||||
|
// 7. rounded_up_label:
|
||||||
|
auto label_up = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
|
||||||
|
label_up->addOperand(std::make_unique<LabelOperand>(rounded_up_label));
|
||||||
|
CurMBB->addInstruction(std::move(label_up));
|
||||||
|
|
||||||
|
// 8. addiw dest_vreg, temp_i_vreg, -1
|
||||||
|
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(temp_i_vreg));
|
||||||
|
addi->addOperand(std::make_unique<ImmOperand>(-1));
|
||||||
|
CurMBB->addInstruction(std::move(addi));
|
||||||
|
|
||||||
|
// 9. done_label:
|
||||||
|
auto label_done = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
|
||||||
|
label_done->addOperand(std::make_unique<LabelOperand>(done_label));
|
||||||
|
CurMBB->addInstruction(std::move(label_done));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Instruction::kFNeg: { // 浮点取负
|
case Instruction::kFNeg: { // 浮点取负
|
||||||
@@ -1131,11 +1202,10 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
auto r_value_byte = getVReg(memset->getValue());
|
auto r_value_byte = getVReg(memset->getValue());
|
||||||
|
|
||||||
// 为memset内部逻辑创建新的临时虚拟寄存器
|
// 为memset内部逻辑创建新的临时虚拟寄存器
|
||||||
Type* ptr_type = Type::getPointerType(Type::getIntType());
|
auto r_counter = getNewVReg();
|
||||||
auto r_counter = getNewVReg(ptr_type);
|
auto r_end_addr = getNewVReg();
|
||||||
auto r_end_addr = getNewVReg(ptr_type);
|
auto r_current_addr = getNewVReg();
|
||||||
auto r_current_addr = getNewVReg(ptr_type);
|
auto r_temp_val = getNewVReg();
|
||||||
auto r_temp_val = getNewVReg(Type::getIntType());
|
|
||||||
|
|
||||||
// 定义一系列lambda表达式来简化指令创建
|
// 定义一系列lambda表达式来简化指令创建
|
||||||
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
|
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
|
||||||
@@ -1226,7 +1296,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
|
|
||||||
// --- Step 1: 获取基地址 (此部分逻辑正确,保持不变) ---
|
// --- Step 1: 获取基地址 (此部分逻辑正确,保持不变) ---
|
||||||
auto base_ptr_node = node->operands[0];
|
auto base_ptr_node = node->operands[0];
|
||||||
auto current_addr_vreg = getNewVReg(gep->getType());
|
auto current_addr_vreg = getNewVReg();
|
||||||
|
|
||||||
if (auto alloca_base = dynamic_cast<AllocaInst*>(base_ptr_node->value)) {
|
if (auto alloca_base = dynamic_cast<AllocaInst*>(base_ptr_node->value)) {
|
||||||
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
|
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
|
||||||
@@ -1268,13 +1338,13 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
// 如果步长为0(例如对一个void类型或空结构体索引),则不产生任何偏移
|
// 如果步长为0(例如对一个void类型或空结构体索引),则不产生任何偏移
|
||||||
if (stride != 0) {
|
if (stride != 0) {
|
||||||
// --- 为当前索引和步长生成偏移计算指令 ---
|
// --- 为当前索引和步长生成偏移计算指令 ---
|
||||||
auto offset_vreg = getNewVReg(Type::getIntType());
|
auto offset_vreg = getNewVReg();
|
||||||
|
|
||||||
// 处理索引 - 区分常量与动态值
|
// 处理索引 - 区分常量与动态值
|
||||||
unsigned index_vreg;
|
unsigned index_vreg;
|
||||||
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
|
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
|
||||||
// 对于常量索引,直接创建新的虚拟寄存器
|
// 对于常量索引,直接创建新的虚拟寄存器
|
||||||
index_vreg = getNewVReg(Type::getIntType());
|
index_vreg = getNewVReg();
|
||||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
li->addOperand(std::make_unique<RegOperand>(index_vreg));
|
li->addOperand(std::make_unique<RegOperand>(index_vreg));
|
||||||
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
|
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
|
||||||
@@ -1292,7 +1362,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(mv));
|
CurMBB->addInstruction(std::move(mv));
|
||||||
} else {
|
} else {
|
||||||
// 步长不为1,需要生成乘法指令
|
// 步长不为1,需要生成乘法指令
|
||||||
auto size_vreg = getNewVReg(Type::getIntType());
|
auto size_vreg = getNewVReg();
|
||||||
auto li_size = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li_size = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
li_size->addOperand(std::make_unique<RegOperand>(size_vreg));
|
li_size->addOperand(std::make_unique<RegOperand>(size_vreg));
|
||||||
li_size->addOperand(std::make_unique<ImmOperand>(stride));
|
li_size->addOperand(std::make_unique<ImmOperand>(stride));
|
||||||
|
|||||||
@@ -1,517 +0,0 @@
|
|||||||
#include "RISCv64LinearScan.h"
|
|
||||||
#include "RISCv64LLIR.h"
|
|
||||||
#include "RISCv64ISel.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
extern int DEBUG;
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
RISCv64LinearScan::RISCv64LinearScan(MachineFunction* mfunc)
|
|
||||||
: MFunc(mfunc),
|
|
||||||
ISel(mfunc->getISel()),
|
|
||||||
vreg_type_map(ISel->getVRegTypeMap()) {
|
|
||||||
|
|
||||||
// 初始化可用的物理寄存器池,与图着色版本保持一致
|
|
||||||
// 整数寄存器
|
|
||||||
allocable_int_regs = {
|
|
||||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, /*T5保留作为大立即数加载寄存器*/ PhysicalReg::T6,
|
|
||||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
|
|
||||||
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
|
||||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
|
||||||
};
|
|
||||||
// 浮点寄存器
|
|
||||||
allocable_fp_regs = {
|
|
||||||
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
|
|
||||||
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
|
|
||||||
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, PhysicalReg::F22,
|
|
||||||
PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27,
|
|
||||||
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
|
|
||||||
};
|
|
||||||
// 新增:识别所有通过寄存器传递的参数,并建立vreg到物理寄存器(preg)的映射
|
|
||||||
// 这等同于图着色算法中的“预着色”步骤。
|
|
||||||
if (MFunc->getFunc()) {
|
|
||||||
int int_arg_idx = 0;
|
|
||||||
int fp_arg_idx = 0;
|
|
||||||
for (Argument* arg : MFunc->getFunc()->getArguments()) {
|
|
||||||
unsigned arg_vreg = ISel->getVReg(arg);
|
|
||||||
if (arg->getType()->isFloat()) {
|
|
||||||
if (fp_arg_idx < 8) { // fa0-fa7
|
|
||||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_arg_idx);
|
|
||||||
abi_vreg_map[arg_vreg] = preg;
|
|
||||||
fp_arg_idx++;
|
|
||||||
}
|
|
||||||
} else { // 整数或指针
|
|
||||||
if (int_arg_idx < 8) { // a0-a7
|
|
||||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
|
|
||||||
abi_vreg_map[arg_vreg] = preg;
|
|
||||||
int_arg_idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RISCv64LinearScan::run() {
|
|
||||||
if (DEBUG) std::cerr << "===== Running Linear Scan Register Allocation for function: " << MFunc->getName() << " =====\n";
|
|
||||||
|
|
||||||
bool changed = true;
|
|
||||||
while(changed) {
|
|
||||||
// 1. 准备阶段
|
|
||||||
linearizeBlocks();
|
|
||||||
computeLiveIntervals();
|
|
||||||
|
|
||||||
// 2. 执行线性扫描
|
|
||||||
changed = linearScan();
|
|
||||||
|
|
||||||
// 3. 如果有溢出,重写代码,然后下一轮重新开始
|
|
||||||
if (changed) {
|
|
||||||
rewriteProgram();
|
|
||||||
if (DEBUG) std::cerr << "--- Spilling detected, re-running linear scan ---\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 将最终分配结果应用到机器指令
|
|
||||||
applyAllocation();
|
|
||||||
// 5. 收集用到的被调用者保存寄存器
|
|
||||||
MFunc->getFrameInfo().vreg_to_preg_map = this->vreg_to_preg_map;
|
|
||||||
collectUsedCalleeSavedRegs();
|
|
||||||
|
|
||||||
if (DEBUG) std::cerr << "===== Finished Linear Scan Register Allocation =====\n\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 步骤 1.1: 对基本块进行线性化,这里我们简单地按现有顺序排列
|
|
||||||
void RISCv64LinearScan::linearizeBlocks() {
|
|
||||||
linear_order_blocks.clear();
|
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
|
||||||
linear_order_blocks.push_back(mbb.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RISCv64LinearScan.cpp
|
|
||||||
|
|
||||||
void RISCv64LinearScan::computeLiveIntervals() {
|
|
||||||
instr_numbering.clear();
|
|
||||||
live_intervals.clear();
|
|
||||||
unhandled.clear();
|
|
||||||
|
|
||||||
// a. 对所有指令进行线性编号,并记录CALL指令的位置
|
|
||||||
int num = 0;
|
|
||||||
std::set<int> call_locations;
|
|
||||||
for (auto* mbb : linear_order_blocks) {
|
|
||||||
for (auto& instr : mbb->getInstructions()) {
|
|
||||||
instr_numbering[instr.get()] = num;
|
|
||||||
if (instr->getOpcode() == RVOpcodes::CALL) {
|
|
||||||
call_locations.insert(num);
|
|
||||||
}
|
|
||||||
num += 2; // 指令编号间隔为2,方便在溢出重写时插入指令
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// b. 遍历所有指令,记录每个vreg首次和末次出现的位置
|
|
||||||
std::map<unsigned, std::pair<int, int>> vreg_ranges; // vreg -> {first_instr_num, last_instr_num}
|
|
||||||
|
|
||||||
for (auto* mbb : linear_order_blocks) {
|
|
||||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
|
||||||
const MachineInstr* instr = instr_ptr.get();
|
|
||||||
int instr_num = instr_numbering.at(instr);
|
|
||||||
std::set<unsigned> use, def;
|
|
||||||
getInstrUseDef(instr, use, def);
|
|
||||||
|
|
||||||
auto all_vregs = use;
|
|
||||||
all_vregs.insert(def.begin(), def.end());
|
|
||||||
|
|
||||||
for (unsigned vreg : all_vregs) {
|
|
||||||
if (vreg_ranges.find(vreg) == vreg_ranges.end()) {
|
|
||||||
vreg_ranges[vreg] = {instr_num, instr_num};
|
|
||||||
} else {
|
|
||||||
vreg_ranges[vreg].second = std::max(vreg_ranges[vreg].second, instr_num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// c. 根据记录的边界,创建LiveInterval对象,并检查是否跨越CALL
|
|
||||||
for (auto const& [vreg, range] : vreg_ranges) {
|
|
||||||
live_intervals.emplace(vreg, LiveInterval(vreg));
|
|
||||||
auto& interval = live_intervals.at(vreg);
|
|
||||||
interval.start = range.first;
|
|
||||||
interval.end = range.second;
|
|
||||||
|
|
||||||
// 检查此区间是否跨越了任何CALL指令
|
|
||||||
auto it = call_locations.lower_bound(interval.start);
|
|
||||||
if (it != call_locations.end() && *it < interval.end) {
|
|
||||||
interval.crosses_call = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// d. 将所有计算出的活跃区间放入 unhandled 列表
|
|
||||||
for (auto& pair : live_intervals) {
|
|
||||||
unhandled.push_back(&pair.second);
|
|
||||||
}
|
|
||||||
std::sort(unhandled.begin(), unhandled.end(), [](const LiveInterval* a, const LiveInterval* b){
|
|
||||||
return a->start < b->start;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// RISCv64LinearScan.cpp
|
|
||||||
|
|
||||||
// 在类的定义中添加一个辅助函数来判断寄存器类型
|
|
||||||
bool isCalleeSaved(PhysicalReg preg) {
|
|
||||||
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) return true;
|
|
||||||
if (preg == PhysicalReg::S0) return true; // s0 通常也作为被调用者保存
|
|
||||||
// 浮点寄存器
|
|
||||||
if (preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) return true;
|
|
||||||
if (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 线性扫描主算法
|
|
||||||
bool RISCv64LinearScan::linearScan() {
|
|
||||||
active.clear();
|
|
||||||
spilled_vregs.clear();
|
|
||||||
vreg_to_preg_map.clear();
|
|
||||||
|
|
||||||
// 将寄存器池分为调用者保存和被调用者保存两类
|
|
||||||
std::set<PhysicalReg> free_caller_int_regs, free_callee_int_regs;
|
|
||||||
std::set<PhysicalReg> free_caller_fp_regs, free_callee_fp_regs;
|
|
||||||
|
|
||||||
for (auto preg : allocable_int_regs) {
|
|
||||||
if (isCalleeSaved(preg)) free_callee_int_regs.insert(preg);
|
|
||||||
else free_caller_int_regs.insert(preg);
|
|
||||||
}
|
|
||||||
for (auto preg : allocable_fp_regs) {
|
|
||||||
if (isCalleeSaved(preg)) free_callee_fp_regs.insert(preg);
|
|
||||||
else free_caller_fp_regs.insert(preg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 预处理ABI参数寄存器
|
|
||||||
vreg_to_preg_map.insert(abi_vreg_map.begin(), abi_vreg_map.end());
|
|
||||||
std::vector<LiveInterval*> normal_unhandled;
|
|
||||||
for(LiveInterval* interval : unhandled) {
|
|
||||||
if(abi_vreg_map.count(interval->vreg)) {
|
|
||||||
active.push_back(interval);
|
|
||||||
PhysicalReg preg = abi_vreg_map.at(interval->vreg);
|
|
||||||
if (isFPVReg(interval->vreg)) {
|
|
||||||
if(isCalleeSaved(preg)) free_callee_fp_regs.erase(preg); else free_caller_fp_regs.erase(preg);
|
|
||||||
} else {
|
|
||||||
if(isCalleeSaved(preg)) free_callee_int_regs.erase(preg); else free_caller_int_regs.erase(preg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
normal_unhandled.push_back(interval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unhandled = normal_unhandled;
|
|
||||||
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
|
|
||||||
|
|
||||||
// 主循环
|
|
||||||
for (LiveInterval* current : unhandled) {
|
|
||||||
// a. 释放active列表中已结束的区间
|
|
||||||
std::vector<LiveInterval*> new_active;
|
|
||||||
for (LiveInterval* active_interval : active) {
|
|
||||||
if (active_interval->end < current->start) {
|
|
||||||
PhysicalReg preg = vreg_to_preg_map.at(active_interval->vreg);
|
|
||||||
if (isFPVReg(active_interval->vreg)) {
|
|
||||||
if(isCalleeSaved(preg)) free_callee_fp_regs.insert(preg); else free_caller_fp_regs.insert(preg);
|
|
||||||
} else {
|
|
||||||
if(isCalleeSaved(preg)) free_callee_int_regs.insert(preg); else free_caller_int_regs.insert(preg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
new_active.push_back(active_interval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
active = new_active;
|
|
||||||
|
|
||||||
// b. 约束化地为当前区间分配寄存器
|
|
||||||
bool is_fp = isFPVReg(current->vreg);
|
|
||||||
auto& free_caller = is_fp ? free_caller_fp_regs : free_caller_int_regs;
|
|
||||||
auto& free_callee = is_fp ? free_callee_fp_regs : free_callee_int_regs;
|
|
||||||
|
|
||||||
PhysicalReg allocated_preg = PhysicalReg::INVALID;
|
|
||||||
|
|
||||||
if (current->crosses_call) {
|
|
||||||
// 跨调用区间:必须使用被调用者保存寄存器
|
|
||||||
if (!free_callee.empty()) {
|
|
||||||
allocated_preg = *free_callee.begin();
|
|
||||||
free_callee.erase(allocated_preg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 非跨调用区间:优先使用调用者保存寄存器
|
|
||||||
if (!free_caller.empty()) {
|
|
||||||
allocated_preg = *free_caller.begin();
|
|
||||||
free_caller.erase(allocated_preg);
|
|
||||||
} else if (!free_callee.empty()) {
|
|
||||||
allocated_preg = *free_callee.begin();
|
|
||||||
free_callee.erase(allocated_preg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allocated_preg != PhysicalReg::INVALID) {
|
|
||||||
vreg_to_preg_map[current->vreg] = allocated_preg;
|
|
||||||
active.push_back(current);
|
|
||||||
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
|
|
||||||
} else {
|
|
||||||
// c. 没有可用寄存器,需要溢出
|
|
||||||
spillAtInterval(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return !spilled_vregs.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RISCv64LinearScan::chooseRegForInterval(LiveInterval* current) {
|
|
||||||
bool is_fp = isFPVReg(current->vreg);
|
|
||||||
auto& free_regs = is_fp ? free_fp_regs : free_int_regs;
|
|
||||||
|
|
||||||
if (!free_regs.empty()) {
|
|
||||||
// 有可用寄存器
|
|
||||||
PhysicalReg preg = *free_regs.begin();
|
|
||||||
free_regs.erase(free_regs.begin());
|
|
||||||
vreg_to_preg_map[current->vreg] = preg;
|
|
||||||
active.push_back(current);
|
|
||||||
// 保持 active 列表按结束点排序
|
|
||||||
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){
|
|
||||||
return a->end < b->end;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 没有可用寄存器,需要溢出
|
|
||||||
spillAtInterval(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RISCv64LinearScan::spillAtInterval(LiveInterval* current) {
|
|
||||||
LiveInterval* spill_candidate = nullptr;
|
|
||||||
// 启发式溢出:
|
|
||||||
// 如果current需要callee-saved,则从active中找一个占用callee-saved且结束最晚的区间比较
|
|
||||||
// 否则,找active中结束最晚的区间
|
|
||||||
// 这里简化处理:总是找active中结束最晚的区间
|
|
||||||
auto last_active = active.back();
|
|
||||||
|
|
||||||
if (last_active->end > current->end) {
|
|
||||||
// 溢出active中的区间
|
|
||||||
spill_candidate = last_active;
|
|
||||||
PhysicalReg preg = vreg_to_preg_map.at(spill_candidate->vreg);
|
|
||||||
vreg_to_preg_map[current->vreg] = preg; // 把换出的寄存器给current
|
|
||||||
// 更新active列表
|
|
||||||
active.pop_back();
|
|
||||||
active.push_back(current);
|
|
||||||
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
|
|
||||||
spilled_vregs.insert(spill_candidate->vreg);
|
|
||||||
} else {
|
|
||||||
// 溢出当前区间
|
|
||||||
spilled_vregs.insert(current->vreg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 步骤 3: 重写程序,插入溢出代码
|
|
||||||
void RISCv64LinearScan::rewriteProgram() {
|
|
||||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
|
||||||
int spill_offset = frame_info.locals_size; // 溢出区域接在局部变量之后
|
|
||||||
|
|
||||||
for (unsigned vreg : spilled_vregs) {
|
|
||||||
if (frame_info.spill_offsets.count(vreg)) continue; // 避免重复分配
|
|
||||||
|
|
||||||
int size = isFPVReg(vreg) ? 4 : (vreg_type_map.at(vreg)->isPointer() ? 8 : 4);
|
|
||||||
spill_offset += size;
|
|
||||||
spill_offset = (spill_offset + 7) & ~7; // 8字节对齐
|
|
||||||
frame_info.spill_offsets[vreg] = -(16 + spill_offset);
|
|
||||||
}
|
|
||||||
frame_info.spill_size = spill_offset - frame_info.locals_size;
|
|
||||||
|
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
|
||||||
auto& instrs = mbb->getInstructions();
|
|
||||||
std::vector<std::unique_ptr<MachineInstr>> new_instrs;
|
|
||||||
|
|
||||||
for (auto it = instrs.begin(); it != instrs.end(); ++it) {
|
|
||||||
auto& instr = *it;
|
|
||||||
std::set<unsigned> use_vregs, def_vregs;
|
|
||||||
getInstrUseDef(instr.get(), use_vregs, def_vregs);
|
|
||||||
|
|
||||||
// 建立溢出vreg到新临时vreg的映射
|
|
||||||
std::map<unsigned, unsigned> use_remap;
|
|
||||||
std::map<unsigned, unsigned> def_remap;
|
|
||||||
|
|
||||||
// 1. 为所有溢出的USE创建LOAD指令和映射
|
|
||||||
for (unsigned old_vreg : use_vregs) {
|
|
||||||
if (spilled_vregs.count(old_vreg) && use_remap.find(old_vreg) == use_remap.end()) {
|
|
||||||
Type* type = vreg_type_map.at(old_vreg);
|
|
||||||
unsigned new_temp_vreg = ISel->getNewVReg(type);
|
|
||||||
use_remap[old_vreg] = new_temp_vreg;
|
|
||||||
|
|
||||||
RVOpcodes load_op = isFPVReg(old_vreg) ? RVOpcodes::FLW : (type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
|
|
||||||
auto load = std::make_unique<MachineInstr>(load_op);
|
|
||||||
load->addOperand(std::make_unique<RegOperand>(new_temp_vreg));
|
|
||||||
load->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
|
||||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))
|
|
||||||
));
|
|
||||||
new_instrs.push_back(std::move(load));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 为所有溢出的DEF创建映射
|
|
||||||
for (unsigned old_vreg : def_vregs) {
|
|
||||||
if (spilled_vregs.count(old_vreg) && def_remap.find(old_vreg) == def_remap.end()) {
|
|
||||||
Type* type = vreg_type_map.at(old_vreg);
|
|
||||||
unsigned new_temp_vreg = ISel->getNewVReg(type);
|
|
||||||
def_remap[old_vreg] = new_temp_vreg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 基于角色精确地替换原指令中的操作数
|
|
||||||
auto opcode = instr->getOpcode();
|
|
||||||
auto& operands = instr->getOperands();
|
|
||||||
|
|
||||||
auto replace_reg_op = [](RegOperand* reg_op, const std::map<unsigned, unsigned>& remap) {
|
|
||||||
if (reg_op->isVirtual() && remap.count(reg_op->getVRegNum())) {
|
|
||||||
reg_op->setVRegNum(remap.at(reg_op->getVRegNum()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (op_info.count(opcode)) {
|
|
||||||
const auto& info = op_info.at(opcode);
|
|
||||||
// 替换 Defs
|
|
||||||
for (int idx : info.first) {
|
|
||||||
if (idx < operands.size() && operands[idx]->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
replace_reg_op(static_cast<RegOperand*>(operands[idx].get()), def_remap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 替换 Uses
|
|
||||||
for (int idx : info.second) {
|
|
||||||
if (idx < operands.size()) {
|
|
||||||
if (operands[idx]->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
replace_reg_op(static_cast<RegOperand*>(operands[idx].get()), use_remap);
|
|
||||||
} else if (operands[idx]->getKind() == MachineOperand::KIND_MEM) {
|
|
||||||
replace_reg_op(static_cast<MemOperand*>(operands[idx].get())->getBase(), use_remap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (opcode == RVOpcodes::CALL) {
|
|
||||||
// 特殊处理 CALL 指令
|
|
||||||
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
replace_reg_op(static_cast<RegOperand*>(operands[0].get()), def_remap);
|
|
||||||
}
|
|
||||||
for (size_t i = 1; i < operands.size(); ++i) {
|
|
||||||
if (operands[i]->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
replace_reg_op(static_cast<RegOperand*>(operands[i].get()), use_remap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 将修改后的指令放入新列表
|
|
||||||
new_instrs.push_back(std::move(instr));
|
|
||||||
|
|
||||||
// 5. 为所有溢出的DEF创建STORE指令
|
|
||||||
for(const auto& pair : def_remap) {
|
|
||||||
unsigned old_vreg = pair.first;
|
|
||||||
unsigned new_temp_vreg = pair.second;
|
|
||||||
Type* type = vreg_type_map.at(old_vreg);
|
|
||||||
RVOpcodes store_op = isFPVReg(old_vreg) ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
|
|
||||||
auto store = std::make_unique<MachineInstr>(store_op);
|
|
||||||
store->addOperand(std::make_unique<RegOperand>(new_temp_vreg));
|
|
||||||
store->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
|
||||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))
|
|
||||||
));
|
|
||||||
new_instrs.push_back(std::move(store));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
instrs = std::move(new_instrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 步骤 4: 应用最终分配结果
|
|
||||||
void RISCv64LinearScan::applyAllocation() {
|
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
|
||||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
|
||||||
for (auto& op_ptr : instr_ptr->getOperands()) {
|
|
||||||
if (op_ptr->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
|
|
||||||
if (reg_op->isVirtual()) {
|
|
||||||
unsigned vreg = reg_op->getVRegNum();
|
|
||||||
if (vreg_to_preg_map.count(vreg)) {
|
|
||||||
reg_op->setPReg(vreg_to_preg_map.at(vreg));
|
|
||||||
} else {
|
|
||||||
// 如果一个vreg最终没有颜色,这通常意味着它是一个短生命周期的临时变量
|
|
||||||
// 在溢出重写中产生,但在下一轮分配前就被优化掉了。
|
|
||||||
// 或者是一个从未被使用的定义。
|
|
||||||
// 给他一个临时寄存器以防万一。
|
|
||||||
reg_op->setPReg(PhysicalReg::T5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
|
|
||||||
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
|
|
||||||
auto reg_op = mem_op->getBase();
|
|
||||||
if (reg_op->isVirtual()) {
|
|
||||||
unsigned vreg = reg_op->getVRegNum();
|
|
||||||
if (vreg_to_preg_map.count(vreg)) {
|
|
||||||
reg_op->setPReg(vreg_to_preg_map.at(vreg));
|
|
||||||
} else {
|
|
||||||
reg_op->setPReg(PhysicalReg::T5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RISCv64LinearScan::getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def) {
|
|
||||||
// 这个函数与图着色版本中的 getInstrUseDef 逻辑完全相同,此处直接复用
|
|
||||||
auto opcode = instr->getOpcode();
|
|
||||||
const auto& operands = instr->getOperands();
|
|
||||||
|
|
||||||
// op_info 的定义已被移到函数外部的命名空间中
|
|
||||||
|
|
||||||
auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set<unsigned>& s) {
|
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
auto reg_op = static_cast<const RegOperand*>(op);
|
|
||||||
if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
|
|
||||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
|
||||||
auto mem_op = static_cast<const MemOperand*>(op);
|
|
||||||
auto reg_op = mem_op->getBase();
|
|
||||||
if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (op_info.count(opcode)) {
|
|
||||||
const auto& info = op_info.at(opcode);
|
|
||||||
for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def);
|
|
||||||
for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use);
|
|
||||||
// MemOperand 的基址寄存器总是一个 use
|
|
||||||
for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use);
|
|
||||||
} else if (opcode == RVOpcodes::CALL) {
|
|
||||||
// CALL指令的特殊处理
|
|
||||||
// 第一个操作数(如果有)是def(返回值)
|
|
||||||
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def);
|
|
||||||
// 后续的寄存器操作数是use(参数)
|
|
||||||
for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 辅助函数: 判断是否为浮点vreg
|
|
||||||
bool RISCv64LinearScan::isFPVReg(unsigned vreg) const {
|
|
||||||
return vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 辅助函数: 收集被使用的被调用者保存寄存器
|
|
||||||
void RISCv64LinearScan::collectUsedCalleeSavedRegs() {
|
|
||||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
|
||||||
frame_info.used_callee_saved_regs.clear();
|
|
||||||
|
|
||||||
const auto& callee_saved_int = getCalleeSavedIntRegs();
|
|
||||||
const auto& callee_saved_fp = getCalleeSavedFpRegs();
|
|
||||||
std::set<PhysicalReg> callee_saved_set(callee_saved_int.begin(), callee_saved_int.end());
|
|
||||||
callee_saved_set.insert(callee_saved_fp.begin(), callee_saved_fp.end());
|
|
||||||
callee_saved_set.insert(PhysicalReg::S0); // s0总是被用作帧指针
|
|
||||||
|
|
||||||
for(const auto& pair : vreg_to_preg_map) {
|
|
||||||
PhysicalReg preg = pair.second;
|
|
||||||
if(callee_saved_set.count(preg)) {
|
|
||||||
frame_info.used_callee_saved_regs.insert(preg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@@ -55,12 +55,41 @@ void RISCv64RegAlloc::run() {
|
|||||||
|
|
||||||
if (DEBUG) std::cerr << "===== Running Graph Coloring Register Allocation for function: " << MFunc->getName() << " =====\n";
|
if (DEBUG) std::cerr << "===== Running Graph Coloring Register Allocation for function: " << MFunc->getName() << " =====\n";
|
||||||
|
|
||||||
while (true) {
|
const int MAX_ITERATIONS = 50;
|
||||||
|
int iteration = 0;
|
||||||
|
|
||||||
|
while (iteration++ < MAX_ITERATIONS) {
|
||||||
if (doAllocation()) {
|
if (doAllocation()) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
rewriteProgram();
|
rewriteProgram();
|
||||||
if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation ---\n";
|
if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation (iteration " << iteration << ") ---\n";
|
||||||
|
|
||||||
|
if (iteration >= MAX_ITERATIONS) {
|
||||||
|
std::cerr << "ERROR: Register allocation failed to converge after " << MAX_ITERATIONS << " iterations\n";
|
||||||
|
std::cerr << " Spill worklist size: " << spillWorklist.size() << "\n";
|
||||||
|
std::cerr << " Total nodes: " << (initial.size() + coloredNodes.size()) << "\n";
|
||||||
|
|
||||||
|
// Emergency spill remaining nodes to break the loop
|
||||||
|
std::cerr << " Emergency spilling remaining spill worklist nodes...\n";
|
||||||
|
for (unsigned node : spillWorklist) {
|
||||||
|
spilledNodes.insert(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also spill any nodes that didn't get colors
|
||||||
|
std::set<unsigned> uncolored;
|
||||||
|
for (unsigned node : initial) {
|
||||||
|
if (color_map.find(node) == color_map.end()) {
|
||||||
|
uncolored.insert(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned node : uncolored) {
|
||||||
|
spilledNodes.insert(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force completion
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
|
|
||||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||||
unsigned getVReg(Value* val);
|
unsigned getVReg(Value* val);
|
||||||
|
unsigned getNewVReg() { return vreg_counter++; }
|
||||||
unsigned getNewVReg(Type* type);
|
unsigned getNewVReg(Type* type);
|
||||||
unsigned getVRegCounter() const;
|
unsigned getVRegCounter() const;
|
||||||
// 获取 vreg_map 的公共接口
|
// 获取 vreg_map 的公共接口
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ enum class PhysicalReg {
|
|||||||
// 假设 vreg_counter 不会达到这么大的值
|
// 假设 vreg_counter 不会达到这么大的值
|
||||||
PHYS_REG_START_ID = 1000000,
|
PHYS_REG_START_ID = 1000000,
|
||||||
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
||||||
|
|
||||||
INVALID, ///< 无效寄存器标记
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// RISC-V 指令操作码枚举
|
// RISC-V 指令操作码枚举
|
||||||
@@ -88,7 +86,6 @@ enum class RVOpcodes {
|
|||||||
// 浮点转换
|
// 浮点转换
|
||||||
FCVT_S_W, // fcvt.s.w rd, rs1 (有符号整数 -> 单精度浮点)
|
FCVT_S_W, // fcvt.s.w rd, rs1 (有符号整数 -> 单精度浮点)
|
||||||
FCVT_W_S, // fcvt.w.s rd, rs1 (单精度浮点 -> 有符号整数)
|
FCVT_W_S, // fcvt.w.s rd, rs1 (单精度浮点 -> 有符号整数)
|
||||||
FCVT_W_S_RTZ, // fcvt.w.s rd, rs1, rtz (使用向零截断模式)
|
|
||||||
|
|
||||||
// 浮点传送/移动
|
// 浮点传送/移动
|
||||||
FMV_S, // fmv.s rd, rs1 (浮点寄存器之间)
|
FMV_S, // fmv.s rd, rs1 (浮点寄存器之间)
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
#ifndef RISCV64_LINEARSCAN_H
|
|
||||||
#define RISCV64_LINEARSCAN_H
|
|
||||||
|
|
||||||
#include "RISCv64LLIR.h"
|
|
||||||
#include "RISCv64ISel.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
// 前向声明
|
|
||||||
class MachineBasicBlock;
|
|
||||||
class MachineFunction;
|
|
||||||
class RISCv64ISel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 表示一个虚拟寄存器的活跃区间。
|
|
||||||
* 包含起始和结束指令编号。为了简化,我们不处理有“洞”的区间。
|
|
||||||
*/
|
|
||||||
struct LiveInterval {
|
|
||||||
unsigned vreg = 0;
|
|
||||||
int start = -1;
|
|
||||||
int end = -1;
|
|
||||||
bool crosses_call = false;
|
|
||||||
|
|
||||||
LiveInterval(unsigned vreg) : vreg(vreg) {}
|
|
||||||
|
|
||||||
// 用于排序,按起始点从小到大
|
|
||||||
bool operator<(const LiveInterval& other) const {
|
|
||||||
return start < other.start;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class RISCv64LinearScan {
|
|
||||||
public:
|
|
||||||
RISCv64LinearScan(MachineFunction* mfunc);
|
|
||||||
void run();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// --- 核心算法流程 ---
|
|
||||||
void linearizeBlocks();
|
|
||||||
void computeLiveIntervals();
|
|
||||||
bool linearScan();
|
|
||||||
void rewriteProgram();
|
|
||||||
void applyAllocation();
|
|
||||||
void chooseRegForInterval(LiveInterval* current);
|
|
||||||
void spillAtInterval(LiveInterval* current);
|
|
||||||
|
|
||||||
// --- 辅助函数 ---
|
|
||||||
void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def);
|
|
||||||
bool isFPVReg(unsigned vreg) const;
|
|
||||||
void collectUsedCalleeSavedRegs();
|
|
||||||
|
|
||||||
MachineFunction* MFunc;
|
|
||||||
RISCv64ISel* ISel;
|
|
||||||
|
|
||||||
// --- 线性扫描数据结构 ---
|
|
||||||
std::vector<MachineBasicBlock*> linear_order_blocks;
|
|
||||||
std::map<const MachineInstr*, int> instr_numbering;
|
|
||||||
std::map<unsigned, LiveInterval> live_intervals;
|
|
||||||
|
|
||||||
std::vector<LiveInterval*> unhandled;
|
|
||||||
std::vector<LiveInterval*> active; // 活跃且已分配物理寄存器的区间
|
|
||||||
|
|
||||||
std::set<unsigned> spilled_vregs; // 记录在本轮被决定溢出的vreg
|
|
||||||
|
|
||||||
// --- 寄存器池和分配结果 ---
|
|
||||||
std::vector<PhysicalReg> allocable_int_regs;
|
|
||||||
std::vector<PhysicalReg> allocable_fp_regs;
|
|
||||||
std::set<PhysicalReg> free_int_regs;
|
|
||||||
std::set<PhysicalReg> free_fp_regs;
|
|
||||||
std::map<unsigned, PhysicalReg> vreg_to_preg_map;
|
|
||||||
std::map<unsigned, PhysicalReg> abi_vreg_map;
|
|
||||||
|
|
||||||
const std::map<unsigned, Type*>& vreg_type_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
|
|
||||||
{RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}},
|
|
||||||
{RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}},
|
|
||||||
{RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}},
|
|
||||||
{RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}},
|
|
||||||
{RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}},
|
|
||||||
{RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}}, {RVOpcodes::LB, {{0}, {}}},
|
|
||||||
{RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}},
|
|
||||||
{RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}},
|
|
||||||
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}}, {RVOpcodes::SB, {{}, {0, 1}}},
|
|
||||||
{RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}},
|
|
||||||
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}}, {RVOpcodes::BEQ, {{}, {0, 1}}},
|
|
||||||
{RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}}, {RVOpcodes::BGE, {{}, {0, 1}}},
|
|
||||||
{RVOpcodes::JALR, {{0}, {1}}}, {RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
|
|
||||||
{RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}},
|
|
||||||
{RVOpcodes::RET, {{}, {}}}, {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
|
|
||||||
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}},
|
|
||||||
{RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}},
|
|
||||||
{RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}},
|
|
||||||
{RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
|
|
||||||
#endif // RISCV64_LINEARSCAN_H
|
|
||||||
@@ -20,6 +20,10 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
|
// Global cleanup function to release all statically allocated IR objects
|
||||||
|
void cleanupIRPools();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \defgroup type Types
|
* \defgroup type Types
|
||||||
* @brief Sysy的类型系统
|
* @brief Sysy的类型系统
|
||||||
@@ -83,6 +87,7 @@ class Type {
|
|||||||
auto as() const -> std::enable_if_t<std::is_base_of_v<Type, T>, T *> {
|
auto as() const -> std::enable_if_t<std::is_base_of_v<Type, T>, T *> {
|
||||||
return dynamic_cast<T *>(const_cast<Type *>(this));
|
return dynamic_cast<T *>(const_cast<Type *>(this));
|
||||||
}
|
}
|
||||||
|
virtual void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PointerType : public Type {
|
class PointerType : public Type {
|
||||||
@@ -95,6 +100,9 @@ class PointerType : public Type {
|
|||||||
public:
|
public:
|
||||||
static PointerType* get(Type *baseType); ///< 获取指向baseType的Pointer类型
|
static PointerType* get(Type *baseType); ///< 获取指向baseType的Pointer类型
|
||||||
|
|
||||||
|
// Cleanup method to release all cached pointer types (call at program exit)
|
||||||
|
static void cleanup();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Type* getBaseType() const { return baseType; } ///< 获取指向的类型
|
Type* getBaseType() const { return baseType; } ///< 获取指向的类型
|
||||||
};
|
};
|
||||||
@@ -112,6 +120,9 @@ class FunctionType : public Type {
|
|||||||
/// 获取返回值类型为returnType, 形参类型列表为paramTypes的Function类型
|
/// 获取返回值类型为returnType, 形参类型列表为paramTypes的Function类型
|
||||||
static FunctionType* get(Type *returnType, const std::vector<Type *> ¶mTypes = {});
|
static FunctionType* get(Type *returnType, const std::vector<Type *> ¶mTypes = {});
|
||||||
|
|
||||||
|
// Cleanup method to release all cached function types (call at program exit)
|
||||||
|
static void cleanup();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Type* getReturnType() const { return returnType; } ///< 获取返回值类信息
|
Type* getReturnType() const { return returnType; } ///< 获取返回值类信息
|
||||||
auto getParamTypes() const { return make_range(paramTypes); } ///< 获取形参类型列表
|
auto getParamTypes() const { return make_range(paramTypes); } ///< 获取形参类型列表
|
||||||
@@ -124,6 +135,9 @@ class ArrayType : public Type {
|
|||||||
// numElements:该维度的大小 (例如,int[3] 的 numElements 是 3)
|
// numElements:该维度的大小 (例如,int[3] 的 numElements 是 3)
|
||||||
static ArrayType *get(Type *elementType, unsigned numElements);
|
static ArrayType *get(Type *elementType, unsigned numElements);
|
||||||
|
|
||||||
|
// Cleanup method to release all cached array types (call at program exit)
|
||||||
|
static void cleanup();
|
||||||
|
|
||||||
Type *getElementType() const { return elementType; }
|
Type *getElementType() const { return elementType; }
|
||||||
unsigned getNumElements() const { return numElements; }
|
unsigned getNumElements() const { return numElements; }
|
||||||
|
|
||||||
@@ -206,6 +220,7 @@ class Use {
|
|||||||
User* getUser() const { return user; } ///< 返回使用者
|
User* getUser() const { return user; } ///< 返回使用者
|
||||||
Value* getValue() const { return value; } ///< 返回被使用的值
|
Value* getValue() const { return value; } ///< 返回被使用的值
|
||||||
void setValue(Value *newValue) { value = newValue; } ///< 将被使用的值设置为newValue
|
void setValue(Value *newValue) { value = newValue; } ///< 将被使用的值设置为newValue
|
||||||
|
void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The base class of all value types
|
//! The base class of all value types
|
||||||
@@ -238,6 +253,7 @@ class Value {
|
|||||||
uses.remove(use);
|
uses.remove(use);
|
||||||
} ///< 删除使用关系use
|
} ///< 删除使用关系use
|
||||||
void removeAllUses();
|
void removeAllUses();
|
||||||
|
virtual void print(std::ostream& os) const = 0; ///< 输出值信息到输出流
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,6 +381,9 @@ public:
|
|||||||
// Static factory method to get a canonical ConstantValue from the pool
|
// Static factory method to get a canonical ConstantValue from the pool
|
||||||
static ConstantValue* get(Type* type, ConstantValVariant val);
|
static ConstantValue* get(Type* type, ConstantValVariant val);
|
||||||
|
|
||||||
|
// Cleanup method to release all cached constants (call at program exit)
|
||||||
|
static void cleanup();
|
||||||
|
|
||||||
// Helper methods to access constant values with appropriate casting
|
// Helper methods to access constant values with appropriate casting
|
||||||
int getInt() const {
|
int getInt() const {
|
||||||
auto val = getVal();
|
auto val = getVal();
|
||||||
@@ -402,6 +421,7 @@ public:
|
|||||||
|
|
||||||
virtual bool isZero() const = 0;
|
virtual bool isZero() const = 0;
|
||||||
virtual bool isOne() const = 0;
|
virtual bool isOne() const = 0;
|
||||||
|
void print(std::ostream& os) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConstantInteger : public ConstantValue {
|
class ConstantInteger : public ConstantValue {
|
||||||
@@ -428,6 +448,7 @@ public:
|
|||||||
|
|
||||||
bool isZero() const override { return constVal == 0; }
|
bool isZero() const override { return constVal == 0; }
|
||||||
bool isOne() const override { return constVal == 1; }
|
bool isOne() const override { return constVal == 1; }
|
||||||
|
void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConstantFloating : public ConstantValue {
|
class ConstantFloating : public ConstantValue {
|
||||||
@@ -454,6 +475,7 @@ public:
|
|||||||
|
|
||||||
bool isZero() const override { return constFVal == 0.0f; }
|
bool isZero() const override { return constFVal == 0.0f; }
|
||||||
bool isOne() const override { return constFVal == 1.0f; }
|
bool isOne() const override { return constFVal == 1.0f; }
|
||||||
|
void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UndefinedValue : public ConstantValue {
|
class UndefinedValue : public ConstantValue {
|
||||||
@@ -469,6 +491,9 @@ protected:
|
|||||||
public:
|
public:
|
||||||
static UndefinedValue* get(Type* type);
|
static UndefinedValue* get(Type* type);
|
||||||
|
|
||||||
|
// Cleanup method to release all cached undefined values (call at program exit)
|
||||||
|
static void cleanup();
|
||||||
|
|
||||||
size_t hash() const override {
|
size_t hash() const override {
|
||||||
return std::hash<Type*>{}(getType());
|
return std::hash<Type*>{}(getType());
|
||||||
}
|
}
|
||||||
@@ -485,6 +510,7 @@ public:
|
|||||||
|
|
||||||
bool isZero() const override { return false; }
|
bool isZero() const override { return false; }
|
||||||
bool isOne() const override { return false; }
|
bool isOne() const override { return false; }
|
||||||
|
void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- End of refactored ConstantValue and related classes ---
|
// --- End of refactored ConstantValue and related classes ---
|
||||||
@@ -625,6 +651,11 @@ public:
|
|||||||
}
|
}
|
||||||
} ///< 移除指定位置的指令
|
} ///< 移除指定位置的指令
|
||||||
iterator moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block);
|
iterator moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block);
|
||||||
|
|
||||||
|
/// 清理基本块中的所有使用关系
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! User is the abstract base type of `Value` types which use other `Value` as
|
//! User is the abstract base type of `Value` types which use other `Value` as
|
||||||
@@ -659,6 +690,9 @@ class User : public Value {
|
|||||||
} ///< 增加多个操作数
|
} ///< 增加多个操作数
|
||||||
void replaceOperand(unsigned index, Value *value); ///< 替换操作数
|
void replaceOperand(unsigned index, Value *value); ///< 替换操作数
|
||||||
void setOperand(unsigned index, Value *value); ///< 设置操作数
|
void setOperand(unsigned index, Value *value); ///< 设置操作数
|
||||||
|
|
||||||
|
/// 清理用户的所有操作数使用关系
|
||||||
|
void cleanup();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -736,57 +770,57 @@ public:
|
|||||||
std::string getKindString() const{
|
std::string getKindString() const{
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case kInvalid:
|
case kInvalid:
|
||||||
return "Invalid";
|
return "invalid";
|
||||||
case kAdd:
|
case kAdd:
|
||||||
return "Add";
|
return "add";
|
||||||
case kSub:
|
case kSub:
|
||||||
return "Sub";
|
return "sub";
|
||||||
case kMul:
|
case kMul:
|
||||||
return "Mul";
|
return "mul";
|
||||||
case kDiv:
|
case kDiv:
|
||||||
return "Div";
|
return "sdiv";
|
||||||
case kRem:
|
case kRem:
|
||||||
return "Rem";
|
return "srem";
|
||||||
case kICmpEQ:
|
case kICmpEQ:
|
||||||
return "ICmpEQ";
|
return "icmp eq";
|
||||||
case kICmpNE:
|
case kICmpNE:
|
||||||
return "ICmpNE";
|
return "icmp ne";
|
||||||
case kICmpLT:
|
case kICmpLT:
|
||||||
return "ICmpLT";
|
return "icmp slt";
|
||||||
case kICmpGT:
|
case kICmpGT:
|
||||||
return "ICmpGT";
|
return "icmp sgt";
|
||||||
case kICmpLE:
|
case kICmpLE:
|
||||||
return "ICmpLE";
|
return "icmp sle";
|
||||||
case kICmpGE:
|
case kICmpGE:
|
||||||
return "ICmpGE";
|
return "icmp sge";
|
||||||
case kFAdd:
|
case kFAdd:
|
||||||
return "FAdd";
|
return "fadd";
|
||||||
case kFSub:
|
case kFSub:
|
||||||
return "FSub";
|
return "fsub";
|
||||||
case kFMul:
|
case kFMul:
|
||||||
return "FMul";
|
return "fmul";
|
||||||
case kFDiv:
|
case kFDiv:
|
||||||
return "FDiv";
|
return "fdiv";
|
||||||
case kFCmpEQ:
|
case kFCmpEQ:
|
||||||
return "FCmpEQ";
|
return "fcmp oeq";
|
||||||
case kFCmpNE:
|
case kFCmpNE:
|
||||||
return "FCmpNE";
|
return "fcmp one";
|
||||||
case kFCmpLT:
|
case kFCmpLT:
|
||||||
return "FCmpLT";
|
return "fcmp olt";
|
||||||
case kFCmpGT:
|
case kFCmpGT:
|
||||||
return "FCmpGT";
|
return "fcmp ogt";
|
||||||
case kFCmpLE:
|
case kFCmpLE:
|
||||||
return "FCmpLE";
|
return "fcmp ole";
|
||||||
case kFCmpGE:
|
case kFCmpGE:
|
||||||
return "FCmpGE";
|
return "fcmp oge";
|
||||||
case kAnd:
|
case kAnd:
|
||||||
return "And";
|
return "and";
|
||||||
case kOr:
|
case kOr:
|
||||||
return "Or";
|
return "or";
|
||||||
case kNeg:
|
case kNeg:
|
||||||
return "Neg";
|
return "neg";
|
||||||
case kNot:
|
case kNot:
|
||||||
return "Not";
|
return "not";
|
||||||
case kFNeg:
|
case kFNeg:
|
||||||
return "FNeg";
|
return "FNeg";
|
||||||
case kFNot:
|
case kFNot:
|
||||||
@@ -794,33 +828,35 @@ public:
|
|||||||
case kFtoI:
|
case kFtoI:
|
||||||
return "FtoI";
|
return "FtoI";
|
||||||
case kItoF:
|
case kItoF:
|
||||||
return "IToF";
|
return "iToF";
|
||||||
case kCall:
|
case kCall:
|
||||||
return "Call";
|
return "call";
|
||||||
case kCondBr:
|
case kCondBr:
|
||||||
return "CondBr";
|
return "condBr";
|
||||||
case kBr:
|
case kBr:
|
||||||
return "Br";
|
return "br";
|
||||||
case kReturn:
|
case kReturn:
|
||||||
return "Return";
|
return "return";
|
||||||
|
case kUnreachable:
|
||||||
|
return "unreachable";
|
||||||
case kAlloca:
|
case kAlloca:
|
||||||
return "Alloca";
|
return "alloca";
|
||||||
case kLoad:
|
case kLoad:
|
||||||
return "Load";
|
return "load";
|
||||||
case kStore:
|
case kStore:
|
||||||
return "Store";
|
return "store";
|
||||||
case kGetElementPtr:
|
case kGetElementPtr:
|
||||||
return "GetElementPtr";
|
return "getElementPtr";
|
||||||
case kMemset:
|
case kMemset:
|
||||||
return "Memset";
|
return "memset";
|
||||||
case kPhi:
|
case kPhi:
|
||||||
return "Phi";
|
return "phi";
|
||||||
case kBitItoF:
|
case kBitItoF:
|
||||||
return "BitItoF";
|
return "BitItoF";
|
||||||
case kBitFtoI:
|
case kBitFtoI:
|
||||||
return "BitFtoI";
|
return "BitFtoI";
|
||||||
case kSRA:
|
case kSRA:
|
||||||
return "SRA";
|
return "ashr";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
@@ -887,6 +923,10 @@ public:
|
|||||||
static constexpr uint64_t DefineOpMask = kAlloca | kStore | kPhi;
|
static constexpr uint64_t DefineOpMask = kAlloca | kStore | kPhi;
|
||||||
return (kind & DefineOpMask) != 0U;
|
return (kind & DefineOpMask) != 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual ~Instruction() = default;
|
||||||
|
|
||||||
|
virtual void print(std::ostream& os) const = 0;
|
||||||
}; // class Instruction
|
}; // class Instruction
|
||||||
|
|
||||||
class Function;
|
class Function;
|
||||||
@@ -957,6 +997,7 @@ class PhiInst : public Instruction {
|
|||||||
}
|
}
|
||||||
} ///< 刷新块到值的映射关系
|
} ///< 刷新块到值的映射关系
|
||||||
auto getValues() { return make_range(std::next(operand_begin()), operand_end()); }
|
auto getValues() { return make_range(std::next(operand_begin()), operand_end()); }
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -965,16 +1006,14 @@ class CallInst : public Instruction {
|
|||||||
friend class IRBuilder;
|
friend class IRBuilder;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CallInst(Function *callee, const std::vector<Value *> &args = {},
|
CallInst(Function *callee, const std::vector<Value *> &args, BasicBlock *parent = nullptr, const std::string &name = "");
|
||||||
BasicBlock *parent = nullptr, const std::string &name = "");
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Function* getCallee() const;
|
Function *getCallee() const;
|
||||||
auto getArguments() const {
|
auto getArguments() const {
|
||||||
return make_range(std::next(operand_begin()), operand_end());
|
return make_range(std::next(operand_begin()), operand_end());
|
||||||
}
|
}
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
}; // class CallInst
|
}; // class CallInst
|
||||||
|
|
||||||
//! Unary instruction, includes '!', '-' and type conversion.
|
//! Unary instruction, includes '!', '-' and type conversion.
|
||||||
@@ -992,7 +1031,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Value* getOperand() const { return User::getOperand(0); }
|
Value* getOperand() const { return User::getOperand(0); }
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
}; // class UnaryInst
|
}; // class UnaryInst
|
||||||
|
|
||||||
//! Binary instruction, e.g., arithmatic, relation, logic, etc.
|
//! Binary instruction, e.g., arithmatic, relation, logic, etc.
|
||||||
@@ -1071,6 +1110,7 @@ public:
|
|||||||
// 后端处理数组访存操作时需要创建计算地址的指令,需要在外部构造 BinaryInst 对象
|
// 后端处理数组访存操作时需要创建计算地址的指令,需要在外部构造 BinaryInst 对象
|
||||||
return new BinaryInst(kind, type, lhs, rhs, parent, name);
|
return new BinaryInst(kind, type, lhs, rhs, parent, name);
|
||||||
}
|
}
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
}; // class BinaryInst
|
}; // class BinaryInst
|
||||||
|
|
||||||
//! The return statement
|
//! The return statement
|
||||||
@@ -1091,6 +1131,7 @@ class ReturnInst : public Instruction {
|
|||||||
Value* getReturnValue() const {
|
Value* getReturnValue() const {
|
||||||
return hasReturnValue() ? getOperand(0) : nullptr;
|
return hasReturnValue() ? getOperand(0) : nullptr;
|
||||||
}
|
}
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Unconditional branch
|
//! Unconditional branch
|
||||||
@@ -1120,7 +1161,7 @@ public:
|
|||||||
}
|
}
|
||||||
return succs;
|
return succs;
|
||||||
}
|
}
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
}; // class UncondBrInst
|
}; // class UncondBrInst
|
||||||
|
|
||||||
//! Conditional branch
|
//! Conditional branch
|
||||||
@@ -1160,7 +1201,7 @@ public:
|
|||||||
}
|
}
|
||||||
return succs;
|
return succs;
|
||||||
}
|
}
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
}; // class CondBrInst
|
}; // class CondBrInst
|
||||||
|
|
||||||
class UnreachableInst : public Instruction {
|
class UnreachableInst : public Instruction {
|
||||||
@@ -1168,7 +1209,7 @@ public:
|
|||||||
// 构造函数:设置指令类型为 kUnreachable
|
// 构造函数:设置指令类型为 kUnreachable
|
||||||
explicit UnreachableInst(const std::string& name, BasicBlock *parent = nullptr)
|
explicit UnreachableInst(const std::string& name, BasicBlock *parent = nullptr)
|
||||||
: Instruction(kUnreachable, Type::getVoidType(), parent, "") {}
|
: Instruction(kUnreachable, Type::getVoidType(), parent, "") {}
|
||||||
|
void print(std::ostream& os) const { os << "unreachable"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Allocate memory for stack variables, used for non-global variable declartion
|
//! Allocate memory for stack variables, used for non-global variable declartion
|
||||||
@@ -1186,7 +1227,7 @@ public:
|
|||||||
Type* getAllocatedType() const {
|
Type* getAllocatedType() const {
|
||||||
return getType()->as<PointerType>()->getBaseType();
|
return getType()->as<PointerType>()->getBaseType();
|
||||||
} ///< 获取分配的类型
|
} ///< 获取分配的类型
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
}; // class AllocaInst
|
}; // class AllocaInst
|
||||||
|
|
||||||
|
|
||||||
@@ -1224,6 +1265,7 @@ public:
|
|||||||
BasicBlock *parent = nullptr, const std::string &name = "") {
|
BasicBlock *parent = nullptr, const std::string &name = "") {
|
||||||
return new GetElementPtrInst(resultType, basePointer, indices, parent, name);
|
return new GetElementPtrInst(resultType, basePointer, indices, parent, name);
|
||||||
}
|
}
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Load a value from memory address specified by a pointer value
|
//! Load a value from memory address specified by a pointer value
|
||||||
@@ -1241,7 +1283,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Value* getPointer() const { return getOperand(0); }
|
Value* getPointer() const { return getOperand(0); }
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
}; // class LoadInst
|
}; // class LoadInst
|
||||||
|
|
||||||
//! Store a value to memory address specified by a pointer value
|
//! Store a value to memory address specified by a pointer value
|
||||||
@@ -1260,7 +1302,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
Value* getValue() const { return getOperand(0); }
|
Value* getValue() const { return getOperand(0); }
|
||||||
Value* getPointer() const { return getOperand(1); }
|
Value* getPointer() const { return getOperand(1); }
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
}; // class StoreInst
|
}; // class StoreInst
|
||||||
|
|
||||||
//! Memset instruction
|
//! Memset instruction
|
||||||
@@ -1290,7 +1332,7 @@ public:
|
|||||||
Value* getBegin() const { return getOperand(1); }
|
Value* getBegin() const { return getOperand(1); }
|
||||||
Value* getSize() const { return getOperand(2); }
|
Value* getSize() const { return getOperand(2); }
|
||||||
Value* getValue() const { return getOperand(3); }
|
Value* getValue() const { return getOperand(3); }
|
||||||
|
void print(std::ostream& os) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GlobalValue;
|
class GlobalValue;
|
||||||
@@ -1308,6 +1350,11 @@ public:
|
|||||||
public:
|
public:
|
||||||
Function* getParent() const { return func; }
|
Function* getParent() const { return func; }
|
||||||
int getIndex() const { return index; }
|
int getIndex() const { return index; }
|
||||||
|
|
||||||
|
/// 清理参数的使用关系
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -1385,6 +1432,11 @@ protected:
|
|||||||
blocks.emplace_front(block);
|
blocks.emplace_front(block);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 清理函数中的所有使用关系
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Global value declared at file scope
|
//! Global value declared at file scope
|
||||||
@@ -1450,6 +1502,7 @@ public:
|
|||||||
return getByIndex(index);
|
return getByIndex(index);
|
||||||
} ///< 通过多维索引indices获取初始值
|
} ///< 通过多维索引indices获取初始值
|
||||||
const ValueCounter& getInitValues() const { return initValues; }
|
const ValueCounter& getInitValues() const { return initValues; }
|
||||||
|
void print(std::ostream& os) const;
|
||||||
}; // class GlobalValue
|
}; // class GlobalValue
|
||||||
|
|
||||||
|
|
||||||
@@ -1507,6 +1560,8 @@ class ConstantVariable : public Value {
|
|||||||
return getByIndex(index);
|
return getByIndex(index);
|
||||||
} ///< 通过多维索引indices获取初始值
|
} ///< 通过多维索引indices获取初始值
|
||||||
const ValueCounter& getInitValues() const { return initValues; } ///< 获取初始值
|
const ValueCounter& getInitValues() const { return initValues; } ///< 获取初始值
|
||||||
|
void print(std::ostream& os) const;
|
||||||
|
void print_init(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SymbolTableNode = struct SymbolTableNode {
|
using SymbolTableNode = struct SymbolTableNode {
|
||||||
@@ -1529,6 +1584,8 @@ class SymbolTable {
|
|||||||
|
|
||||||
Value* getVariable(const std::string &name) const; ///< 根据名字name以及当前作用域获取变量
|
Value* getVariable(const std::string &name) const; ///< 根据名字name以及当前作用域获取变量
|
||||||
Value* addVariable(const std::string &name, Value *variable); ///< 添加变量
|
Value* addVariable(const std::string &name, Value *variable); ///< 添加变量
|
||||||
|
void registerParameterName(const std::string &name); ///< 注册函数参数名字,避免alloca重名
|
||||||
|
void addVariableDirectly(const std::string &name, Value *variable); ///< 直接添加变量到当前作用域,不重命名
|
||||||
std::vector<std::unique_ptr<GlobalValue>>& getGlobals(); ///< 获取全局变量列表
|
std::vector<std::unique_ptr<GlobalValue>>& getGlobals(); ///< 获取全局变量列表
|
||||||
const std::vector<std::unique_ptr<ConstantVariable>>& getConsts() const; ///< 获取全局常量列表
|
const std::vector<std::unique_ptr<ConstantVariable>>& getConsts() const; ///< 获取全局常量列表
|
||||||
void enterNewScope(); ///< 进入新的作用域
|
void enterNewScope(); ///< 进入新的作用域
|
||||||
@@ -1536,6 +1593,9 @@ class SymbolTable {
|
|||||||
bool isInGlobalScope() const; ///< 是否位于全局作用域
|
bool isInGlobalScope() const; ///< 是否位于全局作用域
|
||||||
void enterGlobalScope(); ///< 进入全局作用域
|
void enterGlobalScope(); ///< 进入全局作用域
|
||||||
bool isCurNodeNull() { return curNode == nullptr; }
|
bool isCurNodeNull() { return curNode == nullptr; }
|
||||||
|
|
||||||
|
/// 清理符号表中的所有内容
|
||||||
|
void cleanup();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! IR unit for representing a SysY compile unit
|
//! IR unit for representing a SysY compile unit
|
||||||
@@ -1588,6 +1648,12 @@ class Module {
|
|||||||
void addVariable(const std::string &name, AllocaInst *variable) {
|
void addVariable(const std::string &name, AllocaInst *variable) {
|
||||||
variableTable.addVariable(name, variable);
|
variableTable.addVariable(name, variable);
|
||||||
} ///< 添加变量
|
} ///< 添加变量
|
||||||
|
void addVariableDirectly(const std::string &name, AllocaInst *variable) {
|
||||||
|
variableTable.addVariableDirectly(name, variable);
|
||||||
|
} ///< 直接添加变量到当前作用域,不重命名
|
||||||
|
void registerParameterName(const std::string &name) {
|
||||||
|
variableTable.registerParameterName(name);
|
||||||
|
} ///< 注册函数参数名字,避免alloca重名
|
||||||
Value* getVariable(const std::string &name) {
|
Value* getVariable(const std::string &name) {
|
||||||
return variableTable.getVariable(name);
|
return variableTable.getVariable(name);
|
||||||
} ///< 根据名字name和当前作用域获取变量
|
} ///< 根据名字name和当前作用域获取变量
|
||||||
@@ -1600,7 +1666,7 @@ class Module {
|
|||||||
} ///< 获取函数
|
} ///< 获取函数
|
||||||
Function* getExternalFunction(const std::string &name) const {
|
Function* getExternalFunction(const std::string &name) const {
|
||||||
auto result = externalFunctions.find(name);
|
auto result = externalFunctions.find(name);
|
||||||
if (result == functions.end()) {
|
if (result == externalFunctions.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return result->second.get();
|
return result->second.get();
|
||||||
@@ -1620,6 +1686,11 @@ class Module {
|
|||||||
void leaveScope() { variableTable.leaveScope(); } ///< 离开作用域
|
void leaveScope() { variableTable.leaveScope(); } ///< 离开作用域
|
||||||
|
|
||||||
bool isInGlobalArea() const { return variableTable.isInGlobalScope(); } ///< 是否位于全局作用域
|
bool isInGlobalArea() const { return variableTable.isInGlobalScope(); } ///< 是否位于全局作用域
|
||||||
|
|
||||||
|
/// 清理模块中的所有对象,包括函数、基本块、指令等
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
void print(std::ostream& os) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -350,38 +350,31 @@ class IRBuilder {
|
|||||||
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
|
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
|
||||||
|
|
||||||
// 遍历所有索引来深入类型层次结构。
|
// 遍历所有索引来深入类型层次结构。
|
||||||
// `indices` 向量包含了所有 GEP 索引,包括由 `visitLValue` 等函数添加的初始 `0` 索引。
|
// 重要:第一个索引总是用于"解引用"指针,后续索引才用于数组/结构体的索引
|
||||||
for (int i = 0; i < indices.size(); ++i) {
|
for (int i = 0; i < indices.size(); ++i) {
|
||||||
if (currentWalkType->isArray()) {
|
if (i == 0) {
|
||||||
// 情况一:当前遍历类型是 `ArrayType`。
|
// 第一个索引:总是用于"解引用"基指针,不改变currentWalkType
|
||||||
// 索引用于选择数组元素,`currentWalkType` 更新为数组的元素类型。
|
// 例如:对于 `[4 x i32]* ptr, i32 0`,第一个0只是说"访问ptr指向的对象"
|
||||||
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
|
// currentWalkType 保持为 `[4 x i32]`
|
||||||
} else if (currentWalkType->isPointer()) {
|
continue;
|
||||||
// 情况二:当前遍历类型是 `PointerType`。
|
|
||||||
// 这意味着我们正在通过一个指针来访问其指向的内存。
|
|
||||||
// 索引用于选择该指针所指向的“数组”的元素。
|
|
||||||
// `currentWalkType` 更新为该指针所指向的基础类型。
|
|
||||||
// 例如:如果 `currentWalkType` 是 `i32*`,它将变为 `i32`。
|
|
||||||
// 如果 `currentWalkType` 是 `[10 x i32]*`,它将变为 `[10 x i32]`。
|
|
||||||
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
|
|
||||||
} else {
|
} else {
|
||||||
// 情况三:当前遍历类型是标量类型 (例如 `i32`, `float` 等非聚合、非指针类型)。
|
// 后续索引:用于实际的数组/结构体索引
|
||||||
//
|
if (currentWalkType->isArray()) {
|
||||||
// 如果 `currentWalkType` 是标量,并且当前索引 `i` **不是** `indices` 向量中的最后一个索引,
|
// 数组索引:选择数组中的元素
|
||||||
// 这意味着尝试对一个标量类型进行进一步的结构性索引,这是**无效的**。
|
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
|
||||||
// 例如:`int x; x[0];` 对应的 GEP 链中,`x` 的类型是 `i32`,再加 `[0]` 索引就是错误。
|
} else if (currentWalkType->isPointer()) {
|
||||||
//
|
// 指针索引:解引用指针并继续
|
||||||
// 如果 `currentWalkType` 是标量,且这是**最后一个索引** (`i == indices.size() - 1`),
|
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
|
||||||
// 那么 GEP 是合法的,它只是计算一个偏移地址,最终的类型就是这个标量类型。
|
} else {
|
||||||
// 此时 `currentWalkType` 保持不变,循环结束。
|
// 标量类型:不能进一步索引
|
||||||
if (i < indices.size() - 1) {
|
if (i < indices.size() - 1) {
|
||||||
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
|
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
|
||||||
return nullptr; // 返回空指针表示类型推断失败
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 如果是最后一个索引,且当前类型是标量,则类型保持不变,这是合法的。
|
|
||||||
// 循环会自然结束,返回正确的 `currentWalkType`。
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
|
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
|
||||||
return currentWalkType;
|
return currentWalkType;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -52,14 +52,16 @@ bool LargeArrayToGlobalPass::runOnModule(Module *M, AnalysisManager &AM) {
|
|||||||
|
|
||||||
// Calculate the size of the allocated type
|
// Calculate the size of the allocated type
|
||||||
unsigned size = calculateTypeSize(allocatedType);
|
unsigned size = calculateTypeSize(allocatedType);
|
||||||
|
if(DEBUG){
|
||||||
// Debug: print size information
|
// Debug: print size information
|
||||||
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
|
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
|
||||||
<< " for type " << typeToString(allocatedType) << std::endl;
|
<< " for type " << typeToString(allocatedType) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert arrays of 1KB (1024 bytes) or larger to global variables
|
// Convert arrays of 1KB (1024 bytes) or larger to global variables
|
||||||
if (size >= 1024) {
|
if (size >= 1024) {
|
||||||
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
|
if(DEBUG)
|
||||||
|
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
|
||||||
allocasToConvert.emplace_back(alloca, F);
|
allocasToConvert.emplace_back(alloca, F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -280,6 +280,22 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
|
|||||||
return; // 不处理不可达块中的指令的实际值
|
return; // 不处理不可达块中的指令的实际值
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(DEBUG) {
|
||||||
|
std::cout << "Processing instruction: " << inst->getName() << " in block " << inst->getParent()->getName() << std::endl;
|
||||||
|
std::cout << "Old state: ";
|
||||||
|
if (oldState.state == LatticeVal::Top) {
|
||||||
|
std::cout << "Top";
|
||||||
|
} else if (oldState.state == LatticeVal::Constant) {
|
||||||
|
if (oldState.constant_type == ValueType::Integer) {
|
||||||
|
std::cout << "Const<int>(" << std::get<int>(oldState.constantVal) << ")";
|
||||||
|
} else {
|
||||||
|
std::cout << "Const<float>(" << std::get<float>(oldState.constantVal) << ")";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "Bottom";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (inst->getKind()) {
|
switch (inst->getKind()) {
|
||||||
case Instruction::kAdd:
|
case Instruction::kAdd:
|
||||||
case Instruction::kSub:
|
case Instruction::kSub:
|
||||||
@@ -398,6 +414,7 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
|
|||||||
newState = SSAPValue(); // 保持 Top
|
newState = SSAPValue(); // 保持 Top
|
||||||
break;
|
break;
|
||||||
case Instruction::kCall:
|
case Instruction::kCall:
|
||||||
|
// TODO: 处理 Call 指令根据副作用分析可以推断的常量
|
||||||
// 大多数 Call 指令都假定为 Bottom,除非是纯函数且所有参数都是常量
|
// 大多数 Call 指令都假定为 Bottom,除非是纯函数且所有参数都是常量
|
||||||
newState = SSAPValue(LatticeVal::Bottom);
|
newState = SSAPValue(LatticeVal::Bottom);
|
||||||
break;
|
break;
|
||||||
@@ -417,19 +434,71 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
|
|||||||
}
|
}
|
||||||
case Instruction::kPhi: {
|
case Instruction::kPhi: {
|
||||||
PhiInst *phi = static_cast<PhiInst *>(inst);
|
PhiInst *phi = static_cast<PhiInst *>(inst);
|
||||||
|
if(DEBUG) {
|
||||||
|
std::cout << "Processing Phi node: " << phi->getName() << std::endl;
|
||||||
|
}
|
||||||
|
// 标准SCCP的phi节点处理:
|
||||||
|
// 只考虑可执行前驱,但要保证单调性
|
||||||
|
SSAPValue currentPhiState = GetValueState(phi);
|
||||||
SSAPValue phiResult = SSAPValue(); // 初始为 Top
|
SSAPValue phiResult = SSAPValue(); // 初始为 Top
|
||||||
|
bool hasAnyExecutablePred = false;
|
||||||
|
|
||||||
for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) {
|
for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) {
|
||||||
Value *incomingVal = phi->getIncomingValue(i);
|
|
||||||
BasicBlock *incomingBlock = phi->getIncomingBlock(i);
|
BasicBlock *incomingBlock = phi->getIncomingBlock(i);
|
||||||
|
|
||||||
if (executableBlocks.count(incomingBlock)) { // 仅考虑可执行前驱
|
if (executableBlocks.count(incomingBlock)) {
|
||||||
phiResult = Meet(phiResult, GetValueState(incomingVal));
|
hasAnyExecutablePred = true;
|
||||||
if (phiResult.state == LatticeVal::Bottom)
|
Value *incomingVal = phi->getIncomingValue(i);
|
||||||
break; // 如果已经 Bottom,则提前退出
|
SSAPValue incomingState = GetValueState(incomingVal);
|
||||||
|
if(DEBUG) {
|
||||||
|
std::cout << " Incoming from block " << incomingBlock->getName()
|
||||||
|
<< " with value " << incomingVal->getName() << " state: ";
|
||||||
|
if (incomingState.state == LatticeVal::Top)
|
||||||
|
std::cout << "Top";
|
||||||
|
else if (incomingState.state == LatticeVal::Constant) {
|
||||||
|
if (incomingState.constant_type == ValueType::Integer)
|
||||||
|
std::cout << "Const<int>(" << std::get<int>(incomingState.constantVal) << ")";
|
||||||
|
else
|
||||||
|
std::cout << "Const<float>(" << std::get<float>(incomingState.constantVal) << ")";
|
||||||
|
} else
|
||||||
|
std::cout << "Bottom";
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
phiResult = Meet(phiResult, incomingState);
|
||||||
|
|
||||||
|
if (phiResult.state == LatticeVal::Bottom) {
|
||||||
|
break; // 提前退出优化
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 不可执行前驱暂时被忽略
|
||||||
|
// 这是标准SCCP的做法,依赖于单调性保证正确性
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasAnyExecutablePred) {
|
||||||
|
// 没有可执行前驱,保持Top状态
|
||||||
|
newState = SSAPValue();
|
||||||
|
} else {
|
||||||
|
// 关键修复:使用严格的单调性
|
||||||
|
// 确保phi的值只能从Top -> Constant -> Bottom单向变化
|
||||||
|
if (currentPhiState.state == LatticeVal::Top) {
|
||||||
|
// 从Top状态,可以变为任何计算结果
|
||||||
|
newState = phiResult;
|
||||||
|
} else if (currentPhiState.state == LatticeVal::Constant) {
|
||||||
|
// 从Constant状态,只能保持相同常量或变为Bottom
|
||||||
|
if (phiResult.state == LatticeVal::Constant &&
|
||||||
|
currentPhiState.constantVal == phiResult.constantVal &&
|
||||||
|
currentPhiState.constant_type == phiResult.constant_type) {
|
||||||
|
// 保持相同的常量
|
||||||
|
newState = currentPhiState;
|
||||||
|
} else {
|
||||||
|
// 不同的值,必须变为Bottom
|
||||||
|
newState = SSAPValue(LatticeVal::Bottom);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 已经是Bottom,保持Bottom
|
||||||
|
newState = currentPhiState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newState = phiResult;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Instruction::kAlloca: // 对应 kAlloca
|
case Instruction::kAlloca: // 对应 kAlloca
|
||||||
@@ -486,6 +555,22 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "New state: ";
|
||||||
|
if (newState.state == LatticeVal::Top) {
|
||||||
|
std::cout << "Top";
|
||||||
|
} else if (newState.state == LatticeVal::Constant) {
|
||||||
|
if (newState.constant_type == ValueType::Integer) {
|
||||||
|
std::cout << "Const<int>(" << std::get<int>(newState.constantVal) << ")";
|
||||||
|
} else {
|
||||||
|
std::cout << "Const<float>(" << std::get<float>(newState.constantVal) << ")";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "Bottom";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 辅助函数:处理单条控制流边
|
// 辅助函数:处理单条控制流边
|
||||||
@@ -493,14 +578,22 @@ void SCCPContext::ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge)
|
|||||||
BasicBlock *fromBB = edge.first;
|
BasicBlock *fromBB = edge.first;
|
||||||
BasicBlock *toBB = edge.second;
|
BasicBlock *toBB = edge.second;
|
||||||
|
|
||||||
|
// 检查目标块是否已经可执行
|
||||||
|
bool wasAlreadyExecutable = executableBlocks.count(toBB) > 0;
|
||||||
|
|
||||||
|
// 标记目标块为可执行(如果还不是的话)
|
||||||
MarkBlockExecutable(toBB);
|
MarkBlockExecutable(toBB);
|
||||||
|
|
||||||
// 对于目标块中的所有 Phi 指令,重新评估其值,因为可能有新的前驱被激活
|
// 如果目标块之前就已经可执行,那么需要重新处理其中的phi节点
|
||||||
for (auto &inst_ptr : toBB->getInstructions()) {
|
// 因为现在有新的前驱变为可执行,phi节点的值可能需要更新
|
||||||
if (dynamic_cast<PhiInst *>(inst_ptr.get())) {
|
if (wasAlreadyExecutable) {
|
||||||
instWorkList.push(inst_ptr.get());
|
for (auto &inst_ptr : toBB->getInstructions()) {
|
||||||
|
if (dynamic_cast<PhiInst *>(inst_ptr.get())) {
|
||||||
|
instWorkList.push(inst_ptr.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 如果目标块是新变为可执行的,MarkBlockExecutable已经添加了所有指令
|
||||||
}
|
}
|
||||||
|
|
||||||
// 阶段1: 常量传播与折叠
|
// 阶段1: 常量传播与折叠
|
||||||
@@ -515,18 +608,29 @@ bool SCCPContext::PropagateConstants(Function *func) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化函数参数为Bottom(因为它们在编译时是未知的)
|
||||||
|
for (auto arg : func->getArguments()) {
|
||||||
|
valueState[arg] = SSAPValue(LatticeVal::Bottom);
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "Initializing function argument " << arg->getName() << " to Bottom" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 标记入口块为可执行
|
// 标记入口块为可执行
|
||||||
if (!func->getBasicBlocks().empty()) {
|
if (!func->getBasicBlocks().empty()) {
|
||||||
MarkBlockExecutable(func->getEntryBlock());
|
MarkBlockExecutable(func->getEntryBlock());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主循环:处理工作列表直到不动点
|
// 主循环:标准的SCCP工作列表算法
|
||||||
|
// 交替处理边工作列表和指令工作列表直到不动点
|
||||||
while (!instWorkList.empty() || !edgeWorkList.empty()) {
|
while (!instWorkList.empty() || !edgeWorkList.empty()) {
|
||||||
|
// 处理所有待处理的CFG边
|
||||||
while (!edgeWorkList.empty()) {
|
while (!edgeWorkList.empty()) {
|
||||||
ProcessEdge(edgeWorkList.front());
|
ProcessEdge(edgeWorkList.front());
|
||||||
edgeWorkList.pop();
|
edgeWorkList.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理所有待处理的指令
|
||||||
while (!instWorkList.empty()) {
|
while (!instWorkList.empty()) {
|
||||||
Instruction *inst = instWorkList.front();
|
Instruction *inst = instWorkList.front();
|
||||||
instWorkList.pop();
|
instWorkList.pop();
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
|
|||||||
++Branchiter;
|
++Branchiter;
|
||||||
while (Branchiter != instructions.end()) {
|
while (Branchiter != instructions.end()) {
|
||||||
changed = true;
|
changed = true;
|
||||||
Branchiter = instructions.erase(Branchiter);
|
Branchiter = SysYIROptUtils::usedelete(Branchiter); // 删除指令
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Branch) { // 更新前驱后继关系
|
if (Branch) { // 更新前驱后继关系
|
||||||
@@ -77,6 +77,11 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
|||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
for (auto blockiter = func->getBasicBlocks().begin(); blockiter != func->getBasicBlocks().end();) {
|
for (auto blockiter = func->getBasicBlocks().begin(); blockiter != func->getBasicBlocks().end();) {
|
||||||
|
// 检查当前块是是不是entry块
|
||||||
|
if( blockiter->get() == func->getEntryBlock() ) {
|
||||||
|
blockiter++;
|
||||||
|
continue; // 跳过入口块
|
||||||
|
}
|
||||||
if (blockiter->get()->getNumSuccessors() == 1) {
|
if (blockiter->get()->getNumSuccessors() == 1) {
|
||||||
// 如果当前块只有一个后继块
|
// 如果当前块只有一个后继块
|
||||||
// 且后继块只有一个前驱块
|
// 且后继块只有一个前驱块
|
||||||
@@ -86,7 +91,7 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
|||||||
BasicBlock *block = blockiter->get();
|
BasicBlock *block = blockiter->get();
|
||||||
BasicBlock *nextBlock = blockiter->get()->getSuccessors()[0];
|
BasicBlock *nextBlock = blockiter->get()->getSuccessors()[0];
|
||||||
// auto nextarguments = nextBlock->getArguments();
|
// auto nextarguments = nextBlock->getArguments();
|
||||||
// 删除br指令
|
// 删除block的br指令
|
||||||
if (block->getNumInstructions() != 0) {
|
if (block->getNumInstructions() != 0) {
|
||||||
auto thelastinstinst = block->terminator();
|
auto thelastinstinst = block->terminator();
|
||||||
if (thelastinstinst->get()->isUnconditional()) {
|
if (thelastinstinst->get()->isUnconditional()) {
|
||||||
@@ -98,14 +103,21 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
|||||||
if (brinst->getThenBlock() == brinst->getElseBlock()) {
|
if (brinst->getThenBlock() == brinst->getElseBlock()) {
|
||||||
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
|
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
assert(false && "SysYBlockMerge: unexpected conditional branch with different then and else blocks");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 将后继块的指令移动到当前块
|
// 将后继块的指令移动到当前块
|
||||||
// 并将后继块的父指针改为当前块
|
// 并将后继块的父指针改为当前块
|
||||||
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
||||||
institer->get()->setParent(block);
|
// institer->get()->setParent(block);
|
||||||
block->getInstructions().emplace_back(institer->release());
|
// block->getInstructions().emplace_back(institer->release());
|
||||||
institer = nextBlock->getInstructions().erase(institer);
|
// 用usedelete删除会导致use关系被删除我只希望移动指令到当前块
|
||||||
|
// institer = SysYIROptUtils::usedelete(institer);
|
||||||
|
// institer = nextBlock->getInstructions().erase(institer);
|
||||||
|
institer = nextBlock->moveInst(institer, block->getInstructions().end(), block);
|
||||||
|
|
||||||
}
|
}
|
||||||
// 更新前驱后继关系,类似树节点操作
|
// 更新前驱后继关系,类似树节点操作
|
||||||
block->removeSuccessor(nextBlock);
|
block->removeSuccessor(nextBlock);
|
||||||
@@ -288,13 +300,12 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder *pBuilder) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val,
|
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val, BasicBlock *currentDefBlock) -> Value * {
|
||||||
BasicBlock *currentDefBlock) -> Value * {
|
|
||||||
// 如果值不是指令,例如常量或函数参数,则它本身就是最终来源
|
if(!dynamic_cast<Instruction *>(val)) {
|
||||||
if (auto instr = dynamic_cast<Instruction *>(val)) { // Assuming Value* has a method to check if it's an instruction
|
// 如果 val 不是指令,直接返回它
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction *inst = dynamic_cast<Instruction *>(val);
|
Instruction *inst = dynamic_cast<Instruction *>(val);
|
||||||
// 如果定义指令不在任何空块中,它就是最终来源
|
// 如果定义指令不在任何空块中,它就是最终来源
|
||||||
if (!emptyBlockRedirectMap.count(currentDefBlock)) {
|
if (!emptyBlockRedirectMap.count(currentDefBlock)) {
|
||||||
|
|||||||
@@ -389,26 +389,7 @@ void SysYIRGenerator::compute() {
|
|||||||
case BinaryOp::ADD: resultValue = builder.createAddInst(lhs, rhs); break;
|
case BinaryOp::ADD: resultValue = builder.createAddInst(lhs, rhs); break;
|
||||||
case BinaryOp::SUB: resultValue = builder.createSubInst(lhs, rhs); break;
|
case BinaryOp::SUB: resultValue = builder.createSubInst(lhs, rhs); break;
|
||||||
case BinaryOp::MUL: resultValue = builder.createMulInst(lhs, rhs); break;
|
case BinaryOp::MUL: resultValue = builder.createMulInst(lhs, rhs); break;
|
||||||
case BinaryOp::DIV: {
|
case BinaryOp::DIV: resultValue = builder.createDivInst(lhs, rhs); break;
|
||||||
ConstantInteger *rhsConst = dynamic_cast<ConstantInteger *>(rhs);
|
|
||||||
if (rhsConst) {
|
|
||||||
int divisor = rhsConst->getInt();
|
|
||||||
if (divisor > 0 && (divisor & (divisor - 1)) == 0) {
|
|
||||||
int shift = 0;
|
|
||||||
int temp = divisor;
|
|
||||||
while (temp > 1) {
|
|
||||||
temp >>= 1;
|
|
||||||
shift++;
|
|
||||||
}
|
|
||||||
resultValue = builder.createSRAInst(lhs, ConstantInteger::get(shift));
|
|
||||||
} else {
|
|
||||||
resultValue = builder.createDivInst(lhs, rhs);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
resultValue = builder.createDivInst(lhs, rhs);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinaryOp::MOD: resultValue = builder.createRemInst(lhs, rhs); break;
|
case BinaryOp::MOD: resultValue = builder.createRemInst(lhs, rhs); break;
|
||||||
}
|
}
|
||||||
} else if (commonType == Type::getFloatType()) {
|
} else if (commonType == Type::getFloatType()) {
|
||||||
@@ -1210,15 +1191,25 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
|
|||||||
for(int i = 0; i < paramActualTypes.size(); ++i) {
|
for(int i = 0; i < paramActualTypes.size(); ++i) {
|
||||||
Argument* arg = new Argument(paramActualTypes[i], function, i, paramNames[i]);
|
Argument* arg = new Argument(paramActualTypes[i], function, i, paramNames[i]);
|
||||||
function->insertArgument(arg);
|
function->insertArgument(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先将所有参数名字注册到符号表中,确保alloca不会使用相同的名字
|
||||||
|
for (int i = 0; i < paramNames.size(); ++i) {
|
||||||
|
// 预先注册参数名字,这样addVariable就会使用不同的后缀
|
||||||
|
module->registerParameterName(paramNames[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto funcArgs = function->getArguments();
|
auto funcArgs = function->getArguments();
|
||||||
std::vector<AllocaInst *> allocas;
|
std::vector<AllocaInst *> allocas;
|
||||||
for (int i = 0; i < paramActualTypes.size(); ++i) {
|
for (int i = 0; i < paramActualTypes.size(); ++i) {
|
||||||
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(paramActualTypes[i]), paramNames[i]);
|
// 使用函数特定的前缀来确保参数alloca名字唯一
|
||||||
|
std::string allocaName = name + "_param_" + paramNames[i];
|
||||||
|
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(paramActualTypes[i]), allocaName);
|
||||||
|
// 直接设置唯一名字,不依赖addVariable的命名逻辑
|
||||||
|
alloca->setName(allocaName);
|
||||||
allocas.push_back(alloca);
|
allocas.push_back(alloca);
|
||||||
module->addVariable(paramNames[i], alloca);
|
// 直接添加到符号表,使用原参数名作为查找键
|
||||||
|
module->addVariableDirectly(paramNames[i], alloca);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < paramActualTypes.size(); ++i) {
|
for(int i = 0; i < paramActualTypes.size(); ++i) {
|
||||||
@@ -1287,6 +1278,45 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
|
|||||||
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable)) {
|
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable)) {
|
||||||
LValue = variable;
|
LValue = variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 标量变量的类型推断
|
||||||
|
Type* LType = builder.getIndexedType(variable->getType(), indices);
|
||||||
|
|
||||||
|
Value* RValue = computeExp(ctx->exp(), LType); // 右值计算
|
||||||
|
Type* RType = RValue->getType();
|
||||||
|
|
||||||
|
// TODO:computeExp处理了类型转换,可以考虑删除判断逻辑
|
||||||
|
if (LType != RType) {
|
||||||
|
ConstantValue *constValue = dynamic_cast<ConstantValue *>(RValue);
|
||||||
|
if (constValue != nullptr) {
|
||||||
|
if (LType == Type::getFloatType()) {
|
||||||
|
if(dynamic_cast<ConstantInteger *>(constValue)) {
|
||||||
|
// 如果是整型常量,转换为浮点型
|
||||||
|
RValue = ConstantFloating::get(static_cast<float>(constValue->getInt()));
|
||||||
|
} else if (dynamic_cast<ConstantFloating *>(constValue)) {
|
||||||
|
// 如果是浮点型常量,直接使用
|
||||||
|
RValue = ConstantFloating::get(static_cast<float>(constValue->getFloat()));
|
||||||
|
}
|
||||||
|
} else { // 假设如果不是浮点型,就是整型
|
||||||
|
if(dynamic_cast<ConstantFloating *>(constValue)) {
|
||||||
|
// 如果是浮点型常量,转换为整型
|
||||||
|
RValue = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
|
||||||
|
} else if (dynamic_cast<ConstantInteger *>(constValue)) {
|
||||||
|
// 如果是整型常量,直接使用
|
||||||
|
RValue = ConstantInteger::get(static_cast<int>(constValue->getInt()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (LType == Type::getFloatType() && RType != Type::getFloatType()) {
|
||||||
|
RValue = builder.createItoFInst(RValue);
|
||||||
|
} else if (LType != Type::getFloatType() && RType == Type::getFloatType()) {
|
||||||
|
RValue = builder.createFtoIInst(RValue);
|
||||||
|
}
|
||||||
|
// 如果两者都是同一类型,就不需要转换
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.createStoreInst(RValue, LValue);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 对于数组或多维数组的左值处理
|
// 对于数组或多维数组的左值处理
|
||||||
@@ -1324,51 +1354,47 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
|
|||||||
}
|
}
|
||||||
// 左值为地址
|
// 左值为地址
|
||||||
LValue = getGEPAddressInst(gepBasePointer, gepIndices);
|
LValue = getGEPAddressInst(gepBasePointer, gepIndices);
|
||||||
}
|
|
||||||
|
|
||||||
// Value* RValue = std::any_cast<Value *>(visitExp(ctx->exp())); // 右值
|
// 数组变量的类型推断,使用gepIndices和gepBasePointer的类型
|
||||||
|
Type* LType = builder.getIndexedType(gepBasePointer->getType(), gepIndices);
|
||||||
|
|
||||||
// 先推断 LValue 的类型
|
Value* RValue = computeExp(ctx->exp(), LType); // 右值计算
|
||||||
// 如果 LValue 是指向数组的指针,则需要根据 indices 获取正确的类型
|
Type* RType = RValue->getType();
|
||||||
// 如果 LValue 是标量,则直接使用其类型
|
|
||||||
// 注意:LValue 的类型可能是指向数组的指针 (e.g., int(*)[3]) 或者指向标量的指针 (e.g., int*) 也能推断
|
|
||||||
Type* LType = builder.getIndexedType(variable->getType(), indices);
|
|
||||||
|
|
||||||
Value* RValue = computeExp(ctx->exp(), LType); // 右值计算
|
// TODO:computeExp处理了类型转换,可以考虑删除判断逻辑
|
||||||
Type* RType = RValue->getType();
|
if (LType != RType) {
|
||||||
|
ConstantValue *constValue = dynamic_cast<ConstantValue *>(RValue);
|
||||||
// TODO:computeExp处理了类型转换,可以考虑删除判断逻辑
|
if (constValue != nullptr) {
|
||||||
if (LType != RType) {
|
if (LType == Type::getFloatType()) {
|
||||||
ConstantValue *constValue = dynamic_cast<ConstantValue *>(RValue);
|
if(dynamic_cast<ConstantInteger *>(constValue)) {
|
||||||
if (constValue != nullptr) {
|
// 如果是整型常量,转换为浮点型
|
||||||
if (LType == Type::getFloatType()) {
|
RValue = ConstantFloating::get(static_cast<float>(constValue->getInt()));
|
||||||
if(dynamic_cast<ConstantInteger *>(constValue)) {
|
} else if (dynamic_cast<ConstantFloating *>(constValue)) {
|
||||||
// 如果是整型常量,转换为浮点型
|
// 如果是浮点型常量,直接使用
|
||||||
RValue = ConstantFloating::get(static_cast<float>(constValue->getInt()));
|
RValue = ConstantFloating::get(static_cast<float>(constValue->getFloat()));
|
||||||
} else if (dynamic_cast<ConstantFloating *>(constValue)) {
|
}
|
||||||
// 如果是浮点型常量,直接使用
|
} else { // 假设如果不是浮点型,就是整型
|
||||||
RValue = ConstantFloating::get(static_cast<float>(constValue->getFloat()));
|
if(dynamic_cast<ConstantFloating *>(constValue)) {
|
||||||
|
// 如果是浮点型常量,转换为整型
|
||||||
|
RValue = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
|
||||||
|
} else if (dynamic_cast<ConstantInteger *>(constValue)) {
|
||||||
|
// 如果是整型常量,直接使用
|
||||||
|
RValue = ConstantInteger::get(static_cast<int>(constValue->getInt()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else { // 假设如果不是浮点型,就是整型
|
} else {
|
||||||
if(dynamic_cast<ConstantFloating *>(constValue)) {
|
if (LType == Type::getFloatType() && RType != Type::getFloatType()) {
|
||||||
// 如果是浮点型常量,转换为整型
|
RValue = builder.createItoFInst(RValue);
|
||||||
RValue = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
|
} else if (LType != Type::getFloatType() && RType == Type::getFloatType()) {
|
||||||
} else if (dynamic_cast<ConstantInteger *>(constValue)) {
|
RValue = builder.createFtoIInst(RValue);
|
||||||
// 如果是整型常量,直接使用
|
|
||||||
RValue = ConstantInteger::get(static_cast<int>(constValue->getInt()));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
// 如果两者都是同一类型,就不需要转换
|
||||||
} else {
|
|
||||||
if (LType == Type::getFloatType()) {
|
|
||||||
RValue = builder.createItoFInst(RValue);
|
|
||||||
} else { // 假设如果不是浮点型,就是整型
|
|
||||||
RValue = builder.createFtoIInst(RValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.createStoreInst(RValue, LValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.createStoreInst(RValue, LValue);
|
|
||||||
invalidateExpressionsOnStore(LValue);
|
invalidateExpressionsOnStore(LValue);
|
||||||
return std::any();
|
return std::any();
|
||||||
}
|
}
|
||||||
@@ -1535,7 +1561,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.createUncondBrInst(headBlock);
|
builder.createUncondBrInst(headBlock);
|
||||||
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
|
BasicBlock::conectBlocks(builder.getBasicBlock(), headBlock);
|
||||||
builder.popBreakBlock();
|
builder.popBreakBlock();
|
||||||
builder.popContinueBlock();
|
builder.popContinueBlock();
|
||||||
|
|
||||||
@@ -1652,11 +1678,19 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (allIndicesConstant) {
|
// 如果是常量变量且所有索引都是常量,并且不是数组名单独出现的情况
|
||||||
|
if (allIndicesConstant && !dims.empty()) {
|
||||||
// 如果是常量变量且所有索引都是常量,直接通过 getByIndices 获取编译时值
|
// 如果是常量变量且所有索引都是常量,直接通过 getByIndices 获取编译时值
|
||||||
// 这个方法会根据索引深度返回最终的标量值或指向子数组的指针 (作为 ConstantValue/Variable)
|
// 这个方法会根据索引深度返回最终的标量值或指向子数组的指针 (作为 ConstantValue/Variable)
|
||||||
return constVar->getByIndices(dims);
|
return constVar->getByIndices(dims);
|
||||||
}
|
}
|
||||||
|
// 如果dims为空,检查是否是常量标量
|
||||||
|
if (dims.empty() && declaredNumDims == 0) {
|
||||||
|
// 常量标量,直接返回其值
|
||||||
|
// 默认传入空索引列表,表示访问标量本身
|
||||||
|
return constVar->getByIndices(dims);
|
||||||
|
}
|
||||||
|
// 如果dims为空但不是标量(数组名单独出现),需要走GEP路径来实现数组到指针的退化
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 处理可变变量 (AllocaInst/GlobalValue) 或带非常量索引的常量变量
|
// 3. 处理可变变量 (AllocaInst/GlobalValue) 或带非常量索引的常量变量
|
||||||
@@ -1666,7 +1700,8 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
|
|||||||
if (dims.empty() && declaredNumDims == 0) {
|
if (dims.empty() && declaredNumDims == 0) {
|
||||||
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable)) {
|
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable)) {
|
||||||
targetAddress = variable;
|
targetAddress = variable;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
assert(false && "Unhandled scalar variable type in LValue access.");
|
assert(false && "Unhandled scalar variable type in LValue access.");
|
||||||
return static_cast<Value*>(nullptr);
|
return static_cast<Value*>(nullptr);
|
||||||
}
|
}
|
||||||
@@ -1681,16 +1716,39 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
|
|||||||
} else {
|
} else {
|
||||||
gepBasePointer = alloc;
|
gepBasePointer = alloc;
|
||||||
gepIndices.push_back(ConstantInteger::get(0));
|
gepIndices.push_back(ConstantInteger::get(0));
|
||||||
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
if (dims.empty() && declaredNumDims > 0) {
|
||||||
|
// 数组名单独出现(没有索引):在SysY中,多维数组名应该退化为指向第一行的指针
|
||||||
|
// 对于二维数组 T[M][N],退化为 T(*)[N],需要GEP: getelementptr T[M][N], T[M][N]* ptr, i32 0, i32 0
|
||||||
|
// 第一个i32 0: 选择数组本身,第二个i32 0: 选择第0行
|
||||||
|
// 结果类型: T[N]*
|
||||||
|
gepIndices.push_back(ConstantInteger::get(0));
|
||||||
|
} else {
|
||||||
|
// 正常的数组元素访问
|
||||||
|
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (GlobalValue *glob = dynamic_cast<GlobalValue *>(variable)) {
|
} else if (GlobalValue *glob = dynamic_cast<GlobalValue *>(variable)) {
|
||||||
gepBasePointer = glob;
|
gepBasePointer = glob;
|
||||||
gepIndices.push_back(ConstantInteger::get(0));
|
gepIndices.push_back(ConstantInteger::get(0));
|
||||||
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
if (dims.empty() && declaredNumDims > 0) {
|
||||||
|
// 全局数组名单独出现(没有索引):应该退化为指向第一行的指针
|
||||||
|
// 需要添加一个额外的i32 0索引
|
||||||
|
gepIndices.push_back(ConstantInteger::get(0));
|
||||||
|
} else {
|
||||||
|
// 正常的数组元素访问
|
||||||
|
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
||||||
|
}
|
||||||
} else if (ConstantVariable *constV = dynamic_cast<ConstantVariable *>(variable)) {
|
} else if (ConstantVariable *constV = dynamic_cast<ConstantVariable *>(variable)) {
|
||||||
gepBasePointer = constV;
|
gepBasePointer = constV;
|
||||||
gepIndices.push_back(ConstantInteger::get(0));
|
gepIndices.push_back(ConstantInteger::get(0));
|
||||||
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
if (dims.empty() && declaredNumDims > 0) {
|
||||||
|
// 常量数组名单独出现(没有索引):应该退化为指向第一行的指针
|
||||||
|
// 需要添加一个额外的i32 0索引
|
||||||
|
gepIndices.push_back(ConstantInteger::get(0));
|
||||||
|
} else {
|
||||||
|
// 正常的数组元素访问
|
||||||
|
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(false && "LValue variable type not supported for GEP base pointer.");
|
assert(false && "LValue variable type not supported for GEP base pointer.");
|
||||||
return static_cast<Value *>(nullptr);
|
return static_cast<Value *>(nullptr);
|
||||||
@@ -1772,10 +1830,10 @@ std::any SysYIRGenerator::visitCall(SysYParser::CallContext *ctx) {
|
|||||||
|
|
||||||
// 获取形参列表。`getArguments()` 返回的是 `Argument*` 的集合,
|
// 获取形参列表。`getArguments()` 返回的是 `Argument*` 的集合,
|
||||||
// 每个 `Argument` 代表一个函数形参,其 `getType()` 就是指向形参的类型的指针类型。
|
// 每个 `Argument` 代表一个函数形参,其 `getType()` 就是指向形参的类型的指针类型。
|
||||||
auto formalParams = function->getArguments();
|
const auto& formalParams = function->getArguments();
|
||||||
|
|
||||||
// 检查实参和形参数量是否匹配。
|
// 检查实参和形参数量是否匹配。
|
||||||
if (args.size() != formalParams.size()) {
|
if (args.size() != function->getNumArguments()) {
|
||||||
std::cerr << "Error: Function call argument count mismatch for function '" << funcName << "'." << std::endl;
|
std::cerr << "Error: Function call argument count mismatch for function '" << funcName << "'." << std::endl;
|
||||||
assert(false && "Function call argument count mismatch!");
|
assert(false && "Function call argument count mismatch!");
|
||||||
}
|
}
|
||||||
@@ -1807,15 +1865,27 @@ std::any SysYIRGenerator::visitCall(SysYParser::CallContext *ctx) {
|
|||||||
} else if (formalParamExpectedValueType->isFloat() && actualArgType->isInt()) {
|
} else if (formalParamExpectedValueType->isFloat() && actualArgType->isInt()) {
|
||||||
args[i] = builder.createItoFInst(args[i]);
|
args[i] = builder.createItoFInst(args[i]);
|
||||||
}
|
}
|
||||||
// 2. 指针类型转换 (例如数组退化:`[N x T]*` 到 `T*`,或兼容指针类型之间) TODO:不清楚有没有这种样例
|
// 2. 指针类型转换 (例如数组退化:`[N x T]*` 到 `T*`,或兼容指针类型之间)
|
||||||
// 这种情况常见于数组参数,实参可能是一个更具体的数组指针类型,
|
// 这种情况常见于数组参数,实参可能是一个更具体的数组指针类型,
|
||||||
// 而形参是其退化后的基础指针类型。LLVM 的 `bitcast` 指令可以用于
|
// 而形参是其退化后的基础指针类型。
|
||||||
// 在相同大小的指针类型之间进行转换,这对于数组退化至关重要。
|
else if (formalParamExpectedValueType->isPointer() && actualArgType->isPointer()) {
|
||||||
// else if (formalParamType->isPointer() && actualArgType->isPointer()) {
|
// 检查是否是数组指针到元素指针的decay
|
||||||
// 检查指针基类型是否兼容,或者是否是数组退化导致的类型不同。
|
// 例如:[N x T]* -> T*
|
||||||
// 使用 bitcast,
|
auto formalPtrType = formalParamExpectedValueType->as<PointerType>();
|
||||||
// args[i] = builder.createBitCastInst(args[i], formalParamType);
|
auto actualPtrType = actualArgType->as<PointerType>();
|
||||||
// }
|
|
||||||
|
if (formalPtrType && actualPtrType && actualPtrType->getBaseType()->isArray()) {
|
||||||
|
auto actualArrayType = actualPtrType->getBaseType()->as<ArrayType>();
|
||||||
|
if (actualArrayType &&
|
||||||
|
formalPtrType->getBaseType() == actualArrayType->getElementType()) {
|
||||||
|
// 这是数组decay的情况,添加GEP来获取数组的第一个元素
|
||||||
|
std::vector<Value*> indices;
|
||||||
|
indices.push_back(ConstantInteger::get(0)); // 第一个索引:解引用指针
|
||||||
|
indices.push_back(ConstantInteger::get(0)); // 第二个索引:获取数组第一个元素
|
||||||
|
args[i] = getGEPAddressInst(args[i], indices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// 3. 其他未预期的类型不匹配
|
// 3. 其他未预期的类型不匹配
|
||||||
// 如果代码执行到这里,说明存在编译器前端未处理的类型不兼容或错误。
|
// 如果代码执行到这里,说明存在编译器前端未处理的类型不兼容或错误。
|
||||||
else {
|
else {
|
||||||
@@ -2199,15 +2269,23 @@ void Utils::createExternalFunction(
|
|||||||
const std::vector<std::string> ¶mNames,
|
const std::vector<std::string> ¶mNames,
|
||||||
const std::vector<std::vector<Value *>> ¶mDims, Type *returnType,
|
const std::vector<std::vector<Value *>> ¶mDims, Type *returnType,
|
||||||
const std::string &funcName, Module *pModule, IRBuilder *pBuilder) {
|
const std::string &funcName, Module *pModule, IRBuilder *pBuilder) {
|
||||||
auto funcType = Type::getFunctionType(returnType, paramTypes);
|
// 根据paramDims调整参数类型,数组参数需要转换为指针类型
|
||||||
|
std::vector<Type *> adjustedParamTypes = paramTypes;
|
||||||
|
for (int i = 0; i < paramTypes.size() && i < paramDims.size(); ++i) {
|
||||||
|
if (!paramDims[i].empty()) {
|
||||||
|
// 如果参数有维度信息,说明是数组参数,转换为指针类型
|
||||||
|
adjustedParamTypes[i] = Type::getPointerType(paramTypes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto funcType = Type::getFunctionType(returnType, adjustedParamTypes);
|
||||||
auto function = pModule->createExternalFunction(funcName, funcType);
|
auto function = pModule->createExternalFunction(funcName, funcType);
|
||||||
auto entry = function->getEntryBlock();
|
auto entry = function->getEntryBlock();
|
||||||
pBuilder->setPosition(entry, entry->end());
|
pBuilder->setPosition(entry, entry->end());
|
||||||
|
|
||||||
for (int i = 0; i < paramTypes.size(); ++i) {
|
for (int i = 0; i < paramTypes.size(); ++i) {
|
||||||
auto arg = new Argument(paramTypes[i], function, i, paramNames[i]);
|
auto arg = new Argument(adjustedParamTypes[i], function, i, paramNames[i]);
|
||||||
auto alloca = pBuilder->createAllocaInst(
|
auto alloca = pBuilder->createAllocaInst(
|
||||||
Type::getPointerType(paramTypes[i]), paramNames[i]);
|
Type::getPointerType(adjustedParamTypes[i]), paramNames[i]);
|
||||||
function->insertArgument(arg);
|
function->insertArgument(arg);
|
||||||
auto store = pBuilder->createStoreInst(arg, alloca);
|
auto store = pBuilder->createStoreInst(arg, alloca);
|
||||||
pModule->addVariable(paramNames[i], alloca);
|
pModule->addVariable(paramNames[i], alloca);
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ int main(int argc, char **argv) {
|
|||||||
// 如果指定停止在 AST 阶段,则打印并退出
|
// 如果指定停止在 AST 阶段,则打印并退出
|
||||||
if (argStopAfter == "ast") {
|
if (argStopAfter == "ast") {
|
||||||
cout << moduleAST->toStringTree(true) << '\n';
|
cout << moduleAST->toStringTree(true) << '\n';
|
||||||
|
sysy::cleanupIRPools(); // 清理内存池
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +133,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
cout << "=== Init IR ===\n";
|
cout << "=== Init IR ===\n";
|
||||||
SysYPrinter(moduleIR).printIR(); // 临时打印器用于调试
|
moduleIR->print(cout); // 使用新实现的print方法直接打印IR
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 Pass 管理器并运行优化管道
|
// 创建 Pass 管理器并运行优化管道
|
||||||
@@ -144,10 +145,26 @@ int main(int argc, char **argv) {
|
|||||||
// a) 如果指定停止在 IR 阶段,则打印最终 IR 并退出
|
// a) 如果指定停止在 IR 阶段,则打印最终 IR 并退出
|
||||||
if (argStopAfter == "ir" || argStopAfter == "ird") {
|
if (argStopAfter == "ir" || argStopAfter == "ird") {
|
||||||
// 打印最终 IR
|
// 打印最终 IR
|
||||||
cout << "=== Final IR ===\n";
|
if (DEBUG) cerr << "=== Final IR ===\n";
|
||||||
SysYPrinter printer(moduleIR); // 在这里创建打印器,因为可能之前调试时用过临时打印器
|
if (!argOutputFilename.empty()) {
|
||||||
printer.printIR();
|
// 输出到指定文件
|
||||||
|
ofstream fout(argOutputFilename);
|
||||||
|
if (not fout.is_open()) {
|
||||||
|
cerr << "Failed to open output file: " << argOutputFilename << endl;
|
||||||
|
moduleIR->cleanup(); // 清理模块
|
||||||
|
sysy::cleanupIRPools(); // 清理内存池
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
moduleIR->print(fout);
|
||||||
|
fout.close();
|
||||||
|
} else {
|
||||||
|
// 输出到标准输出
|
||||||
|
moduleIR->print(cout);
|
||||||
|
}
|
||||||
|
moduleIR->cleanup(); // 清理模块
|
||||||
|
sysy::cleanupIRPools(); // 清理内存池
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// b) 如果未停止在 IR 阶段,则继续生成汇编 (后端)
|
// b) 如果未停止在 IR 阶段,则继续生成汇编 (后端)
|
||||||
@@ -166,6 +183,8 @@ int main(int argc, char **argv) {
|
|||||||
ofstream fout(argOutputFilename);
|
ofstream fout(argOutputFilename);
|
||||||
if (not fout.is_open()) {
|
if (not fout.is_open()) {
|
||||||
cerr << "Failed to open output file: " << argOutputFilename << endl;
|
cerr << "Failed to open output file: " << argOutputFilename << endl;
|
||||||
|
moduleIR->cleanup(); // 清理模块
|
||||||
|
sysy::cleanupIRPools(); // 清理内存池
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
fout << asmCode << endl;
|
fout << asmCode << endl;
|
||||||
@@ -173,6 +192,8 @@ int main(int argc, char **argv) {
|
|||||||
} else {
|
} else {
|
||||||
cout << asmCode << endl;
|
cout << asmCode << endl;
|
||||||
}
|
}
|
||||||
|
moduleIR->cleanup(); // 清理模块
|
||||||
|
sysy::cleanupIRPools(); // 清理内存池
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,5 +202,7 @@ int main(int argc, char **argv) {
|
|||||||
cout << "Compilation completed. No output specified (neither -s nor -S). Exiting.\n";
|
cout << "Compilation completed. No output specified (neither -s nor -S). Exiting.\n";
|
||||||
// return EXIT_SUCCESS; // 或者这里调用一个链接器生成可执行文件
|
// return EXIT_SUCCESS; // 或者这里调用一个链接器生成可执行文件
|
||||||
|
|
||||||
|
moduleIR->cleanup(); // 清理模块
|
||||||
|
sysy::cleanupIRPools(); // 清理内存池
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
1
testdata/functional/00_main.out
vendored
Normal file
1
testdata/functional/00_main.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3
|
||||||
3
testdata/functional/00_main.sy
vendored
Normal file
3
testdata/functional/00_main.sy
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
int main(){
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
1
testdata/functional/01_var_defn2.out
vendored
Normal file
1
testdata/functional/01_var_defn2.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
10
|
||||||
8
testdata/functional/01_var_defn2.sy
vendored
Normal file
8
testdata/functional/01_var_defn2.sy
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
//test domain of global var define and local define
|
||||||
|
int a = 3;
|
||||||
|
int b = 5;
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
int a = 5;
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
1
testdata/functional/02_var_defn3.out
vendored
Normal file
1
testdata/functional/02_var_defn3.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5
|
||||||
8
testdata/functional/02_var_defn3.sy
vendored
Normal file
8
testdata/functional/02_var_defn3.sy
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
//test local var define
|
||||||
|
int main(){
|
||||||
|
int a, b0, _c;
|
||||||
|
a = 1;
|
||||||
|
b0 = 2;
|
||||||
|
_c = 3;
|
||||||
|
return b0 + _c;
|
||||||
|
}
|
||||||
1
testdata/functional/03_arr_defn2.out
vendored
Normal file
1
testdata/functional/03_arr_defn2.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0
|
||||||
4
testdata/functional/03_arr_defn2.sy
vendored
Normal file
4
testdata/functional/03_arr_defn2.sy
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
int a[10][10];
|
||||||
|
int main(){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
testdata/functional/04_arr_defn3.out
vendored
Normal file
1
testdata/functional/04_arr_defn3.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
14
|
||||||
9
testdata/functional/04_arr_defn3.sy
vendored
Normal file
9
testdata/functional/04_arr_defn3.sy
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//test array define
|
||||||
|
int main(){
|
||||||
|
int a[4][2] = {};
|
||||||
|
int b[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||||
|
int c[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
|
||||||
|
int d[4][2] = {1, 2, {3}, {5}, 7 , 8};
|
||||||
|
int e[4][2] = {{d[2][1], c[2][1]}, {3, 4}, {5, 6}, {7, 8}};
|
||||||
|
return e[3][1] + e[0][0] + e[0][1] + a[2][0];
|
||||||
|
}
|
||||||
1
testdata/functional/05_arr_defn4.out
vendored
Normal file
1
testdata/functional/05_arr_defn4.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
21
|
||||||
9
testdata/functional/05_arr_defn4.sy
vendored
Normal file
9
testdata/functional/05_arr_defn4.sy
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
int main(){
|
||||||
|
const int a[4][2] = {{1, 2}, {3, 4}, {}, 7};
|
||||||
|
|
||||||
|
int b[4][2] = {};
|
||||||
|
int c[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||||
|
int d[3 + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||||
|
int e[4][2][1] = {{d[2][1], {c[2][1]}}, {3, 4}, {5, 6}, {7, 8}};
|
||||||
|
return e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0];
|
||||||
|
}
|
||||||
1
testdata/functional/06_const_var_defn2.out
vendored
Normal file
1
testdata/functional/06_const_var_defn2.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5
|
||||||
6
testdata/functional/06_const_var_defn2.sy
vendored
Normal file
6
testdata/functional/06_const_var_defn2.sy
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
//test const gloal var define
|
||||||
|
const int a = 10, b = 5;
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
return b;
|
||||||
|
}
|
||||||
1
testdata/functional/07_const_var_defn3.out
vendored
Normal file
1
testdata/functional/07_const_var_defn3.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5
|
||||||
5
testdata/functional/07_const_var_defn3.sy
vendored
Normal file
5
testdata/functional/07_const_var_defn3.sy
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//test const local var define
|
||||||
|
int main(){
|
||||||
|
const int a = 10, b = 5;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
1
testdata/functional/08_const_array_defn.out
vendored
Normal file
1
testdata/functional/08_const_array_defn.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4
|
||||||
5
testdata/functional/08_const_array_defn.sy
vendored
Normal file
5
testdata/functional/08_const_array_defn.sy
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const int a[5]={0,1,2,3,4};
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
return a[4];
|
||||||
|
}
|
||||||
1
testdata/functional/09_func_defn.out
vendored
Normal file
1
testdata/functional/09_func_defn.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
9
|
||||||
11
testdata/functional/09_func_defn.sy
vendored
Normal file
11
testdata/functional/09_func_defn.sy
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
int a;
|
||||||
|
int func(int p){
|
||||||
|
p = p - 1;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
int main(){
|
||||||
|
int b;
|
||||||
|
a = 10;
|
||||||
|
b = func(a);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
1
testdata/functional/10_var_defn_func.out
vendored
Normal file
1
testdata/functional/10_var_defn_func.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4
|
||||||
8
testdata/functional/10_var_defn_func.sy
vendored
Normal file
8
testdata/functional/10_var_defn_func.sy
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
int defn(){
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
int a=defn();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
1
testdata/functional/11_add2.out
vendored
Normal file
1
testdata/functional/11_add2.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
9
|
||||||
7
testdata/functional/11_add2.sy
vendored
Normal file
7
testdata/functional/11_add2.sy
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//test add
|
||||||
|
int main(){
|
||||||
|
int a, b;
|
||||||
|
a = 10;
|
||||||
|
b = -1;
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
1
testdata/functional/12_addc.out
vendored
Normal file
1
testdata/functional/12_addc.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
15
|
||||||
5
testdata/functional/12_addc.sy
vendored
Normal file
5
testdata/functional/12_addc.sy
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//test addc
|
||||||
|
const int a = 10;
|
||||||
|
int main(){
|
||||||
|
return a + 5;
|
||||||
|
}
|
||||||
1
testdata/functional/13_sub2.out
vendored
Normal file
1
testdata/functional/13_sub2.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
248
|
||||||
7
testdata/functional/13_sub2.sy
vendored
Normal file
7
testdata/functional/13_sub2.sy
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//test sub
|
||||||
|
const int a = 10;
|
||||||
|
int main(){
|
||||||
|
int b;
|
||||||
|
b = 2;
|
||||||
|
return b - a;
|
||||||
|
}
|
||||||
1
testdata/functional/14_subc.out
vendored
Normal file
1
testdata/functional/14_subc.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
8
|
||||||
6
testdata/functional/14_subc.sy
vendored
Normal file
6
testdata/functional/14_subc.sy
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
//test subc
|
||||||
|
int main(){
|
||||||
|
int a;
|
||||||
|
a = 10;
|
||||||
|
return a - 2;
|
||||||
|
}
|
||||||
1
testdata/functional/15_mul.out
vendored
Normal file
1
testdata/functional/15_mul.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
50
|
||||||
7
testdata/functional/15_mul.sy
vendored
Normal file
7
testdata/functional/15_mul.sy
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//test mul
|
||||||
|
int main(){
|
||||||
|
int a, b;
|
||||||
|
a = 10;
|
||||||
|
b = 5;
|
||||||
|
return a * b;
|
||||||
|
}
|
||||||
1
testdata/functional/16_mulc.out
vendored
Normal file
1
testdata/functional/16_mulc.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
25
|
||||||
5
testdata/functional/16_mulc.sy
vendored
Normal file
5
testdata/functional/16_mulc.sy
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//test mulc
|
||||||
|
const int a = 5;
|
||||||
|
int main(){
|
||||||
|
return a * 5;
|
||||||
|
}
|
||||||
1
testdata/functional/17_div.out
vendored
Normal file
1
testdata/functional/17_div.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2
|
||||||
7
testdata/functional/17_div.sy
vendored
Normal file
7
testdata/functional/17_div.sy
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//test div
|
||||||
|
int main(){
|
||||||
|
int a, b;
|
||||||
|
a = 10;
|
||||||
|
b = 5;
|
||||||
|
return a / b;
|
||||||
|
}
|
||||||
1
testdata/functional/18_divc.out
vendored
Normal file
1
testdata/functional/18_divc.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2
|
||||||
5
testdata/functional/18_divc.sy
vendored
Normal file
5
testdata/functional/18_divc.sy
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//test divc
|
||||||
|
const int a = 10;
|
||||||
|
int main(){
|
||||||
|
return a / 5;
|
||||||
|
}
|
||||||
1
testdata/functional/19_mod.out
vendored
Normal file
1
testdata/functional/19_mod.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3
|
||||||
6
testdata/functional/19_mod.sy
vendored
Normal file
6
testdata/functional/19_mod.sy
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
//test mod
|
||||||
|
int main(){
|
||||||
|
int a;
|
||||||
|
a = 10;
|
||||||
|
return a / 3;
|
||||||
|
}
|
||||||
1
testdata/functional/20_rem.out
vendored
Normal file
1
testdata/functional/20_rem.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
6
testdata/functional/20_rem.sy
vendored
Normal file
6
testdata/functional/20_rem.sy
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
//test rem
|
||||||
|
int main(){
|
||||||
|
int a;
|
||||||
|
a = 10;
|
||||||
|
return a % 3;
|
||||||
|
}
|
||||||
2
testdata/functional/21_if_test2.out
vendored
Normal file
2
testdata/functional/21_if_test2.out
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-5
|
||||||
|
0
|
||||||
25
testdata/functional/21_if_test2.sy
vendored
Normal file
25
testdata/functional/21_if_test2.sy
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// test if-else-if
|
||||||
|
int ifElseIf() {
|
||||||
|
int a;
|
||||||
|
a = 5;
|
||||||
|
int b;
|
||||||
|
b = 10;
|
||||||
|
if(a == 6 || b == 0xb) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (b == 10 && a == 1)
|
||||||
|
a = 25;
|
||||||
|
else if (b == 10 && a == -5)
|
||||||
|
a = a + 15;
|
||||||
|
else
|
||||||
|
a = -+a;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
putint(ifElseIf());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
testdata/functional/22_if_test3.out
vendored
Normal file
1
testdata/functional/22_if_test3.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
25
|
||||||
18
testdata/functional/22_if_test3.sy
vendored
Normal file
18
testdata/functional/22_if_test3.sy
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// test if-if-else
|
||||||
|
int ififElse() {
|
||||||
|
int a;
|
||||||
|
a = 5;
|
||||||
|
int b;
|
||||||
|
b = 10;
|
||||||
|
if(a == 5)
|
||||||
|
if (b == 10)
|
||||||
|
a = 25;
|
||||||
|
else
|
||||||
|
a = a + 15;
|
||||||
|
|
||||||
|
return (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
return (ififElse());
|
||||||
|
}
|
||||||
1
testdata/functional/23_if_test4.out
vendored
Normal file
1
testdata/functional/23_if_test4.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
25
|
||||||
18
testdata/functional/23_if_test4.sy
vendored
Normal file
18
testdata/functional/23_if_test4.sy
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// test if-{if-else}
|
||||||
|
int if_ifElse_() {
|
||||||
|
int a;
|
||||||
|
a = 5;
|
||||||
|
int b;
|
||||||
|
b = 10;
|
||||||
|
if(a == 5){
|
||||||
|
if (b == 10)
|
||||||
|
a = 25;
|
||||||
|
else
|
||||||
|
a = a + 15;
|
||||||
|
}
|
||||||
|
return (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
return (if_ifElse_());
|
||||||
|
}
|
||||||
1
testdata/functional/24_if_test5.out
vendored
Normal file
1
testdata/functional/24_if_test5.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
25
|
||||||
18
testdata/functional/24_if_test5.sy
vendored
Normal file
18
testdata/functional/24_if_test5.sy
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// test if-{if}-else
|
||||||
|
int if_if_Else() {
|
||||||
|
int a;
|
||||||
|
a = 5;
|
||||||
|
int b;
|
||||||
|
b = 10;
|
||||||
|
if(a == 5){
|
||||||
|
if (b == 10)
|
||||||
|
a = 25;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a = a + 15;
|
||||||
|
return (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
return (if_if_Else());
|
||||||
|
}
|
||||||
2
testdata/functional/25_while_if.out
vendored
Normal file
2
testdata/functional/25_while_if.out
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
88
|
||||||
|
0
|
||||||
31
testdata/functional/25_while_if.sy
vendored
Normal file
31
testdata/functional/25_while_if.sy
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
int get_one(int a) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deepWhileBr(int a, int b) {
|
||||||
|
int c;
|
||||||
|
c = a + b;
|
||||||
|
while (c < 75) {
|
||||||
|
int d;
|
||||||
|
d = 42;
|
||||||
|
if (c < 100) {
|
||||||
|
c = c + d;
|
||||||
|
if (c > 99) {
|
||||||
|
int e;
|
||||||
|
e = d * 2;
|
||||||
|
if (get_one(0) == 1) {
|
||||||
|
c = e * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int p;
|
||||||
|
p = 2;
|
||||||
|
p = deepWhileBr(p, p);
|
||||||
|
putint(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
testdata/functional/26_while_test1.out
vendored
Normal file
1
testdata/functional/26_while_test1.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3
|
||||||
18
testdata/functional/26_while_test1.sy
vendored
Normal file
18
testdata/functional/26_while_test1.sy
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
int doubleWhile() {
|
||||||
|
int i;
|
||||||
|
i = 5;
|
||||||
|
int j;
|
||||||
|
j = 7;
|
||||||
|
while (i < 100) {
|
||||||
|
i = i + 30;
|
||||||
|
while(j < 100){
|
||||||
|
j = j + 6;
|
||||||
|
}
|
||||||
|
j = j - 100;
|
||||||
|
}
|
||||||
|
return (j);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return doubleWhile();
|
||||||
|
}
|
||||||
1
testdata/functional/27_while_test2.out
vendored
Normal file
1
testdata/functional/27_while_test2.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
54
|
||||||
31
testdata/functional/27_while_test2.sy
vendored
Normal file
31
testdata/functional/27_while_test2.sy
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
int FourWhile() {
|
||||||
|
int a;
|
||||||
|
a = 5;
|
||||||
|
int b;
|
||||||
|
int c;
|
||||||
|
b = 6;
|
||||||
|
c = 7;
|
||||||
|
int d;
|
||||||
|
d = 10;
|
||||||
|
while (a < 20) {
|
||||||
|
a = a + 3;
|
||||||
|
while(b < 10){
|
||||||
|
b = b + 1;
|
||||||
|
while(c == 7){
|
||||||
|
c = c - 1;
|
||||||
|
while(d < 20){
|
||||||
|
d = d + 3;
|
||||||
|
}
|
||||||
|
d = d - 1;
|
||||||
|
}
|
||||||
|
c = c + 1;
|
||||||
|
}
|
||||||
|
b = b - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (a + (b + d) + c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return FourWhile();
|
||||||
|
}
|
||||||
1
testdata/functional/28_while_test3.out
vendored
Normal file
1
testdata/functional/28_while_test3.out
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
23
|
||||||
55
testdata/functional/28_while_test3.sy
vendored
Normal file
55
testdata/functional/28_while_test3.sy
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
int g;
|
||||||
|
int h;
|
||||||
|
int f;
|
||||||
|
int e;
|
||||||
|
int EightWhile() {
|
||||||
|
int a;
|
||||||
|
a = 5;
|
||||||
|
int b;
|
||||||
|
int c;
|
||||||
|
b = 6;
|
||||||
|
c = 7;
|
||||||
|
int d;
|
||||||
|
d = 10;
|
||||||
|
while (a < 20) {
|
||||||
|
a = a + 3;
|
||||||
|
while(b < 10){
|
||||||
|
b = b + 1;
|
||||||
|
while(c == 7){
|
||||||
|
c = c - 1;
|
||||||
|
while(d < 20){
|
||||||
|
d = d + 3;
|
||||||
|
while(e > 1){
|
||||||
|
e = e-1;
|
||||||
|
while(f > 2){
|
||||||
|
f = f -2;
|
||||||
|
while(g < 3){
|
||||||
|
g = g +10;
|
||||||
|
while(h < 10){
|
||||||
|
h = h + 8;
|
||||||
|
}
|
||||||
|
h = h-1;
|
||||||
|
}
|
||||||
|
g = g- 8;
|
||||||
|
}
|
||||||
|
f = f + 1;
|
||||||
|
}
|
||||||
|
e = e + 1;
|
||||||
|
}
|
||||||
|
d = d - 1;
|
||||||
|
}
|
||||||
|
c = c + 1;
|
||||||
|
}
|
||||||
|
b = b - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (a + (b + d) + c)-(e + d - g + h);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
g = 1;
|
||||||
|
h = 2;
|
||||||
|
e = 4;
|
||||||
|
f = 6;
|
||||||
|
return EightWhile();
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user