Compare commits

..

7 Commits

Author SHA1 Message Date
Lixuanwang
ba7c581da5 Merge branch 'backend' into deploy-20250804 2025-08-04 21:58:51 +08:00
Lixuanwang
f7f1cf2b41 [backend]浮点逻辑与gcc保持一致 2025-08-04 21:54:24 +08:00
Lixuanwang
881c2a9723 [backend]强化了线性扫描逻辑 2025-08-04 19:28:15 +08:00
Lixuanwang
b5f14d9385 [backend]在后端主函数中添加了调试逻辑 2025-08-04 18:17:09 +08:00
Lixuanwang
72b06c67ca [backend]为图着色引入保底修复 2025-08-04 18:13:09 +08:00
Lixuanwang
f4ba1df93b Merge branch 'backend' into deploy-20250804 2025-08-04 16:50:57 +08:00
Lixuanwang
6dc74b173b [deploy]部署版本4 2025-08-04 02:42:55 +08:00
539 changed files with 1166 additions and 708936 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 KiB

View File

@@ -1,169 +0,0 @@
这个头文件定义了一个用于生成中间表示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 *> &paramTypes)`,用于获取函数类型。
- `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 转换为中间代码,并支持后续的优化和目标代码生成。

View File

@@ -1,156 +0,0 @@
`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 的生成更加模块化和易于维护。

View File

@@ -1,121 +0,0 @@
这个 `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 *> &paramTypes)`:返回函数类型。
- **`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 *> &paramTypes)`:返回函数类型,使用 `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转换为中间代码并支持后续的优化和目标代码生成。

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2,67 +2,66 @@
# runit-single.sh - 用于编译和测试单个或少量 SysY 程序的脚本
# 模仿 runit.sh 的功能,但以具体文件路径作为输入。
# 此脚本应该位于 mysysy/script/
export ASAN_OPTIONS=detect_leaks=0
# --- 配置区 ---
# 请根据你的环境修改这些路径
# 假设此脚本位于你的项目根目录或一个脚本目录中
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
# 默认寻找项目根目录下的 build 和 lib
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
LIB_DIR="${SCRIPT_DIR}/../lib"
# 临时文件会存储在脚本所在目录的 tmp 子目录中
TMP_DIR="${SCRIPT_DIR}/tmp"
# 定义编译器和模拟器
SYSYC="${BUILD_BIN_DIR}/sysyc"
LLC_CMD="llc-19" # 新增
GCC_RISCV64="riscv64-linux-gnu-gcc"
QEMU_RISCV64="qemu-riscv64"
# --- 初始化变量 ---
EXECUTE_MODE=false
IR_EXECUTE_MODE=false # 新增
CLEAN_MODE=false
OPTIMIZE_FLAG=""
SYSYC_TIMEOUT=30
LLC_TIMEOUT=10 # 新增
GCC_TIMEOUT=10
EXEC_TIMEOUT=30
MAX_OUTPUT_LINES=20
SY_FILES=()
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
SY_FILES=() # 存储用户提供的 .sy 文件列表
PASSED_CASES=0
FAILED_CASES_LIST=""
INTERRUPTED=false # 新增
# =================================================================
# --- 函数定义 ---
# =================================================================
show_help() {
echo "用法: $0 [文件1.sy] [文件2.sy] ... [选项]"
echo "编译并测试指定的 .sy 文件。必须提供 -e 或 -eir 之一。"
echo "编译并测试指定的 .sy 文件。"
echo ""
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
echo ""
echo "选项:"
echo " -e 通过汇编运行测试 (sysyc -> gcc -> qemu)。"
echo " -eir 通过IR运行测试 (sysyc -> llc -> gcc -> qemu)。"
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
echo " -O1 启用 sysyc 的 -O1 优化。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
}
# --- 新增功能: 显示文件内容并根据行数截断 ---
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
if [ ! -f "$file_path" ]; then return; fi
if [ ! -f "$file_path" ]; then
return
fi
echo -e "$title"
local line_count
line_count=$(wc -l < "$file_path")
if [ "$line_count" -gt "$max_lines" ]; then
head -n "$max_lines" "$file_path"
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
@@ -71,79 +70,55 @@ display_file_content() {
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
case "$1" in
-e|--executable) EXECUTE_MODE=true; shift ;;
-eir) IR_EXECUTE_MODE=true; shift ;; # 新增
-c|--clean) CLEAN_MODE=true; shift ;;
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;; # 新增
-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 ;;
*)
-e|--executable)
EXECUTE_MODE=true
shift # 消耗选项
;;
-c|--clean)
CLEAN_MODE=true
shift # 消耗选项
;;
-O1)
OPTIMIZE_FLAG="-O1"
shift # 消耗选项
;;
-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
SY_FILES+=("$1")
else
echo "警告: 无效文件或不是 .sy 文件,已忽略: $1"
fi
shift
shift # 消耗文件参数
;;
esac
done
if ${CLEAN_MODE}; then
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
if [ -d "${TMP_DIR}" ]; then
@@ -152,22 +127,19 @@ if ${CLEAN_MODE}; then
else
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
fi
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE}; then
exit 0
fi
fi
if ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
echo "错误: 请提供 -e 或 -eir 选项来运行测试。"
# --- 主逻辑开始 ---
if ! ${EXECUTE_MODE}; then
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
show_help
exit 1
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
echo "错误: 未提供任何 .sy 文件作为输入。"
show_help
@@ -179,17 +151,18 @@ TOTAL_CASES=${#SY_FILES[@]}
echo "SysY 单例测试运行器启动..."
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
echo ""
for sy_file in "${SY_FILES[@]}"; do
is_passed=1
compilation_ok=1
base_name=$(basename "${sy_file}" .sy)
source_dir=$(dirname "${sy_file}")
ir_file="${TMP_DIR}/${base_name}.ll"
ir_file="${TMP_DIR}/${base_name}_sysyc_riscv64.ll"
assembly_file="${TMP_DIR}/${base_name}.s"
assembly_debug_file="${TMP_DIR}/${base_name}_d.s"
executable_file="${TMP_DIR}/${base_name}"
input_file="${source_dir}/${base_name}.in"
output_reference_file="${source_dir}/${base_name}.out"
@@ -198,39 +171,47 @@ for sy_file in "${SY_FILES[@]}"; do
echo "======================================================================"
echo "正在处理: ${sy_file}"
# --- 编译阶段 ---
if ${IR_EXECUTE_MODE}; then
# 路径1: sysyc -> llc -> gcc
echo " [1/3] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} -o "${ir_file}"
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (IR) 编译失败或超时。\e[0m"; compilation_ok=0; fi
# --- 本次修改点: 拷贝源文件到 tmp 目录 ---
echo " 拷贝源文件到 ${TMP_DIR}..."
cp "${sy_file}" "${TMP_DIR}/$(basename "${sy_file}")"
if [ -f "${input_file}" ]; then
cp "${input_file}" "${TMP_DIR}/$(basename "${input_file}")"
fi
if [ -f "${output_reference_file}" ]; then
cp "${output_reference_file}" "${TMP_DIR}/$(basename "${output_reference_file}")"
fi
# 步骤 1: sysyc 编译
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} > "${ir_file}"
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
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
if [ "$compilation_ok" -eq 1 ]; then
echo " [2/3] 使用 llc 编译为汇编 (超时 ${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}"
if [ $? -ne 0 ]; then echo -e "\e[31m错误: llc 编译失败或超时。\e[0m"; compilation_ok=0; fi
fi
if [ "$compilation_ok" -eq 1 ]; then
echo " [3/3] 使用 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
else # EXECUTE_MODE
# 路径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
# 步骤 2: GCC 编译
if [ "$is_passed" -eq 1 ]; then
echo " 使用 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"
is_passed=0
fi
fi
# --- 执行与测试阶段 (公共逻辑) ---
if [ "$compilation_ok" -eq 1 ]; then
# 步骤 3: 执行与测试
if [ "$is_passed" -eq 1 ]; then
# 检查是自动化测试还是交互模式
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
# --- 自动化测试模式 ---
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
@@ -253,26 +234,24 @@ for sy_file in "${SY_FILES[@]}"; do
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name}.expected_stdout"
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
echo -e "\e[31m 标准输出测试失败。\e[0m"; out_ok=0
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
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
else
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
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
@@ -281,16 +260,20 @@ for sy_file in "${SY_FILES[@]}"; do
fi
else
# --- 交互模式 ---
echo -e "\e[33m\n 未找到 .in 或 .out 文件,进入交互模式...\e[0m"
echo -e "\e[33m"
echo " **********************************************************"
echo " ** 未找到 .in 或 .out 文件,进入交互模式。 **"
echo " ** 程序即将运行,你可以直接在终端中输入。 **"
echo " ** 按下 Ctrl+D (EOF) 或以其他方式结束程序以继续。 **"
echo " **********************************************************"
echo -e "\e[0m"
"${QEMU_RISCV64}" "${executable_file}"
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
else
is_passed=0
fi
# --- 状态总结 ---
if [ "$is_passed" -eq 1 ]; then
echo -e "\e[32m状态: 通过\e[0m"
((PASSED_CASES++))
@@ -301,4 +284,20 @@ for sy_file in "${SY_FILES[@]}"; do
done
# --- 打印最终总结 ---
print_summary
echo "======================================================================"
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

View File

@@ -1,41 +1,31 @@
#!/bin/bash
# runit.sh - 用于编译和测试 SysY 程序的脚本
# 此脚本应该位于 mysysy/script/
export ASAN_OPTIONS=detect_leaks=0
# 此脚本应该位于 mysysy/test_script/
# 定义相对于脚本位置的目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
TESTDATA_DIR="${SCRIPT_DIR}/../testdata"
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
LIB_DIR="${SCRIPT_DIR}/../lib"
# TMP_DIR="${SCRIPT_DIR}/tmp"
TMP_DIR="${SCRIPT_DIR}/tmp"
# 定义编译器和模拟器
SYSYC="${BUILD_BIN_DIR}/sysyc"
LLC_CMD="llc-19"
GCC_RISCV64="riscv64-linux-gnu-gcc"
QEMU_RISCV64="qemu-riscv64"
# --- 状态变量 ---
EXECUTE_MODE=false
IR_EXECUTE_MODE=false
OPTIMIZE_FLAG=""
SYSYC_TIMEOUT=30
LLC_TIMEOUT=10
GCC_TIMEOUT=10
EXEC_TIMEOUT=30
MAX_OUTPUT_LINES=20
TEST_SETS=()
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
TEST_SETS=() # 用于存储要运行的测试集
TOTAL_CASES=0
PASSED_CASES=0
FAILED_CASES_LIST=""
INTERRUPTED=false # 新增:用于标记是否被中断
# =================================================================
# --- 函数定义 ---
# =================================================================
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
# 显示帮助信息的函数
show_help() {
@@ -43,32 +33,31 @@ show_help() {
echo "此脚本用于按文件名前缀数字升序编译和测试 .sy 文件。"
echo ""
echo "选项:"
echo " -e, --executable 编译为汇编并运行测试 (sysyc -> gcc -> qemu)。"
echo " -eir 通过IR编译为可执行文件并运行测试 (sysyc -> llc -> gcc -> qemu)。"
echo " -e, --executable 编译为可执行文件并运行测试。"
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
echo " -O1 启用 sysyc 的 -O1 优化。"
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
echo " 可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
}
# 显示文件内容并根据行数截断的函数
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
if [ ! -f "$file_path" ]; then return; fi
if [ ! -f "$file_path" ]; then
return
fi
echo -e "$title"
local line_count
line_count=$(wc -l < "$file_path")
if [ "$line_count" -gt "$max_lines" ]; then
head -n "$max_lines" "$file_path"
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
@@ -83,90 +72,63 @@ clean_tmp() {
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}"
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-e|--executable) EXECUTE_MODE=true; shift ;;
-eir) IR_EXECUTE_MODE=true; shift ;;
-c|--clean) clean_tmp; exit 0 ;;
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
-set)
-e|--executable)
EXECUTE_MODE=true
shift
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do 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 ;;
-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 ;;
-c|--clean)
clean_tmp
exit 0
;;
-O1)
OPTIMIZE_FLAG="-O1"
shift
;;
-set)
shift # 移过 '-set'
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do
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
;;
esac
done
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
exit 1
fi
# --- 本次修改点: 根据 -set 参数构建查找路径 ---
declare -A SET_MAP
SET_MAP[f]="functional"
SET_MAP[h]="h_functional"
SET_MAP[p]="performance"
SEARCH_PATHS=()
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
SEARCH_PATHS+=("${TESTDATA_DIR}")
else
@@ -188,21 +150,9 @@ echo "SysY 测试运行器启动..."
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
echo "输入目录: ${SEARCH_PATHS[@]}"
echo "临时目录: ${TMP_DIR}"
RUN_MODE_INFO=""
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 "执行模式: ${EXECUTE_MODE}"
if ${EXECUTE_MODE}; then
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
fi
echo ""
@@ -215,228 +165,132 @@ fi
TOTAL_CASES=$(echo "$sy_files" | wc -w)
while IFS= read -r sy_file; do
is_passed=0 # 0 表示失败, 1 表示通过
is_passed=1 # 1 表示通过, 0 表示失败
relative_path_no_ext=$(realpath --relative-to="${TESTDATA_DIR}" "${sy_file%.*}")
output_base_name=$(echo "${relative_path_no_ext}" | tr '/' '_')
assembly_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.s"
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"
assembly_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.s"
executable_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64"
input_file="${sy_file%.*}.in"
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 " 使用 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
# --- 模式 1: IR 执行模式 (-eir) ---
if ${IR_EXECUTE_MODE}; then
step_failed=0
test_logic_passed=0
echo " [1/4] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -ne 0 ]; then
[ $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
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
GCC_STATUS=$?
if [ $GCC_STATUS -eq 124 ]; then
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 超时\e[0m"
is_passed=0
elif [ $GCC_STATUS -ne 0 ]; then
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 失败,退出码: ${GCC_STATUS}\e[0m"
is_passed=0
fi
if [ "$step_failed" -eq 0 ]; then
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}"
LLC_STATUS=$?
if [ $LLC_STATUS -ne 0 ]; then
[ $LLC_STATUS -eq 124 ] && echo -e "\e[31m错误: llc-19 编译超时\e[0m" || echo -e "\e[31m错误: llc-19 编译失败,退出码: ${LLC_STATUS}\e[0m"
step_failed=1
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 [ "$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
if [ "$is_passed" -eq 1 ]; then
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
if [ -f "${input_file}" ]; then
exec_cmd+=" < \"${input_file}\""
fi
exec_cmd+=" > \"${output_actual_file}\""
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=$?
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 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
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
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
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
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
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
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
test_logic_passed=1
fi
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
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
# --- 统计结果 ---
if [ "$is_passed" -eq 1 ]; then
((PASSED_CASES++))
else
# 确保 FAILED_CASES_LIST 的每一项都以换行符结尾
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
fi
echo ""
done <<< "$sy_files"
# --- 修改:调用总结函数 ---
print_summary
echo "========================================"
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

View File

@@ -5,6 +5,7 @@ add_library(riscv64_backend_lib STATIC
RISCv64ISel.cpp
RISCv64LLIR.cpp
RISCv64RegAlloc.cpp
RISCv64LinearScan.cpp
Handler/CalleeSavedHandler.cpp
Handler/LegalizeImmediates.cpp
Handler/PrologueEpilogueInsertion.cpp

View File

@@ -82,7 +82,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::SB: *OS << "sb "; break; case RVOpcodes::LD: *OS << "ld "; break;
case RVOpcodes::SD: *OS << "sd "; break; case RVOpcodes::FLW: *OS << "flw "; break;
case RVOpcodes::FSW: *OS << "fsw "; break; case RVOpcodes::FLD: *OS << "fld "; break;
case RVOpcodes::FSD: *OS << "fsd "; break;
case RVOpcodes::FSD: *OS << "fsd "; break;
case RVOpcodes::J: *OS << "j "; break; case RVOpcodes::JAL: *OS << "jal "; break;
case RVOpcodes::JALR: *OS << "jalr "; break; case RVOpcodes::RET: *OS << "ret"; break;
case RVOpcodes::BEQ: *OS << "beq "; break; case RVOpcodes::BNE: *OS << "bne "; break;
@@ -102,6 +102,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::FLE_S: *OS << "fle.s "; 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_RTZ: *OS << "fcvt.w.s "; break;
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;

View File

@@ -1,10 +1,13 @@
#include "RISCv64Backend.h"
#include "RISCv64ISel.h"
#include "RISCv64RegAlloc.h"
#include "RISCv64LinearScan.h" // <--- 新增此行
#include "RISCv64AsmPrinter.h"
#include "RISCv64Passes.h"
#include <sstream>
#include <future> // <--- 新增此行
#include <chrono> // <--- 新增此行
#include <iostream> // <--- 新增此行,用于打印超时警告
namespace sysy {
// 顶层入口
@@ -196,9 +199,6 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
// === 完整的后端处理流水线 ===
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
DEBUG = 0;
DEEPDEBUG = 0;
RISCv64ISel isel;
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
@@ -206,9 +206,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
std::stringstream ss_after_isel;
RISCv64AsmPrinter printer_isel(mfunc.get());
printer_isel.run(ss_after_isel, true);
if (DEBUG) {
std::cout << ss_after_isel.str();
}
if (DEBUG) {
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
<< ss_after_isel.str();
@@ -228,13 +226,13 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
<< ss_after_eli.str();
}
// 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
DivStrengthReduction div_strength_reduction;
div_strength_reduction.runOnMachineFunction(mfunc.get());
// // 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
// DivStrengthReduction div_strength_reduction;
// div_strength_reduction.runOnMachineFunction(mfunc.get());
// 阶段 2.1: 指令调度 (Instruction Scheduling)
PreRA_Scheduler scheduler;
scheduler.runOnMachineFunction(mfunc.get());
// // 阶段 2.1: 指令调度 (Instruction Scheduling)
// PreRA_Scheduler scheduler;
// scheduler.runOnMachineFunction(mfunc.get());
// 阶段 3: 物理寄存器分配 (Register Allocation)
RISCv64RegAlloc reg_alloc(mfunc.get());
@@ -254,9 +252,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
mfunc->dumpStackFrameInfo(std::cerr);
}
// 阶段 4: 窥孔优化 (Peephole Optimization)
PeepholeOptimizer peephole;
peephole.runOnMachineFunction(mfunc.get());
// // 阶段 4: 窥孔优化 (Peephole Optimization)
// PeepholeOptimizer peephole;
// peephole.runOnMachineFunction(mfunc.get());
// 阶段 5: 局部指令调度 (Local Scheduling)
PostRA_Scheduler local_scheduler;
@@ -276,7 +274,6 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
printer.run(ss);
return ss.str();
}
} // namespace sysy

View File

@@ -745,83 +745,12 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFtoI: { // 浮点 to 整数 (带向下取整)
// 目标:实现 floor(x) 的效果, C/C++中浮点转整数是截断(truncate)
// 对于正数floor(x) == truncate(x)
// RISC-V的 fcvt.w.s 默认是“四舍五入到偶数”
// 我们需要手动实现截断逻辑
// 逻辑:
// 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));
case Instruction::kFtoI: { // 浮点 to 整数 (使用硬件指令进行向零截断)
// 直接生成一条带有 rtz 舍入模式的转换指令
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S_RTZ);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFNeg: { // 浮点取负
@@ -1202,10 +1131,11 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto r_value_byte = getVReg(memset->getValue());
// 为memset内部逻辑创建新的临时虚拟寄存器
auto r_counter = getNewVReg();
auto r_end_addr = getNewVReg();
auto r_current_addr = getNewVReg();
auto r_temp_val = getNewVReg();
Type* ptr_type = Type::getPointerType(Type::getIntType());
auto r_counter = getNewVReg(ptr_type);
auto r_end_addr = getNewVReg(ptr_type);
auto r_current_addr = getNewVReg(ptr_type);
auto r_temp_val = getNewVReg(Type::getIntType());
// 定义一系列lambda表达式来简化指令创建
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
@@ -1296,7 +1226,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
// --- Step 1: 获取基地址 (此部分逻辑正确,保持不变) ---
auto base_ptr_node = node->operands[0];
auto current_addr_vreg = getNewVReg();
auto current_addr_vreg = getNewVReg(gep->getType());
if (auto alloca_base = dynamic_cast<AllocaInst*>(base_ptr_node->value)) {
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
@@ -1338,13 +1268,13 @@ void RISCv64ISel::selectNode(DAGNode* node) {
// 如果步长为0例如对一个void类型或空结构体索引则不产生任何偏移
if (stride != 0) {
// --- 为当前索引和步长生成偏移计算指令 ---
auto offset_vreg = getNewVReg();
auto offset_vreg = getNewVReg(Type::getIntType());
// 处理索引 - 区分常量与动态值
unsigned index_vreg;
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
// 对于常量索引,直接创建新的虚拟寄存器
index_vreg = getNewVReg();
index_vreg = getNewVReg(Type::getIntType());
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(index_vreg));
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
@@ -1362,7 +1292,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(mv));
} else {
// 步长不为1需要生成乘法指令
auto size_vreg = getNewVReg();
auto size_vreg = getNewVReg(Type::getIntType());
auto li_size = std::make_unique<MachineInstr>(RVOpcodes::LI);
li_size->addOperand(std::make_unique<RegOperand>(size_vreg));
li_size->addOperand(std::make_unique<ImmOperand>(stride));

View File

@@ -0,0 +1,517 @@
#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

View File

@@ -55,41 +55,12 @@ void RISCv64RegAlloc::run() {
if (DEBUG) std::cerr << "===== Running Graph Coloring Register Allocation for function: " << MFunc->getName() << " =====\n";
const int MAX_ITERATIONS = 50;
int iteration = 0;
while (iteration++ < MAX_ITERATIONS) {
while (true) {
if (doAllocation()) {
break;
} else {
rewriteProgram();
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;
}
if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation ---\n";
}
}

View File

@@ -22,7 +22,6 @@ public:
// 公开接口以便后续模块如RegAlloc可以查询或创建vreg
unsigned getVReg(Value* val);
unsigned getNewVReg() { return vreg_counter++; }
unsigned getNewVReg(Type* type);
unsigned getVRegCounter() const;
// 获取 vreg_map 的公共接口

View File

@@ -41,6 +41,8 @@ enum class PhysicalReg {
// 假设 vreg_counter 不会达到这么大的值
PHYS_REG_START_ID = 1000000,
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
INVALID, ///< 无效寄存器标记
};
// RISC-V 指令操作码枚举
@@ -86,6 +88,7 @@ enum class RVOpcodes {
// 浮点转换
FCVT_S_W, // fcvt.s.w 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 (浮点寄存器之间)

View File

@@ -0,0 +1,104 @@
#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

View File

@@ -20,10 +20,6 @@
#include <algorithm>
namespace sysy {
// Global cleanup function to release all statically allocated IR objects
void cleanupIRPools();
/**
* \defgroup type Types
* @brief Sysy的类型系统
@@ -87,7 +83,6 @@ class Type {
auto as() const -> std::enable_if_t<std::is_base_of_v<Type, T>, T *> {
return dynamic_cast<T *>(const_cast<Type *>(this));
}
virtual void print(std::ostream& os) const;
};
class PointerType : public Type {
@@ -99,9 +94,6 @@ class PointerType : public Type {
public:
static PointerType* get(Type *baseType); ///< 获取指向baseType的Pointer类型
// Cleanup method to release all cached pointer types (call at program exit)
static void cleanup();
public:
Type* getBaseType() const { return baseType; } ///< 获取指向的类型
@@ -119,9 +111,6 @@ class FunctionType : public Type {
public:
/// 获取返回值类型为returnType 形参类型列表为paramTypes的Function类型
static FunctionType* get(Type *returnType, const std::vector<Type *> &paramTypes = {});
// Cleanup method to release all cached function types (call at program exit)
static void cleanup();
public:
Type* getReturnType() const { return returnType; } ///< 获取返回值类信息
@@ -134,9 +123,6 @@ class ArrayType : public Type {
// elements数组的元素类型 (例如int[3] 的 elementType 是 int)
// numElements该维度的大小 (例如int[3] 的 numElements 是 3)
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; }
unsigned getNumElements() const { return numElements; }
@@ -220,7 +206,6 @@ class Use {
User* getUser() const { return user; } ///< 返回使用者
Value* getValue() const { return value; } ///< 返回被使用的值
void setValue(Value *newValue) { value = newValue; } ///< 将被使用的值设置为newValue
void print(std::ostream& os) const;
};
//! The base class of all value types
@@ -253,7 +238,6 @@ class Value {
uses.remove(use);
} ///< 删除使用关系use
void removeAllUses();
virtual void print(std::ostream& os) const = 0; ///< 输出值信息到输出流
};
/**
@@ -380,9 +364,6 @@ public:
// Static factory method to get a canonical ConstantValue from the pool
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
int getInt() const {
@@ -421,7 +402,6 @@ public:
virtual bool isZero() const = 0;
virtual bool isOne() const = 0;
void print(std::ostream& os) const = 0;
};
class ConstantInteger : public ConstantValue {
@@ -448,7 +428,6 @@ public:
bool isZero() const override { return constVal == 0; }
bool isOne() const override { return constVal == 1; }
void print(std::ostream& os) const;
};
class ConstantFloating : public ConstantValue {
@@ -475,7 +454,6 @@ public:
bool isZero() const override { return constFVal == 0.0f; }
bool isOne() const override { return constFVal == 1.0f; }
void print(std::ostream& os) const;
};
class UndefinedValue : public ConstantValue {
@@ -490,9 +468,6 @@ protected:
public:
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 {
return std::hash<Type*>{}(getType());
@@ -510,7 +485,6 @@ public:
bool isZero() const override { return false; }
bool isOne() const override { return false; }
void print(std::ostream& os) const;
};
// --- End of refactored ConstantValue and related classes ---
@@ -651,11 +625,6 @@ public:
}
} ///< 移除指定位置的指令
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
@@ -690,9 +659,6 @@ class User : public Value {
} ///< 增加多个操作数
void replaceOperand(unsigned index, Value *value); ///< 替换操作数
void setOperand(unsigned index, Value *value); ///< 设置操作数
/// 清理用户的所有操作数使用关系
void cleanup();
};
/*!
@@ -770,57 +736,57 @@ public:
std::string getKindString() const{
switch (kind) {
case kInvalid:
return "invalid";
return "Invalid";
case kAdd:
return "add";
return "Add";
case kSub:
return "sub";
return "Sub";
case kMul:
return "mul";
return "Mul";
case kDiv:
return "sdiv";
return "Div";
case kRem:
return "srem";
return "Rem";
case kICmpEQ:
return "icmp eq";
return "ICmpEQ";
case kICmpNE:
return "icmp ne";
return "ICmpNE";
case kICmpLT:
return "icmp slt";
return "ICmpLT";
case kICmpGT:
return "icmp sgt";
return "ICmpGT";
case kICmpLE:
return "icmp sle";
return "ICmpLE";
case kICmpGE:
return "icmp sge";
return "ICmpGE";
case kFAdd:
return "fadd";
return "FAdd";
case kFSub:
return "fsub";
return "FSub";
case kFMul:
return "fmul";
return "FMul";
case kFDiv:
return "fdiv";
return "FDiv";
case kFCmpEQ:
return "fcmp oeq";
return "FCmpEQ";
case kFCmpNE:
return "fcmp one";
return "FCmpNE";
case kFCmpLT:
return "fcmp olt";
return "FCmpLT";
case kFCmpGT:
return "fcmp ogt";
return "FCmpGT";
case kFCmpLE:
return "fcmp ole";
return "FCmpLE";
case kFCmpGE:
return "fcmp oge";
return "FCmpGE";
case kAnd:
return "and";
return "And";
case kOr:
return "or";
return "Or";
case kNeg:
return "neg";
return "Neg";
case kNot:
return "not";
return "Not";
case kFNeg:
return "FNeg";
case kFNot:
@@ -828,35 +794,33 @@ public:
case kFtoI:
return "FtoI";
case kItoF:
return "iToF";
return "IToF";
case kCall:
return "call";
return "Call";
case kCondBr:
return "condBr";
return "CondBr";
case kBr:
return "br";
return "Br";
case kReturn:
return "return";
case kUnreachable:
return "unreachable";
return "Return";
case kAlloca:
return "alloca";
return "Alloca";
case kLoad:
return "load";
return "Load";
case kStore:
return "store";
return "Store";
case kGetElementPtr:
return "getElementPtr";
return "GetElementPtr";
case kMemset:
return "memset";
return "Memset";
case kPhi:
return "phi";
return "Phi";
case kBitItoF:
return "BitItoF";
case kBitFtoI:
return "BitFtoI";
case kSRA:
return "ashr";
return "SRA";
default:
return "Unknown";
}
@@ -923,10 +887,6 @@ public:
static constexpr uint64_t DefineOpMask = kAlloca | kStore | kPhi;
return (kind & DefineOpMask) != 0U;
}
virtual ~Instruction() = default;
virtual void print(std::ostream& os) const = 0;
}; // class Instruction
class Function;
@@ -997,7 +957,6 @@ class PhiInst : public Instruction {
}
} ///< 刷新块到值的映射关系
auto getValues() { return make_range(std::next(operand_begin()), operand_end()); }
void print(std::ostream& os) const override;
};
@@ -1006,14 +965,16 @@ class CallInst : public Instruction {
friend class IRBuilder;
protected:
CallInst(Function *callee, const std::vector<Value *> &args, BasicBlock *parent = nullptr, const std::string &name = "");
CallInst(Function *callee, const std::vector<Value *> &args = {},
BasicBlock *parent = nullptr, const std::string &name = "");
public:
Function *getCallee() const;
Function* getCallee() const;
auto getArguments() const {
return make_range(std::next(operand_begin()), operand_end());
}
void print(std::ostream& os) const override;
}; // class CallInst
//! Unary instruction, includes '!', '-' and type conversion.
@@ -1031,7 +992,7 @@ protected:
public:
Value* getOperand() const { return User::getOperand(0); }
void print(std::ostream& os) const override;
}; // class UnaryInst
//! Binary instruction, e.g., arithmatic, relation, logic, etc.
@@ -1110,7 +1071,6 @@ public:
// 后端处理数组访存操作时需要创建计算地址的指令,需要在外部构造 BinaryInst 对象
return new BinaryInst(kind, type, lhs, rhs, parent, name);
}
void print(std::ostream& os) const override;
}; // class BinaryInst
//! The return statement
@@ -1131,7 +1091,6 @@ class ReturnInst : public Instruction {
Value* getReturnValue() const {
return hasReturnValue() ? getOperand(0) : nullptr;
}
void print(std::ostream& os) const override;
};
//! Unconditional branch
@@ -1161,7 +1120,7 @@ public:
}
return succs;
}
void print(std::ostream& os) const override;
}; // class UncondBrInst
//! Conditional branch
@@ -1201,7 +1160,7 @@ public:
}
return succs;
}
void print(std::ostream& os) const override;
}; // class CondBrInst
class UnreachableInst : public Instruction {
@@ -1209,7 +1168,7 @@ public:
// 构造函数:设置指令类型为 kUnreachable
explicit UnreachableInst(const std::string& name, BasicBlock *parent = nullptr)
: Instruction(kUnreachable, Type::getVoidType(), parent, "") {}
void print(std::ostream& os) const { os << "unreachable"; }
};
//! Allocate memory for stack variables, used for non-global variable declartion
@@ -1227,7 +1186,7 @@ public:
Type* getAllocatedType() const {
return getType()->as<PointerType>()->getBaseType();
} ///< 获取分配的类型
void print(std::ostream& os) const override;
}; // class AllocaInst
@@ -1265,7 +1224,6 @@ public:
BasicBlock *parent = nullptr, const std::string &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
@@ -1283,7 +1241,7 @@ protected:
public:
Value* getPointer() const { return getOperand(0); }
void print(std::ostream& os) const override;
}; // class LoadInst
//! Store a value to memory address specified by a pointer value
@@ -1302,7 +1260,7 @@ protected:
public:
Value* getValue() const { return getOperand(0); }
Value* getPointer() const { return getOperand(1); }
void print(std::ostream& os) const override;
}; // class StoreInst
//! Memset instruction
@@ -1332,7 +1290,7 @@ public:
Value* getBegin() const { return getOperand(1); }
Value* getSize() const { return getOperand(2); }
Value* getValue() const { return getOperand(3); }
void print(std::ostream& os) const override;
};
class GlobalValue;
@@ -1350,11 +1308,6 @@ public:
public:
Function* getParent() const { return func; }
int getIndex() const { return index; }
/// 清理参数的使用关系
void cleanup();
void print(std::ostream& os) const;
};
@@ -1432,11 +1385,6 @@ protected:
blocks.emplace_front(block);
return block;
}
/// 清理函数中的所有使用关系
void cleanup();
void print(std::ostream& os) const;
};
//! Global value declared at file scope
@@ -1502,7 +1450,6 @@ public:
return getByIndex(index);
} ///< 通过多维索引indices获取初始值
const ValueCounter& getInitValues() const { return initValues; }
void print(std::ostream& os) const;
}; // class GlobalValue
@@ -1560,8 +1507,6 @@ class ConstantVariable : public Value {
return getByIndex(index);
} ///< 通过多维索引indices获取初始值
const ValueCounter& getInitValues() const { return initValues; } ///< 获取初始值
void print(std::ostream& os) const;
void print_init(std::ostream& os) const;
};
using SymbolTableNode = struct SymbolTableNode {
@@ -1584,8 +1529,6 @@ class SymbolTable {
Value* getVariable(const std::string &name) const; ///< 根据名字name以及当前作用域获取变量
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(); ///< 获取全局变量列表
const std::vector<std::unique_ptr<ConstantVariable>>& getConsts() const; ///< 获取全局常量列表
void enterNewScope(); ///< 进入新的作用域
@@ -1593,9 +1536,6 @@ class SymbolTable {
bool isInGlobalScope() const; ///< 是否位于全局作用域
void enterGlobalScope(); ///< 进入全局作用域
bool isCurNodeNull() { return curNode == nullptr; }
/// 清理符号表中的所有内容
void cleanup();
};
//! IR unit for representing a SysY compile unit
@@ -1648,12 +1588,6 @@ class Module {
void addVariable(const std::string &name, AllocaInst *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) {
return variableTable.getVariable(name);
} ///< 根据名字name和当前作用域获取变量
@@ -1666,7 +1600,7 @@ class Module {
} ///< 获取函数
Function* getExternalFunction(const std::string &name) const {
auto result = externalFunctions.find(name);
if (result == externalFunctions.end()) {
if (result == functions.end()) {
return nullptr;
}
return result->second.get();
@@ -1686,11 +1620,6 @@ class Module {
void leaveScope() { variableTable.leaveScope(); } ///< 离开作用域
bool isInGlobalArea() const { return variableTable.isInGlobalScope(); } ///< 是否位于全局作用域
/// 清理模块中的所有对象,包括函数、基本块、指令等
void cleanup();
void print(std::ostream& os) const;
};
/*!

View File

@@ -350,31 +350,38 @@ class IRBuilder {
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
// 遍历所有索引来深入类型层次结构。
// 重要:第一个索引总是用于"解引用"指针,后续索引才用于数组/结构体的索引
// `indices` 向量包含了所有 GEP 索引,包括由 `visitLValue` 等函数添加的初始 `0` 索引
for (int i = 0; i < indices.size(); ++i) {
if (i == 0) {
// 第一个索引:总是用于"解引用"基指针不改变currentWalkType
// 例如:对于 `[4 x i32]* ptr, i32 0`第一个0只是说"访问ptr指向的对象"
// currentWalkType 保持为 `[4 x i32]`
continue;
if (currentWalkType->isArray()) {
// 情况一:当前遍历类型是 `ArrayType`。
// 索引用于选择数组元素,`currentWalkType` 更新为数组的元素类型。
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
} else if (currentWalkType->isPointer()) {
// 情况二:当前遍历类型是 `PointerType`。
// 这意味着我们正在通过一个指针来访问其指向的内存。
// 索引用于选择该指针所指向的“数组”的元素。
// `currentWalkType` 更新为该指针所指向的基础类型。
// 例如:如果 `currentWalkType` 是 `i32*`,它将变为 `i32`。
// 如果 `currentWalkType` 是 `[10 x i32]*`,它将变为 `[10 x i32]`。
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
} else {
// 后续索引:用于实际的数组/结构体索引
if (currentWalkType->isArray()) {
// 数组索引:选择数组中的元素
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
} else if (currentWalkType->isPointer()) {
// 指针索引:解引用指针并继续
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
} else {
// 标量类型:不能进一步索引
if (i < indices.size() - 1) {
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
return nullptr;
}
// 情况三:当前遍历类型是标量类型 (例如 `i32`, `float` 等非聚合、非指针类型)。
//
// 如果 `currentWalkType` 是标量,并且当前索引 `i` **不是** `indices` 向量中的最后一个索引,
// 这意味着尝试对一个标量类型进行进一步的结构性索引,这是**无效的**。
// 例如:`int x; x[0];` 对应的 GEP 链中,`x` 的类型是 `i32`,再加 `[0]` 索引就是错误。
//
// 如果 `currentWalkType` 是标量,且这是**最后一个索引** (`i == indices.size() - 1`)
// 那么 GEP 是合法的,它只是计算一个偏移地址,最终的类型就是这个标量类型。
// 此时 `currentWalkType` 保持不变,循环结束。
if (i < indices.size() - 1) {
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
return nullptr; // 返回空指针表示类型推断失败
}
// 如果是最后一个索引,且当前类型是标量,则类型保持不变,这是合法的。
// 循环会自然结束,返回正确的 `currentWalkType`。
}
}
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
return currentWalkType;
}

File diff suppressed because it is too large Load Diff

View File

@@ -52,16 +52,14 @@ bool LargeArrayToGlobalPass::runOnModule(Module *M, AnalysisManager &AM) {
// Calculate the size of the allocated type
unsigned size = calculateTypeSize(allocatedType);
if(DEBUG){
// Debug: print size information
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
// Debug: print size information
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
<< " for type " << typeToString(allocatedType) << std::endl;
}
// Convert arrays of 1KB (1024 bytes) or larger to global variables
if (size >= 1024) {
if(DEBUG)
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
allocasToConvert.emplace_back(alloca, F);
}
}

View File

@@ -280,22 +280,6 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
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()) {
case Instruction::kAdd:
case Instruction::kSub:
@@ -414,7 +398,6 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
newState = SSAPValue(); // 保持 Top
break;
case Instruction::kCall:
// TODO: 处理 Call 指令根据副作用分析可以推断的常量
// 大多数 Call 指令都假定为 Bottom除非是纯函数且所有参数都是常量
newState = SSAPValue(LatticeVal::Bottom);
break;
@@ -434,71 +417,19 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
}
case Instruction::kPhi: {
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
bool hasAnyExecutablePred = false;
for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) {
Value *incomingVal = phi->getIncomingValue(i);
BasicBlock *incomingBlock = phi->getIncomingBlock(i);
if (executableBlocks.count(incomingBlock)) {
hasAnyExecutablePred = true;
Value *incomingVal = phi->getIncomingValue(i);
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;
if (executableBlocks.count(incomingBlock)) { // 仅考虑可执行前驱
phiResult = Meet(phiResult, GetValueState(incomingVal));
if (phiResult.state == LatticeVal::Bottom)
break; // 如果已经 Bottom则提前退出
}
}
newState = phiResult;
break;
}
case Instruction::kAlloca: // 对应 kAlloca
@@ -555,22 +486,6 @@ 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;
}
}
// 辅助函数:处理单条控制流边
@@ -578,22 +493,14 @@ void SCCPContext::ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge)
BasicBlock *fromBB = edge.first;
BasicBlock *toBB = edge.second;
// 检查目标块是否已经可执行
bool wasAlreadyExecutable = executableBlocks.count(toBB) > 0;
// 标记目标块为可执行(如果还不是的话)
MarkBlockExecutable(toBB);
// 如果目标块之前就已经可执行那么需要重新处理其中的phi节点
// 因为现在有新的前驱变为可执行phi节点的值可能需要更新
if (wasAlreadyExecutable) {
for (auto &inst_ptr : toBB->getInstructions()) {
if (dynamic_cast<PhiInst *>(inst_ptr.get())) {
instWorkList.push(inst_ptr.get());
}
// 对于目标块中的所有 Phi 指令,重新评估其值,因为可能有新的前驱被激活
for (auto &inst_ptr : toBB->getInstructions()) {
if (dynamic_cast<PhiInst *>(inst_ptr.get())) {
instWorkList.push(inst_ptr.get());
}
}
// 如果目标块是新变为可执行的MarkBlockExecutable已经添加了所有指令
}
// 阶段1: 常量传播与折叠
@@ -608,29 +515,18 @@ 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()) {
MarkBlockExecutable(func->getEntryBlock());
}
// 主循环:标准的SCCP工作列表算法
// 交替处理边工作列表和指令工作列表直到不动点
// 主循环:处理工作列表直到不动点
while (!instWorkList.empty() || !edgeWorkList.empty()) {
// 处理所有待处理的CFG边
while (!edgeWorkList.empty()) {
ProcessEdge(edgeWorkList.front());
edgeWorkList.pop();
}
// 处理所有待处理的指令
while (!instWorkList.empty()) {
Instruction *inst = instWorkList.front();
instWorkList.pop();

View File

@@ -42,7 +42,7 @@ bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
++Branchiter;
while (Branchiter != instructions.end()) {
changed = true;
Branchiter = SysYIROptUtils::usedelete(Branchiter); // 删除指令
Branchiter = instructions.erase(Branchiter);
}
if (Branch) { // 更新前驱后继关系
@@ -77,11 +77,6 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
bool changed = false;
for (auto blockiter = func->getBasicBlocks().begin(); blockiter != func->getBasicBlocks().end();) {
// 检查当前块是是不是entry块
if( blockiter->get() == func->getEntryBlock() ) {
blockiter++;
continue; // 跳过入口块
}
if (blockiter->get()->getNumSuccessors() == 1) {
// 如果当前块只有一个后继块
// 且后继块只有一个前驱块
@@ -91,7 +86,7 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
BasicBlock *block = blockiter->get();
BasicBlock *nextBlock = blockiter->get()->getSuccessors()[0];
// auto nextarguments = nextBlock->getArguments();
// 删除block的br指令
// 删除br指令
if (block->getNumInstructions() != 0) {
auto thelastinstinst = block->terminator();
if (thelastinstinst->get()->isUnconditional()) {
@@ -103,21 +98,14 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
if (brinst->getThenBlock() == brinst->getElseBlock()) {
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();) {
// institer->get()->setParent(block);
// block->getInstructions().emplace_back(institer->release());
// 用usedelete删除会导致use关系被删除我只希望移动指令到当前块
// institer = SysYIROptUtils::usedelete(institer);
// institer = nextBlock->getInstructions().erase(institer);
institer = nextBlock->moveInst(institer, block->getInstructions().end(), block);
institer->get()->setParent(block);
block->getInstructions().emplace_back(institer->release());
institer = nextBlock->getInstructions().erase(institer);
}
// 更新前驱后继关系,类似树节点操作
block->removeSuccessor(nextBlock);
@@ -300,12 +288,13 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder *pBuilder) {
continue;
}
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val, BasicBlock *currentDefBlock) -> Value * {
if(!dynamic_cast<Instruction *>(val)) {
// 如果 val 不是指令,直接返回它
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val,
BasicBlock *currentDefBlock) -> Value * {
// 如果值不是指令,例如常量或函数参数,则它本身就是最终来源
if (auto instr = dynamic_cast<Instruction *>(val)) { // Assuming Value* has a method to check if it's an instruction
return val;
}
Instruction *inst = dynamic_cast<Instruction *>(val);
// 如果定义指令不在任何空块中,它就是最终来源
if (!emptyBlockRedirectMap.count(currentDefBlock)) {

View File

@@ -389,7 +389,26 @@ void SysYIRGenerator::compute() {
case BinaryOp::ADD: resultValue = builder.createAddInst(lhs, rhs); break;
case BinaryOp::SUB: resultValue = builder.createSubInst(lhs, rhs); break;
case BinaryOp::MUL: resultValue = builder.createMulInst(lhs, rhs); break;
case BinaryOp::DIV: resultValue = builder.createDivInst(lhs, rhs); break;
case BinaryOp::DIV: {
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;
}
} else if (commonType == Type::getFloatType()) {
@@ -1191,25 +1210,15 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
for(int i = 0; i < paramActualTypes.size(); ++i) {
Argument* arg = new Argument(paramActualTypes[i], function, i, paramNames[i]);
function->insertArgument(arg);
}
// 先将所有参数名字注册到符号表中确保alloca不会使用相同的名字
for (int i = 0; i < paramNames.size(); ++i) {
// 预先注册参数名字这样addVariable就会使用不同的后缀
module->registerParameterName(paramNames[i]);
}
auto funcArgs = function->getArguments();
std::vector<AllocaInst *> allocas;
for (int i = 0; i < paramActualTypes.size(); ++i) {
// 使用函数特定的前缀来确保参数alloca名字唯一
std::string allocaName = name + "_param_" + paramNames[i];
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(paramActualTypes[i]), allocaName);
// 直接设置唯一名字不依赖addVariable的命名逻辑
alloca->setName(allocaName);
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(paramActualTypes[i]), paramNames[i]);
allocas.push_back(alloca);
// 直接添加到符号表,使用原参数名作为查找键
module->addVariableDirectly(paramNames[i], alloca);
module->addVariable(paramNames[i], alloca);
}
for(int i = 0; i < paramActualTypes.size(); ++i) {
@@ -1278,45 +1287,6 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(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 {
// 对于数组或多维数组的左值处理
@@ -1354,47 +1324,51 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
}
// 左值为地址
LValue = getGEPAddressInst(gepBasePointer, gepIndices);
// 数组变量的类型推断使用gepIndices和gepBasePointer的类型
Type* LType = builder.getIndexedType(gepBasePointer->getType(), gepIndices);
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);
}
// Value* RValue = std::any_cast<Value *>(visitExp(ctx->exp())); // 右值
// 先推断 LValue 的类型
// 如果 LValue 是指向数组的指针,则需要根据 indices 获取正确的类型
// 如果 LValue 是标量,则直接使用其类型
// 注意LValue 的类型可能是指向数组的指针 (e.g., int(*)[3]) 或者指向标量的指针 (e.g., int*) 也能推断
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()) {
RValue = builder.createItoFInst(RValue);
} else { // 假设如果不是浮点型,就是整型
RValue = builder.createFtoIInst(RValue);
}
}
}
builder.createStoreInst(RValue, LValue);
invalidateExpressionsOnStore(LValue);
return std::any();
}
@@ -1561,7 +1535,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
}
builder.createUncondBrInst(headBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), headBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
builder.popBreakBlock();
builder.popContinueBlock();
@@ -1678,19 +1652,11 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
break;
}
}
// 如果是常量变量且所有索引都是常量,并且不是数组名单独出现的情况
if (allIndicesConstant && !dims.empty()) {
if (allIndicesConstant) {
// 如果是常量变量且所有索引都是常量,直接通过 getByIndices 获取编译时值
// 这个方法会根据索引深度返回最终的标量值或指向子数组的指针 (作为 ConstantValue/Variable)
return constVar->getByIndices(dims);
}
// 如果dims为空检查是否是常量标量
if (dims.empty() && declaredNumDims == 0) {
// 常量标量,直接返回其值
// 默认传入空索引列表,表示访问标量本身
return constVar->getByIndices(dims);
}
// 如果dims为空但不是标量数组名单独出现需要走GEP路径来实现数组到指针的退化
}
// 3. 处理可变变量 (AllocaInst/GlobalValue) 或带非常量索引的常量变量
@@ -1700,8 +1666,7 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
if (dims.empty() && declaredNumDims == 0) {
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable)) {
targetAddress = variable;
}
else {
} else {
assert(false && "Unhandled scalar variable type in LValue access.");
return static_cast<Value*>(nullptr);
}
@@ -1716,39 +1681,16 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
} else {
gepBasePointer = alloc;
gepIndices.push_back(ConstantInteger::get(0));
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());
}
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
}
} else if (GlobalValue *glob = dynamic_cast<GlobalValue *>(variable)) {
gepBasePointer = glob;
gepIndices.push_back(ConstantInteger::get(0));
if (dims.empty() && declaredNumDims > 0) {
// 全局数组名单独出现(没有索引):应该退化为指向第一行的指针
// 需要添加一个额外的i32 0索引
gepIndices.push_back(ConstantInteger::get(0));
} else {
// 正常的数组元素访问
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
}
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
} else if (ConstantVariable *constV = dynamic_cast<ConstantVariable *>(variable)) {
gepBasePointer = constV;
gepIndices.push_back(ConstantInteger::get(0));
if (dims.empty() && declaredNumDims > 0) {
// 常量数组名单独出现(没有索引):应该退化为指向第一行的指针
// 需要添加一个额外的i32 0索引
gepIndices.push_back(ConstantInteger::get(0));
} else {
// 正常的数组元素访问
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
}
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
} else {
assert(false && "LValue variable type not supported for GEP base pointer.");
return static_cast<Value *>(nullptr);
@@ -1830,10 +1772,10 @@ std::any SysYIRGenerator::visitCall(SysYParser::CallContext *ctx) {
// 获取形参列表。`getArguments()` 返回的是 `Argument*` 的集合,
// 每个 `Argument` 代表一个函数形参,其 `getType()` 就是指向形参的类型的指针类型。
const auto& formalParams = function->getArguments();
auto formalParams = function->getArguments();
// 检查实参和形参数量是否匹配。
if (args.size() != function->getNumArguments()) {
if (args.size() != formalParams.size()) {
std::cerr << "Error: Function call argument count mismatch for function '" << funcName << "'." << std::endl;
assert(false && "Function call argument count mismatch!");
}
@@ -1865,27 +1807,15 @@ std::any SysYIRGenerator::visitCall(SysYParser::CallContext *ctx) {
} else if (formalParamExpectedValueType->isFloat() && actualArgType->isInt()) {
args[i] = builder.createItoFInst(args[i]);
}
// 2. 指针类型转换 (例如数组退化:`[N x T]*` 到 `T*`,或兼容指针类型之间)
// 2. 指针类型转换 (例如数组退化:`[N x T]*` 到 `T*`,或兼容指针类型之间) TODO不清楚有没有这种样例
// 这种情况常见于数组参数,实参可能是一个更具体的数组指针类型,
// 而形参是其退化后的基础指针类型。
else if (formalParamExpectedValueType->isPointer() && actualArgType->isPointer()) {
// 检查是否是数组指针到元素指针的decay
// 例如:[N x T]* -> T*
auto formalPtrType = formalParamExpectedValueType->as<PointerType>();
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);
}
}
}
// 而形参是其退化后的基础指针类型。LLVM 的 `bitcast` 指令可以用于
// 在相同大小的指针类型之间进行转换,这对于数组退化至关重要。
// else if (formalParamType->isPointer() && actualArgType->isPointer()) {
// 检查指针基类型是否兼容,或者是否是数组退化导致的类型不同。
// 使用 bitcast
// args[i] = builder.createBitCastInst(args[i], formalParamType);
// }
// 3. 其他未预期的类型不匹配
// 如果代码执行到这里,说明存在编译器前端未处理的类型不兼容或错误。
else {
@@ -2269,23 +2199,15 @@ void Utils::createExternalFunction(
const std::vector<std::string> &paramNames,
const std::vector<std::vector<Value *>> &paramDims, Type *returnType,
const std::string &funcName, Module *pModule, IRBuilder *pBuilder) {
// 根据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 funcType = Type::getFunctionType(returnType, paramTypes);
auto function = pModule->createExternalFunction(funcName, funcType);
auto entry = function->getEntryBlock();
pBuilder->setPosition(entry, entry->end());
for (int i = 0; i < paramTypes.size(); ++i) {
auto arg = new Argument(adjustedParamTypes[i], function, i, paramNames[i]);
auto arg = new Argument(paramTypes[i], function, i, paramNames[i]);
auto alloca = pBuilder->createAllocaInst(
Type::getPointerType(adjustedParamTypes[i]), paramNames[i]);
Type::getPointerType(paramTypes[i]), paramNames[i]);
function->insertArgument(arg);
auto store = pBuilder->createStoreInst(arg, alloca);
pModule->addVariable(paramNames[i], alloca);

View File

@@ -110,7 +110,6 @@ int main(int argc, char **argv) {
// 如果指定停止在 AST 阶段,则打印并退出
if (argStopAfter == "ast") {
cout << moduleAST->toStringTree(true) << '\n';
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}
@@ -133,7 +132,7 @@ int main(int argc, char **argv) {
if (DEBUG) {
cout << "=== Init IR ===\n";
moduleIR->print(cout); // 使用新实现的print方法直接打印IR
SysYPrinter(moduleIR).printIR(); // 临时打印器用于调试
}
// 创建 Pass 管理器并运行优化管道
@@ -145,26 +144,10 @@ int main(int argc, char **argv) {
// a) 如果指定停止在 IR 阶段,则打印最终 IR 并退出
if (argStopAfter == "ir" || argStopAfter == "ird") {
// 打印最终 IR
if (DEBUG) cerr << "=== Final IR ===\n";
if (!argOutputFilename.empty()) {
// 输出到指定文件
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(); // 清理内存池
cout << "=== Final IR ===\n";
SysYPrinter printer(moduleIR); // 在这里创建打印器,因为可能之前调试时用过临时打印器
printer.printIR();
return EXIT_SUCCESS;
}
// b) 如果未停止在 IR 阶段,则继续生成汇编 (后端)
@@ -183,8 +166,6 @@ int main(int argc, char **argv) {
ofstream fout(argOutputFilename);
if (not fout.is_open()) {
cerr << "Failed to open output file: " << argOutputFilename << endl;
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_FAILURE;
}
fout << asmCode << endl;
@@ -192,8 +173,6 @@ int main(int argc, char **argv) {
} else {
cout << asmCode << endl;
}
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}
@@ -202,7 +181,5 @@ int main(int argc, char **argv) {
cout << "Compilation completed. No output specified (neither -s nor -S). Exiting.\n";
// return EXIT_SUCCESS; // 或者这里调用一个链接器生成可执行文件
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}

View File

@@ -1 +0,0 @@
3

View File

@@ -1,3 +0,0 @@
int main(){
return 3;
}

View File

@@ -1 +0,0 @@
10

View File

@@ -1,8 +0,0 @@
//test domain of global var define and local define
int a = 3;
int b = 5;
int main(){
int a = 5;
return a + b;
}

View File

@@ -1 +0,0 @@
5

View File

@@ -1,8 +0,0 @@
//test local var define
int main(){
int a, b0, _c;
a = 1;
b0 = 2;
_c = 3;
return b0 + _c;
}

View File

@@ -1 +0,0 @@
0

View File

@@ -1,4 +0,0 @@
int a[10][10];
int main(){
return 0;
}

View File

@@ -1 +0,0 @@
14

View File

@@ -1,9 +0,0 @@
//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];
}

View File

@@ -1 +0,0 @@
21

View File

@@ -1,9 +0,0 @@
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];
}

View File

@@ -1 +0,0 @@
5

View File

@@ -1,6 +0,0 @@
//test const gloal var define
const int a = 10, b = 5;
int main(){
return b;
}

View File

@@ -1 +0,0 @@
5

View File

@@ -1,5 +0,0 @@
//test const local var define
int main(){
const int a = 10, b = 5;
return b;
}

View File

@@ -1 +0,0 @@
4

View File

@@ -1,5 +0,0 @@
const int a[5]={0,1,2,3,4};
int main(){
return a[4];
}

View File

@@ -1 +0,0 @@
9

View File

@@ -1,11 +0,0 @@
int a;
int func(int p){
p = p - 1;
return p;
}
int main(){
int b;
a = 10;
b = func(a);
return b;
}

View File

@@ -1 +0,0 @@
4

View File

@@ -1,8 +0,0 @@
int defn(){
return 4;
}
int main(){
int a=defn();
return a;
}

View File

@@ -1 +0,0 @@
9

View File

@@ -1,7 +0,0 @@
//test add
int main(){
int a, b;
a = 10;
b = -1;
return a + b;
}

View File

@@ -1 +0,0 @@
15

View File

@@ -1,5 +0,0 @@
//test addc
const int a = 10;
int main(){
return a + 5;
}

View File

@@ -1 +0,0 @@
248

View File

@@ -1,7 +0,0 @@
//test sub
const int a = 10;
int main(){
int b;
b = 2;
return b - a;
}

View File

@@ -1 +0,0 @@
8

View File

@@ -1,6 +0,0 @@
//test subc
int main(){
int a;
a = 10;
return a - 2;
}

View File

@@ -1 +0,0 @@
50

View File

@@ -1,7 +0,0 @@
//test mul
int main(){
int a, b;
a = 10;
b = 5;
return a * b;
}

View File

@@ -1 +0,0 @@
25

View File

@@ -1,5 +0,0 @@
//test mulc
const int a = 5;
int main(){
return a * 5;
}

View File

@@ -1 +0,0 @@
2

View File

@@ -1,7 +0,0 @@
//test div
int main(){
int a, b;
a = 10;
b = 5;
return a / b;
}

View File

@@ -1 +0,0 @@
2

View File

@@ -1,5 +0,0 @@
//test divc
const int a = 10;
int main(){
return a / 5;
}

View File

@@ -1 +0,0 @@
3

View File

@@ -1,6 +0,0 @@
//test mod
int main(){
int a;
a = 10;
return a / 3;
}

View File

@@ -1 +0,0 @@
1

View File

@@ -1,6 +0,0 @@
//test rem
int main(){
int a;
a = 10;
return a % 3;
}

View File

@@ -1,2 +0,0 @@
-5
0

View File

@@ -1,25 +0,0 @@
// 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;
}

View File

@@ -1 +0,0 @@
25

View File

@@ -1,18 +0,0 @@
// 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());
}

View File

@@ -1 +0,0 @@
25

View File

@@ -1,18 +0,0 @@
// 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_());
}

View File

@@ -1 +0,0 @@
25

View File

@@ -1,18 +0,0 @@
// 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());
}

View File

@@ -1,2 +0,0 @@
88
0

View File

@@ -1,31 +0,0 @@
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;
}

View File

@@ -1 +0,0 @@
3

View File

@@ -1,18 +0,0 @@
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();
}

View File

@@ -1 +0,0 @@
54

View File

@@ -1,31 +0,0 @@
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();
}

View File

@@ -1 +0,0 @@
23

View File

@@ -1,55 +0,0 @@
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