Compare commits
14 Commits
SCCP
...
deploy-202
| Author | SHA1 | Date | |
|---|---|---|---|
| ef4bdfc8eb | |||
| 0e492cd6d7 | |||
| 2040670f8c | |||
| b20bda2f52 | |||
| 20a5c5cbfb | |||
| cf88ca77cb | |||
| fd6fe22020 | |||
| e8fe710c26 | |||
| 9c87cb397b | |||
| c45938d41d | |||
| 3baccbc03a | |||
| 24d8e730f1 | |||
| bbfbf96b5e | |||
| f7e811b756 |
11
README.md
11
README.md
@ -37,13 +37,4 @@ mysysy/ $ bash setup.sh
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 配套脚本
|
### 配套脚本
|
||||||
(TODO: 需要完善)
|
(TODO: 需要完善)
|
||||||
|
|
||||||
|
|
||||||
### TODO_list:
|
|
||||||
|
|
||||||
除开注释中的TODO后续时间充足可以考虑的TODO:
|
|
||||||
|
|
||||||
- store load指令由于gep指令的引入, 维度信息的记录是非必须的, 考虑删除
|
|
||||||
|
|
||||||
- use def关系经过mem2reg和phi函数明确转换为ssa形式, 以及函数参数通过value数组明确定义, 使得基本块的args参数信息记录非必须, 考虑删除
|
|
||||||
@ -57,11 +57,22 @@ bool AddressCalculationExpansion::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (GlobalValue* globalValue = dynamic_cast<GlobalValue*>(basePointer)) {
|
} else if (GlobalValue* globalValue = dynamic_cast<GlobalValue*>(basePointer)) {
|
||||||
std::cerr << "Warning: GlobalValue dimension handling needs explicit implementation for GEP expansion. Skipping GEP for: ";
|
// 遍历 GlobalValue 的所有维度操作数
|
||||||
SysYPrinter::printValue(globalValue);
|
for (const auto& use_ptr : globalValue->getDims()) {
|
||||||
std::cerr << "\n";
|
Value* dimValue = use_ptr->getValue();
|
||||||
++it;
|
// 将维度值转换为常量整数
|
||||||
continue;
|
if (ConstantInteger* constVal = dynamic_cast<ConstantInteger*>(dimValue)) {
|
||||||
|
dims.push_back(constVal->getInt());
|
||||||
|
} else {
|
||||||
|
// 如果维度不是常量整数,则无法处理。
|
||||||
|
// 根据 IR.h 中 GlobalValue 的构造函数,这种情况不应发生,但作为安全检查是好的。
|
||||||
|
std::cerr << "Warning: GlobalValue dimension is not a constant integer. Skipping GEP expansion for: ";
|
||||||
|
SysYPrinter::printValue(globalValue);
|
||||||
|
std::cerr << "\n";
|
||||||
|
dims.clear(); // 清空已收集的部分维度信息
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Warning: Base pointer is not AllocaInst/GlobalValue or its array dimensions cannot be determined for GEP expansion. Skipping GEP for: ";
|
std::cerr << "Warning: Base pointer is not AllocaInst/GlobalValue or its array dimensions cannot be determined for GEP expansion. Skipping GEP for: ";
|
||||||
SysYPrinter::printValue(basePointer);
|
SysYPrinter::printValue(basePointer);
|
||||||
|
|||||||
@ -21,8 +21,8 @@ add_executable(sysyc
|
|||||||
IR.cpp
|
IR.cpp
|
||||||
SysYIRGenerator.cpp
|
SysYIRGenerator.cpp
|
||||||
SysYIRPrinter.cpp
|
SysYIRPrinter.cpp
|
||||||
SysYIRCFGOpt.cpp
|
SysYIROptPre.cpp
|
||||||
# SysYIRAnalyser.cpp
|
SysYIRAnalyser.cpp
|
||||||
# DeadCodeElimination.cpp
|
# DeadCodeElimination.cpp
|
||||||
AddressCalculationExpansion.cpp
|
AddressCalculationExpansion.cpp
|
||||||
# Mem2Reg.cpp
|
# Mem2Reg.cpp
|
||||||
|
|||||||
@ -1,259 +0,0 @@
|
|||||||
#include "DeadCodeElimination.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
extern int DEBUG;
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
void DeadCodeElimination::runDCEPipeline() {
|
|
||||||
const auto& functions = pModule->getFunctions();
|
|
||||||
for (const auto& function : functions) {
|
|
||||||
const auto& func = function.second;
|
|
||||||
bool changed = true;
|
|
||||||
while (changed) {
|
|
||||||
changed = false;
|
|
||||||
eliminateDeadStores(func.get(), changed);
|
|
||||||
eliminateDeadLoads(func.get(), changed);
|
|
||||||
eliminateDeadAllocas(func.get(), changed);
|
|
||||||
eliminateDeadRedundantLoadStore(func.get(), changed);
|
|
||||||
eliminateDeadGlobals(changed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消除无用存储 消除条件:
|
|
||||||
// 存储的目标指针(pointer)不是全局变量(!isGlobal(pointer))。
|
|
||||||
// 存储的目标指针不是数组参数(!isArr(pointer) 或不在函数参数列表里)。
|
|
||||||
// 该指针的所有使用者(uses)仅限 alloca 或 store(即没有 load 或其他指令使用它)。
|
|
||||||
void DeadCodeElimination::eliminateDeadStores(Function* func, bool& changed) {
|
|
||||||
for (const auto& block : func->getBasicBlocks()) {
|
|
||||||
auto& instrs = block->getInstructions();
|
|
||||||
for (auto iter = instrs.begin(); iter != instrs.end();) {
|
|
||||||
auto inst = iter->get();
|
|
||||||
if (!inst->isStore()) {
|
|
||||||
++iter;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto storeInst = dynamic_cast<StoreInst*>(inst);
|
|
||||||
auto pointer = storeInst->getPointer();
|
|
||||||
// 如果是全局变量或者是函数的数组参数
|
|
||||||
if (SysYIROptUtils::isGlobal(pointer) || (SysYIROptUtils::isArr(pointer) &&
|
|
||||||
std::find(func->getEntryBlock()->getArguments().begin(),
|
|
||||||
func->getEntryBlock()->getArguments().end(),
|
|
||||||
pointer) != func->getEntryBlock()->getArguments().end())) {
|
|
||||||
++iter;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool changetag = true;
|
|
||||||
for (auto& use : pointer->getUses()) {
|
|
||||||
// 依次判断store的指针是否被其他指令使用
|
|
||||||
auto user = use->getUser();
|
|
||||||
auto userInst = dynamic_cast<Instruction*>(user);
|
|
||||||
// 如果使用store的指针的指令不是Alloca或Store,则不删除
|
|
||||||
if (userInst != nullptr && !userInst->isAlloca() && !userInst->isStore()) {
|
|
||||||
changetag = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changetag) {
|
|
||||||
changed = true;
|
|
||||||
if(DEBUG){
|
|
||||||
std::cout << "=== Dead Store Found ===\n";
|
|
||||||
SysYPrinter::printInst(storeInst);
|
|
||||||
}
|
|
||||||
SysYIROptUtils::usedelete(storeInst);
|
|
||||||
iter = instrs.erase(iter);
|
|
||||||
} else {
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 消除无用加载 消除条件:
|
|
||||||
// 该指令的结果未被使用(inst->getUses().empty())。
|
|
||||||
void DeadCodeElimination::eliminateDeadLoads(Function* func, bool& changed) {
|
|
||||||
for (const auto& block : func->getBasicBlocks()) {
|
|
||||||
auto& instrs = block->getInstructions();
|
|
||||||
for (auto iter = instrs.begin(); iter != instrs.end();) {
|
|
||||||
auto inst = iter->get();
|
|
||||||
if (inst->isBinary() || inst->isUnary() || inst->isLoad()) {
|
|
||||||
if (inst->getUses().empty()) {
|
|
||||||
changed = true;
|
|
||||||
if(DEBUG){
|
|
||||||
std::cout << "=== Dead Load Binary Unary Found ===\n";
|
|
||||||
SysYPrinter::printInst(inst);
|
|
||||||
}
|
|
||||||
SysYIROptUtils::usedelete(inst);
|
|
||||||
iter = instrs.erase(iter);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消除无用加载 消除条件:
|
|
||||||
// 该 alloca 未被任何指令使用(allocaInst->getUses().empty())。
|
|
||||||
// 该 alloca 不是函数的参数(不在 entry 块的参数列表里)。
|
|
||||||
void DeadCodeElimination::eliminateDeadAllocas(Function* func, bool& changed) {
|
|
||||||
for (const auto& block : func->getBasicBlocks()) {
|
|
||||||
auto& instrs = block->getInstructions();
|
|
||||||
for (auto iter = instrs.begin(); iter != instrs.end();) {
|
|
||||||
auto inst = iter->get();
|
|
||||||
if (inst->isAlloca()) {
|
|
||||||
auto allocaInst = dynamic_cast<AllocaInst*>(inst);
|
|
||||||
if (allocaInst->getUses().empty() &&
|
|
||||||
std::find(func->getEntryBlock()->getArguments().begin(),
|
|
||||||
func->getEntryBlock()->getArguments().end(),
|
|
||||||
allocaInst) == func->getEntryBlock()->getArguments().end()) {
|
|
||||||
changed = true;
|
|
||||||
if(DEBUG){
|
|
||||||
std::cout << "=== Dead Alloca Found ===\n";
|
|
||||||
SysYPrinter::printInst(inst);
|
|
||||||
}
|
|
||||||
SysYIROptUtils::usedelete(inst);
|
|
||||||
iter = instrs.erase(iter);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeadCodeElimination::eliminateDeadIndirectiveAllocas(Function* func, bool& changed) {
|
|
||||||
// 删除mem2reg时引入的且现在已经没有value使用了的隐式alloca
|
|
||||||
FunctionAnalysisInfo* funcInfo = pCFA->getFunctionAnalysisInfo(func);
|
|
||||||
for (auto it = funcInfo->getIndirectAllocas().begin(); it != funcInfo->getIndirectAllocas().end();) {
|
|
||||||
auto &allocaInst = *it;
|
|
||||||
if (allocaInst->getUses().empty()) {
|
|
||||||
changed = true;
|
|
||||||
if(DEBUG){
|
|
||||||
std::cout << "=== Dead Indirect Alloca Found ===\n";
|
|
||||||
SysYPrinter::printInst(allocaInst.get());
|
|
||||||
}
|
|
||||||
it = funcInfo->getIndirectAllocas().erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 该全局变量未被任何指令使用(global->getUses().empty())。
|
|
||||||
void DeadCodeElimination::eliminateDeadGlobals(bool& changed) {
|
|
||||||
auto& globals = pModule->getGlobals();
|
|
||||||
for (auto it = globals.begin(); it != globals.end();) {
|
|
||||||
auto& global = *it;
|
|
||||||
if (global->getUses().empty()) {
|
|
||||||
changed = true;
|
|
||||||
if(DEBUG){
|
|
||||||
std::cout << "=== Dead Global Found ===\n";
|
|
||||||
SysYPrinter::printValue(global.get());
|
|
||||||
}
|
|
||||||
it = globals.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消除冗余加载和存储 消除条件:
|
|
||||||
// phi 指令的目标指针仅被该 phi 使用(无其他 store/load 使用)。
|
|
||||||
// memset 指令的目标指针未被使用(pointer->getUses().empty())
|
|
||||||
// store -> load -> store 模式
|
|
||||||
void DeadCodeElimination::eliminateDeadRedundantLoadStore(Function* func, bool& changed) {
|
|
||||||
for (const auto& block : func->getBasicBlocks()) {
|
|
||||||
auto& instrs = block->getInstructions();
|
|
||||||
for (auto iter = instrs.begin(); iter != instrs.end();) {
|
|
||||||
auto inst = iter->get();
|
|
||||||
if (inst->isPhi()) {
|
|
||||||
auto phiInst = dynamic_cast<PhiInst*>(inst);
|
|
||||||
auto pointer = phiInst->getPointer();
|
|
||||||
bool tag = true;
|
|
||||||
for (const auto& use : pointer->getUses()) {
|
|
||||||
auto user = use->getUser();
|
|
||||||
if (user != inst) {
|
|
||||||
tag = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// 如果 pointer 仅被该 phi 使用,可以删除 ph
|
|
||||||
if (tag) {
|
|
||||||
changed = true;
|
|
||||||
SysYIROptUtils::usedelete(inst);
|
|
||||||
iter = instrs.erase(iter);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 数组指令还不完善,不保证memset优化效果
|
|
||||||
} else if (inst->isMemset()) {
|
|
||||||
auto memsetInst = dynamic_cast<MemsetInst*>(inst);
|
|
||||||
auto pointer = memsetInst->getPointer();
|
|
||||||
if (pointer->getUses().empty()) {
|
|
||||||
changed = true;
|
|
||||||
SysYIROptUtils::usedelete(inst);
|
|
||||||
iter = instrs.erase(iter);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}else if(inst->isLoad()) {
|
|
||||||
if (iter != instrs.begin()) {
|
|
||||||
auto loadInst = dynamic_cast<LoadInst*>(inst);
|
|
||||||
auto loadPointer = loadInst->getPointer();
|
|
||||||
// TODO:store -> load -> store 模式
|
|
||||||
auto prevIter = std::prev(iter);
|
|
||||||
auto prevInst = prevIter->get();
|
|
||||||
if (prevInst->isStore()) {
|
|
||||||
auto prevStore = dynamic_cast<StoreInst*>(prevInst);
|
|
||||||
auto prevStorePointer = prevStore->getPointer();
|
|
||||||
auto prevStoreValue = prevStore->getOperand(0);
|
|
||||||
// 确保前一个 store 不是数组操作
|
|
||||||
if (prevStore->getIndices().empty()) {
|
|
||||||
// 检查后一条指令是否是 store 同一个值
|
|
||||||
auto nextIter = std::next(iter);
|
|
||||||
if (nextIter != instrs.end()) {
|
|
||||||
auto nextInst = nextIter->get();
|
|
||||||
if (nextInst->isStore()) {
|
|
||||||
auto nextStore = dynamic_cast<StoreInst*>(nextInst);
|
|
||||||
auto nextStorePointer = nextStore->getPointer();
|
|
||||||
auto nextStoreValue = nextStore->getOperand(0);
|
|
||||||
// 确保后一个 store 不是数组操作
|
|
||||||
if (nextStore->getIndices().empty()) {
|
|
||||||
// 判断优化条件:
|
|
||||||
// 1. prevStore 的指针操作数 == load 的指针操作数
|
|
||||||
// 2. nextStore 的值操作数 == load 指令本身
|
|
||||||
if (prevStorePointer == loadPointer &&
|
|
||||||
nextStoreValue == loadInst) {
|
|
||||||
// 可以优化直接把prevStorePointer的值存到nextStorePointer
|
|
||||||
changed = true;
|
|
||||||
nextStore->setOperand(0, prevStoreValue);
|
|
||||||
if(DEBUG){
|
|
||||||
std::cout << "=== Dead Store Load Store Found(now only del Load) ===\n";
|
|
||||||
SysYPrinter::printInst(prevStore);
|
|
||||||
SysYPrinter::printInst(loadInst);
|
|
||||||
SysYPrinter::printInst(nextStore);
|
|
||||||
}
|
|
||||||
SysYIROptUtils::usedelete(loadInst);
|
|
||||||
iter = instrs.erase(iter);
|
|
||||||
// 删除 prevStore 这里是不是可以留给删除无用store处理?
|
|
||||||
// if (prevStore->getUses().empty()) {
|
|
||||||
// usedelete(prevStore);
|
|
||||||
// instrs.erase(prevIter); // 删除 prevStore
|
|
||||||
// }
|
|
||||||
continue; // 跳过 ++iter,因为已经移动迭代器
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
53
src/IR.cpp
53
src/IR.cpp
@ -49,11 +49,6 @@ auto Type::getFunctionType(Type *returnType, const std::vector<Type *> ¶mTyp
|
|||||||
return FunctionType::get(returnType, paramTypes);
|
return FunctionType::get(returnType, paramTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Type::getArrayType(Type *elementType, unsigned numElements) -> Type * {
|
|
||||||
// forward to ArrayType
|
|
||||||
return ArrayType::get(elementType, numElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Type::getSize() const -> unsigned {
|
auto Type::getSize() const -> unsigned {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case kInt:
|
case kInt:
|
||||||
@ -63,10 +58,6 @@ auto Type::getSize() const -> unsigned {
|
|||||||
case kPointer:
|
case kPointer:
|
||||||
case kFunction:
|
case kFunction:
|
||||||
return 8;
|
return 8;
|
||||||
case Kind::kArray: {
|
|
||||||
const ArrayType* arrType = static_cast<const ArrayType*>(this);
|
|
||||||
return arrType->getElementType()->getSize() * arrType->getNumElements();
|
|
||||||
}
|
|
||||||
case kVoid:
|
case kVoid:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -104,11 +95,6 @@ FunctionType*FunctionType::get(Type *returnType, const std::vector<Type *> ¶
|
|||||||
return result.first->get();
|
return result.first->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayType *ArrayType::get(Type *elementType, unsigned numElements) {
|
|
||||||
// TODO:可以考虑在这里添加缓存,避免重复创建相同的数组类型
|
|
||||||
return new ArrayType(elementType, numElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Value::replaceAllUsesWith(Value *value) {
|
void Value::replaceAllUsesWith(Value *value) {
|
||||||
for (auto &use : uses) {
|
for (auto &use : uses) {
|
||||||
use->getUser()->setOperand(use->getIndex(), value);
|
use->getUser()->setOperand(use->getIndex(), value);
|
||||||
@ -479,7 +465,44 @@ Function * Function::clone(const std::string &suffix) const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:复制GEP指令
|
case Instruction::kLa: {
|
||||||
|
auto oldLaInst = dynamic_cast<LaInst *>(inst);
|
||||||
|
auto oldPointer = oldLaInst->getPointer();
|
||||||
|
Value *newPointer;
|
||||||
|
std::vector<Value *> newIndices;
|
||||||
|
newPointer = oldNewValueMap.at(oldPointer);
|
||||||
|
|
||||||
|
for (const auto &index : oldLaInst->getIndices()) {
|
||||||
|
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||||
|
}
|
||||||
|
ss << oldLaInst->getName() << suffix;
|
||||||
|
auto newLaInst = new LaInst(newPointer, newIndices, oldNewBlockMap.at(oldLaInst->getParent()), ss.str());
|
||||||
|
ss.str("");
|
||||||
|
oldNewValueMap.emplace(oldLaInst, newLaInst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Instruction::kGetSubArray: {
|
||||||
|
auto oldGetSubArrayInst = dynamic_cast<GetSubArrayInst *>(inst);
|
||||||
|
auto oldFather = oldGetSubArrayInst->getFatherArray();
|
||||||
|
auto oldChild = oldGetSubArrayInst->getChildArray();
|
||||||
|
Value *newFather;
|
||||||
|
Value *newChild;
|
||||||
|
std::vector<Value *> newIndices;
|
||||||
|
newFather = oldNewValueMap.at(oldFather);
|
||||||
|
newChild = oldNewValueMap.at(oldChild);
|
||||||
|
|
||||||
|
for (const auto &index : oldGetSubArrayInst->getIndices()) {
|
||||||
|
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||||
|
}
|
||||||
|
ss << oldGetSubArrayInst->getName() << suffix;
|
||||||
|
auto newGetSubArrayInst =
|
||||||
|
new GetSubArrayInst(dynamic_cast<LVal *>(newFather), dynamic_cast<LVal *>(newChild), newIndices,
|
||||||
|
oldNewBlockMap.at(oldGetSubArrayInst->getParent()), ss.str());
|
||||||
|
ss.str("");
|
||||||
|
oldNewValueMap.emplace(oldGetSubArrayInst, newGetSubArrayInst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Instruction::kMemset: {
|
case Instruction::kMemset: {
|
||||||
auto oldMemsetInst = dynamic_cast<MemsetInst *>(inst);
|
auto oldMemsetInst = dynamic_cast<MemsetInst *>(inst);
|
||||||
|
|||||||
515
src/Mem2Reg.cpp
515
src/Mem2Reg.cpp
@ -1,515 +0,0 @@
|
|||||||
#include "Mem2Reg.h"
|
|
||||||
#include "SysYIRPrinter.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <memory>
|
|
||||||
#include <queue>
|
|
||||||
#include <stack>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
// --- 私有成员函数实现 ---
|
|
||||||
|
|
||||||
// 计算给定定义块集合的迭代支配边界
|
|
||||||
std::unordered_set<BasicBlock*> Mem2Reg::computeIteratedDomFrontiers(const std::unordered_set<BasicBlock*>& blocks) {
|
|
||||||
std::unordered_set<BasicBlock*> result;
|
|
||||||
std::queue<BasicBlock*> worklist; // 使用队列进行 BFS-like 遍历
|
|
||||||
|
|
||||||
for (auto* block : blocks)
|
|
||||||
worklist.push(block);
|
|
||||||
|
|
||||||
while (!worklist.empty()) {
|
|
||||||
auto* block = worklist.front();
|
|
||||||
worklist.pop();
|
|
||||||
|
|
||||||
auto* blockInfo = controlFlowAnalysis->getBlockAnalysisInfo(block);
|
|
||||||
if (!blockInfo) continue;
|
|
||||||
|
|
||||||
for (auto* df : blockInfo->getDomFrontiers()) {
|
|
||||||
if (result.find(df) == result.end()) { // If not already in result
|
|
||||||
result.insert(df);
|
|
||||||
worklist.push(df);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分析一个 alloca 的所有 uses,填充 allocaDefsBlock 和 allocaUsesBlock
|
|
||||||
void Mem2Reg::allocaAnalysis(AllocaInst* alloca) {
|
|
||||||
allocaDefsBlock[alloca].clear();
|
|
||||||
allocaUsesBlock[alloca].clear();
|
|
||||||
|
|
||||||
for (auto use : alloca->getUses()) {
|
|
||||||
Instruction* userInst = dynamic_cast<Instruction*>(use->getUser());
|
|
||||||
if (!userInst) continue;
|
|
||||||
|
|
||||||
if (StoreInst* store = dynamic_cast<StoreInst*>(userInst)) {
|
|
||||||
if (store->getOperand(1) == alloca) { // Store's second operand is the pointer
|
|
||||||
allocaDefsBlock[alloca].insert(store->getParent()); // Store's parent is the defining block
|
|
||||||
}
|
|
||||||
} else if (LoadInst* load = dynamic_cast<LoadInst*>(userInst)) {
|
|
||||||
if (load->getOperand(0) == alloca) { // Load's first operand is the pointer
|
|
||||||
allocaUsesBlock[alloca].insert(load->getParent()); // Load's parent is the using block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断一个 alloca 是否可以被提升为寄存器 (无地址逃逸,标量类型)
|
|
||||||
bool Mem2Reg::is_promoted(AllocaInst* alloca) {
|
|
||||||
// 检查是否是标量类型 (非数组、非全局变量等)
|
|
||||||
if(!(SysYIROptUtils::isArr(alloca) || SysYIROptUtils::isGlobal(alloca))){
|
|
||||||
return false; // 只有标量类型的 alloca 才能被提升
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取 alloca 指向的基类型
|
|
||||||
PointerType* ptrType = dynamic_cast<PointerType*>(alloca->getType());
|
|
||||||
if (!ptrType) return false; // Should always be a pointer type
|
|
||||||
Type* allocabaseType = ptrType->getBaseType();
|
|
||||||
|
|
||||||
for (const auto& use : alloca->getUses()) {
|
|
||||||
Instruction* userInst = dynamic_cast<Instruction*>(use->getUser());
|
|
||||||
if (!userInst) {
|
|
||||||
// 如果不是指令的 use,比如作为全局变量的初始值等,通常认为逃逸
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LoadInst* load = dynamic_cast<LoadInst*>(userInst)) {
|
|
||||||
// Load 指令结果的类型必须与 alloca 的基类型一致
|
|
||||||
if (load->getType() != allocabaseType) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (StoreInst* store = dynamic_cast<StoreInst*>(userInst)) {
|
|
||||||
// Store 指令的值操作数类型必须与 alloca 的基类型一致
|
|
||||||
// 且 store 的指针操作数必须是当前 alloca
|
|
||||||
if (store->getOperand(1) != alloca || store->getOperand(0)->getType() != allocabaseType) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (userInst->isGetSubArray()) {
|
|
||||||
// GSA 指令表示对数组的访问
|
|
||||||
// 这意味着地址逃逸,不能简单提升为单个寄存器
|
|
||||||
return false;
|
|
||||||
} else if (userInst->isCall()) {
|
|
||||||
// 如果 alloca 作为函数参数传递,通常认为地址逃逸
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 如果有其他类型的指令使用 alloca 的地址,也需要判断是否是逃逸
|
|
||||||
// 例如:BitCastInst, PtrToIntInst, 如果这些操作将地址暴露,则不能提升
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在迭代支配边界处插入 Phi 指令
|
|
||||||
void Mem2Reg::insertPhiNodes(Function* func) {
|
|
||||||
// 清空上次 Phi 插入的结果
|
|
||||||
phiMap.clear();
|
|
||||||
allPhiInstructions.clear();
|
|
||||||
|
|
||||||
std::unordered_set<BasicBlock*> phiPlacementBlocks; // 存放需要插入 Phi 的块
|
|
||||||
std::queue<BasicBlock*> workQueue; // BFS 队列,用于迭代支配边界计算
|
|
||||||
|
|
||||||
// 遍历所有可提升的 alloca
|
|
||||||
for (AllocaInst* alloca : currentFunctionAllocas) {
|
|
||||||
phiPlacementBlocks.clear(); // 为每个 alloca 重新计算 Phi 放置位置
|
|
||||||
|
|
||||||
// 初始化工作队列,放入所有定义该 alloca 的基本块
|
|
||||||
for (BasicBlock* defBB : allocaDefsBlock[alloca]) {
|
|
||||||
workQueue.push(defBB);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!workQueue.empty()) {
|
|
||||||
BasicBlock* currentBB = workQueue.front();
|
|
||||||
workQueue.pop();
|
|
||||||
|
|
||||||
auto* blockInfo = controlFlowAnalysis->getBlockAnalysisInfo(currentBB);
|
|
||||||
if (!blockInfo) continue;
|
|
||||||
|
|
||||||
// 遍历当前块的支配边界
|
|
||||||
for (BasicBlock* domFrontierBB : blockInfo->getDomFrontiers()) {
|
|
||||||
// 如果这个支配边界块还没有为当前 alloca 插入 Phi 指令
|
|
||||||
if (phiPlacementBlocks.find(domFrontierBB) == phiPlacementBlocks.end()) {
|
|
||||||
// 获取 alloca 的基类型,作为 Phi 指令的结果类型
|
|
||||||
Type* phiType = dynamic_cast<PointerType*>(alloca->getType())->getBaseType();
|
|
||||||
|
|
||||||
// 在支配边界块的开头插入 Phi 指令
|
|
||||||
pBuilder->setPosition(domFrontierBB->begin());
|
|
||||||
PhiInst* newPhi = pBuilder->createPhiInst(phiType, {}, {}); // 初始入边为空
|
|
||||||
|
|
||||||
allPhiInstructions.push_back(newPhi); // 记录所有 Phi
|
|
||||||
phiPlacementBlocks.insert(domFrontierBB); // 标记已插入
|
|
||||||
|
|
||||||
// 将 Phi 指令映射到它所代表的原始 alloca
|
|
||||||
phiMap[domFrontierBB][newPhi] = alloca;
|
|
||||||
|
|
||||||
// 如果支配边界块本身没有定义该 alloca,则其支配边界也可能需要 Phi
|
|
||||||
// 只有当这个块不是当前alloca的定义块时,才将其加入workQueue,以计算其DF。
|
|
||||||
if (allocaDefsBlock[alloca].find(domFrontierBB) == allocaDefsBlock[alloca].end()) {
|
|
||||||
workQueue.push(domFrontierBB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取前驱块在后继块前驱列表中的索引
|
|
||||||
int Mem2Reg::getPredIndex(BasicBlock* pred, BasicBlock* succ) {
|
|
||||||
int index = 0;
|
|
||||||
for (auto* elem : succ->getPredecessors()) {
|
|
||||||
if (elem == pred) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
// 断言通常在你的 IR 框架中应该确保前驱是存在的
|
|
||||||
// assert(false && "Predecessor not found in successor's predecessor list");
|
|
||||||
return -1; // 应该不会发生
|
|
||||||
}
|
|
||||||
|
|
||||||
// 递归地重命名基本块中的变量并填充 Phi 指令
|
|
||||||
void Mem2Reg::renameBlock(BasicBlock* block,
|
|
||||||
std::unordered_map<AllocaInst*, Value*>& currentIncomings,
|
|
||||||
std::unordered_set<BasicBlock*>& visitedBlocks) {
|
|
||||||
|
|
||||||
// 记录在此块中发生的定义,以便在退出时将它们从栈中弹出
|
|
||||||
std::unordered_map<AllocaInst*, int> definitionsInBlockCount;
|
|
||||||
|
|
||||||
// 如果已经访问过这个块,直接返回(防止无限循环或重复处理,在DFS中尤其重要)
|
|
||||||
if (visitedBlocks.count(block)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
visitedBlocks.insert(block);
|
|
||||||
|
|
||||||
// --- 1. 处理当前基本块内的指令 ---
|
|
||||||
// 使用迭代器安全地遍历和删除指令
|
|
||||||
for (auto it = block->getInstructions().begin(); it != block->getInstructions().end(); ) {
|
|
||||||
Instruction* currentInst = it->get();
|
|
||||||
|
|
||||||
if (AllocaInst* alloca = dynamic_cast<AllocaInst*>(currentInst)) {
|
|
||||||
// 如果是可提升的 alloca,标记为删除
|
|
||||||
if (std::find(currentFunctionAllocas.begin(), currentFunctionAllocas.end(), alloca) != currentFunctionAllocas.end()) {
|
|
||||||
SysYIROptUtils::usedelete(currentInst); // 标记为删除(或直接删除取决于你的 IR 管理)
|
|
||||||
it = block->getInstructions().erase(it); // 从列表中移除
|
|
||||||
continue; // 继续下一个指令
|
|
||||||
}
|
|
||||||
} else if (LoadInst* load = dynamic_cast<LoadInst*>(currentInst)) {
|
|
||||||
AllocaInst* originalAlloca = dynamic_cast<AllocaInst*>(load->getOperand(0)); // load 的第一个操作数是指针
|
|
||||||
if (originalAlloca && std::find(currentFunctionAllocas.begin(), currentFunctionAllocas.end(), originalAlloca) != currentFunctionAllocas.end()) {
|
|
||||||
// 如果是可提升 alloca 的 load 指令
|
|
||||||
Value* incomingVal = nullptr;
|
|
||||||
if (currentIncomings.count(originalAlloca)) {
|
|
||||||
incomingVal = currentIncomings[originalAlloca];
|
|
||||||
} else {
|
|
||||||
// 如果在当前路径上没有找到定义,则使用 UndefinedValue
|
|
||||||
incomingVal = UndefinedValue::get(originalAlloca->getType()->isPointer() ?
|
|
||||||
dynamic_cast<PointerType*>(originalAlloca->getType())->getBaseType() :
|
|
||||||
originalAlloca->getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
load->replaceAllUsesWith(incomingVal); // 用最新值替换所有 load 的用途
|
|
||||||
SysYIROptUtils::usedelete(currentInst);
|
|
||||||
it = block->getInstructions().erase(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (StoreInst* store = dynamic_cast<StoreInst*>(currentInst)) {
|
|
||||||
AllocaInst* originalAlloca = dynamic_cast<AllocaInst*>(store->getOperand(1)); // store 的第二个操作数是指针
|
|
||||||
if (originalAlloca && std::find(currentFunctionAllocas.begin(), currentFunctionAllocas.end(), originalAlloca) != currentFunctionAllocas.end()) {
|
|
||||||
// 如果是可提升 alloca 的 store 指令,更新当前值
|
|
||||||
currentIncomings[originalAlloca] = store->getOperand(0); // store 的第一个操作数是值
|
|
||||||
definitionsInBlockCount[originalAlloca]++; // 记录在该块中进行的定义数量
|
|
||||||
SysYIROptUtils::usedelete(currentInst);
|
|
||||||
it = block->getInstructions().erase(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (PhiInst* phi = dynamic_cast<PhiInst*>(currentInst)) {
|
|
||||||
// 如果是 Mem2Reg 插入的 Phi 指令 (通过 phiMap 判断)
|
|
||||||
if (phiMap[block].count(phi)) {
|
|
||||||
AllocaInst* originalAlloca = phiMap[block][phi];
|
|
||||||
currentIncomings[originalAlloca] = phi; // Phi 指令本身成为该变量的新定义
|
|
||||||
definitionsInBlockCount[originalAlloca]++; // 记录该 Phi 的定义
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++it; // 移动到下一个指令
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 2. 填充后继基本块中 Phi 指令的入边 ---
|
|
||||||
for (BasicBlock* successorBB : block->getSuccessors()) {
|
|
||||||
int predIndex = getPredIndex(block, successorBB);
|
|
||||||
if (predIndex == -1) continue;
|
|
||||||
|
|
||||||
// Phi 指令总是在基本块的开头
|
|
||||||
for (auto& inst_ptr : successorBB->getInstructions()) {
|
|
||||||
if (PhiInst* phi = dynamic_cast<PhiInst*>(inst_ptr.get())) {
|
|
||||||
if (phiMap[successorBB].count(phi)) { // 确保这是我们关心的 Phi 指令
|
|
||||||
AllocaInst* originalAlloca = phiMap[successorBB][phi];
|
|
||||||
Value* incomingValue = nullptr;
|
|
||||||
|
|
||||||
if (currentIncomings.count(originalAlloca)) {
|
|
||||||
incomingValue = currentIncomings[originalAlloca];
|
|
||||||
} else {
|
|
||||||
// 如果在当前块没有找到对应的定义,使用 UndefinedValue
|
|
||||||
incomingValue = UndefinedValue::get(originalAlloca->getType()->isPointer() ?
|
|
||||||
dynamic_cast<PointerType*>(originalAlloca->getType())->getBaseType() :
|
|
||||||
originalAlloca->getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (incomingValue) {
|
|
||||||
phi->addIncoming(incomingValue, block); // 添加 (值, 前驱块) 对
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 遇到非 Phi 指令,说明已经处理完所有 Phi,可以跳出
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 3. 递归调用支配树的子节点 ---
|
|
||||||
auto* blockInfo = controlFlowAnalysis->getBlockAnalysisInfo(block);
|
|
||||||
if (blockInfo) {
|
|
||||||
for (BasicBlock* dominatedChildBB : blockInfo->getSdoms()) { // getSdoms 获取直接支配的子节点
|
|
||||||
// 递归调用,传递当前 Incomings 的副本(或通过值传递以实现回溯)
|
|
||||||
// 注意:这里是传递 `currentIncomings` 的拷贝,以便递归返回后可以恢复。
|
|
||||||
// 但如果 `currentIncomings` 是引用传递,则这里需要回溯逻辑。
|
|
||||||
// 鉴于它是值传递,此处的 `definitionsInBlockCount` 仅用于统计,无需实际操作 `currentIncomings`。
|
|
||||||
renameBlock(dominatedChildBB, currentIncomings, visitedBlocks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 4. 回溯:从栈中弹出在此块中创建的所有定义 ---
|
|
||||||
for (auto const& [alloca, count] : definitionsInBlockCount) {
|
|
||||||
// 在我们的实现中,`currentIncomings` 是通过值传递的,每次递归都收到一个新的拷贝。
|
|
||||||
// 因此,不需要显式地 "pop" 栈。`currentIncomings` 在函数返回时会自动销毁。
|
|
||||||
// 这种方式模拟了 "SSA 栈" 的行为,每个函数调用帧有自己的局部定义环境。
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 简化冗余的 Phi 指令 (当所有输入都相同时)
|
|
||||||
void Mem2Reg::simplifyphi(PhiInst* phi) {
|
|
||||||
BasicBlock* phifromblock = phi->getParent();
|
|
||||||
if (!phifromblock) return; // 指令可能已经被删除
|
|
||||||
|
|
||||||
Value* commonValue = nullptr;
|
|
||||||
bool allSame = true;
|
|
||||||
|
|
||||||
// Phi 指令的操作数是 Value, BasicBlock 交替出现,所以是 getOperandSize() / 2 个入边
|
|
||||||
if (phi->getNumOperands() == 0) { // 空 Phi,通常是无效的,直接删除
|
|
||||||
phi->replaceAllUsesWith(UndefinedValue::get(phi->getType())); // 用 UndefinedValue 替换所有用途
|
|
||||||
// phi->getParent()->delete_inst(phi);
|
|
||||||
// 删除 Phi 指令后直接返回
|
|
||||||
// phi指令在开头一个比较快
|
|
||||||
// TODO:后续可优化查找
|
|
||||||
auto tofind = std::find_if(phifromblock->getInstructions().begin(), phifromblock->getInstructions().end(),
|
|
||||||
[phi](const auto &instr) { return instr.get() == phi; });
|
|
||||||
SysYIROptUtils::usedelete(phi); // 使用 SysYIROptUtils 删除指令
|
|
||||||
phifromblock->getInstructions().erase(tofind);
|
|
||||||
// 从基本块中删除 Phi 指令
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < phi->getNumIncomingValues(); ++i) {
|
|
||||||
Value* incomingVal = phi->getOperand(2 * i); // 值位于偶数索引
|
|
||||||
|
|
||||||
if (incomingVal == phi) { // 如果 Phi 指令引用自身 (循环变量)
|
|
||||||
// 这种情况下,Phi 暂时不能简化,除非所有入边都是它自己,这通常通过其他优化处理
|
|
||||||
// 为避免复杂性,我们在此处不处理自引用 Phi 的简化,除非它是唯一选择。
|
|
||||||
// 更好的做法是,如果所有入边都指向自身,则该Phi是冗余的,可以替换为undef或其第一个实际值
|
|
||||||
// 但这需要更复杂的分析来确定循环的初始值。目前简单返回。
|
|
||||||
// TODO:留到后续循环优化处理
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commonValue == nullptr) {
|
|
||||||
commonValue = incomingVal;
|
|
||||||
} else if (commonValue != incomingVal) {
|
|
||||||
allSame = false;
|
|
||||||
break; // 发现不同的入边值
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allSame && commonValue != nullptr) {
|
|
||||||
// 所有入边值都相同,用这个值替换 Phi 指令的所有用途
|
|
||||||
phi->replaceAllUsesWith(commonValue);
|
|
||||||
// 从基本块中删除 Phi 指令
|
|
||||||
auto tofind = std::find_if(phifromblock->getInstructions().begin(), phifromblock->getInstructions().end(),
|
|
||||||
[phi](const auto &instr) { return instr.get() == phi; });
|
|
||||||
SysYIROptUtils::usedelete(phi); // 使用 SysYIROptUtils 删除指令
|
|
||||||
phifromblock->getInstructions().erase(tofind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对单个函数执行内存到寄存器的提升
|
|
||||||
bool Mem2Reg::promoteMemoryToRegisters(Function* func) {
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
// 每次开始对一个函数进行 Mem2Reg 时,清空所有上下文信息
|
|
||||||
currentFunctionAllocas.clear();
|
|
||||||
allocaDefsBlock.clear();
|
|
||||||
allocaUsesBlock.clear();
|
|
||||||
phiMap.clear();
|
|
||||||
allPhiInstructions.clear();
|
|
||||||
|
|
||||||
// 1. 收集所有可提升的 AllocaInst,并进行初步分析
|
|
||||||
BasicBlock* entryBB = func->getEntryBlock();
|
|
||||||
if (!entryBB) return false;
|
|
||||||
|
|
||||||
// 逆序遍历入口块的指令,安全地识别 Alloca
|
|
||||||
for (auto it = entryBB->getInstructions().rbegin(); it != entryBB->getInstructions().rend(); ++it) {
|
|
||||||
if (AllocaInst* alloca = dynamic_cast<AllocaInst*>(it->get())) {
|
|
||||||
if (is_promoted(alloca)) {
|
|
||||||
currentFunctionAllocas.push_back(alloca);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 收集后反转,使其按原始顺序排列 (如果需要的话,但对后续分析影响不大)
|
|
||||||
std::reverse(currentFunctionAllocas.begin(), currentFunctionAllocas.end());
|
|
||||||
|
|
||||||
// 对收集到的所有 alloca 进行 DefsBlock 和 UsesBlock 分析
|
|
||||||
for (AllocaInst* alloca : currentFunctionAllocas) {
|
|
||||||
allocaAnalysis(alloca);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 预处理:删除无用的 AllocaInst (没有 Load 和 Store)
|
|
||||||
// 迭代 currentFunctionAllocas,安全删除
|
|
||||||
for (unsigned int i = 0; i < currentFunctionAllocas.size(); ) {
|
|
||||||
AllocaInst* alloca = currentFunctionAllocas[i];
|
|
||||||
|
|
||||||
bool hasRelevantUse = false;
|
|
||||||
// 检查 alloca 的 uses 列表,看是否有 Load 或 Store
|
|
||||||
// 只要有 Load/Store,就认为是"相关用途",不删除
|
|
||||||
for (auto use_ptr : alloca->getUses()) {
|
|
||||||
Instruction* user_inst = dynamic_cast<Instruction*>(use_ptr->getUser());
|
|
||||||
if (user_inst && (dynamic_cast<LoadInst*>(user_inst) || dynamic_cast<StoreInst*>(user_inst))) {
|
|
||||||
hasRelevantUse = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果没有相关用途(没有 Load 和 Store),则 alloca 是死代码
|
|
||||||
if (!hasRelevantUse && allocaDefsBlock[alloca].empty() && allocaUsesBlock[alloca].empty()) {
|
|
||||||
if (alloca->getParent()) {
|
|
||||||
// alloca->getParent()->delete_inst(alloca); // 从其所在块删除 alloca 指令
|
|
||||||
auto tofind = std::find_if(alloca->getParent()->getInstructions().begin(), alloca->getParent()->getInstructions().end(),
|
|
||||||
[alloca](const auto &instr) { return instr.get() == alloca; });
|
|
||||||
SysYIROptUtils::usedelete(alloca);
|
|
||||||
alloca->getParent()->getInstructions().erase(tofind);
|
|
||||||
}
|
|
||||||
currentFunctionAllocas.erase(currentFunctionAllocas.begin() + i); // 从列表中移除
|
|
||||||
changed = true; // 发生了改变
|
|
||||||
} else {
|
|
||||||
i++; // 否则,移动到下一个 alloca
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果没有可提升的 alloca 了,直接返回
|
|
||||||
if (currentFunctionAllocas.empty()) {
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 插入 Phi 指令
|
|
||||||
insertPhiNodes(func);
|
|
||||||
if (!allPhiInstructions.empty()) changed = true;
|
|
||||||
|
|
||||||
// 4. 重命名变量,转换为 SSA 形式并填充 Phi 指令
|
|
||||||
std::unordered_map<AllocaInst*, Value*> initialIncomings;
|
|
||||||
std::unordered_set<BasicBlock*> visitedBlocks; // 用于 DFS 遍历,防止循环
|
|
||||||
|
|
||||||
// 初始化 entry block 的 Incomings 状态
|
|
||||||
for (AllocaInst* alloca : currentFunctionAllocas) {
|
|
||||||
initialIncomings[alloca] = UndefinedValue::get(dynamic_cast<PointerType*>(alloca->getType())->getBaseType());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从入口块开始递归重命名
|
|
||||||
renameBlock(entryBB, initialIncomings, visitedBlocks);
|
|
||||||
|
|
||||||
// 5. 简化 Phi 指令
|
|
||||||
// 由于 renameBlock 可能会删除 Phi,这里复制一份列表以安全迭代
|
|
||||||
std::vector<PhiInst*> phisToSimplify = allPhiInstructions;
|
|
||||||
for (PhiInst* phi : phisToSimplify) {
|
|
||||||
// 检查 phi 是否还在 IR 中 (可能已被其他优化删除)
|
|
||||||
// 一个简单检查是看它是否有父块
|
|
||||||
if (phi->getParent()) {
|
|
||||||
simplifyphi(phi);
|
|
||||||
// simplifyphi 内部会删除 Phi,所以这里不需要再处理 allPhiInstructions
|
|
||||||
// 最终的 allPhiInstructions 清理将在 promoteMemoryToRegisters 结束后进行
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理所有 Phi 的列表和映射
|
|
||||||
// 遍历 allPhiInstructions,删除那些在 simplifyphi 后可能仍然存在的、但已经没有 uses 的 Phi
|
|
||||||
std::vector<PhiInst*> remainingPhis;
|
|
||||||
for(PhiInst* phi : allPhiInstructions) {
|
|
||||||
if(phi->getParent() && phi->getUses().empty()){ // 如果还在IR中但没有用处
|
|
||||||
|
|
||||||
// phi->getParent()->delete_inst(phi);
|
|
||||||
// 找到phi节点对应的迭代器
|
|
||||||
auto tofind = std::find_if(phi->getParent()->getInstructions().begin(), phi->getParent()->getInstructions().end(),
|
|
||||||
[phi](const auto &instr) { return instr.get() == phi; });
|
|
||||||
SysYIROptUtils::usedelete(phi); // 使用 SysYIROptUtils 删除指令
|
|
||||||
phi->getParent()->getInstructions().erase(tofind);
|
|
||||||
|
|
||||||
changed = true;
|
|
||||||
} else if (phi->getParent()) { // 仍在IR中且有uses
|
|
||||||
remainingPhis.push_back(phi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allPhiInstructions = remainingPhis; // 更新为仅包含未被删除的 Phi
|
|
||||||
|
|
||||||
// 重新清理 phiMap 中已经删除的 Phi 指令项
|
|
||||||
for (auto& pairBBPhiMap : phiMap) {
|
|
||||||
std::vector<PhiInst*> phisToRemoveFromMap;
|
|
||||||
for (auto& pairPhiAlloca : pairBBPhiMap.second) {
|
|
||||||
if (!pairPhiAlloca.first->getParent()) { // 如果 Phi 已经被删除
|
|
||||||
phisToRemoveFromMap.push_back(pairPhiAlloca.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (PhiInst* phi : phisToRemoveFromMap) {
|
|
||||||
pairBBPhiMap.second.erase(phi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- run函数实现 ---
|
|
||||||
void Mem2Reg::run() {
|
|
||||||
// 每次运行整个 Mem2Reg Pass 时,重新进行分析
|
|
||||||
controlFlowAnalysis->clear();
|
|
||||||
controlFlowAnalysis->runControlFlowAnalysis();
|
|
||||||
activeVarAnalysis->clear();
|
|
||||||
// 假设 dataFlowAnalysisUtils 可以管理和运行各个分析器
|
|
||||||
dataFlowAnalysisUtils.addBackwardAnalyzer(activeVarAnalysis);
|
|
||||||
dataFlowAnalysisUtils.backwardAnalyze(pModule); // 运行活跃变量分析
|
|
||||||
|
|
||||||
bool globalChanged = false;
|
|
||||||
// 循环直到没有更多的 alloca 可以被提升
|
|
||||||
// 每次 promoteMemoryToRegisters 会尝试在一个函数内完成所有 Mem2Reg 优化
|
|
||||||
do {
|
|
||||||
globalChanged = false;
|
|
||||||
for (const auto& [_, func] : pModule->getFunctions()) {
|
|
||||||
// 对每个函数执行 Mem2Reg
|
|
||||||
if (promoteMemoryToRegisters(func.get())) {
|
|
||||||
globalChanged = true;
|
|
||||||
// 如果一个函数发生改变,可能影响其他函数或需要重新分析
|
|
||||||
// 因此需要重新运行控制流和活跃变量分析,以备下一次循环
|
|
||||||
controlFlowAnalysis->clear();
|
|
||||||
controlFlowAnalysis->runControlFlowAnalysis();
|
|
||||||
activeVarAnalysis->clear();
|
|
||||||
dataFlowAnalysisUtils.backwardAnalyze(pModule); // 重新分析活跃变量
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (globalChanged); // 如果全局有任何函数发生改变,则继续迭代
|
|
||||||
|
|
||||||
// 最终清理和重新分析
|
|
||||||
controlFlowAnalysis->clear();
|
|
||||||
controlFlowAnalysis->runControlFlowAnalysis();
|
|
||||||
activeVarAnalysis->clear();
|
|
||||||
dataFlowAnalysisUtils.backwardAnalyze(pModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@ -18,7 +18,7 @@ bool isMemoryOp(RVOpcodes opcode) {
|
|||||||
|
|
||||||
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
|
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
|
||||||
|
|
||||||
void RISCv64AsmPrinter::run(std::ostream& os) {
|
void RISCv64AsmPrinter::run(std::ostream& os, bool debug) {
|
||||||
OS = &os;
|
OS = &os;
|
||||||
|
|
||||||
*OS << ".globl " << MFunc->getName() << "\n";
|
*OS << ".globl " << MFunc->getName() << "\n";
|
||||||
@ -27,7 +27,7 @@ void RISCv64AsmPrinter::run(std::ostream& os) {
|
|||||||
printPrologue();
|
printPrologue();
|
||||||
|
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
for (auto& mbb : MFunc->getBlocks()) {
|
||||||
printBasicBlock(mbb.get());
|
printBasicBlock(mbb.get(), debug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ void RISCv64AsmPrinter::printPrologue() {
|
|||||||
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
|
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
|
||||||
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||||
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||||
*OS << " mv s0, sp\n";
|
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 忠实还原保存函数入口参数的逻辑
|
// 忠实还原保存函数入口参数的逻辑
|
||||||
@ -73,24 +73,31 @@ void RISCv64AsmPrinter::printEpilogue() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb) {
|
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
|
||||||
if (!mbb->getName().empty()) {
|
if (!mbb->getName().empty()) {
|
||||||
*OS << mbb->getName() << ":\n";
|
*OS << mbb->getName() << ":\n";
|
||||||
}
|
}
|
||||||
for (auto& instr : mbb->getInstructions()) {
|
for (auto& instr : mbb->getInstructions()) {
|
||||||
printInstruction(instr.get());
|
printInstruction(instr.get(), debug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
|
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||||
auto opcode = instr->getOpcode();
|
auto opcode = instr->getOpcode();
|
||||||
if (opcode == RVOpcodes::RET) {
|
if (opcode == RVOpcodes::RET) {
|
||||||
printEpilogue();
|
printEpilogue();
|
||||||
}
|
}
|
||||||
if (opcode != RVOpcodes::LABEL) {
|
|
||||||
*OS << " ";
|
if (opcode == RVOpcodes::LABEL) {
|
||||||
|
// 标签直接打印,不加缩进
|
||||||
|
printOperand(instr->getOperands()[0].get());
|
||||||
|
*OS << ":\n";
|
||||||
|
return; // 处理完毕,直接返回
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 对于所有非标签指令,先打印缩进
|
||||||
|
*OS << " ";
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
|
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
|
||||||
case RVOpcodes::ADDW: *OS << "addw "; break; case RVOpcodes::ADDIW: *OS << "addiw "; break;
|
case RVOpcodes::ADDW: *OS << "addw "; break; case RVOpcodes::ADDIW: *OS << "addiw "; break;
|
||||||
@ -126,13 +133,21 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
|
|||||||
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
||||||
case RVOpcodes::CALL: *OS << "call "; break;
|
case RVOpcodes::CALL: *OS << "call "; break;
|
||||||
case RVOpcodes::LABEL:
|
case RVOpcodes::LABEL:
|
||||||
printOperand(instr->getOperands()[0].get());
|
// printOperand(instr->getOperands()[0].get());
|
||||||
*OS << ":";
|
// *OS << ":";
|
||||||
break;
|
break;
|
||||||
case RVOpcodes::FRAME_LOAD:
|
case RVOpcodes::FRAME_LOAD:
|
||||||
|
// It should have been eliminated by RegAlloc
|
||||||
|
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||||
|
*OS << "frame_load "; break;
|
||||||
case RVOpcodes::FRAME_STORE:
|
case RVOpcodes::FRAME_STORE:
|
||||||
// These should have been eliminated by RegAlloc
|
// It should have been eliminated by RegAlloc
|
||||||
throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||||
|
*OS << "frame_store "; break;
|
||||||
|
case RVOpcodes::FRAME_ADDR:
|
||||||
|
// It should have been eliminated by RegAlloc
|
||||||
|
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||||
|
*OS << "frame_addr "; break;
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Unknown opcode in AsmPrinter");
|
throw std::runtime_error("Unknown opcode in AsmPrinter");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,10 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
RISCv64ISel isel;
|
RISCv64ISel isel;
|
||||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||||
|
|
||||||
|
std::stringstream ss1;
|
||||||
|
RISCv64AsmPrinter printer1(mfunc.get());
|
||||||
|
printer1.run(ss1, true);
|
||||||
|
|
||||||
// 阶段 2: 指令调度 (Instruction Scheduling)
|
// 阶段 2: 指令调度 (Instruction Scheduling)
|
||||||
PreRA_Scheduler scheduler;
|
PreRA_Scheduler scheduler;
|
||||||
scheduler.runOnMachineFunction(mfunc.get());
|
scheduler.runOnMachineFunction(mfunc.get());
|
||||||
@ -81,7 +85,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
RISCv64AsmPrinter printer(mfunc.get());
|
RISCv64AsmPrinter printer(mfunc.get());
|
||||||
printer.run(ss);
|
printer.run(ss);
|
||||||
|
if (DEBUG) ss << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <cmath> // For std::fabs
|
#include <cmath> // For std::fabs
|
||||||
#include <limits> // For std::numeric_limits
|
#include <limits> // For std::numeric_limits
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@ -82,6 +83,10 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
|
|||||||
CurMBB = bb_map.at(bb);
|
CurMBB = bb_map.at(bb);
|
||||||
auto dag = build_dag(bb);
|
auto dag = build_dag(bb);
|
||||||
|
|
||||||
|
if (DEBUG) { // 使用 DEBUG 宏或变量来控制是否打印
|
||||||
|
print_dag(dag, bb->getName());
|
||||||
|
}
|
||||||
|
|
||||||
std::map<Value*, DAGNode*> value_to_node;
|
std::map<Value*, DAGNode*> value_to_node;
|
||||||
for(const auto& node : dag) {
|
for(const auto& node : dag) {
|
||||||
if (node->value) {
|
if (node->value) {
|
||||||
@ -92,6 +97,10 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
|
|||||||
std::set<DAGNode*> selected_nodes;
|
std::set<DAGNode*> selected_nodes;
|
||||||
std::function<void(DAGNode*)> select_recursive =
|
std::function<void(DAGNode*)> select_recursive =
|
||||||
[&](DAGNode* node) {
|
[&](DAGNode* node) {
|
||||||
|
if (DEEPDEBUG) {
|
||||||
|
std::cout << "[DEEPDEBUG] select_recursive: Visiting node with kind: " << node->kind
|
||||||
|
<< " (Value: " << (node->value ? node->value->getName() : "null") << ")" << std::endl;
|
||||||
|
}
|
||||||
if (!node || selected_nodes.count(node)) return;
|
if (!node || selected_nodes.count(node)) return;
|
||||||
for (auto operand : node->operands) {
|
for (auto operand : node->operands) {
|
||||||
select_recursive(operand);
|
select_recursive(operand);
|
||||||
@ -118,24 +127,37 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 核心函数:为DAG节点选择并生成MachineInstr (忠实移植版)
|
// 核心函数:为DAG节点选择并生成MachineInstr (已修复和增强的完整版本)
|
||||||
void RISCv64ISel::selectNode(DAGNode* node) {
|
void RISCv64ISel::selectNode(DAGNode* node) {
|
||||||
|
// 调用者(select_recursive)已经保证了操作数节点会先于当前节点被选择。
|
||||||
|
// 因此,这里我们只处理当前节点。
|
||||||
|
|
||||||
switch (node->kind) {
|
switch (node->kind) {
|
||||||
|
// [V2优点] 采纳“延迟物化”(Late Materialization)思想。
|
||||||
|
// 这两个节点仅作为标记,不直接生成指令。它们的目的是在DAG中保留类型信息。
|
||||||
|
// 加载其值的责任,被转移给了使用它们的父节点(如STORE, BINARY等)。
|
||||||
|
// 这修复了之前版本中“使用未初始化虚拟寄存器”的根本性bug。
|
||||||
case DAGNode::CONSTANT:
|
case DAGNode::CONSTANT:
|
||||||
case DAGNode::ALLOCA_ADDR:
|
case DAGNode::ALLOCA_ADDR:
|
||||||
if (node->value) getVReg(node->value);
|
if (node->value) {
|
||||||
|
// 确保它有一个关联的虚拟寄存器即可,不生成代码。
|
||||||
|
getVReg(node->value);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DAGNode::LOAD: {
|
case DAGNode::LOAD: {
|
||||||
auto dest_vreg = getVReg(node->value);
|
auto dest_vreg = getVReg(node->value);
|
||||||
Value* ptr_val = node->operands[0]->value;
|
Value* ptr_val = node->operands[0]->value;
|
||||||
|
|
||||||
|
// [V1设计保留] 对于从栈变量加载,继续使用伪指令 FRAME_LOAD。
|
||||||
|
// 这种设计将栈帧布局的具体计算推迟到后续的 `eliminateFrameIndices` 阶段,保持了模块化。
|
||||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_LOAD);
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_LOAD);
|
||||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
||||||
CurMBB->addInstruction(std::move(instr));
|
CurMBB->addInstruction(std::move(instr));
|
||||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||||
|
// 对于全局变量,先用 la 加载其地址,再用 lw 加载其值。
|
||||||
auto addr_vreg = getNewVReg();
|
auto addr_vreg = getNewVReg();
|
||||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||||
@ -150,6 +172,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
));
|
));
|
||||||
CurMBB->addInstruction(std::move(lw));
|
CurMBB->addInstruction(std::move(lw));
|
||||||
} else {
|
} else {
|
||||||
|
// 对于已经在虚拟寄存器中的指针地址,直接通过该地址加载。
|
||||||
auto ptr_vreg = getVReg(ptr_val);
|
auto ptr_vreg = getVReg(ptr_val);
|
||||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
@ -166,7 +189,13 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
Value* val_to_store = node->operands[0]->value;
|
Value* val_to_store = node->operands[0]->value;
|
||||||
Value* ptr_val = node->operands[1]->value;
|
Value* ptr_val = node->operands[1]->value;
|
||||||
|
|
||||||
|
// [V2优点] 在STORE节点内部负责加载作为源的常量。
|
||||||
|
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它。
|
||||||
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
|
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "[DEBUG] selectNode-BINARY: Found constant operand with value " << val_const->getInt()
|
||||||
|
<< ". Generating LI instruction." << std::endl;
|
||||||
|
}
|
||||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
||||||
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
||||||
@ -174,13 +203,15 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
}
|
}
|
||||||
auto val_vreg = getVReg(val_to_store);
|
auto val_vreg = getVReg(val_to_store);
|
||||||
|
|
||||||
|
// [V1设计保留] 同样,对于向栈变量的存储,使用 FRAME_STORE 伪指令。
|
||||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_STORE);
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_STORE);
|
||||||
instr->addOperand(std::make_unique<RegOperand>(val_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
||||||
CurMBB->addInstruction(std::move(instr));
|
CurMBB->addInstruction(std::move(instr));
|
||||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||||
auto addr_vreg = getNewVReg();
|
// 向全局变量存储。
|
||||||
|
auto addr_vreg = getNewVReg();
|
||||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||||
@ -194,6 +225,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
));
|
));
|
||||||
CurMBB->addInstruction(std::move(sw));
|
CurMBB->addInstruction(std::move(sw));
|
||||||
} else {
|
} else {
|
||||||
|
// 向一个指针(存储在虚拟寄存器中)指向的地址存储。
|
||||||
auto ptr_vreg = getVReg(ptr_val);
|
auto ptr_vreg = getVReg(ptr_val);
|
||||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||||
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
|
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||||
@ -210,37 +242,108 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
||||||
Value* lhs = bin->getLhs();
|
Value* lhs = bin->getLhs();
|
||||||
Value* rhs = bin->getRhs();
|
Value* rhs = bin->getRhs();
|
||||||
|
|
||||||
|
if (bin->getKind() == BinaryInst::kAdd) {
|
||||||
|
Value* base = nullptr;
|
||||||
|
Value* offset = nullptr;
|
||||||
|
|
||||||
|
// [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
|
||||||
|
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
|
||||||
|
base = lhs;
|
||||||
|
offset = rhs;
|
||||||
|
} else if (dynamic_cast<AllocaInst*>(rhs) || dynamic_cast<GlobalValue*>(rhs)) {
|
||||||
|
base = rhs;
|
||||||
|
offset = lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果成功匹配到地址计算模式
|
||||||
|
if (base) {
|
||||||
|
// 1. 先为偏移量加载常量(如果它是常量的话)
|
||||||
|
if (auto const_offset = dynamic_cast<ConstantValue*>(offset)) {
|
||||||
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
|
li->addOperand(std::make_unique<RegOperand>(getVReg(const_offset)));
|
||||||
|
li->addOperand(std::make_unique<ImmOperand>(const_offset->getInt()));
|
||||||
|
CurMBB->addInstruction(std::move(li));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
|
||||||
|
auto base_addr_vreg = getNewVReg(); // 创建一个新的临时vreg来存放基地址
|
||||||
|
|
||||||
|
// 情况一:基地址是局部栈变量
|
||||||
|
if (auto alloca_base = dynamic_cast<AllocaInst*>(base)) {
|
||||||
|
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
|
||||||
|
frame_addr_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
|
||||||
|
frame_addr_instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca_base)));
|
||||||
|
CurMBB->addInstruction(std::move(frame_addr_instr));
|
||||||
|
}
|
||||||
|
// 情况二:基地址是全局变量
|
||||||
|
else if (auto global_base = dynamic_cast<GlobalValue*>(base)) {
|
||||||
|
auto la_instr = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||||
|
la_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
|
||||||
|
la_instr->addOperand(std::make_unique<LabelOperand>(global_base->getName()));
|
||||||
|
CurMBB->addInstruction(std::move(la_instr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 生成真正的add指令,计算最终地址(这部分逻辑保持不变)
|
||||||
|
auto final_addr_vreg = getVReg(bin); // 这是整个二元运算的结果vreg
|
||||||
|
auto offset_vreg = getVReg(offset);
|
||||||
|
auto add_instr = std::make_unique<MachineInstr>(RVOpcodes::ADD); // 指针运算是64位
|
||||||
|
add_instr->addOperand(std::make_unique<RegOperand>(final_addr_vreg));
|
||||||
|
add_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
|
||||||
|
add_instr->addOperand(std::make_unique<RegOperand>(offset_vreg));
|
||||||
|
CurMBB->addInstruction(std::move(add_instr));
|
||||||
|
|
||||||
|
return; // 地址计算处理完毕,直接返回
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [V2优点] 在BINARY节点内部按需加载常量操作数。
|
||||||
auto load_val_if_const = [&](Value* val) {
|
auto load_val_if_const = [&](Value* val) {
|
||||||
if (auto c = dynamic_cast<ConstantValue*>(val)) {
|
if (auto c = dynamic_cast<ConstantValue*>(val)) {
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "[DEBUG] selectNode-BINARY: Found constant operand with value " << c->getInt()
|
||||||
|
<< ". Generating LI instruction." << std::endl;
|
||||||
|
}
|
||||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
li->addOperand(std::make_unique<RegOperand>(getVReg(c)));
|
li->addOperand(std::make_unique<RegOperand>(getVReg(c)));
|
||||||
li->addOperand(std::make_unique<ImmOperand>(c->getInt()));
|
li->addOperand(std::make_unique<ImmOperand>(c->getInt()));
|
||||||
CurMBB->addInstruction(std::move(li));
|
CurMBB->addInstruction(std::move(li));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
load_val_if_const(lhs);
|
|
||||||
load_val_if_const(rhs);
|
|
||||||
|
|
||||||
auto dest_vreg = getVReg(bin);
|
// 检查是否能应用立即数优化。
|
||||||
auto lhs_vreg = getVReg(lhs);
|
bool rhs_is_imm_opt = false;
|
||||||
auto rhs_vreg = getVReg(rhs);
|
if (auto rhs_const = dynamic_cast<ConstantValue*>(rhs)) {
|
||||||
|
if (bin->getKind() == BinaryInst::kAdd && rhs_const->getInt() >= -2048 && rhs_const->getInt() < 2048) {
|
||||||
if (bin->getKind() == BinaryInst::kAdd) {
|
rhs_is_imm_opt = true;
|
||||||
if (auto rhs_const = dynamic_cast<ConstantValue*>(rhs)) {
|
|
||||||
if (rhs_const->getInt() >= -2048 && rhs_const->getInt() < 2048) {
|
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
|
||||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
|
||||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
|
||||||
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
|
|
||||||
CurMBB->addInstruction(std::move(instr));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 仅在不能作为立即数操作数时才需要提前加载。
|
||||||
|
load_val_if_const(lhs);
|
||||||
|
if (!rhs_is_imm_opt) {
|
||||||
|
load_val_if_const(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dest_vreg = getVReg(bin);
|
||||||
|
auto lhs_vreg = getVReg(lhs);
|
||||||
|
|
||||||
|
// [V2优点] 融合 ADDIW 优化。
|
||||||
|
if (rhs_is_imm_opt) {
|
||||||
|
auto rhs_const = dynamic_cast<ConstantValue*>(rhs);
|
||||||
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
||||||
|
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
|
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||||
|
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
|
||||||
|
CurMBB->addInstruction(std::move(instr));
|
||||||
|
return; // 指令已生成,直接返回。
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rhs_vreg = getVReg(rhs);
|
||||||
|
|
||||||
switch (bin->getKind()) {
|
switch (bin->getKind()) {
|
||||||
case BinaryInst::kAdd: {
|
case BinaryInst::kAdd: {
|
||||||
|
// 区分指针运算(64位)和整数运算(32位)。
|
||||||
RVOpcodes opcode = (lhs->getType()->isPointer() || rhs->getType()->isPointer()) ? RVOpcodes::ADD : RVOpcodes::ADDW;
|
RVOpcodes opcode = (lhs->getType()->isPointer() || rhs->getType()->isPointer()) ? RVOpcodes::ADD : RVOpcodes::ADDW;
|
||||||
auto instr = std::make_unique<MachineInstr>(opcode);
|
auto instr = std::make_unique<MachineInstr>(opcode);
|
||||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
@ -281,7 +384,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(instr));
|
CurMBB->addInstruction(std::move(instr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BinaryInst::kICmpEQ: {
|
case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz)
|
||||||
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||||
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||||
@ -294,7 +397,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(seqz));
|
CurMBB->addInstruction(std::move(seqz));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BinaryInst::kICmpNE: {
|
case BinaryInst::kICmpNE: { // 不等于 (a != b) -> (subw; snez)
|
||||||
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||||
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||||
@ -307,7 +410,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(snez));
|
CurMBB->addInstruction(std::move(snez));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BinaryInst::kICmpLT: {
|
case BinaryInst::kICmpLT: { // 小于 (a < b) -> slt
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||||
@ -315,7 +418,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(instr));
|
CurMBB->addInstruction(std::move(instr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BinaryInst::kICmpGT: {
|
case BinaryInst::kICmpGT: { // 大于 (a > b) -> (b < a) -> slt
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||||
@ -323,7 +426,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(instr));
|
CurMBB->addInstruction(std::move(instr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BinaryInst::kICmpLE: {
|
case BinaryInst::kICmpLE: { // 小于等于 (a <= b) -> !(b < a) -> (slt; xori)
|
||||||
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||||
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||||
@ -337,7 +440,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(xori));
|
CurMBB->addInstruction(std::move(xori));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BinaryInst::kICmpGE: {
|
case BinaryInst::kICmpGE: { // 大于等于 (a >= b) -> !(a < b) -> (slt; xori)
|
||||||
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||||
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||||
@ -363,7 +466,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
auto src_vreg = getVReg(unary->getOperand());
|
auto src_vreg = getVReg(unary->getOperand());
|
||||||
|
|
||||||
switch (unary->getKind()) {
|
switch (unary->getKind()) {
|
||||||
case UnaryInst::kNeg: {
|
case UnaryInst::kNeg: { // 取负: 0 - src
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
@ -371,7 +474,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(instr));
|
CurMBB->addInstruction(std::move(instr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case UnaryInst::kNot: {
|
case UnaryInst::kNot: { // 逻辑非: src == 0 ? 1 : 0
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
|
||||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||||
@ -386,7 +489,10 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
|
|
||||||
case DAGNode::CALL: {
|
case DAGNode::CALL: {
|
||||||
auto call = dynamic_cast<CallInst*>(node->value);
|
auto call = dynamic_cast<CallInst*>(node->value);
|
||||||
for (size_t i = 0; i < node->operands.size() && i < 8; ++i) {
|
// 处理函数参数,放入a0-a7物理寄存器
|
||||||
|
size_t num_operands = node->operands.size();
|
||||||
|
size_t reg_arg_count = std::min(num_operands, (size_t)8);
|
||||||
|
for (size_t i = 0; i < reg_arg_count; ++i) {
|
||||||
DAGNode* arg_node = node->operands[i];
|
DAGNode* arg_node = node->operands[i];
|
||||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
|
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
|
||||||
|
|
||||||
@ -405,11 +511,64 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(mv));
|
CurMBB->addInstruction(std::move(mv));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (num_operands > 8) {
|
||||||
|
size_t stack_arg_count = num_operands - 8;
|
||||||
|
int stack_space = stack_arg_count * 8; // RV64中每个参数槽位8字节
|
||||||
|
|
||||||
|
// 2a. 在栈上分配空间
|
||||||
|
auto alloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
|
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
|
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
|
alloc_instr->addOperand(std::make_unique<ImmOperand>(-stack_space));
|
||||||
|
CurMBB->addInstruction(std::move(alloc_instr));
|
||||||
|
|
||||||
|
// 2b. 存储每个栈参数
|
||||||
|
for (size_t i = 8; i < num_operands; ++i) {
|
||||||
|
DAGNode* arg_node = node->operands[i];
|
||||||
|
unsigned src_vreg;
|
||||||
|
|
||||||
|
// 准备源寄存器
|
||||||
|
if (arg_node->kind == DAGNode::CONSTANT) {
|
||||||
|
// 如果是常量,先加载到临时寄存器
|
||||||
|
src_vreg = getNewVReg();
|
||||||
|
auto const_val = dynamic_cast<ConstantValue*>(arg_node->value);
|
||||||
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
|
li->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||||
|
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||||
|
CurMBB->addInstruction(std::move(li));
|
||||||
|
} else {
|
||||||
|
src_vreg = getVReg(arg_node->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算在栈上的偏移量
|
||||||
|
int offset = (i - 8) * 8;
|
||||||
|
|
||||||
|
// 生成 sd 指令
|
||||||
|
auto sd_instr = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||||
|
sd_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||||
|
sd_instr->addOperand(std::make_unique<MemOperand>(
|
||||||
|
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||||
|
std::make_unique<ImmOperand>(offset)
|
||||||
|
));
|
||||||
|
CurMBB->addInstruction(std::move(sd_instr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
||||||
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
|
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
|
||||||
CurMBB->addInstruction(std::move(call_instr));
|
CurMBB->addInstruction(std::move(call_instr));
|
||||||
|
|
||||||
|
if (num_operands > 8) {
|
||||||
|
size_t stack_arg_count = num_operands - 8;
|
||||||
|
int stack_space = stack_arg_count * 8;
|
||||||
|
|
||||||
|
auto dealloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
|
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
|
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
|
dealloc_instr->addOperand(std::make_unique<ImmOperand>(stack_space));
|
||||||
|
CurMBB->addInstruction(std::move(dealloc_instr));
|
||||||
|
}
|
||||||
|
// 处理返回值,从a0移动到目标虚拟寄存器
|
||||||
if (!call->getType()->isVoid()) {
|
if (!call->getType()->isVoid()) {
|
||||||
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||||
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
|
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
|
||||||
@ -423,6 +582,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
|
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
|
||||||
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
|
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
|
||||||
Value* ret_val = ret_inst_ir->getReturnValue();
|
Value* ret_val = ret_inst_ir->getReturnValue();
|
||||||
|
// [V2优点] 在RETURN节点内加载常量返回值
|
||||||
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
||||||
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||||
@ -435,36 +595,121 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(mv_instr));
|
CurMBB->addInstruction(std::move(mv_instr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// [V1设计保留] 函数尾声(epilogue)不由RETURN节点生成,
|
||||||
|
// 而是由后续的AsmPrinter或其它Pass统一处理,这是一种常见且有效的模块化设计。
|
||||||
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
|
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
|
||||||
CurMBB->addInstruction(std::move(ret_mi));
|
CurMBB->addInstruction(std::move(ret_mi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DAGNode::BRANCH: {
|
case DAGNode::BRANCH: {
|
||||||
if (auto cond_br = dynamic_cast<CondBrInst*>(node->value)) {
|
// 处理条件分支
|
||||||
|
if (auto cond_br = dynamic_cast<CondBrInst*>(node->value)) {
|
||||||
|
Value* condition = cond_br->getCondition();
|
||||||
|
auto then_bb_name = cond_br->getThenBlock()->getName();
|
||||||
|
auto else_bb_name = cond_br->getElseBlock()->getName();
|
||||||
|
|
||||||
|
// [优化] 检查分支条件是否为编译期常量
|
||||||
|
if (auto const_cond = dynamic_cast<ConstantValue*>(condition)) {
|
||||||
|
// 如果条件是常量,直接生成一个无条件跳转J,而不是BNE
|
||||||
|
if (const_cond->getInt() != 0) { // 条件为 true
|
||||||
|
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||||
|
j_instr->addOperand(std::make_unique<LabelOperand>(then_bb_name));
|
||||||
|
CurMBB->addInstruction(std::move(j_instr));
|
||||||
|
} else { // 条件为 false
|
||||||
|
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||||
|
j_instr->addOperand(std::make_unique<LabelOperand>(else_bb_name));
|
||||||
|
CurMBB->addInstruction(std::move(j_instr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果条件不是常量,则执行标准流程
|
||||||
|
else {
|
||||||
|
// [修复] 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
|
||||||
|
// 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获
|
||||||
|
if (auto const_val = dynamic_cast<ConstantValue*>(condition)) {
|
||||||
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
|
li->addOperand(std::make_unique<RegOperand>(getVReg(const_val)));
|
||||||
|
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||||
|
CurMBB->addInstruction(std::move(li));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cond_vreg = getVReg(condition);
|
||||||
|
|
||||||
|
// 生成 bne cond, zero, then_label (如果cond不为0,则跳转到then)
|
||||||
auto br_instr = std::make_unique<MachineInstr>(RVOpcodes::BNE);
|
auto br_instr = std::make_unique<MachineInstr>(RVOpcodes::BNE);
|
||||||
br_instr->addOperand(std::make_unique<RegOperand>(getVReg(cond_br->getCondition())));
|
br_instr->addOperand(std::make_unique<RegOperand>(cond_vreg));
|
||||||
br_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
br_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
br_instr->addOperand(std::make_unique<LabelOperand>(cond_br->getThenBlock()->getName()));
|
br_instr->addOperand(std::make_unique<LabelOperand>(then_bb_name));
|
||||||
CurMBB->addInstruction(std::move(br_instr));
|
CurMBB->addInstruction(std::move(br_instr));
|
||||||
} else if (auto uncond_br = dynamic_cast<UncondBrInst*>(node->value)) {
|
|
||||||
|
// 为else分支生成无条件跳转 (后续Pass可以优化掉不必要的跳转)
|
||||||
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||||
j_instr->addOperand(std::make_unique<LabelOperand>(uncond_br->getBlock()->getName()));
|
j_instr->addOperand(std::make_unique<LabelOperand>(else_bb_name));
|
||||||
CurMBB->addInstruction(std::move(j_instr));
|
CurMBB->addInstruction(std::move(j_instr));
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
// 处理无条件分支
|
||||||
|
else if (auto uncond_br = dynamic_cast<UncondBrInst*>(node->value)) {
|
||||||
|
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||||
|
j_instr->addOperand(std::make_unique<LabelOperand>(uncond_br->getBlock()->getName()));
|
||||||
|
CurMBB->addInstruction(std::move(j_instr));
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DAGNode::MEMSET: {
|
case DAGNode::MEMSET: {
|
||||||
|
// [V1设计保留] Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。
|
||||||
|
// 之前的bug是由于其输入(地址、值、大小)的虚拟寄存器未被正确初始化。
|
||||||
|
// 在修复了CONSTANT/ALLOCA_ADDR的加载问题后,此处的逻辑现在可以正常工作。
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "[DEBUG] selectNode-MEMSET: Processing MEMSET node." << std::endl;
|
||||||
|
}
|
||||||
auto memset = dynamic_cast<MemsetInst*>(node->value);
|
auto memset = dynamic_cast<MemsetInst*>(node->value);
|
||||||
|
Value* val_to_set = memset->getValue();
|
||||||
|
Value* size_to_set = memset->getSize();
|
||||||
|
Value* ptr_val = memset->getPointer();
|
||||||
|
auto dest_addr_vreg = getVReg(ptr_val);
|
||||||
|
|
||||||
|
if (auto const_val = dynamic_cast<ConstantValue*>(val_to_set)) {
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "[DEBUG] selectNode-MEMSET: Found constant 'value' operand (" << const_val->getInt() << "). Generating LI." << std::endl;
|
||||||
|
}
|
||||||
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
|
li->addOperand(std::make_unique<RegOperand>(getVReg(const_val)));
|
||||||
|
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||||
|
CurMBB->addInstruction(std::move(li));
|
||||||
|
}
|
||||||
|
if (auto const_size = dynamic_cast<ConstantValue*>(size_to_set)) {
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "[DEBUG] selectNode-MEMSET: Found constant 'size' operand (" << const_size->getInt() << "). Generating LI." << std::endl;
|
||||||
|
}
|
||||||
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
|
li->addOperand(std::make_unique<RegOperand>(getVReg(const_size)));
|
||||||
|
li->addOperand(std::make_unique<ImmOperand>(const_size->getInt()));
|
||||||
|
CurMBB->addInstruction(std::move(li));
|
||||||
|
}
|
||||||
|
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "[DEBUG] selectNode-MEMSET: Found 'pointer' operand is an AllocaInst. Generating FRAME_ADDR." << std::endl;
|
||||||
|
}
|
||||||
|
// 生成新的伪指令来获取栈地址
|
||||||
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
|
||||||
|
instr->addOperand(std::make_unique<RegOperand>(dest_addr_vreg)); // 目标虚拟寄存器
|
||||||
|
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca))); // 源AllocaInst
|
||||||
|
CurMBB->addInstruction(std::move(instr));
|
||||||
|
}
|
||||||
auto r_dest_addr = getVReg(memset->getPointer());
|
auto r_dest_addr = getVReg(memset->getPointer());
|
||||||
auto r_num_bytes = getVReg(memset->getSize());
|
auto r_num_bytes = getVReg(memset->getSize());
|
||||||
auto r_value_byte = getVReg(memset->getValue());
|
auto r_value_byte = getVReg(memset->getValue());
|
||||||
|
|
||||||
|
// 为memset内部逻辑创建新的临时虚拟寄存器
|
||||||
auto r_counter = getNewVReg();
|
auto r_counter = getNewVReg();
|
||||||
auto r_end_addr = getNewVReg();
|
auto r_end_addr = getNewVReg();
|
||||||
auto r_current_addr = getNewVReg();
|
auto r_current_addr = getNewVReg();
|
||||||
auto r_temp_val = getNewVReg();
|
auto r_temp_val = getNewVReg();
|
||||||
|
|
||||||
|
// 定义一系列lambda表达式来简化指令创建
|
||||||
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
|
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
|
||||||
auto i = std::make_unique<MachineInstr>(op);
|
auto i = std::make_unique<MachineInstr>(op);
|
||||||
i->addOperand(std::make_unique<RegOperand>(rd));
|
i->addOperand(std::make_unique<RegOperand>(rd));
|
||||||
@ -503,12 +748,14 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(i));
|
CurMBB->addInstruction(std::move(i));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 生成唯一的循环标签
|
||||||
int unique_id = this->local_label_counter++;
|
int unique_id = this->local_label_counter++;
|
||||||
std::string loop_start_label = MFunc->getName() + "_memset_loop_start_" + std::to_string(unique_id);
|
std::string loop_start_label = MFunc->getName() + "_memset_loop_start_" + std::to_string(unique_id);
|
||||||
std::string loop_end_label = MFunc->getName() + "_memset_loop_end_" + std::to_string(unique_id);
|
std::string loop_end_label = MFunc->getName() + "_memset_loop_end_" + std::to_string(unique_id);
|
||||||
std::string remainder_label = MFunc->getName() + "_memset_remainder_" + std::to_string(unique_id);
|
std::string remainder_label = MFunc->getName() + "_memset_remainder_" + std::to_string(unique_id);
|
||||||
std::string done_label = MFunc->getName() + "_memset_done_" + std::to_string(unique_id);
|
std::string done_label = MFunc->getName() + "_memset_done_" + std::to_string(unique_id);
|
||||||
|
|
||||||
|
// 构造64位的填充值
|
||||||
addi_instr(RVOpcodes::ANDI, r_temp_val, r_value_byte, 255);
|
addi_instr(RVOpcodes::ANDI, r_temp_val, r_value_byte, 255);
|
||||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 8);
|
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 8);
|
||||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||||
@ -516,6 +763,8 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 32);
|
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 32);
|
||||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||||
|
|
||||||
|
// 计算循环边界
|
||||||
add_instr(RVOpcodes::ADD, r_end_addr, r_dest_addr, r_num_bytes);
|
add_instr(RVOpcodes::ADD, r_end_addr, r_dest_addr, r_num_bytes);
|
||||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||||
mv->addOperand(std::make_unique<RegOperand>(r_current_addr));
|
mv->addOperand(std::make_unique<RegOperand>(r_current_addr));
|
||||||
@ -523,17 +772,22 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(mv));
|
CurMBB->addInstruction(std::move(mv));
|
||||||
addi_instr(RVOpcodes::ANDI, r_counter, r_num_bytes, -8);
|
addi_instr(RVOpcodes::ANDI, r_counter, r_num_bytes, -8);
|
||||||
add_instr(RVOpcodes::ADD, r_counter, r_dest_addr, r_counter);
|
add_instr(RVOpcodes::ADD, r_counter, r_dest_addr, r_counter);
|
||||||
|
|
||||||
|
// 8字节主循环
|
||||||
label_instr(loop_start_label);
|
label_instr(loop_start_label);
|
||||||
branch_instr(RVOpcodes::BGEU, r_current_addr, r_counter, loop_end_label);
|
branch_instr(RVOpcodes::BGEU, r_current_addr, r_counter, loop_end_label);
|
||||||
store_instr(RVOpcodes::SD, r_temp_val, r_current_addr, 0);
|
store_instr(RVOpcodes::SD, r_temp_val, r_current_addr, 0);
|
||||||
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 8);
|
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 8);
|
||||||
jump_instr(loop_start_label);
|
jump_instr(loop_start_label);
|
||||||
|
|
||||||
|
// 1字节收尾循环
|
||||||
label_instr(loop_end_label);
|
label_instr(loop_end_label);
|
||||||
label_instr(remainder_label);
|
label_instr(remainder_label);
|
||||||
branch_instr(RVOpcodes::BGEU, r_current_addr, r_end_addr, done_label);
|
branch_instr(RVOpcodes::BGEU, r_current_addr, r_end_addr, done_label);
|
||||||
store_instr(RVOpcodes::SB, r_temp_val, r_current_addr, 0);
|
store_instr(RVOpcodes::SB, r_temp_val, r_current_addr, 0);
|
||||||
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 1);
|
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 1);
|
||||||
jump_instr(remainder_label);
|
jump_instr(remainder_label);
|
||||||
|
|
||||||
label_instr(done_label);
|
label_instr(done_label);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -590,6 +844,12 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
|||||||
memset_node->operands.push_back(get_operand_node(memset->getBegin(), value_to_node, nodes_storage));
|
memset_node->operands.push_back(get_operand_node(memset->getBegin(), value_to_node, nodes_storage));
|
||||||
memset_node->operands.push_back(get_operand_node(memset->getSize(), value_to_node, nodes_storage));
|
memset_node->operands.push_back(get_operand_node(memset->getSize(), value_to_node, nodes_storage));
|
||||||
memset_node->operands.push_back(get_operand_node(memset->getValue(), value_to_node, nodes_storage));
|
memset_node->operands.push_back(get_operand_node(memset->getValue(), value_to_node, nodes_storage));
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "[DEBUG] build_dag: Created MEMSET node for: " << memset->getName() << std::endl;
|
||||||
|
for (size_t i = 0; i < memset_node->operands.size(); ++i) {
|
||||||
|
std::cout << " -> Operand " << i << " has kind: " << memset_node->operands[i]->kind << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
||||||
auto load_node = create_node(DAGNode::LOAD, load, value_to_node, nodes_storage);
|
auto load_node = create_node(DAGNode::LOAD, load, value_to_node, nodes_storage);
|
||||||
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
|
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
|
||||||
@ -632,4 +892,98 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
|||||||
return nodes_storage;
|
return nodes_storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [新] 打印DAG图以供调试的辅助函数
|
||||||
|
void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name) {
|
||||||
|
// 检查是否有DEBUG宏或者全局变量,避免在非调试模式下打印
|
||||||
|
// if (!DEBUG) return;
|
||||||
|
|
||||||
|
std::cerr << "=== DAG for Basic Block: " << bb_name << " ===\n";
|
||||||
|
std::set<DAGNode*> visited;
|
||||||
|
|
||||||
|
// 为节点分配临时ID,方便阅读
|
||||||
|
std::map<DAGNode*, int> node_to_id;
|
||||||
|
int current_id = 0;
|
||||||
|
for (const auto& node_ptr : dag) {
|
||||||
|
node_to_id[node_ptr.get()] = current_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将NodeKind枚举转换为字符串的辅助函数
|
||||||
|
auto get_kind_string = [](DAGNode::NodeKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case DAGNode::CONSTANT: return "CONSTANT";
|
||||||
|
case DAGNode::LOAD: return "LOAD";
|
||||||
|
case DAGNode::STORE: return "STORE";
|
||||||
|
case DAGNode::BINARY: return "BINARY";
|
||||||
|
case DAGNode::CALL: return "CALL";
|
||||||
|
case DAGNode::RETURN: return "RETURN";
|
||||||
|
case DAGNode::BRANCH: return "BRANCH";
|
||||||
|
case DAGNode::ALLOCA_ADDR: return "ALLOCA_ADDR";
|
||||||
|
case DAGNode::UNARY: return "UNARY";
|
||||||
|
case DAGNode::MEMSET: return "MEMSET";
|
||||||
|
default: return "UNKNOWN";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 递归打印节点的lambda表达式
|
||||||
|
std::function<void(DAGNode*, int)> print_node =
|
||||||
|
[&](DAGNode* node, int indent) {
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
std::string current_indent(indent, ' ');
|
||||||
|
int node_id = node_to_id.count(node) ? node_to_id[node] : -1;
|
||||||
|
|
||||||
|
std::cerr << current_indent << "Node#" << node_id << ": " << get_kind_string(node->kind);
|
||||||
|
|
||||||
|
// 尝试打印关联的虚拟寄存器
|
||||||
|
if (node->value && vreg_map.count(node->value)) {
|
||||||
|
std::cerr << " (vreg: %vreg" << vreg_map.at(node->value) << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印关联的IR Value信息
|
||||||
|
if (node->value) {
|
||||||
|
std::cerr << " [";
|
||||||
|
if (auto inst = dynamic_cast<Instruction*>(node->value)) {
|
||||||
|
std::cerr << inst->getKindString();
|
||||||
|
if (!inst->getName().empty()) {
|
||||||
|
std::cerr << "(" << inst->getName() << ")";
|
||||||
|
}
|
||||||
|
} else if (auto constant = dynamic_cast<ConstantValue*>(node->value)) {
|
||||||
|
std::cerr << "Const(" << constant->getInt() << ")";
|
||||||
|
} else if (auto global = dynamic_cast<GlobalValue*>(node->value)) {
|
||||||
|
std::cerr << "Global(" << global->getName() << ")";
|
||||||
|
} else if (auto alloca = dynamic_cast<AllocaInst*>(node->value)) {
|
||||||
|
std::cerr << "Alloca(" << alloca->getName() << ")";
|
||||||
|
}
|
||||||
|
std::cerr << "]";
|
||||||
|
}
|
||||||
|
std::cerr << "\n";
|
||||||
|
|
||||||
|
if (visited.count(node)) {
|
||||||
|
std::cerr << current_indent << " (已打印过子节点)\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
visited.insert(node);
|
||||||
|
|
||||||
|
if (!node->operands.empty()) {
|
||||||
|
std::cerr << current_indent << " Operands:\n";
|
||||||
|
for (auto operand : node->operands) {
|
||||||
|
print_node(operand, indent + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 从根节点(没有用户的节点,或有副作用的节点)开始打印
|
||||||
|
for (const auto& node_ptr : dag) {
|
||||||
|
if (node_ptr->users.empty() ||
|
||||||
|
node_ptr->kind == DAGNode::STORE ||
|
||||||
|
node_ptr->kind == DAGNode::RETURN ||
|
||||||
|
node_ptr->kind == DAGNode::BRANCH ||
|
||||||
|
node_ptr->kind == DAGNode::MEMSET)
|
||||||
|
{
|
||||||
|
print_node(node_ptr.get(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cerr << "======================================\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
@ -27,7 +27,8 @@ void RISCv64RegAlloc::run() {
|
|||||||
|
|
||||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||||
int current_offset = 0;
|
int current_offset = 20; // 这里写20是为了在$s0和第一个变量之间留出20字节的安全区,
|
||||||
|
// 以防止一些函数调用方面的恶性bug。
|
||||||
Function* F = MFunc->getFunc();
|
Function* F = MFunc->getFunc();
|
||||||
RISCv64ISel* isel = MFunc->getISel();
|
RISCv64ISel* isel = MFunc->getISel();
|
||||||
|
|
||||||
@ -94,6 +95,18 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
|||||||
std::make_unique<RegOperand>(addr_vreg),
|
std::make_unique<RegOperand>(addr_vreg),
|
||||||
std::make_unique<ImmOperand>(0)));
|
std::make_unique<ImmOperand>(0)));
|
||||||
new_instructions.push_back(std::move(sw));
|
new_instructions.push_back(std::move(sw));
|
||||||
|
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) { // [新] 处理FRAME_ADDR
|
||||||
|
auto& operands = instr_ptr->getOperands();
|
||||||
|
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||||
|
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||||
|
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||||
|
|
||||||
|
// 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset`
|
||||||
|
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0)); // 基地址是帧指针 s0
|
||||||
|
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||||
|
new_instructions.push_back(std::move(addi));
|
||||||
} else {
|
} else {
|
||||||
new_instructions.push_back(std::move(instr_ptr));
|
new_instructions.push_back(std::move(instr_ptr));
|
||||||
}
|
}
|
||||||
|
|||||||
122
src/Reg2Mem.cpp
122
src/Reg2Mem.cpp
@ -1,122 +0,0 @@
|
|||||||
#include "Reg2Mem.h"
|
|
||||||
#include <cstddef>
|
|
||||||
#include <iostream>
|
|
||||||
#include <list>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除phi节点
|
|
||||||
* 删除phi节点后可能会生成冗余存储代码
|
|
||||||
*/
|
|
||||||
void Reg2Mem::DeletePhiInst(){
|
|
||||||
auto &functions = pModule->getFunctions();
|
|
||||||
for (auto &function : functions) {
|
|
||||||
auto basicBlocks = function.second->getBasicBlocks();
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
|
|
||||||
for (auto iter = basicBlock->begin(); iter != basicBlock->end();) {
|
|
||||||
auto &instruction = *iter;
|
|
||||||
if (instruction->isPhi()) {
|
|
||||||
auto predBlocks = basicBlock->getPredecessors();
|
|
||||||
// 寻找源和目的
|
|
||||||
// 目的就是phi指令的第一个操作数
|
|
||||||
// 源就是phi指令的后续操作数
|
|
||||||
auto destination = instruction->getOperand(0);
|
|
||||||
int predBlockindex = 0;
|
|
||||||
for (auto &predBlock : predBlocks) {
|
|
||||||
++predBlockindex;
|
|
||||||
// 判断前驱块儿只有一个后继还是多个后继
|
|
||||||
// 如果有多个
|
|
||||||
auto source = instruction->getOperand(predBlockindex);
|
|
||||||
if (source == destination) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// std::cout << predBlock->getNumSuccessors() << std::endl;
|
|
||||||
if (predBlock->getNumSuccessors() > 1) {
|
|
||||||
// 创建一个basicblock
|
|
||||||
auto newbasicBlock = function.second->addBasicBlock();
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "phidel.L" << pBuilder->getLabelIndex();
|
|
||||||
newbasicBlock->setName(ss.str());
|
|
||||||
ss.str("");
|
|
||||||
// // 修改前驱后继关系
|
|
||||||
basicBlock->replacePredecessor(predBlock, newbasicBlock);
|
|
||||||
// predBlock = newbasicBlock;
|
|
||||||
newbasicBlock->addPredecessor(predBlock);
|
|
||||||
newbasicBlock->addSuccessor(basicBlock.get());
|
|
||||||
predBlock->removeSuccessor(basicBlock.get());
|
|
||||||
predBlock->addSuccessor(newbasicBlock);
|
|
||||||
// std::cout << "the block name is " << basicBlock->getName() << std::endl;
|
|
||||||
// for (auto pb : basicBlock->getPredecessors()) {
|
|
||||||
// // newbasicBlock->addPredecessor(pb);
|
|
||||||
// std::cout << pb->getName() << std::endl;
|
|
||||||
// }
|
|
||||||
// sysy::BasicBlock::conectBlocks(newbasicBlock, static_cast<BasicBlock *>(basicBlock.get()));
|
|
||||||
// 若后为跳转指令,应该修改跳转指令所到达的位置
|
|
||||||
auto thelastinst = predBlock->end();
|
|
||||||
(--thelastinst);
|
|
||||||
|
|
||||||
if (thelastinst->get()->isConditional() || thelastinst->get()->isUnconditional()) { // 如果是跳转指令
|
|
||||||
auto opnum = thelastinst->get()->getNumOperands();
|
|
||||||
for (size_t i = 0; i < opnum; i++) {
|
|
||||||
if (thelastinst->get()->getOperand(i) == basicBlock.get()) {
|
|
||||||
thelastinst->get()->replaceOperand(i, newbasicBlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 在新块中插入store指令
|
|
||||||
pBuilder->setPosition(newbasicBlock, newbasicBlock->end());
|
|
||||||
// pBuilder->createStoreInst(source, destination);
|
|
||||||
if (source->isInt() || source->isFloat()) {
|
|
||||||
pBuilder->createStoreInst(source, destination);
|
|
||||||
} else {
|
|
||||||
auto loadInst = pBuilder->createLoadInst(source);
|
|
||||||
pBuilder->createStoreInst(loadInst, destination);
|
|
||||||
}
|
|
||||||
// pBuilder->createMoveInst(Instruction::kMove, destination->getType(), destination, source,
|
|
||||||
// newbasicBlock);
|
|
||||||
pBuilder->setPosition(newbasicBlock, newbasicBlock->end());
|
|
||||||
pBuilder->createUncondBrInst(basicBlock.get(), {});
|
|
||||||
} else {
|
|
||||||
// 如果前驱块只有一个后继
|
|
||||||
auto thelastinst = predBlock->end();
|
|
||||||
(--thelastinst);
|
|
||||||
// std::cout << predBlock->getName() << std::endl;
|
|
||||||
// std::cout << thelastinst->get() << std::endl;
|
|
||||||
// std::cout << "First point 11 " << std::endl;
|
|
||||||
if (thelastinst->get()->isConditional() || thelastinst->get()->isUnconditional()) {
|
|
||||||
// 在跳转语句前insert st指令
|
|
||||||
pBuilder->setPosition(predBlock, thelastinst);
|
|
||||||
} else {
|
|
||||||
pBuilder->setPosition(predBlock, predBlock->end());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source->isInt() || source->isFloat()) {
|
|
||||||
pBuilder->createStoreInst(source, destination);
|
|
||||||
} else {
|
|
||||||
auto loadInst = pBuilder->createLoadInst(source);
|
|
||||||
pBuilder->createStoreInst(loadInst, destination);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 删除phi指令
|
|
||||||
auto &instructions = basicBlock->getInstructions();
|
|
||||||
SysYIROptUtils::usedelete(iter->get());
|
|
||||||
iter = instructions.erase(iter);
|
|
||||||
if (basicBlock->getNumInstructions() == 0) {
|
|
||||||
if (basicBlock->getNumSuccessors() == 1) {
|
|
||||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
|
||||||
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@ -523,6 +523,9 @@ bool ActiveVarAnalysis::analyze(Module *pModule, BasicBlock *block) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto ActiveVarAnalysis::getActiveTable() const -> const std::map<BasicBlock *, std::vector<std::set<User *>>> & {
|
||||||
|
return activeTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|||||||
@ -1,565 +0,0 @@
|
|||||||
#include "SysYIRCFGOpt.h"
|
|
||||||
#include "SysYIROptUtils.h"
|
|
||||||
#include <cassert>
|
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <iostream>
|
|
||||||
#include "IR.h"
|
|
||||||
#include "IRBuilder.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
|
|
||||||
// 删除br后的无用指令
|
|
||||||
bool SysYCFGOpt::SysYDelInstAfterBr(Function *func) {
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
auto basicBlocks = func->getBasicBlocks();
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
bool Branch = false;
|
|
||||||
auto &instructions = basicBlock->getInstructions();
|
|
||||||
auto Branchiter = instructions.end();
|
|
||||||
for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
|
|
||||||
if (Branch)
|
|
||||||
SysYIROptUtils::usedelete(iter->get());
|
|
||||||
else if ((*iter)->isTerminator()){
|
|
||||||
Branch = true;
|
|
||||||
Branchiter = iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Branchiter != instructions.end()) ++Branchiter;
|
|
||||||
while (Branchiter != instructions.end()) {
|
|
||||||
changed = true;
|
|
||||||
Branchiter = instructions.erase(Branchiter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Branch) { // 更新前驱后继关系
|
|
||||||
auto thelastinstinst = basicBlock->getInstructions().end();
|
|
||||||
--thelastinstinst;
|
|
||||||
auto &Successors = basicBlock->getSuccessors();
|
|
||||||
for (auto iterSucc = Successors.begin(); iterSucc != Successors.end();) {
|
|
||||||
(*iterSucc)->removePredecessor(basicBlock.get());
|
|
||||||
basicBlock->removeSuccessor(*iterSucc);
|
|
||||||
}
|
|
||||||
if (thelastinstinst->get()->isUnconditional()) {
|
|
||||||
BasicBlock* branchBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(0));
|
|
||||||
basicBlock->addSuccessor(branchBlock);
|
|
||||||
branchBlock->addPredecessor(basicBlock.get());
|
|
||||||
} else if (thelastinstinst->get()->isConditional()) {
|
|
||||||
BasicBlock* thenBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(1));
|
|
||||||
BasicBlock* elseBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(2));
|
|
||||||
basicBlock->addSuccessor(thenBlock);
|
|
||||||
basicBlock->addSuccessor(elseBlock);
|
|
||||||
thenBlock->addPredecessor(basicBlock.get());
|
|
||||||
elseBlock->addPredecessor(basicBlock.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合并空基本块
|
|
||||||
bool SysYCFGOpt::SysYBlockMerge(Function *func) {
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
for (auto blockiter = func->getBasicBlocks().begin();
|
|
||||||
blockiter != func->getBasicBlocks().end();) {
|
|
||||||
if (blockiter->get()->getNumSuccessors() == 1) {
|
|
||||||
// 如果当前块只有一个后继块
|
|
||||||
// 且后继块只有一个前驱块
|
|
||||||
// 则将当前块和后继块合并
|
|
||||||
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
|
|
||||||
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
|
|
||||||
BasicBlock* block = blockiter->get();
|
|
||||||
BasicBlock* nextBlock = blockiter->get()->getSuccessors()[0];
|
|
||||||
auto nextarguments = nextBlock->getArguments();
|
|
||||||
// 删除br指令
|
|
||||||
if (block->getNumInstructions() != 0) {
|
|
||||||
auto thelastinstinst = block->end();
|
|
||||||
(--thelastinstinst);
|
|
||||||
if (thelastinstinst->get()->isUnconditional()) {
|
|
||||||
SysYIROptUtils::usedelete(thelastinstinst->get());
|
|
||||||
block->getInstructions().erase(thelastinstinst);
|
|
||||||
} else if (thelastinstinst->get()->isConditional()) {
|
|
||||||
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
|
|
||||||
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
|
|
||||||
SysYIROptUtils::usedelete(thelastinstinst->get());
|
|
||||||
block->getInstructions().erase(thelastinstinst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 将后继块的指令移动到当前块
|
|
||||||
// 并将后继块的父指针改为当前块
|
|
||||||
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
|
||||||
institer->get()->setParent(block);
|
|
||||||
block->getInstructions().emplace_back(institer->release());
|
|
||||||
institer = nextBlock->getInstructions().erase(institer);
|
|
||||||
}
|
|
||||||
// 合并参数
|
|
||||||
// TODO:是否需要去重?
|
|
||||||
for (auto &argm : nextarguments) {
|
|
||||||
argm->setParent(block);
|
|
||||||
block->insertArgument(argm);
|
|
||||||
}
|
|
||||||
// 更新前驱后继关系,类似树节点操作
|
|
||||||
block->removeSuccessor(nextBlock);
|
|
||||||
nextBlock->removePredecessor(block);
|
|
||||||
std::list<BasicBlock *> succshoulddel;
|
|
||||||
for (auto &succ : nextBlock->getSuccessors()) {
|
|
||||||
block->addSuccessor(succ);
|
|
||||||
succ->replacePredecessor(nextBlock, block);
|
|
||||||
succshoulddel.push_back(succ);
|
|
||||||
}
|
|
||||||
for (auto del : succshoulddel) {
|
|
||||||
nextBlock->removeSuccessor(del);
|
|
||||||
}
|
|
||||||
|
|
||||||
func->removeBasicBlock(nextBlock);
|
|
||||||
changed = true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
blockiter++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
blockiter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除无前驱块,兼容SSA后的处理
|
|
||||||
bool SysYCFGOpt::SysYDelNoPreBLock(Function *func) {
|
|
||||||
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
for (auto &block : func->getBasicBlocks()) {
|
|
||||||
block->setreachableFalse();
|
|
||||||
}
|
|
||||||
// 对函数基本块做一个拓扑排序,排查不可达基本块
|
|
||||||
auto entryBlock = func->getEntryBlock();
|
|
||||||
entryBlock->setreachableTrue();
|
|
||||||
std::queue<BasicBlock *> blockqueue;
|
|
||||||
blockqueue.push(entryBlock);
|
|
||||||
while (!blockqueue.empty()) {
|
|
||||||
auto block = blockqueue.front();
|
|
||||||
blockqueue.pop();
|
|
||||||
for (auto &succ : block->getSuccessors()) {
|
|
||||||
if (!succ->getreachable()) {
|
|
||||||
succ->setreachableTrue();
|
|
||||||
blockqueue.push(succ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除不可达基本块指令
|
|
||||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();blockIter++) {
|
|
||||||
if (!blockIter->get()->getreachable())
|
|
||||||
for (auto &iterInst : blockIter->get()->getInstructions())
|
|
||||||
SysYIROptUtils::usedelete(iterInst.get());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
|
||||||
if (!blockIter->get()->getreachable()) {
|
|
||||||
for (auto succblock : blockIter->get()->getSuccessors()) {
|
|
||||||
int indexphi = 1;
|
|
||||||
for (auto pred : succblock->getPredecessors()) {
|
|
||||||
if (pred == blockIter->get()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
indexphi++;
|
|
||||||
}
|
|
||||||
for (auto &phiinst : succblock->getInstructions()) {
|
|
||||||
if (phiinst->getKind() != Instruction::kPhi) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
phiinst->removeOperand(indexphi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 删除不可达基本块,注意迭代器不可达问题
|
|
||||||
func->removeBasicBlock((blockIter++)->get());
|
|
||||||
changed = true;
|
|
||||||
} else {
|
|
||||||
blockIter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除空块
|
|
||||||
bool SysYCFGOpt::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
// 收集不可达基本块
|
|
||||||
// 这里的不可达基本块是指没有实际指令的基本块
|
|
||||||
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时,也会被视作不可达
|
|
||||||
auto basicBlocks = func->getBasicBlocks();
|
|
||||||
std::map<sysy::BasicBlock *, BasicBlock *> EmptyBlocks;
|
|
||||||
// 空块儿和后继的基本块的映射
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
if (basicBlock->getNumInstructions() == 0) {
|
|
||||||
if (basicBlock->getNumSuccessors() == 1) {
|
|
||||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// 如果只有phi指令和一个uncondbr。(phi)*(uncondbr)?
|
|
||||||
// 判断除了最后一个指令之外是不是只有phi指令
|
|
||||||
bool onlyPhi = true;
|
|
||||||
for (auto &inst : basicBlock->getInstructions()) {
|
|
||||||
if (!inst->isPhi() && !inst->isUnconditional()) {
|
|
||||||
onlyPhi = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(onlyPhi)
|
|
||||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
// 更新基本块信息,增加必要指令
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
// 把空块转换成只有跳转指令的不可达块
|
|
||||||
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
|
|
||||||
if (basicBlock->getNumSuccessors() == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (basicBlock->getNumSuccessors() > 1) {
|
|
||||||
assert("");
|
|
||||||
}
|
|
||||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
|
||||||
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto thelastinst = basicBlock->getInstructions().end();
|
|
||||||
--thelastinst;
|
|
||||||
|
|
||||||
// 根据br指令传递的后继块信息,跳过空块链
|
|
||||||
if (thelastinst->get()->isUnconditional()) {
|
|
||||||
BasicBlock* OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
|
||||||
BasicBlock *thelastBlockOld = nullptr;
|
|
||||||
// 如果空块链表为多个块
|
|
||||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
|
||||||
EmptyBlocks.end()) {
|
|
||||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
|
||||||
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
|
|
||||||
}
|
|
||||||
|
|
||||||
basicBlock->removeSuccessor(OldBrBlock);
|
|
||||||
OldBrBlock->removePredecessor(basicBlock.get());
|
|
||||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
|
||||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
|
||||||
|
|
||||||
if (thelastBlockOld != nullptr) {
|
|
||||||
int indexphi = 0;
|
|
||||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
|
||||||
if (pred == thelastBlockOld) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
indexphi++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新phi指令的操作数
|
|
||||||
// 移除thelastBlockOld对应的phi操作数
|
|
||||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
|
||||||
if (InstInNew->isPhi()) {
|
|
||||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (thelastinst->get()->getKind() == Instruction::kCondBr) {
|
|
||||||
auto OldThenBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
|
||||||
auto OldElseBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
|
||||||
|
|
||||||
BasicBlock *thelastBlockOld = nullptr;
|
|
||||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))) !=
|
|
||||||
EmptyBlocks.end()) {
|
|
||||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
|
||||||
thelastinst->get()->replaceOperand(
|
|
||||||
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
|
|
||||||
}
|
|
||||||
basicBlock->removeSuccessor(OldThenBlock);
|
|
||||||
OldThenBlock->removePredecessor(basicBlock.get());
|
|
||||||
// 处理 then 和 else 分支合并的情况
|
|
||||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
|
||||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
|
||||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
|
||||||
SysYIROptUtils::usedelete(thelastinst->get());
|
|
||||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
|
||||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
|
||||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
|
|
||||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
|
|
||||||
// auto indexInNew = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors().
|
|
||||||
|
|
||||||
if (thelastBlockOld != nullptr) {
|
|
||||||
int indexphi = 0;
|
|
||||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getPredecessors()) {
|
|
||||||
if (pred == thelastBlockOld) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
indexphi++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
|
|
||||||
if (InstInNew->isPhi()) {
|
|
||||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thelastBlockOld = nullptr;
|
|
||||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) !=
|
|
||||||
EmptyBlocks.end()) {
|
|
||||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
|
||||||
thelastinst->get()->replaceOperand(
|
|
||||||
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
|
|
||||||
}
|
|
||||||
basicBlock->removeSuccessor(OldElseBlock);
|
|
||||||
OldElseBlock->removePredecessor(basicBlock.get());
|
|
||||||
// 处理 then 和 else 分支合并的情况
|
|
||||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
|
||||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
|
||||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
|
||||||
SysYIROptUtils::usedelete(thelastinst->get());
|
|
||||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
|
||||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
|
||||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
|
|
||||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
|
|
||||||
|
|
||||||
if (thelastBlockOld != nullptr) {
|
|
||||||
int indexphi = 0;
|
|
||||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getPredecessors()) {
|
|
||||||
if (pred == thelastBlockOld) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
indexphi++;
|
|
||||||
}
|
|
||||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
|
|
||||||
if (InstInNew->isPhi()) {
|
|
||||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (basicBlock->getNumSuccessors() == 1) {
|
|
||||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
|
||||||
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
|
||||||
auto thelastinst = basicBlock->getInstructions().end();
|
|
||||||
(--thelastinst);
|
|
||||||
auto OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
|
||||||
sysy::BasicBlock *thelastBlockOld = nullptr;
|
|
||||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
|
||||||
EmptyBlocks.end()) {
|
|
||||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
|
||||||
|
|
||||||
thelastinst->get()->replaceOperand(
|
|
||||||
0, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))]);
|
|
||||||
}
|
|
||||||
|
|
||||||
basicBlock->removeSuccessor(OldBrBlock);
|
|
||||||
OldBrBlock->removePredecessor(basicBlock.get());
|
|
||||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
|
||||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
|
||||||
if (thelastBlockOld != nullptr) {
|
|
||||||
int indexphi = 0;
|
|
||||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
|
||||||
if (pred == thelastBlockOld) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
indexphi++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
|
||||||
if (InstInNew->isPhi()) {
|
|
||||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto iter = func->getBasicBlocks().begin(); iter != func->getBasicBlocks().end();) {
|
|
||||||
|
|
||||||
if (EmptyBlocks.find(iter->get()) != EmptyBlocks.end()) {
|
|
||||||
// EntryBlock跳过
|
|
||||||
if (iter->get() == func->getEntryBlock()) {
|
|
||||||
++iter;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &iterInst : iter->get()->getInstructions())
|
|
||||||
SysYIROptUtils::usedelete(iterInst.get());
|
|
||||||
// 删除不可达基本块的phi指令的操作数
|
|
||||||
for (auto &succ : iter->get()->getSuccessors()) {
|
|
||||||
int index = 0;
|
|
||||||
for (auto &pred : succ->getPredecessors()) {
|
|
||||||
if (pred == iter->get()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &instinsucc : succ->getInstructions()) {
|
|
||||||
if (instinsucc->isPhi()) {
|
|
||||||
dynamic_cast<PhiInst *>(instinsucc.get())->removeOperand(index);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func->removeBasicBlock((iter++)->get());
|
|
||||||
changed = true;
|
|
||||||
} else {
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
|
|
||||||
bool SysYCFGOpt::SysYAddReturn(Function *func, IRBuilder* pBuilder) {
|
|
||||||
bool changed = false;
|
|
||||||
auto basicBlocks = func->getBasicBlocks();
|
|
||||||
for (auto &block : basicBlocks) {
|
|
||||||
if (block->getNumSuccessors() == 0) {
|
|
||||||
changed = true;
|
|
||||||
// 如果基本块没有后继块,则添加一个返回指令
|
|
||||||
if (block->getNumInstructions() == 0) {
|
|
||||||
pBuilder->setPosition(block.get(), block->end());
|
|
||||||
pBuilder->createReturnInst();
|
|
||||||
}
|
|
||||||
auto thelastinst = block->getInstructions().end();
|
|
||||||
--thelastinst;
|
|
||||||
if (thelastinst->get()->getKind() != Instruction::kReturn) {
|
|
||||||
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default return." << std::endl;
|
|
||||||
|
|
||||||
pBuilder->setPosition(block.get(), block->end());
|
|
||||||
// TODO: 如果int float函数缺少返回值是否需要报错
|
|
||||||
if (func->getReturnType()->isInt()) {
|
|
||||||
pBuilder->createReturnInst(ConstantInteger::get(0));
|
|
||||||
} else if (func->getReturnType()->isFloat()) {
|
|
||||||
pBuilder->createReturnInst(ConstantFloating::get(0.0F));
|
|
||||||
} else {
|
|
||||||
pBuilder->createReturnInst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 条件分支转换为无条件分支
|
|
||||||
// 主要针对已知条件值的分支转换为无条件分支
|
|
||||||
// 例如 if (cond) { ... } else { ... } 中的 cond 已经
|
|
||||||
// 确定为 true 或 false 的情况
|
|
||||||
bool SysYCFGOpt::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
for (auto &basicblock : func->getBasicBlocks()) {
|
|
||||||
if (basicblock->getNumInstructions() == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto thelast = basicblock->getInstructions().end();
|
|
||||||
--thelast;
|
|
||||||
|
|
||||||
if (thelast->get()->isConditional()){
|
|
||||||
ConstantValue *constOperand = dynamic_cast<ConstantValue *>(thelast->get()->getOperand(0));
|
|
||||||
std::string opname;
|
|
||||||
int constint = 0;
|
|
||||||
float constfloat = 0.0F;
|
|
||||||
bool constint_Use = false;
|
|
||||||
bool constfloat_Use = false;
|
|
||||||
if (constOperand != nullptr) {
|
|
||||||
if (constOperand->isFloat()) {
|
|
||||||
constfloat = constOperand->getFloat();
|
|
||||||
constfloat_Use = true;
|
|
||||||
} else {
|
|
||||||
constint = constOperand->getInt();
|
|
||||||
constint_Use = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果可以计算
|
|
||||||
if (constfloat_Use || constint_Use) {
|
|
||||||
changed = true;
|
|
||||||
|
|
||||||
auto thenBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(1));
|
|
||||||
auto elseBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(2));
|
|
||||||
SysYIROptUtils::usedelete(thelast->get());
|
|
||||||
thelast = basicblock->getInstructions().erase(thelast);
|
|
||||||
if ((constfloat_Use && constfloat == 1.0F) || (constint_Use && constint == 1)) {
|
|
||||||
|
|
||||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
|
||||||
pBuilder->createUncondBrInst(thenBlock, {});
|
|
||||||
int phiindex = 0;
|
|
||||||
for (auto pred : elseBlock->getPredecessors()) {
|
|
||||||
phiindex++;
|
|
||||||
if (pred == basicblock.get()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &phiinst : elseBlock->getInstructions()) {
|
|
||||||
if (phiinst->getKind() != Instruction::kPhi) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
phiinst->removeOperand(phiindex);
|
|
||||||
}
|
|
||||||
basicblock->removeSuccessor(elseBlock);
|
|
||||||
elseBlock->removePredecessor(basicblock.get());
|
|
||||||
} else {
|
|
||||||
|
|
||||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
|
||||||
pBuilder->createUncondBrInst(elseBlock, {});
|
|
||||||
int phiindex = 0;
|
|
||||||
for (auto pred : thenBlock->getPredecessors()) {
|
|
||||||
phiindex++;
|
|
||||||
if (pred == basicblock.get()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &phiinst : thenBlock->getInstructions()) {
|
|
||||||
if (phiinst->getKind() != Instruction::kPhi) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
phiinst->removeOperand(phiindex);
|
|
||||||
}
|
|
||||||
basicblock->removeSuccessor(thenBlock);
|
|
||||||
thenBlock->removePredecessor(basicblock.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@ -15,73 +15,6 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
|
|
||||||
Type* SysYIRGenerator::buildArrayType(Type* baseType, const std::vector<Value*>& dims){
|
|
||||||
Type* currentType = baseType;
|
|
||||||
// 从最内层维度开始构建 ArrayType
|
|
||||||
// 例如对于 int arr[2][3],先处理 [3],再处理 [2]
|
|
||||||
// 注意:SysY 的 dims 是从最外层到最内层,所以我们需要反向迭代
|
|
||||||
// 或者调整逻辑,使得从内到外构建 ArrayType
|
|
||||||
// 假设 dims 列表是 [dim1, dim2, dim3...] (例如 [2, 3] for int[2][3])
|
|
||||||
// 我们需要从最内层维度开始向外构建 ArrayType
|
|
||||||
for (int i = dims.size() - 1; i >= 0; --i) {
|
|
||||||
// 维度大小必须是常量,否则无法构建 ArrayType
|
|
||||||
ConstantInteger* constDim = dynamic_cast<ConstantInteger*>(dims[i]);
|
|
||||||
if (constDim == nullptr) {
|
|
||||||
// 如果维度不是常量,可能需要特殊处理,例如将其视为指针
|
|
||||||
// 对于函数参数 int arr[] 这种,第一个维度可以为未知
|
|
||||||
// 在这里,我们假设所有声明的数组维度都是常量
|
|
||||||
assert(false && "Array dimension must be a constant integer!");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
unsigned dimSize = constDim->getInt();
|
|
||||||
currentType = Type::getArrayType(currentType, dimSize);
|
|
||||||
}
|
|
||||||
return currentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* SysYIRGenerator::getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices) {
|
|
||||||
// 检查 basePointer 是否为指针类型
|
|
||||||
if (!basePointer->getType()->isPointer()) {
|
|
||||||
assert(false && "GEP base pointer must be a pointer type!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取基指针所指向的实际类型 (例如 int* 指向 int, int[2][3]* 指向 int[2][3])
|
|
||||||
Type* currentElementType = basePointer->getType()->as<PointerType>()->getBaseType();
|
|
||||||
|
|
||||||
std::vector<Value*> actualGEPIndices;
|
|
||||||
// GEP 指令的第一个索引通常是0,用于“跳过”基指针指向的聚合类型本身,直接指向其第一个元素。
|
|
||||||
// 例如,对于 AllocaInst 返回的 `int[2][3]*`,第一个 `0` 索引表示从数组的开始而不是指针本身开始索引。
|
|
||||||
actualGEPIndices.push_back(ConstantInteger::get(0));
|
|
||||||
|
|
||||||
// 将用户提供的索引添加到 GEP 操作数中
|
|
||||||
for (Value* index : indices) {
|
|
||||||
actualGEPIndices.push_back(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据索引链计算最终的元素类型
|
|
||||||
Type* finalTargetType = currentElementType;
|
|
||||||
|
|
||||||
// 遍历用户提供的索引(不包括我们添加的第一个0),逐步确定 GEP 的最终结果类型
|
|
||||||
// 每个索引都“深入”一个维度
|
|
||||||
for (size_t i = 0; i < indices.size(); ++i) { // 这里遍历的是用户提供的索引
|
|
||||||
if (finalTargetType && finalTargetType->isArray()) {
|
|
||||||
finalTargetType = finalTargetType->as<ArrayType>()->getElementType();
|
|
||||||
} else {
|
|
||||||
// 如果索引链还在继续,但当前类型已经不是数组或聚合类型,这通常是一个错误
|
|
||||||
// 或者表示访问的是标量,后续索引无效。此时,finalTargetType 已经是最终的标量类型,不能再深入。
|
|
||||||
// 例如,对 int arr[5]; 访问 arr[i][j] (j 是多余的),这里会停止类型推断。
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GEP 的结果总是指针类型,指向最终计算出的元素
|
|
||||||
Type* gepResultType = Type::getPointerType(finalTargetType);
|
|
||||||
|
|
||||||
// 创建 GEP 指令。假设 builder.createGetElementPtrInst 的签名为
|
|
||||||
// (Type* resultType, Value* basePointer, const std::vector<Value*>& indices)
|
|
||||||
return builder.createGetElementPtrInst(basePointer, actualGEPIndices);
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* @brief: visit compUnit
|
* @brief: visit compUnit
|
||||||
* @details:
|
* @details:
|
||||||
@ -185,28 +118,24 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* variableType = type;
|
|
||||||
if (!dims.empty()) { // 如果有维度,说明是数组
|
|
||||||
variableType = buildArrayType(type, dims); // 构建完整的 ArrayType
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对于数组,alloca 的类型将是指针指向数组类型,例如 `int[2][3]*`
|
|
||||||
// 对于标量,alloca 的类型将是指针指向标量类型,例如 `int*`
|
|
||||||
AllocaInst* alloca =
|
AllocaInst* alloca =
|
||||||
builder.createAllocaInst(Type::getPointerType(type), dims, name);
|
builder.createAllocaInst(Type::getPointerType(type), dims, name);
|
||||||
|
|
||||||
if (varDef->initVal() != nullptr) {
|
if (varDef->initVal() != nullptr) {
|
||||||
ValueCounter values;
|
ValueCounter values;
|
||||||
|
// 这里的varDef->initVal()可能是ScalarInitValue或ArrayInitValue
|
||||||
ArrayValueTree* root = std::any_cast<ArrayValueTree *>(varDef->initVal()->accept(this));
|
ArrayValueTree* root = std::any_cast<ArrayValueTree *>(varDef->initVal()->accept(this));
|
||||||
Utils::tree2Array(type, root, dims, dims.size(), values, &builder);
|
Utils::tree2Array(type, root, dims, dims.size(), values, &builder);
|
||||||
delete root;
|
delete root;
|
||||||
|
if (dims.empty()) {
|
||||||
if (dims.empty()) { // 标量变量初始化
|
|
||||||
builder.createStoreInst(values.getValue(0), alloca);
|
builder.createStoreInst(values.getValue(0), alloca);
|
||||||
} else { // 数组变量初始化
|
} else{
|
||||||
|
// **数组变量初始化**
|
||||||
const std::vector<sysy::Value *> &counterValues = values.getValues();
|
const std::vector<sysy::Value *> &counterValues = values.getValues();
|
||||||
|
|
||||||
|
// 计算数组的**总元素数量**和**总字节大小**
|
||||||
int numElements = 1;
|
int numElements = 1;
|
||||||
|
// 存储每个维度的实际整数大小,用于索引计算
|
||||||
std::vector<int> dimSizes;
|
std::vector<int> dimSizes;
|
||||||
for (Value *dimVal : dims) {
|
for (Value *dimVal : dims) {
|
||||||
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal)) {
|
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal)) {
|
||||||
@ -216,11 +145,12 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
|
|||||||
}
|
}
|
||||||
// TODO else 错误处理:数组维度必须是常量(对于静态分配)
|
// TODO else 错误处理:数组维度必须是常量(对于静态分配)
|
||||||
}
|
}
|
||||||
unsigned int elementSizeInBytes = type->getSize();
|
unsigned int elementSizeInBytes = type->getSize(); // 获取单个元素的大小(字节)
|
||||||
unsigned int totalSizeInBytes = numElements * elementSizeInBytes;
|
unsigned int totalSizeInBytes = numElements * elementSizeInBytes;
|
||||||
|
|
||||||
|
// **判断是否可以进行全零初始化优化**
|
||||||
bool allValuesAreZero = false;
|
bool allValuesAreZero = false;
|
||||||
if (counterValues.empty()) {
|
if (counterValues.empty()) { // 例如 int arr[3] = {}; 或 int arr[3][4] = {};
|
||||||
allValuesAreZero = true;
|
allValuesAreZero = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -233,6 +163,7 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
// 如果值不是常量,我们通常不能确定它是否为零,所以不进行 memset 优化
|
||||||
allValuesAreZero = false;
|
allValuesAreZero = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -240,51 +171,64 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (allValuesAreZero) {
|
if (allValuesAreZero) {
|
||||||
|
// 如果所有初始化值都是零(或没有明确初始化但语法允许),使用 memset 优化
|
||||||
builder.createMemsetInst(
|
builder.createMemsetInst(
|
||||||
alloca,
|
alloca, // 目标数组的起始地址
|
||||||
ConstantInteger::get(0),
|
ConstantInteger::get(0), // 偏移量(通常为0),后续删除
|
||||||
ConstantInteger::get(totalSizeInBytes),
|
ConstantInteger::get(totalSizeInBytes),
|
||||||
ConstantInteger::get(0));
|
ConstantInteger::get(0)); // 填充的总字节数
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// **逐元素存储:遍历所有初始值,并为每个值生成一个 store 指令**
|
||||||
for (size_t k = 0; k < counterValues.size(); ++k) {
|
for (size_t k = 0; k < counterValues.size(); ++k) {
|
||||||
|
// 用于存储当前元素的索引列表
|
||||||
std::vector<Value *> currentIndices;
|
std::vector<Value *> currentIndices;
|
||||||
int tempLinearIndex = k;
|
int tempLinearIndex = k; // 临时线性索引,用于计算多维索引
|
||||||
|
|
||||||
// 将线性索引转换为多维索引
|
// **将线性索引转换为多维索引**
|
||||||
|
// 这个循环从最内层维度开始倒推,计算每个维度的索引
|
||||||
|
// 假设是行主序(row-major order),这是 C/C++ 数组的标准存储方式
|
||||||
for (int dimIdx = dimSizes.size() - 1; dimIdx >= 0; --dimIdx)
|
for (int dimIdx = dimSizes.size() - 1; dimIdx >= 0; --dimIdx)
|
||||||
{
|
{
|
||||||
|
// 计算当前维度的索引,并插入到列表的最前面
|
||||||
currentIndices.insert(currentIndices.begin(),
|
currentIndices.insert(currentIndices.begin(),
|
||||||
ConstantInteger::get(static_cast<int>(tempLinearIndex % dimSizes[dimIdx])));
|
ConstantInteger::get(static_cast<int>(tempLinearIndex % dimSizes[dimIdx])));
|
||||||
|
// 更新线性索引,用于计算下一个更高维度的索引
|
||||||
tempLinearIndex /= dimSizes[dimIdx];
|
tempLinearIndex /= dimSizes[dimIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算元素的地址
|
// **生成 store 指令,传入值、基指针和计算出的索引列表**
|
||||||
Value* elementAddress = getGEPAddressInst(alloca, currentIndices);
|
// 你的 builder.createStoreInst 签名需要能够接受这些参数
|
||||||
// 生成 store 指令 (假设 createStoreInst 接受 Value* value, Value* pointer)
|
// 假设你的 builder.createStoreInst(Value *val, Value *ptr, const std::vector<Value *> &indices, ...)
|
||||||
builder.createStoreInst(counterValues[k], elementAddress);
|
builder.createStoreInst(counterValues[k], alloca, currentIndices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // 如果没有显式初始化值,默认对数组进行零初始化
|
else
|
||||||
if (!dims.empty()) { // 只有数组才需要默认的零初始化
|
{ // **如果没有显式初始化值,默认对数组进行零初始化**
|
||||||
|
if (!dims.empty())
|
||||||
|
{ // 只有数组才需要默认的零初始化
|
||||||
int numElements = 1;
|
int numElements = 1;
|
||||||
for (Value *dimVal : dims) {
|
for (Value *dimVal : dims)
|
||||||
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal)) {
|
{
|
||||||
|
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal))
|
||||||
|
{
|
||||||
numElements *= constInt->getInt();
|
numElements *= constInt->getInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsigned int elementSizeInBytes = type->getSize();
|
unsigned int elementSizeInBytes = type->getSize();
|
||||||
unsigned int totalSizeInBytes = numElements * elementSizeInBytes;
|
unsigned int totalSizeInBytes = numElements * elementSizeInBytes;
|
||||||
|
|
||||||
|
// 使用 memset 将整个数组清零
|
||||||
builder.createMemsetInst(
|
builder.createMemsetInst(
|
||||||
alloca,
|
alloca,
|
||||||
ConstantInteger::get(0),
|
ConstantInteger::get(0),
|
||||||
ConstantInteger::get(totalSizeInBytes),
|
ConstantInteger::get(totalSizeInBytes),
|
||||||
ConstantInteger::get(0)
|
ConstantInteger::get(0)
|
||||||
);
|
); // 填充的总字节数
|
||||||
}
|
}
|
||||||
|
// 标量变量如果没有初始化值,通常不生成额外的初始化指令,因为其内存已分配但未赋值。
|
||||||
}
|
}
|
||||||
|
|
||||||
module->addVariable(name, alloca);
|
module->addVariable(name, alloca);
|
||||||
@ -340,6 +284,7 @@ std::any SysYIRGenerator::visitFuncType(SysYParser::FuncTypeContext *ctx) {
|
|||||||
std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
|
std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
|
||||||
// 更新作用域
|
// 更新作用域
|
||||||
module->enterNewScope();
|
module->enterNewScope();
|
||||||
|
HasReturnInst = false;
|
||||||
|
|
||||||
auto name = ctx->Ident()->getText();
|
auto name = ctx->Ident()->getText();
|
||||||
std::vector<Type *> paramTypes;
|
std::vector<Type *> paramTypes;
|
||||||
@ -375,34 +320,22 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
|
|||||||
module->addVariable(paramNames[i], alloca);
|
module->addVariable(paramNames[i], alloca);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在处理函数体之前,创建一个新的基本块作为函数体的实际入口
|
|
||||||
// 这样 entryBB 就可以在完成初始化后跳转到这里
|
|
||||||
BasicBlock* funcBodyEntry = function->addBasicBlock("funcBodyEntry");
|
|
||||||
|
|
||||||
// 从 entryBB 无条件跳转到 funcBodyEntry
|
|
||||||
builder.createUncondBrInst(funcBodyEntry, {});
|
|
||||||
builder.setPosition(funcBodyEntry,funcBodyEntry->end()); // 将插入点设置到 funcBodyEntry
|
|
||||||
|
|
||||||
for (auto item : ctx->blockStmt()->blockItem()) {
|
for (auto item : ctx->blockStmt()->blockItem()) {
|
||||||
visitBlockItem(item);
|
visitBlockItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果函数没有显式的返回语句,且返回类型不是 void,则需要添加一个默认的返回值
|
if(HasReturnInst == false) {
|
||||||
ReturnInst* retinst = nullptr;
|
// 如果没有return语句,则默认返回0
|
||||||
retinst = dynamic_cast<ReturnInst*>(builder.getBasicBlock()->terminator()->get());
|
if (returnType != Type::getVoidType()) {
|
||||||
|
Value* returnValue = ConstantInteger::get(0);
|
||||||
if (!retinst) {
|
if (returnType == Type::getFloatType()) {
|
||||||
if (returnType->isVoid()) {
|
returnValue = ConstantFloating::get(0.0f);
|
||||||
builder.createReturnInst();
|
}
|
||||||
} else if (returnType->isInt()) {
|
builder.createReturnInst(returnValue);
|
||||||
builder.createReturnInst(ConstantInteger::get(0)); // 默认返回 0
|
|
||||||
} else if (returnType->isFloat()) {
|
|
||||||
builder.createReturnInst(ConstantFloating::get(0.0f)); // 默认返回 0.0f
|
|
||||||
} else {
|
} else {
|
||||||
assert(false && "Function with no explicit return and non-void type should return a value.");
|
builder.createReturnInst();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module->leaveScope();
|
module->leaveScope();
|
||||||
|
|
||||||
return std::any();
|
return std::any();
|
||||||
@ -423,56 +356,29 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
|
|||||||
for (const auto &exp : lVal->exp()) {
|
for (const auto &exp : lVal->exp()) {
|
||||||
dims.push_back(std::any_cast<Value *>(visitExp(exp)));
|
dims.push_back(std::any_cast<Value *>(visitExp(exp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto variable = module->getVariable(name); // 获取 AllocaInst 或 GlobalValue
|
|
||||||
Value* value = std::any_cast<Value *>(visitExp(ctx->exp())); // 右值
|
|
||||||
|
|
||||||
if (variable == nullptr) {
|
auto variable = module->getVariable(name);
|
||||||
throw std::runtime_error("Variable " + name + " not found in assignment.");
|
Value* value = std::any_cast<Value *>(visitExp(ctx->exp()));
|
||||||
}
|
Type* variableType = dynamic_cast<PointerType *>(variable->getType())->getBaseType();
|
||||||
|
|
||||||
// 计算最终赋值目标元素的类型
|
// 左值右值类型不同处理
|
||||||
// variable 本身应该是一个指针类型 (例如 int* 或 int[2][3]*)
|
if (variableType != value->getType()) {
|
||||||
if (!variable->getType()->isPointer()) {
|
|
||||||
assert(false && "Variable to be assigned must be a pointer type!");
|
|
||||||
return std::any();
|
|
||||||
}
|
|
||||||
Type* targetElementType = variable->getType()->as<PointerType>()->getBaseType(); // 从基指针指向的类型开始
|
|
||||||
|
|
||||||
// 模拟 GEP 路径,根据 dims 确定最终元素的类型
|
|
||||||
for (size_t i = 0; i < dims.size(); ++i) {
|
|
||||||
if (targetElementType && targetElementType->isArray()) {
|
|
||||||
targetElementType = targetElementType->as<ArrayType>()->getElementType();
|
|
||||||
} else {
|
|
||||||
break; // 如果不是数组类型但还有索引,或者索引超出维度,则停止推断
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 左值右值类型不同处理:根据最终元素类型进行转换
|
|
||||||
if (targetElementType != value->getType()) {
|
|
||||||
ConstantValue * constValue = dynamic_cast<ConstantValue *>(value);
|
ConstantValue * constValue = dynamic_cast<ConstantValue *>(value);
|
||||||
if (constValue != nullptr) {
|
if (constValue != nullptr) {
|
||||||
if (targetElementType == Type::getFloatType()) {
|
if (variableType == Type::getFloatType()) {
|
||||||
value = ConstantFloating::get(static_cast<float>(constValue->getInt()));
|
value = ConstantInteger::get(static_cast<float>(constValue->getInt()));
|
||||||
} else { // 假设如果不是浮点型,就是整型
|
} else {
|
||||||
value = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
|
value = ConstantFloating::get(static_cast<int>(constValue->getFloat()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetElementType == Type::getFloatType()) {
|
if (variableType == Type::getFloatType()) {
|
||||||
value = builder.createIToFInst(value);
|
value = builder.createIToFInst(value);
|
||||||
} else { // 假设如果不是浮点型,就是整型
|
} else {
|
||||||
value = builder.createFtoIInst(value);
|
value = builder.createFtoIInst(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
builder.createStoreInst(value, variable, dims, variable->getName());
|
||||||
// 计算目标地址:如果 dims 为空,就是变量本身地址;否则通过 GEP 计算
|
|
||||||
Value* targetAddress = variable;
|
|
||||||
if (!dims.empty()) {
|
|
||||||
targetAddress = getGEPAddressInst(variable, dims);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.createStoreInst(value, targetAddress);
|
|
||||||
|
|
||||||
return std::any();
|
return std::any();
|
||||||
}
|
}
|
||||||
@ -560,7 +466,6 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
|
|||||||
ctx->stmt(0)->accept(this);
|
ctx->stmt(0)->accept(this);
|
||||||
module->leaveScope();
|
module->leaveScope();
|
||||||
}
|
}
|
||||||
builder.createUncondBrInst(exitBlock, {});
|
|
||||||
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
|
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
|
||||||
|
|
||||||
labelstring << "if_exit.L" << builder.getLabelIndex();
|
labelstring << "if_exit.L" << builder.getLabelIndex();
|
||||||
@ -582,7 +487,6 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
|
|||||||
labelstring << "while_head.L" << builder.getLabelIndex();
|
labelstring << "while_head.L" << builder.getLabelIndex();
|
||||||
BasicBlock *headBlock = function->addBasicBlock(labelstring.str());
|
BasicBlock *headBlock = function->addBasicBlock(labelstring.str());
|
||||||
labelstring.str("");
|
labelstring.str("");
|
||||||
builder.createUncondBrInst(headBlock, {});
|
|
||||||
BasicBlock::conectBlocks(curBlock, headBlock);
|
BasicBlock::conectBlocks(curBlock, headBlock);
|
||||||
builder.setPosition(headBlock, headBlock->end());
|
builder.setPosition(headBlock, headBlock->end());
|
||||||
|
|
||||||
@ -667,94 +571,56 @@ std::any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.createReturnInst(returnValue);
|
builder.createReturnInst(returnValue);
|
||||||
|
HasReturnInst = true;
|
||||||
return std::any();
|
return std::any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SysYIRGenerator.cpp (修改部分)
|
|
||||||
|
|
||||||
std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
|
std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
|
||||||
std::string name = ctx->Ident()->getText();
|
std::string name = ctx->Ident()->getText();
|
||||||
User* variable = module->getVariable(name);
|
User* variable = module->getVariable(name);
|
||||||
|
|
||||||
Value* value = nullptr;
|
Value* value = nullptr;
|
||||||
if (variable == nullptr) {
|
|
||||||
throw std::runtime_error("Variable " + name + " not found.");
|
|
||||||
}
|
|
||||||
std::vector<Value *> dims;
|
std::vector<Value *> dims;
|
||||||
for (const auto &exp : ctx->exp()) {
|
for (const auto &exp : ctx->exp()) {
|
||||||
dims.push_back(std::any_cast<Value *>(visitExp(exp)));
|
dims.push_back(std::any_cast<Value *>(visitExp(exp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 获取变量的声明维度数量
|
if (variable == nullptr) {
|
||||||
unsigned declaredNumDims = 0;
|
throw std::runtime_error("Variable " + name + " not found.");
|
||||||
if (AllocaInst* alloc = dynamic_cast<AllocaInst*>(variable)) {
|
}
|
||||||
declaredNumDims = alloc->getNumDims();
|
|
||||||
} else if (GlobalValue* glob = dynamic_cast<GlobalValue*>(variable)) {
|
bool indicesConstant = true;
|
||||||
declaredNumDims = glob->getNumDims();
|
for (const auto &dim : dims) {
|
||||||
} else if (ConstantVariable* constV = dynamic_cast<ConstantVariable*>(variable)) {
|
if (dynamic_cast<ConstantValue *>(dim) == nullptr) {
|
||||||
declaredNumDims = constV->getNumDims();
|
indicesConstant = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 处理常量变量 (ConstantVariable) 且所有索引都是常量的情况
|
|
||||||
ConstantVariable* constVar = dynamic_cast<ConstantVariable *>(variable);
|
ConstantVariable* constVar = dynamic_cast<ConstantVariable *>(variable);
|
||||||
if (constVar != nullptr) {
|
GlobalValue* globalVar = dynamic_cast<GlobalValue *>(variable);
|
||||||
bool allIndicesConstant = true;
|
AllocaInst* localVar = dynamic_cast<AllocaInst *>(variable);
|
||||||
for (const auto &dim : dims) {
|
if (constVar != nullptr && indicesConstant) {
|
||||||
if (dynamic_cast<ConstantValue *>(dim) == nullptr) {
|
// 如果是常量变量,且索引是常量,则直接获取子数组
|
||||||
allIndicesConstant = false;
|
value = constVar->getByIndices(dims);
|
||||||
break;
|
} else if (module->isInGlobalArea() && (globalVar != nullptr)) {
|
||||||
}
|
assert(indicesConstant);
|
||||||
}
|
value = globalVar->getByIndices(dims);
|
||||||
if (allIndicesConstant) {
|
|
||||||
// 如果是常量变量且所有索引都是常量,直接通过 getByIndices 获取编译时值
|
|
||||||
// 这个方法会根据索引深度返回最终的标量值或指向子数组的指针 (作为 ConstantValue/Variable)
|
|
||||||
return constVar->getByIndices(dims);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 处理可变变量 (AllocaInst/GlobalValue) 或带非常量索引的常量变量
|
|
||||||
// 这里区分标量访问和数组元素/子数组访问
|
|
||||||
|
|
||||||
// 检查是否是访问标量变量本身(没有索引,且声明维度为0)
|
|
||||||
if (dims.empty() && declaredNumDims == 0) {
|
|
||||||
// 对于标量变量,直接加载其值。
|
|
||||||
// variable 本身就是指向标量的指针 (e.g., int* %a)
|
|
||||||
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable)) {
|
|
||||||
value = builder.createLoadInst(variable);
|
|
||||||
} else {
|
|
||||||
// 如果走到这里且不是AllocaInst/GlobalValue,但dims为空且declaredNumDims为0,
|
|
||||||
// 且又不是ConstantVariable (前面已处理),则可能是错误情况。
|
|
||||||
assert(false && "Unhandled scalar variable type in LValue access.");
|
|
||||||
return static_cast<Value*>(nullptr);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 访问数组元素或子数组(有索引,或变量本身是数组/多维指针)
|
if ((globalVar != nullptr && globalVar->getNumDims() > dims.size()) ||
|
||||||
Value* targetAddress = nullptr;
|
(localVar != nullptr && localVar->getNumDims() > dims.size()) ||
|
||||||
|
(constVar != nullptr && constVar->getNumDims() > dims.size())) {
|
||||||
// GEP 的基指针就是变量本身(它是一个指向内存的指针)
|
// value = builder.createLaInst(variable, indices);
|
||||||
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable) || (constVar != nullptr)) {
|
// 如果变量是全局变量或局部变量,且索引数量小于维度数量,则创建createGetSubArray获取子数组
|
||||||
// 允许对 ConstantVariable (如果它代表全局数组常量) 进行 GEP
|
auto getArrayInst =
|
||||||
targetAddress = getGEPAddressInst(variable, dims);
|
builder.createGetSubArray(dynamic_cast<LVal *>(variable), dims);
|
||||||
|
value = getArrayInst->getChildArray();
|
||||||
} else {
|
} else {
|
||||||
// 其他情况(例如尝试对非指针类型或不支持的 LValue 进行 GEP)应报错
|
value = builder.createLoadInst(variable, dims);
|
||||||
assert(false && "LValue variable type not supported for GEP or dynamic load.");
|
|
||||||
return static_cast<Value*>(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 现在 targetAddress 持有元素或子数组的地址。
|
|
||||||
// 需要判断是加载值,还是返回子数组的地址。
|
|
||||||
|
|
||||||
// 如果提供的索引数量少于声明的维度数量,则表示访问的是子数组,返回其地址
|
|
||||||
if (dims.size() < declaredNumDims) {
|
|
||||||
value = targetAddress;
|
|
||||||
} else {
|
|
||||||
// 否则,表示访问的是最终的标量元素,加载其值
|
|
||||||
// 假设 createLoadInst 接受 Value* pointer
|
|
||||||
value = builder.createLoadInst(targetAddress);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
484
src/SysYIROptPre.cpp
Normal file
484
src/SysYIROptPre.cpp
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
#include "SysYIROptPre.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include "IR.h"
|
||||||
|
#include "IRBuilder.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* use删除operand,以免扰乱后续分析
|
||||||
|
* instr: 要删除的指令
|
||||||
|
*/
|
||||||
|
void SysYOptPre::usedelete(Instruction *instr) {
|
||||||
|
for (auto &use : instr->getOperands()) {
|
||||||
|
Value* val = use->getValue();
|
||||||
|
// std::cout << delete << val->getName() << std::endl;
|
||||||
|
val->removeUse(use);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 删除br后的无用指令
|
||||||
|
void SysYOptPre::SysYDelInstAfterBr() {
|
||||||
|
auto &functions = pModule->getFunctions();
|
||||||
|
for (auto &function : functions) {
|
||||||
|
auto basicBlocks = function.second->getBasicBlocks();
|
||||||
|
for (auto &basicBlock : basicBlocks) {
|
||||||
|
bool Branch = false;
|
||||||
|
auto &instructions = basicBlock->getInstructions();
|
||||||
|
auto Branchiter = instructions.end();
|
||||||
|
for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
|
||||||
|
if (Branch)
|
||||||
|
usedelete(iter->get());
|
||||||
|
else if ((*iter)->isTerminator()){
|
||||||
|
Branch = true;
|
||||||
|
Branchiter = iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Branchiter != instructions.end()) ++Branchiter;
|
||||||
|
while (Branchiter != instructions.end())
|
||||||
|
Branchiter = instructions.erase(Branchiter);
|
||||||
|
|
||||||
|
if (Branch) { // 更新前驱后继关系
|
||||||
|
auto thelastinstinst = basicBlock->getInstructions().end();
|
||||||
|
--thelastinstinst;
|
||||||
|
auto &Successors = basicBlock->getSuccessors();
|
||||||
|
for (auto iterSucc = Successors.begin(); iterSucc != Successors.end();) {
|
||||||
|
(*iterSucc)->removePredecessor(basicBlock.get());
|
||||||
|
basicBlock->removeSuccessor(*iterSucc);
|
||||||
|
}
|
||||||
|
if (thelastinstinst->get()->isUnconditional()) {
|
||||||
|
BasicBlock* branchBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(0));
|
||||||
|
basicBlock->addSuccessor(branchBlock);
|
||||||
|
branchBlock->addPredecessor(basicBlock.get());
|
||||||
|
} else if (thelastinstinst->get()->isConditional()) {
|
||||||
|
BasicBlock* thenBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(1));
|
||||||
|
BasicBlock* elseBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(2));
|
||||||
|
basicBlock->addSuccessor(thenBlock);
|
||||||
|
basicBlock->addSuccessor(elseBlock);
|
||||||
|
thenBlock->addPredecessor(basicBlock.get());
|
||||||
|
elseBlock->addPredecessor(basicBlock.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SysYOptPre::SysYBlockMerge() {
|
||||||
|
auto &functions = pModule->getFunctions(); //std::map<std::string, std::unique_ptr<Function>>
|
||||||
|
for (auto &function : functions) {
|
||||||
|
// auto basicBlocks = function.second->getBasicBlocks();
|
||||||
|
auto &func = function.second;
|
||||||
|
for (auto blockiter = func->getBasicBlocks().begin();
|
||||||
|
blockiter != func->getBasicBlocks().end();) {
|
||||||
|
if (blockiter->get()->getNumSuccessors() == 1) {
|
||||||
|
// 如果当前块只有一个后继块
|
||||||
|
// 且后继块只有一个前驱块
|
||||||
|
// 则将当前块和后继块合并
|
||||||
|
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
|
||||||
|
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
|
||||||
|
BasicBlock* block = blockiter->get();
|
||||||
|
BasicBlock* nextBlock = blockiter->get()->getSuccessors()[0];
|
||||||
|
auto nextarguments = nextBlock->getArguments();
|
||||||
|
// 删除br指令
|
||||||
|
if (block->getNumInstructions() != 0) {
|
||||||
|
auto thelastinstinst = block->end();
|
||||||
|
(--thelastinstinst);
|
||||||
|
if (thelastinstinst->get()->isUnconditional()) {
|
||||||
|
usedelete(thelastinstinst->get());
|
||||||
|
block->getInstructions().erase(thelastinstinst);
|
||||||
|
} else if (thelastinstinst->get()->isConditional()) {
|
||||||
|
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
|
||||||
|
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
|
||||||
|
usedelete(thelastinstinst->get());
|
||||||
|
block->getInstructions().erase(thelastinstinst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 将后继块的指令移动到当前块
|
||||||
|
// 并将后继块的父指针改为当前块
|
||||||
|
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
||||||
|
institer->get()->setParent(block);
|
||||||
|
block->getInstructions().emplace_back(institer->release());
|
||||||
|
institer = nextBlock->getInstructions().erase(institer);
|
||||||
|
}
|
||||||
|
// 合并参数
|
||||||
|
// TODO:是否需要去重?
|
||||||
|
for (auto &argm : nextarguments) {
|
||||||
|
argm->setParent(block);
|
||||||
|
block->insertArgument(argm);
|
||||||
|
}
|
||||||
|
// 更新前驱后继关系,类似树节点操作
|
||||||
|
block->removeSuccessor(nextBlock);
|
||||||
|
nextBlock->removePredecessor(block);
|
||||||
|
std::list<BasicBlock *> succshoulddel;
|
||||||
|
for (auto &succ : nextBlock->getSuccessors()) {
|
||||||
|
block->addSuccessor(succ);
|
||||||
|
succ->replacePredecessor(nextBlock, block);
|
||||||
|
succshoulddel.push_back(succ);
|
||||||
|
}
|
||||||
|
for (auto del : succshoulddel) {
|
||||||
|
nextBlock->removeSuccessor(del);
|
||||||
|
}
|
||||||
|
|
||||||
|
func->removeBasicBlock(nextBlock);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
blockiter++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blockiter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除无前驱块,兼容SSA后的处理
|
||||||
|
void SysYOptPre::SysYDelNoPreBLock() {
|
||||||
|
|
||||||
|
auto &functions = pModule->getFunctions(); // std::map<std::string, std::unique_ptr<sysy::Function>>
|
||||||
|
for (auto &function : functions) {
|
||||||
|
auto &func = function.second;
|
||||||
|
|
||||||
|
for (auto &block : func->getBasicBlocks()) {
|
||||||
|
block->setreachableFalse();
|
||||||
|
}
|
||||||
|
// 对函数基本块做一个拓扑排序,排查不可达基本块
|
||||||
|
auto entryBlock = func->getEntryBlock();
|
||||||
|
entryBlock->setreachableTrue();
|
||||||
|
std::queue<BasicBlock *> blockqueue;
|
||||||
|
blockqueue.push(entryBlock);
|
||||||
|
while (!blockqueue.empty()) {
|
||||||
|
auto block = blockqueue.front();
|
||||||
|
blockqueue.pop();
|
||||||
|
for (auto &succ : block->getSuccessors()) {
|
||||||
|
if (!succ->getreachable()) {
|
||||||
|
succ->setreachableTrue();
|
||||||
|
blockqueue.push(succ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除不可达基本块指令
|
||||||
|
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();blockIter++) {
|
||||||
|
|
||||||
|
if (!blockIter->get()->getreachable())
|
||||||
|
for (auto &iterInst : blockIter->get()->getInstructions())
|
||||||
|
usedelete(iterInst.get());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||||
|
if (!blockIter->get()->getreachable()) {
|
||||||
|
for (auto succblock : blockIter->get()->getSuccessors()) {
|
||||||
|
int indexphi = 1;
|
||||||
|
for (auto pred : succblock->getPredecessors()) {
|
||||||
|
if (pred == blockIter->get()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indexphi++;
|
||||||
|
}
|
||||||
|
for (auto &phiinst : succblock->getInstructions()) {
|
||||||
|
if (phiinst->getKind() != Instruction::kPhi) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
phiinst->removeOperand(indexphi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 删除不可达基本块,注意迭代器不可达问题
|
||||||
|
func->removeBasicBlock((blockIter++)->get());
|
||||||
|
} else {
|
||||||
|
blockIter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysYOptPre::SysYDelEmptyBlock() {
|
||||||
|
auto &functions = pModule->getFunctions();
|
||||||
|
for (auto &function : functions) {
|
||||||
|
// 收集不可达基本块
|
||||||
|
// 这里的不可达基本块是指没有实际指令的基本块
|
||||||
|
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时,也会被视作不可达
|
||||||
|
auto basicBlocks = function.second->getBasicBlocks();
|
||||||
|
std::map<sysy::BasicBlock *, BasicBlock *> EmptyBlocks;
|
||||||
|
// 空块儿和后继的基本块的映射
|
||||||
|
for (auto &basicBlock : basicBlocks) {
|
||||||
|
if (basicBlock->getNumInstructions() == 0) {
|
||||||
|
if (basicBlock->getNumSuccessors() == 1) {
|
||||||
|
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// 如果只有phi指令和一个uncondbr。(phi)*(uncondbr)?
|
||||||
|
// 判断除了最后一个指令之外是不是只有phi指令
|
||||||
|
bool onlyPhi = true;
|
||||||
|
for (auto &inst : basicBlock->getInstructions()) {
|
||||||
|
if (!inst->isPhi() && !inst->isUnconditional()) {
|
||||||
|
onlyPhi = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(onlyPhi)
|
||||||
|
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// 更新基本块信息,增加必要指令
|
||||||
|
for (auto &basicBlock : basicBlocks) {
|
||||||
|
// 把空块转换成只有跳转指令的不可达块
|
||||||
|
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
|
||||||
|
if (basicBlock->getNumSuccessors() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (basicBlock->getNumSuccessors() > 1) {
|
||||||
|
assert("");
|
||||||
|
}
|
||||||
|
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||||
|
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto thelastinst = basicBlock->getInstructions().end();
|
||||||
|
--thelastinst;
|
||||||
|
|
||||||
|
// 根据br指令传递的后继块信息,跳过空块链
|
||||||
|
if (thelastinst->get()->isUnconditional()) {
|
||||||
|
BasicBlock* OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||||
|
BasicBlock *thelastBlockOld = nullptr;
|
||||||
|
// 如果空块链表为多个块
|
||||||
|
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
||||||
|
EmptyBlocks.end()) {
|
||||||
|
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||||
|
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
|
||||||
|
}
|
||||||
|
|
||||||
|
basicBlock->removeSuccessor(OldBrBlock);
|
||||||
|
OldBrBlock->removePredecessor(basicBlock.get());
|
||||||
|
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||||
|
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||||
|
|
||||||
|
if (thelastBlockOld != nullptr) {
|
||||||
|
int indexphi = 0;
|
||||||
|
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
||||||
|
if (pred == thelastBlockOld) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indexphi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新phi指令的操作数
|
||||||
|
// 移除thelastBlockOld对应的phi操作数
|
||||||
|
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||||
|
if (InstInNew->isPhi()) {
|
||||||
|
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (thelastinst->get()->getKind() == Instruction::kCondBr) {
|
||||||
|
auto OldThenBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||||
|
auto OldElseBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||||
|
|
||||||
|
BasicBlock *thelastBlockOld = nullptr;
|
||||||
|
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))) !=
|
||||||
|
EmptyBlocks.end()) {
|
||||||
|
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||||
|
thelastinst->get()->replaceOperand(
|
||||||
|
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
|
||||||
|
}
|
||||||
|
basicBlock->removeSuccessor(OldThenBlock);
|
||||||
|
OldThenBlock->removePredecessor(basicBlock.get());
|
||||||
|
// 处理 then 和 else 分支合并的情况
|
||||||
|
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||||
|
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||||
|
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||||
|
usedelete(thelastinst->get());
|
||||||
|
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||||
|
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||||
|
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
|
||||||
|
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
|
||||||
|
// auto indexInNew = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors().
|
||||||
|
|
||||||
|
if (thelastBlockOld != nullptr) {
|
||||||
|
int indexphi = 0;
|
||||||
|
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getPredecessors()) {
|
||||||
|
if (pred == thelastBlockOld) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indexphi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
|
||||||
|
if (InstInNew->isPhi()) {
|
||||||
|
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thelastBlockOld = nullptr;
|
||||||
|
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) !=
|
||||||
|
EmptyBlocks.end()) {
|
||||||
|
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||||
|
thelastinst->get()->replaceOperand(
|
||||||
|
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
|
||||||
|
}
|
||||||
|
basicBlock->removeSuccessor(OldElseBlock);
|
||||||
|
OldElseBlock->removePredecessor(basicBlock.get());
|
||||||
|
// 处理 then 和 else 分支合并的情况
|
||||||
|
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||||
|
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||||
|
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||||
|
usedelete(thelastinst->get());
|
||||||
|
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||||
|
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||||
|
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
|
||||||
|
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
|
||||||
|
|
||||||
|
if (thelastBlockOld != nullptr) {
|
||||||
|
int indexphi = 0;
|
||||||
|
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getPredecessors()) {
|
||||||
|
if (pred == thelastBlockOld) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indexphi++;
|
||||||
|
}
|
||||||
|
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
|
||||||
|
if (InstInNew->isPhi()) {
|
||||||
|
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (basicBlock->getNumSuccessors() == 1) {
|
||||||
|
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||||
|
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||||
|
auto thelastinst = basicBlock->getInstructions().end();
|
||||||
|
(--thelastinst);
|
||||||
|
auto OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||||
|
sysy::BasicBlock *thelastBlockOld = nullptr;
|
||||||
|
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
||||||
|
EmptyBlocks.end()) {
|
||||||
|
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||||
|
|
||||||
|
thelastinst->get()->replaceOperand(
|
||||||
|
0, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))]);
|
||||||
|
}
|
||||||
|
|
||||||
|
basicBlock->removeSuccessor(OldBrBlock);
|
||||||
|
OldBrBlock->removePredecessor(basicBlock.get());
|
||||||
|
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||||
|
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||||
|
if (thelastBlockOld != nullptr) {
|
||||||
|
int indexphi = 0;
|
||||||
|
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
||||||
|
if (pred == thelastBlockOld) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indexphi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||||
|
if (InstInNew->isPhi()) {
|
||||||
|
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto iter = function.second->getBasicBlocks().begin(); iter != function.second->getBasicBlocks().end();) {
|
||||||
|
|
||||||
|
if (EmptyBlocks.find(iter->get()) != EmptyBlocks.end()) {
|
||||||
|
// EntryBlock跳过
|
||||||
|
if (iter->get() == function.second->getEntryBlock()) {
|
||||||
|
++iter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &iterInst : iter->get()->getInstructions())
|
||||||
|
usedelete(iterInst.get());
|
||||||
|
// 删除不可达基本块的phi指令的操作数
|
||||||
|
for (auto &succ : iter->get()->getSuccessors()) {
|
||||||
|
int index = 0;
|
||||||
|
for (auto &pred : succ->getPredecessors()) {
|
||||||
|
if (pred == iter->get()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &instinsucc : succ->getInstructions()) {
|
||||||
|
if (instinsucc->isPhi()) {
|
||||||
|
dynamic_cast<PhiInst *>(instinsucc.get())->removeOperand(index);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function.second->removeBasicBlock((iter++)->get());
|
||||||
|
} else {
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
|
||||||
|
void SysYOptPre::SysYAddReturn() {
|
||||||
|
auto &functions = pModule->getFunctions();
|
||||||
|
for (auto &function : functions) {
|
||||||
|
auto &func = function.second;
|
||||||
|
auto basicBlocks = func->getBasicBlocks();
|
||||||
|
for (auto &block : basicBlocks) {
|
||||||
|
if (block->getNumSuccessors() == 0) {
|
||||||
|
// 如果基本块没有后继块,则添加一个返回指令
|
||||||
|
if (block->getNumInstructions() == 0) {
|
||||||
|
pBuilder->setPosition(block.get(), block->end());
|
||||||
|
pBuilder->createReturnInst();
|
||||||
|
}
|
||||||
|
auto thelastinst = block->getInstructions().end();
|
||||||
|
--thelastinst;
|
||||||
|
if (thelastinst->get()->getKind() != Instruction::kReturn) {
|
||||||
|
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default return." << std::endl;
|
||||||
|
|
||||||
|
pBuilder->setPosition(block.get(), block->end());
|
||||||
|
// TODO: 如果int float函数缺少返回值是否需要报错
|
||||||
|
if (func->getReturnType()->isInt()) {
|
||||||
|
pBuilder->createReturnInst(ConstantInteger::get(0));
|
||||||
|
} else if (func->getReturnType()->isFloat()) {
|
||||||
|
pBuilder->createReturnInst(ConstantFloating::get(0.0F));
|
||||||
|
} else {
|
||||||
|
pBuilder->createReturnInst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@ -1,36 +0,0 @@
|
|||||||
// PassManager.cpp
|
|
||||||
#include "SysYIRPassManager.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
void PassManager::run(Module& M) {
|
|
||||||
// 首先运行Module级别的Pass
|
|
||||||
for (auto& pass : modulePasses) {
|
|
||||||
std::cout << "Running Module Pass: " << pass->getPassName() << std::endl;
|
|
||||||
pass->runOnModule(M);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 然后对每个函数运行Function级别的Pass
|
|
||||||
auto& functions = M.getFunctions();
|
|
||||||
for (auto& pair : functions) {
|
|
||||||
Function& F = *(pair.second); // 获取Function的引用
|
|
||||||
std::cout << " Processing Function: " << F.getName() << std::endl;
|
|
||||||
|
|
||||||
// 在每个函数上运行FunctionPasses
|
|
||||||
bool changedInFunction;
|
|
||||||
do {
|
|
||||||
changedInFunction = false;
|
|
||||||
for (auto& pass : functionPasses) {
|
|
||||||
// 对于FunctionPasses,可以考虑一个迭代执行的循环,直到稳定
|
|
||||||
std::cout << " Running Function Pass: " << pass->getPassName() << std::endl;
|
|
||||||
changedInFunction |= pass->runOnFunction(F);
|
|
||||||
}
|
|
||||||
} while (changedInFunction); // 循环直到函数稳定,这模拟了您SysYCFGOpt的while(changed)逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分析Pass的运行可以在其他Pass需要时触发,或者在特定的PassManager阶段触发
|
|
||||||
// 对于依赖于分析结果的Pass,可以在其run方法中通过PassManager::getAnalysis()来获取
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@ -3,11 +3,12 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "IR.h" // 确保IR.h包含了ArrayType、GetElementPtrInst等的定义
|
#include "IR.h"
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
void SysYPrinter::printIR() {
|
void SysYPrinter::printIR() {
|
||||||
|
|
||||||
const auto &functions = pModule->getFunctions();
|
const auto &functions = pModule->getFunctions();
|
||||||
|
|
||||||
//TODO: Print target datalayout and triple (minimal required by LLVM)
|
//TODO: Print target datalayout and triple (minimal required by LLVM)
|
||||||
@ -35,18 +36,11 @@ std::string SysYPrinter::getTypeString(Type *type) {
|
|||||||
return "i32";
|
return "i32";
|
||||||
} else if (type->isFloat()) {
|
} else if (type->isFloat()) {
|
||||||
return "float";
|
return "float";
|
||||||
|
|
||||||
} else if (auto ptrType = dynamic_cast<PointerType*>(type)) {
|
} else if (auto ptrType = dynamic_cast<PointerType*>(type)) {
|
||||||
// 递归打印指针指向的类型,然后加上 '*'
|
|
||||||
return getTypeString(ptrType->getBaseType()) + "*";
|
return getTypeString(ptrType->getBaseType()) + "*";
|
||||||
} else if (auto funcType = dynamic_cast<FunctionType*>(type)) {
|
} else if (auto ptrType = dynamic_cast<FunctionType*>(type)) {
|
||||||
// 对于函数类型,打印其返回类型
|
return getTypeString(ptrType->getReturnType());
|
||||||
// 注意:这里可能需要更完整的函数签名打印,取决于你的IR表示方式
|
|
||||||
// 比如:`retType (paramType1, paramType2, ...)`
|
|
||||||
// 但为了简化和LLVM IR兼容性,通常在定义时完整打印
|
|
||||||
return getTypeString(funcType->getReturnType());
|
|
||||||
} else if (auto arrayType = dynamic_cast<ArrayType*>(type)) { // 新增:处理数组类型
|
|
||||||
// 打印格式为 [num_elements x element_type]
|
|
||||||
return "[" + std::to_string(arrayType->getNumElements()) + " x " + getTypeString(arrayType->getElementType()) + "]";
|
|
||||||
}
|
}
|
||||||
assert(false && "Unsupported type");
|
assert(false && "Unsupported type");
|
||||||
return "";
|
return "";
|
||||||
@ -57,23 +51,15 @@ std::string SysYPrinter::getValueName(Value *value) {
|
|||||||
return "@" + global->getName();
|
return "@" + global->getName();
|
||||||
} else if (auto inst = dynamic_cast<Instruction*>(value)) {
|
} else if (auto inst = dynamic_cast<Instruction*>(value)) {
|
||||||
return "%" + inst->getName();
|
return "%" + inst->getName();
|
||||||
} else if (auto constInt = dynamic_cast<ConstantInteger*>(value)) { // 优先匹配具体的常量类型
|
} else if (auto constVal = dynamic_cast<ConstantValue*>(value)) {
|
||||||
return std::to_string(constInt->getInt());
|
if (constVal->isFloat()) {
|
||||||
} else if (auto constFloat = dynamic_cast<ConstantFloating*>(value)) { // 优先匹配具体的常量类型
|
return std::to_string(constVal->getFloat());
|
||||||
return std::to_string(constFloat->getFloat());
|
|
||||||
} else if (auto constUndef = dynamic_cast<UndefinedValue*>(value)) { // 如果有Undef类型
|
|
||||||
return "undef";
|
|
||||||
} else if (auto constVal = dynamic_cast<ConstantValue*>(value)) { // fallback for generic ConstantValue
|
|
||||||
// 这里的逻辑可能需要根据你ConstantValue的实际设计调整
|
|
||||||
// 确保它能处理所有可能的ConstantValue
|
|
||||||
if (constVal->getType()->isFloat()) {
|
|
||||||
return std::to_string(constVal->getFloat());
|
|
||||||
}
|
}
|
||||||
return std::to_string(constVal->getInt());
|
return std::to_string(constVal->getInt());
|
||||||
} else if (auto constVar = dynamic_cast<ConstantVariable*>(value)) {
|
} else if (auto constVar = dynamic_cast<ConstantVariable*>(value)) {
|
||||||
return constVar->getName(); // 假设ConstantVariable有自己的名字或通过getByIndices获取值
|
return constVar->getName();
|
||||||
}
|
}
|
||||||
assert(false && "Unknown value type or unable to get value name");
|
assert(false && "Unknown value type");
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,35 +77,44 @@ void SysYPrinter::printGlobalVariable() {
|
|||||||
for (const auto &global : globals) {
|
for (const auto &global : globals) {
|
||||||
std::cout << "@" << global->getName() << " = global ";
|
std::cout << "@" << global->getName() << " = global ";
|
||||||
|
|
||||||
// 全局变量的类型是一个指针,指向其基类型 (可能是 ArrayType 或 Integer/FloatType)
|
auto baseType = dynamic_cast<PointerType *>(global->getType())->getBaseType();
|
||||||
auto globalVarBaseType = dynamic_cast<PointerType *>(global->getType())->getBaseType();
|
printType(baseType);
|
||||||
printType(globalVarBaseType); // 打印全局变量的实际类型 (例如 i32 或 [10 x i32])
|
|
||||||
|
if (global->getNumDims() > 0) {
|
||||||
|
// Array type
|
||||||
|
std::cout << " [";
|
||||||
|
for (unsigned i = 0; i < global->getNumDims(); i++) {
|
||||||
|
if (i > 0) std::cout << " x ";
|
||||||
|
std::cout << getValueName(global->getDim(i));
|
||||||
|
}
|
||||||
|
std::cout << "]";
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
|
|
||||||
// 检查是否是数组类型 (通过检查 globalVarBaseType 是否是 ArrayType)
|
if (global->getNumDims() > 0) {
|
||||||
if (globalVarBaseType->isArray()) {
|
// Array initializer
|
||||||
// 数组初始化器
|
std::cout << "[";
|
||||||
std::cout << "["; // LLVM IR 数组初始化器格式: [type value, type value, ...]
|
auto values = global->getInitValues();
|
||||||
auto values = global->getInitValues(); // 假设 getInitValues() 返回一个 ValueCounter
|
auto counterValues = values.getValues();
|
||||||
const std::vector<sysy::Value *> &counterValues = values.getValues(); // 获取所有值
|
auto counterNumbers = values.getNumbers();
|
||||||
|
|
||||||
for (size_t i = 0; i < counterValues.size(); i++) {
|
for (size_t i = 0; i < counterNumbers.size(); i++) {
|
||||||
if (i > 0) std::cout << ", ";
|
if (i > 0) std::cout << ", ";
|
||||||
// 打印元素类型,这个元素类型应该是数组的最终元素类型,例如 i32 或 float
|
if (baseType->isFloat()) {
|
||||||
// 可以从 globalVarBaseType 逐层剥离得到最终元素类型,但这里简化为直接从值获取
|
std::cout << "float " << dynamic_cast<ConstantValue*>(counterValues[i])->getFloat();
|
||||||
printType(counterValues[i]->getType());
|
} else {
|
||||||
std::cout << " ";
|
std::cout << "i32 " << dynamic_cast<ConstantValue*>(counterValues[i])->getInt();
|
||||||
printValue(counterValues[i]);
|
}
|
||||||
}
|
}
|
||||||
std::cout << "]";
|
std::cout << "]";
|
||||||
} else {
|
} else {
|
||||||
// 标量初始化器
|
// Scalar initializer
|
||||||
// 假设标量全局变量的初始化值通过 getByIndex(0) 获取
|
if (baseType->isFloat()) {
|
||||||
Value* initVal = global->getByIndex(0);
|
std::cout << "float " << dynamic_cast<ConstantValue*>(global->getByIndex(0))->getFloat();
|
||||||
printType(initVal->getType()); // 打印标量值的类型
|
} else {
|
||||||
std::cout << " ";
|
std::cout << "i32 " << dynamic_cast<ConstantValue*>(global->getByIndex(0))->getInt();
|
||||||
printValue(initVal); // 打印标量值
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << ", align 4" << std::endl;
|
std::cout << ", align 4" << std::endl;
|
||||||
@ -214,19 +209,19 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
case Kind::kFDiv: std::cout << "fdiv"; break;
|
case Kind::kFDiv: std::cout << "fdiv"; break;
|
||||||
case Kind::kICmpEQ: std::cout << "icmp eq"; break;
|
case Kind::kICmpEQ: std::cout << "icmp eq"; break;
|
||||||
case Kind::kICmpNE: std::cout << "icmp ne"; break;
|
case Kind::kICmpNE: std::cout << "icmp ne"; break;
|
||||||
case Kind::kICmpLT: std::cout << "icmp slt"; break; // LLVM uses slt/sgt for signed less/greater than
|
case Kind::kICmpLT: std::cout << "icmp slt"; break;
|
||||||
case Kind::kICmpGT: std::cout << "icmp sgt"; break;
|
case Kind::kICmpGT: std::cout << "icmp sgt"; break;
|
||||||
case Kind::kICmpLE: std::cout << "icmp sle"; break;
|
case Kind::kICmpLE: std::cout << "icmp sle"; break;
|
||||||
case Kind::kICmpGE: std::cout << "icmp sge"; break;
|
case Kind::kICmpGE: std::cout << "icmp sge"; break;
|
||||||
case Kind::kFCmpEQ: std::cout << "fcmp oeq"; break; // oeq for ordered equal
|
case Kind::kFCmpEQ: std::cout << "fcmp oeq"; break;
|
||||||
case Kind::kFCmpNE: std::cout << "fcmp one"; break; // one for ordered not equal
|
case Kind::kFCmpNE: std::cout << "fcmp one"; break;
|
||||||
case Kind::kFCmpLT: std::cout << "fcmp olt"; break; // olt for ordered less than
|
case Kind::kFCmpLT: std::cout << "fcmp olt"; break;
|
||||||
case Kind::kFCmpGT: std::cout << "fcmp ogt"; break; // ogt for ordered greater than
|
case Kind::kFCmpGT: std::cout << "fcmp ogt"; break;
|
||||||
case Kind::kFCmpLE: std::cout << "fcmp ole"; break; // ole for ordered less than or equal
|
case Kind::kFCmpLE: std::cout << "fcmp ole"; break;
|
||||||
case Kind::kFCmpGE: std::cout << "fcmp oge"; break; // oge for ordered greater than or equal
|
case Kind::kFCmpGE: std::cout << "fcmp oge"; break;
|
||||||
case Kind::kAnd: std::cout << "and"; break;
|
case Kind::kAnd: std::cout << "and"; break;
|
||||||
case Kind::kOr: std::cout << "or"; break;
|
case Kind::kOr: std::cout << "or"; break;
|
||||||
default: break; // Should not reach here
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Types and operands
|
// Types and operands
|
||||||
@ -243,6 +238,7 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
case Kind::kNeg:
|
case Kind::kNeg:
|
||||||
case Kind::kNot:
|
case Kind::kNot:
|
||||||
case Kind::kFNeg:
|
case Kind::kFNeg:
|
||||||
|
case Kind::kFNot:
|
||||||
case Kind::kFtoI:
|
case Kind::kFtoI:
|
||||||
case Kind::kBitFtoI:
|
case Kind::kBitFtoI:
|
||||||
case Kind::kItoF:
|
case Kind::kItoF:
|
||||||
@ -254,39 +250,31 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (pInst->getKind()) {
|
switch (pInst->getKind()) {
|
||||||
case Kind::kNeg: std::cout << "sub "; break; // integer negation is `sub i32 0, operand`
|
case Kind::kNeg: std::cout << "sub "; break;
|
||||||
case Kind::kNot: std::cout << "xor "; break; // logical/bitwise NOT is `xor i32 -1, operand` or `xor i1 true, operand`
|
case Kind::kNot: std::cout << "not "; break;
|
||||||
case Kind::kFNeg: std::cout << "fneg "; break; // float negation
|
case Kind::kFNeg: std::cout << "fneg "; break;
|
||||||
case Kind::kFtoI: std::cout << "fptosi "; break; // float to signed integer
|
case Kind::kFNot: std::cout << "fneg "; break; // FNot not standard, map to fneg
|
||||||
case Kind::kBitFtoI: std::cout << "bitcast "; break; // bitcast float to int
|
case Kind::kFtoI: std::cout << "fptosi "; break;
|
||||||
case Kind::kItoF: std::cout << "sitofp "; break; // signed integer to float
|
case Kind::kBitFtoI: std::cout << "bitcast "; break;
|
||||||
case Kind::kBitItoF: std::cout << "bitcast "; break; // bitcast int to float
|
case Kind::kItoF: std::cout << "sitofp "; break;
|
||||||
default: break; // Should not reach here
|
case Kind::kBitItoF: std::cout << "bitcast "; break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printType(unyInst->getOperand()->getType()); // Print operand type
|
printType(unyInst->getType());
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
|
|
||||||
// Special handling for integer negation and logical NOT
|
// Special handling for negation
|
||||||
if (pInst->getKind() == Kind::kNeg) {
|
if (pInst->getKind() == Kind::kNeg || pInst->getKind() == Kind::kNot) {
|
||||||
std::cout << "0, "; // for 'sub i32 0, operand'
|
std::cout << "i32 0, ";
|
||||||
} else if (pInst->getKind() == Kind::kNot) {
|
|
||||||
// For logical NOT (i1 -> i1), use 'xor i1 true, operand'
|
|
||||||
// For bitwise NOT (i32 -> i32), use 'xor i32 -1, operand'
|
|
||||||
if (unyInst->getOperand()->getType()->isInt()) { // Assuming i32 for bitwise NOT
|
|
||||||
std::cout << "NOT, "; // or specific bitmask for NOT
|
|
||||||
} else { // Assuming i1 for logical NOT
|
|
||||||
std::cout << "true, ";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printValue(pInst->getOperand(0));
|
printValue(pInst->getOperand(0));
|
||||||
|
|
||||||
// For type conversions (fptosi, sitofp, bitcast), need to specify destination type
|
// For bitcast, need to specify destination type
|
||||||
if (pInst->getKind() == Kind::kFtoI || pInst->getKind() == Kind::kItoF ||
|
if (pInst->getKind() == Kind::kBitFtoI || pInst->getKind() == Kind::kBitItoF) {
|
||||||
pInst->getKind() == Kind::kBitFtoI || pInst->getKind() == Kind::kBitItoF) {
|
|
||||||
std::cout << " to ";
|
std::cout << " to ";
|
||||||
printType(unyInst->getType()); // Print result type
|
printType(unyInst->getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
@ -301,7 +289,7 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "call ";
|
std::cout << "call ";
|
||||||
printType(callInst->getType()); // Return type of the call
|
printType(callInst->getType());
|
||||||
std::cout << " @" << function->getName() << "(";
|
std::cout << " @" << function->getName() << "(";
|
||||||
|
|
||||||
auto params = callInst->getArguments();
|
auto params = callInst->getArguments();
|
||||||
@ -309,9 +297,9 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
for (auto ¶m : params) {
|
for (auto ¶m : params) {
|
||||||
if (!first) std::cout << ", ";
|
if (!first) std::cout << ", ";
|
||||||
first = false;
|
first = false;
|
||||||
printType(param->getValue()->getType()); // Type of argument
|
printType(param->getValue()->getType());
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
printValue(param->getValue()); // Value of argument
|
printValue(param->getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << ")" << std::endl;
|
std::cout << ")" << std::endl;
|
||||||
@ -319,7 +307,7 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
|
|
||||||
case Kind::kCondBr: {
|
case Kind::kCondBr: {
|
||||||
auto condBrInst = dynamic_cast<CondBrInst *>(pInst);
|
auto condBrInst = dynamic_cast<CondBrInst *>(pInst);
|
||||||
std::cout << "br i1 "; // Condition type should be i1
|
std::cout << "br i1 ";
|
||||||
printValue(condBrInst->getCondition());
|
printValue(condBrInst->getCondition());
|
||||||
std::cout << ", label %" << condBrInst->getThenBlock()->getName();
|
std::cout << ", label %" << condBrInst->getThenBlock()->getName();
|
||||||
std::cout << ", label %" << condBrInst->getElseBlock()->getName();
|
std::cout << ", label %" << condBrInst->getElseBlock()->getName();
|
||||||
@ -349,17 +337,14 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
auto allocaInst = dynamic_cast<AllocaInst *>(pInst);
|
auto allocaInst = dynamic_cast<AllocaInst *>(pInst);
|
||||||
std::cout << "%" << allocaInst->getName() << " = alloca ";
|
std::cout << "%" << allocaInst->getName() << " = alloca ";
|
||||||
|
|
||||||
// AllocaInst 的类型现在应该是一个 PointerType,指向正确的 ArrayType 或 ScalarType
|
auto baseType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
|
||||||
// 例如:alloca i32, align 4 或者 alloca [10 x i32], align 4
|
printType(baseType);
|
||||||
auto allocatedType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
|
|
||||||
printType(allocatedType);
|
|
||||||
|
|
||||||
// 仍然打印维度信息,如果存在的话
|
if (allocaInst->getNumDims() > 0) {
|
||||||
if (allocaInst->getNumDims() > 0) {
|
|
||||||
std::cout << ", ";
|
std::cout << ", ";
|
||||||
for (size_t i = 0; i < allocaInst->getNumDims(); i++) {
|
for (size_t i = 0; i < allocaInst->getNumDims(); i++) {
|
||||||
if (i > 0) std::cout << ", ";
|
if (i > 0) std::cout << ", ";
|
||||||
printType(Type::getIntType()); // 维度大小通常是 i32 类型
|
printType(Type::getIntType());
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
printValue(allocaInst->getDim(i));
|
printValue(allocaInst->getDim(i));
|
||||||
}
|
}
|
||||||
@ -371,74 +356,70 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
case Kind::kLoad: {
|
case Kind::kLoad: {
|
||||||
auto loadInst = dynamic_cast<LoadInst *>(pInst);
|
auto loadInst = dynamic_cast<LoadInst *>(pInst);
|
||||||
std::cout << "%" << loadInst->getName() << " = load ";
|
std::cout << "%" << loadInst->getName() << " = load ";
|
||||||
printType(loadInst->getType()); // 加载的结果类型
|
printType(loadInst->getType());
|
||||||
std::cout << ", ";
|
std::cout << ", ";
|
||||||
printType(loadInst->getPointer()->getType()); // 指针类型
|
printType(loadInst->getPointer()->getType());
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
printValue(loadInst->getPointer()); // 要加载的地址
|
printValue(loadInst->getPointer());
|
||||||
|
|
||||||
// 仍然打印索引信息,如果存在的话
|
|
||||||
if (loadInst->getNumIndices() > 0) {
|
if (loadInst->getNumIndices() > 0) {
|
||||||
std::cout << ", indices "; // 或者其他分隔符,取决于你期望的格式
|
std::cout << ", ";
|
||||||
for (size_t i = 0; i < loadInst->getNumIndices(); i++) {
|
for (size_t i = 0; i < loadInst->getNumIndices(); i++) {
|
||||||
if (i > 0) std::cout << ", ";
|
if (i > 0) std::cout << ", ";
|
||||||
printType(loadInst->getIndex(i)->getType());
|
printType(Type::getIntType());
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
printValue(loadInst->getIndex(i));
|
printValue(loadInst->getIndex(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << ", align 4" << std::endl;
|
std::cout << ", align 4" << std::endl;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case Kind::kLa: {
|
||||||
|
auto laInst = dynamic_cast<LaInst *>(pInst);
|
||||||
|
std::cout << "%" << laInst->getName() << " = getelementptr inbounds ";
|
||||||
|
|
||||||
|
auto ptrType = dynamic_cast<PointerType*>(laInst->getPointer()->getType());
|
||||||
|
printType(ptrType->getBaseType());
|
||||||
|
std::cout << ", ";
|
||||||
|
printType(laInst->getPointer()->getType());
|
||||||
|
std::cout << " ";
|
||||||
|
printValue(laInst->getPointer());
|
||||||
|
std::cout << ", ";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < laInst->getNumIndices(); i++) {
|
||||||
|
if (i > 0) std::cout << ", ";
|
||||||
|
printType(Type::getIntType());
|
||||||
|
std::cout << " ";
|
||||||
|
printValue(laInst->getIndex(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
} break;
|
||||||
|
|
||||||
case Kind::kStore: {
|
case Kind::kStore: {
|
||||||
auto storeInst = dynamic_cast<StoreInst *>(pInst);
|
auto storeInst = dynamic_cast<StoreInst *>(pInst);
|
||||||
std::cout << "store ";
|
std::cout << "store ";
|
||||||
printType(storeInst->getValue()->getType()); // 要存储的值的类型
|
printType(storeInst->getValue()->getType());
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
printValue(storeInst->getValue()); // 要存储的值
|
printValue(storeInst->getValue());
|
||||||
std::cout << ", ";
|
std::cout << ", ";
|
||||||
printType(storeInst->getPointer()->getType()); // 目标指针的类型
|
printType(storeInst->getPointer()->getType());
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
printValue(storeInst->getPointer()); // 目标地址
|
printValue(storeInst->getPointer());
|
||||||
|
|
||||||
// 仍然打印索引信息,如果存在的话
|
|
||||||
if (storeInst->getNumIndices() > 0) {
|
if (storeInst->getNumIndices() > 0) {
|
||||||
std::cout << ", indices "; // 或者其他分隔符
|
std::cout << ", ";
|
||||||
for (size_t i = 0; i < storeInst->getNumIndices(); i++) {
|
for (size_t i = 0; i < storeInst->getNumIndices(); i++) {
|
||||||
if (i > 0) std::cout << ", ";
|
if (i > 0) std::cout << ", ";
|
||||||
printType(storeInst->getIndex(i)->getType());
|
printType(Type::getIntType());
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
printValue(storeInst->getIndex(i));
|
printValue(storeInst->getIndex(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << ", align 4" << std::endl;
|
std::cout << ", align 4" << std::endl;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Kind::kGetElementPtr: { // 新增:GetElementPtrInst 打印
|
|
||||||
auto gepInst = dynamic_cast<GetElementPtrInst*>(pInst);
|
|
||||||
std::cout << "%" << gepInst->getName() << " = getelementptr inbounds "; // 假设总是 inbounds
|
|
||||||
|
|
||||||
// GEP 的第一个操作数是基指针,其类型是一个指向聚合类型的指针
|
|
||||||
// 第一个参数是基指针所指向的聚合类型的类型 (e.g., [10 x i32])
|
|
||||||
auto basePtrType = dynamic_cast<PointerType*>(gepInst->getBasePointer()->getType());
|
|
||||||
printType(basePtrType->getBaseType()); // 打印基指针指向的类型
|
|
||||||
|
|
||||||
std::cout << ", ";
|
|
||||||
printType(gepInst->getBasePointer()->getType()); // 打印基指针自身的类型 (e.g., [10 x i32]*)
|
|
||||||
std::cout << " ";
|
|
||||||
printValue(gepInst->getBasePointer()); // 打印基指针
|
|
||||||
|
|
||||||
// 打印所有索引
|
|
||||||
for (auto indexVal : gepInst->getIndices()) { // 使用 getIndices() 迭代器
|
|
||||||
std::cout << ", ";
|
|
||||||
printType(indexVal->getValue()->getType()); // 打印索引的类型 (通常是 i32)
|
|
||||||
std::cout << " ";
|
|
||||||
printValue(indexVal->getValue()); // 打印索引值
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Kind::kMemset: {
|
case Kind::kMemset: {
|
||||||
auto memsetInst = dynamic_cast<MemsetInst *>(pInst);
|
auto memsetInst = dynamic_cast<MemsetInst *>(pInst);
|
||||||
@ -452,40 +433,51 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
printValue(memsetInst->getValue());
|
printValue(memsetInst->getValue());
|
||||||
std::cout << ", i32 ";
|
std::cout << ", i32 ";
|
||||||
printValue(memsetInst->getSize());
|
printValue(memsetInst->getSize());
|
||||||
std::cout << ", i1 false)" << std::endl; // alignment for memset is typically i1
|
std::cout << ", i1 false)" << std::endl;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Kind::kPhi: {
|
case Kind::kPhi: {
|
||||||
auto phiInst = dynamic_cast<PhiInst *>(pInst);
|
auto phiInst = dynamic_cast<PhiInst *>(pInst);
|
||||||
// Phi 指令的名称通常是结果变量
|
printValue(phiInst->getOperand(0));
|
||||||
std::cout << "%" << phiInst->getName() << " = phi ";
|
std::cout << " = phi ";
|
||||||
printType(phiInst->getType()); // Phi 结果类型
|
printType(phiInst->getType());
|
||||||
|
|
||||||
// Phi 指令的操作数是成对的 [value, basic_block]
|
for (unsigned i = 1; i < phiInst->getNumOperands(); i++) {
|
||||||
// 这里假设 getOperands() 返回的是 (val1, block1, val2, block2...)
|
if (i > 0) std::cout << ", ";
|
||||||
// 如果你的 PhiInst 存储方式是 getIncomingValues() 和 getIncomingBlocks(),请相应调整
|
|
||||||
// LLVM IR 格式: phi type [value1, block1], [value2, block2]
|
|
||||||
bool firstPair = true;
|
|
||||||
for (unsigned i = 0; i < phiInst->getNumOperands() / 2; ++i) { // 遍历成对的操作数
|
|
||||||
if (!firstPair) std::cout << ", ";
|
|
||||||
firstPair = false;
|
|
||||||
std::cout << "[ ";
|
std::cout << "[ ";
|
||||||
printValue(phiInst->getOperand(i * 2)); // value
|
printValue(phiInst->getOperand(i));
|
||||||
std::cout << ", %";
|
|
||||||
printValue(phiInst->getOperand(i * 2 + 1)); // block
|
|
||||||
std::cout << " ]";
|
std::cout << " ]";
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
// 以下两个 Kind 应该删除或替换为 kGEP
|
case Kind::kGetSubArray: {
|
||||||
// case Kind::kLa: { /* REMOVED */ } break;
|
auto getSubArrayInst = dynamic_cast<GetSubArrayInst *>(pInst);
|
||||||
// case Kind::kGetSubArray: { /* REMOVED */ } break;
|
std::cout << "%" << getSubArrayInst->getName() << " = getelementptr inbounds ";
|
||||||
|
|
||||||
|
auto ptrType = dynamic_cast<PointerType*>(getSubArrayInst->getFatherArray()->getType());
|
||||||
|
printType(ptrType->getBaseType());
|
||||||
|
std::cout << ", ";
|
||||||
|
printType(getSubArrayInst->getFatherArray()->getType());
|
||||||
|
std::cout << " ";
|
||||||
|
printValue(getSubArrayInst->getFatherArray());
|
||||||
|
std::cout << ", ";
|
||||||
|
bool firstIndex = true;
|
||||||
|
for (auto &index : getSubArrayInst->getIndices()) {
|
||||||
|
if (!firstIndex) std::cout << ", ";
|
||||||
|
firstIndex = false;
|
||||||
|
printType(Type::getIntType());
|
||||||
|
std::cout << " ";
|
||||||
|
printValue(index->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false && "Unsupported instruction kind in SysYPrinter");
|
assert(false && "Unsupported instruction kind");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
#include "IR.h"
|
#include "IR.h"
|
||||||
#include "SysYIRAnalyser.h"
|
#include "SysYIRAnalyser.h"
|
||||||
#include "SysYIRPrinter.h"
|
#include "SysYIRPrinter.h"
|
||||||
#include "SysYIROptUtils.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@ -32,5 +31,9 @@ class DeadCodeElimination {
|
|||||||
void eliminateDeadGlobals(bool& changed); // 消除无用全局变量
|
void eliminateDeadGlobals(bool& changed); // 消除无用全局变量
|
||||||
void eliminateDeadIndirectiveAllocas(Function* func, bool& changed); // 消除无用间接内存分配(phi节点)
|
void eliminateDeadIndirectiveAllocas(Function* func, bool& changed); // 消除无用间接内存分配(phi节点)
|
||||||
void eliminateDeadRedundantLoadStore(Function* func, bool& changed); // 消除冗余加载和存储
|
void eliminateDeadRedundantLoadStore(Function* func, bool& changed); // 消除冗余加载和存储
|
||||||
|
bool isGlobal(Value *val);
|
||||||
|
bool isArr(Value *val);
|
||||||
|
void usedelete(Instruction *instr);
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|||||||
222
src/include/IR.h
222
src/include/IR.h
@ -49,7 +49,6 @@ class Type {
|
|||||||
kLabel,
|
kLabel,
|
||||||
kPointer,
|
kPointer,
|
||||||
kFunction,
|
kFunction,
|
||||||
kArray,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Kind kind; ///< 表示具体类型的变量
|
Kind kind; ///< 表示具体类型的变量
|
||||||
@ -66,7 +65,6 @@ class Type {
|
|||||||
static Type* getPointerType(Type *baseType); ///< 返回表示指向baseType类型的Pointer类型的Type指针
|
static Type* getPointerType(Type *baseType); ///< 返回表示指向baseType类型的Pointer类型的Type指针
|
||||||
static Type* getFunctionType(Type *returnType, const std::vector<Type *> ¶mTypes = {});
|
static Type* getFunctionType(Type *returnType, const std::vector<Type *> ¶mTypes = {});
|
||||||
///< 返回表示返回类型为returnType,形参类型列表为paramTypes的函数类型的Type指针
|
///< 返回表示返回类型为returnType,形参类型列表为paramTypes的函数类型的Type指针
|
||||||
static Type* getArrayType(Type *elementType, unsigned numElements);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Kind getKind() const { return kind; } ///< 返回Type对象代表原始标量类型
|
Kind getKind() const { return kind; } ///< 返回Type对象代表原始标量类型
|
||||||
@ -76,7 +74,6 @@ class Type {
|
|||||||
bool isLabel() const { return kind == kLabel; } ///< 判定是否为Label类型
|
bool isLabel() const { return kind == kLabel; } ///< 判定是否为Label类型
|
||||||
bool isPointer() const { return kind == kPointer; } ///< 判定是否为Pointer类型
|
bool isPointer() const { return kind == kPointer; } ///< 判定是否为Pointer类型
|
||||||
bool isFunction() const { return kind == kFunction; } ///< 判定是否为Function类型
|
bool isFunction() const { return kind == kFunction; } ///< 判定是否为Function类型
|
||||||
bool isArray() const { return kind == Kind::kArray; }
|
|
||||||
unsigned getSize() const; ///< 返回类型所占的空间大小(字节)
|
unsigned getSize() const; ///< 返回类型所占的空间大小(字节)
|
||||||
/// 尝试将一个变量转换为给定的Type及其派生类类型的变量
|
/// 尝试将一个变量转换为给定的Type及其派生类类型的变量
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -118,22 +115,6 @@ class FunctionType : public Type {
|
|||||||
unsigned getNumParams() const { return paramTypes.size(); } ///< 获取形参数量
|
unsigned getNumParams() const { return paramTypes.size(); } ///< 获取形参数量
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArrayType : public Type {
|
|
||||||
public:
|
|
||||||
// elements:数组的元素类型 (例如,int[3] 的 elementType 是 int)
|
|
||||||
// numElements:该维度的大小 (例如,int[3] 的 numElements 是 3)
|
|
||||||
static ArrayType *get(Type *elementType, unsigned numElements);
|
|
||||||
|
|
||||||
Type *getElementType() const { return elementType; }
|
|
||||||
unsigned getNumElements() const { return numElements; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ArrayType(Type *elementType, unsigned numElements)
|
|
||||||
: Type(Kind::kArray), elementType(elementType), numElements(numElements) {}
|
|
||||||
Type *elementType;
|
|
||||||
unsigned numElements; // 当前维度的大小
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
@ -621,6 +602,49 @@ class User : public Value {
|
|||||||
void setOperand(unsigned index, Value *value); ///< 设置操作数
|
void setOperand(unsigned index, Value *value); ///< 设置操作数
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GetSubArrayInst;
|
||||||
|
/**
|
||||||
|
* 左值 具有地址的对象
|
||||||
|
*/
|
||||||
|
class LVal {
|
||||||
|
friend class GetSubArrayInst;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
LVal *fatherLVal{}; ///< 父左值
|
||||||
|
std::list<std::unique_ptr<LVal>> childrenLVals; ///< 子左值
|
||||||
|
GetSubArrayInst *defineInst{}; /// 定义该左值的GetSubArray指令
|
||||||
|
|
||||||
|
protected:
|
||||||
|
LVal() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~LVal() = default;
|
||||||
|
virtual std::vector<Value *> getLValDims() const = 0; ///< 获取左值的维度
|
||||||
|
virtual unsigned getLValNumDims() const = 0; ///< 获取左值的维度数量
|
||||||
|
|
||||||
|
public:
|
||||||
|
LVal* getFatherLVal() const { return fatherLVal; } ///< 获取父左值
|
||||||
|
const std::list<std::unique_ptr<LVal>>& getChildrenLVals() const {
|
||||||
|
return childrenLVals;
|
||||||
|
} ///< 获取子左值列表
|
||||||
|
LVal* getAncestorLVal() const {
|
||||||
|
auto curLVal = const_cast<LVal *>(this);
|
||||||
|
while (curLVal->getFatherLVal() != nullptr) {
|
||||||
|
curLVal = curLVal->getFatherLVal();
|
||||||
|
}
|
||||||
|
return curLVal;
|
||||||
|
} ///< 获取祖先左值
|
||||||
|
void setFatherLVal(LVal *father) { fatherLVal = father; } ///< 设置父左值
|
||||||
|
void setDefineInst(GetSubArrayInst *inst) { defineInst = inst; } ///< 设置定义指令
|
||||||
|
void addChild(LVal *child) { childrenLVals.emplace_back(child); } ///< 添加子左值
|
||||||
|
void removeChild(LVal *child) {
|
||||||
|
auto iter = std::find_if(childrenLVals.begin(), childrenLVals.end(),
|
||||||
|
[child](const std::unique_ptr<LVal> &ptr) { return ptr.get() == child; });
|
||||||
|
childrenLVals.erase(iter);
|
||||||
|
} ///< 移除子左值
|
||||||
|
GetSubArrayInst* getDefineInst() const { return defineInst; } ///< 获取定义指令
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Base of all concrete instruction types.
|
* Base of all concrete instruction types.
|
||||||
*/
|
*/
|
||||||
@ -670,15 +694,15 @@ class Instruction : public User {
|
|||||||
kAlloca = 0x1UL << 33,
|
kAlloca = 0x1UL << 33,
|
||||||
kLoad = 0x1UL << 34,
|
kLoad = 0x1UL << 34,
|
||||||
kStore = 0x1UL << 35,
|
kStore = 0x1UL << 35,
|
||||||
kGetElementPtr = 0x1UL << 36,
|
kLa = 0x1UL << 36,
|
||||||
kMemset = 0x1UL << 37,
|
kMemset = 0x1UL << 37,
|
||||||
// kGetSubArray = 0x1UL << 38,
|
kGetSubArray = 0x1UL << 38,
|
||||||
// Constant Kind removed as Constants are now Values, not Instructions.
|
// Constant Kind removed as Constants are now Values, not Instructions.
|
||||||
// kConstant = 0x1UL << 37, // Conflicts with kMemset if kept as is
|
// kConstant = 0x1UL << 37, // Conflicts with kMemset if kept as is
|
||||||
// phi
|
// phi
|
||||||
kPhi = 0x1UL << 39,
|
kPhi = 0x1UL << 39,
|
||||||
kBitItoF = 0x1UL << 40,
|
kBitItoF = 0x1UL << 40,
|
||||||
kBitFtoI = 0x1UL << 41,
|
kBitFtoI = 0x1UL << 41
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -769,12 +793,14 @@ public:
|
|||||||
return "Load";
|
return "Load";
|
||||||
case kStore:
|
case kStore:
|
||||||
return "Store";
|
return "Store";
|
||||||
case kGetElementPtr:
|
case kLa:
|
||||||
return "GetElementPtr";
|
return "La";
|
||||||
case kMemset:
|
case kMemset:
|
||||||
return "Memset";
|
return "Memset";
|
||||||
case kPhi:
|
case kPhi:
|
||||||
return "Phi";
|
return "Phi";
|
||||||
|
case kGetSubArray:
|
||||||
|
return "GetSubArray";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
@ -827,8 +853,9 @@ public:
|
|||||||
bool isAlloca() const { return kind == kAlloca; }
|
bool isAlloca() const { return kind == kAlloca; }
|
||||||
bool isLoad() const { return kind == kLoad; }
|
bool isLoad() const { return kind == kLoad; }
|
||||||
bool isStore() const { return kind == kStore; }
|
bool isStore() const { return kind == kStore; }
|
||||||
bool isGetElementPtr() const { return kind == kGetElementPtr; }
|
bool isLa() const { return kind == kLa; }
|
||||||
bool isMemset() const { return kind == kMemset; }
|
bool isMemset() const { return kind == kMemset; }
|
||||||
|
bool isGetSubArray() const { return kind == kGetSubArray; }
|
||||||
bool isCall() const { return kind == kCall; }
|
bool isCall() const { return kind == kCall; }
|
||||||
bool isReturn() const { return kind == kReturn; }
|
bool isReturn() const { return kind == kReturn; }
|
||||||
bool isDefine() const {
|
bool isDefine() const {
|
||||||
@ -840,6 +867,26 @@ public:
|
|||||||
class Function;
|
class Function;
|
||||||
//! Function call.
|
//! Function call.
|
||||||
|
|
||||||
|
class LaInst : public Instruction {
|
||||||
|
friend class Function;
|
||||||
|
friend class IRBuilder;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit LaInst(Value *pointer, const std::vector<Value *> &indices = {}, BasicBlock *parent = nullptr,
|
||||||
|
const std::string &name = "")
|
||||||
|
: Instruction(Kind::kLa, pointer->getType(), parent, name) {
|
||||||
|
assert(pointer);
|
||||||
|
addOperand(pointer);
|
||||||
|
addOperands(indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
unsigned getNumIndices() const { return getNumOperands() - 1; } ///< 获取索引长度
|
||||||
|
Value* getPointer() const { return getOperand(0); } ///< 获取目标变量的Value指针
|
||||||
|
auto getIndices() const { return make_range(std::next(operand_begin()), operand_end()); } ///< 获取索引列表
|
||||||
|
Value* getIndex(unsigned index) const { return getOperand(index + 1); } ///< 获取位置为index的索引分量
|
||||||
|
};
|
||||||
|
|
||||||
class PhiInst : public Instruction {
|
class PhiInst : public Instruction {
|
||||||
friend class IRBuilder;
|
friend class IRBuilder;
|
||||||
friend class Function;
|
friend class Function;
|
||||||
@ -1087,7 +1134,7 @@ public:
|
|||||||
}; // class CondBrInst
|
}; // class CondBrInst
|
||||||
|
|
||||||
//! Allocate memory for stack variables, used for non-global variable declartion
|
//! Allocate memory for stack variables, used for non-global variable declartion
|
||||||
class AllocaInst : public Instruction {
|
class AllocaInst : public Instruction , public LVal {
|
||||||
friend class IRBuilder;
|
friend class IRBuilder;
|
||||||
friend class Function;
|
friend class Function;
|
||||||
protected:
|
protected:
|
||||||
@ -1098,6 +1145,14 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::vector<Value *> getLValDims() const override {
|
||||||
|
std::vector<Value *> dims;
|
||||||
|
for (const auto &dim : getOperands()) {
|
||||||
|
dims.emplace_back(dim->getValue());
|
||||||
|
}
|
||||||
|
return dims;
|
||||||
|
} ///< 获取作为左值的维度数组
|
||||||
|
unsigned getLValNumDims() const override { return getNumOperands(); }
|
||||||
|
|
||||||
int getNumDims() const { return getNumOperands(); }
|
int getNumDims() const { return getNumOperands(); }
|
||||||
auto getDims() const { return getOperands(); }
|
auto getDims() const { return getOperands(); }
|
||||||
@ -1106,40 +1161,37 @@ public:
|
|||||||
}; // class AllocaInst
|
}; // class AllocaInst
|
||||||
|
|
||||||
|
|
||||||
class GetElementPtrInst : public Instruction {
|
class GetSubArrayInst : public Instruction {
|
||||||
friend class IRBuilder; // 如果您有IRBuilder来创建指令,需要friend
|
friend class IRBuilder;
|
||||||
|
friend class Function;
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
// GEP的构造函数:
|
GetSubArrayInst(LVal *fatherArray, LVal *childArray, const std::vector<Value *> &indices,
|
||||||
// resultType: GEP计算出的地址的类型 (通常是指向目标元素类型的指针)
|
BasicBlock *parent = nullptr, const std::string &name = "")
|
||||||
// basePointer: 基指针 (第一个操作数)
|
: Instruction(Kind::kGetSubArray, Type::getVoidType(), parent, name) {
|
||||||
// indices: 索引列表 (后续操作数)
|
auto predicate = [childArray](const std::unique_ptr<LVal> &child) -> bool { return child.get() == childArray; };
|
||||||
GetElementPtrInst(Value *basePointer,
|
if (std::find_if(fatherArray->childrenLVals.begin(), fatherArray->childrenLVals.end(), predicate) ==
|
||||||
const std::vector<Value *> &indices = {},
|
fatherArray->childrenLVals.end()) {
|
||||||
BasicBlock *parent = nullptr, const std::string &name = "")
|
fatherArray->childrenLVals.emplace_back(childArray);
|
||||||
: Instruction(Kind::kGetElementPtr, basePointer->getType(), parent, name) {
|
}
|
||||||
assert(basePointer && "GEP base pointer cannot be null!");
|
childArray->fatherLVal = fatherArray;
|
||||||
// TODO : 安全检查
|
childArray->defineInst = this;
|
||||||
assert(basePointer->getType()->isPointer() );
|
auto fatherArrayValue = dynamic_cast<Value *>(fatherArray);
|
||||||
addOperand(basePointer); // 第一个操作数是基指针
|
auto childArrayValue = dynamic_cast<Value *>(childArray);
|
||||||
addOperands(indices); // 随后的操作数是索引
|
assert(fatherArrayValue);
|
||||||
|
assert(childArrayValue);
|
||||||
|
addOperand(fatherArrayValue);
|
||||||
|
addOperand(childArrayValue);
|
||||||
|
addOperands(indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Value* getBasePointer() const { return getOperand(0); }
|
Value* getFatherArray() const { return getOperand(0); } ///< 获取父数组
|
||||||
unsigned getNumIndices() const { return getNumOperands() - 1; }
|
Value* getChildArray() const { return getOperand(1); } ///< 获取子数组
|
||||||
auto getIndices() const { return make_range(std::next(operand_begin()), operand_end());}
|
LVal* getFatherLVal() const { return dynamic_cast<LVal *>(getOperand(0)); } ///< 获取父左值
|
||||||
Value* getIndex(unsigned index) const {
|
LVal* getChildLVal() const { return dynamic_cast<LVal *>(getOperand(1)); } ///< 获取子左值
|
||||||
assert(index < getNumIndices() && "Index out of bounds for GEP!");
|
auto getIndices() const { return make_range(std::next(operand_begin(), 2), operand_end()); } ///< 获取索引
|
||||||
return getOperand(index + 1);
|
unsigned getNumIndices() const { return getNumOperands() - 2; } ///< 获取索引数量
|
||||||
}
|
|
||||||
|
|
||||||
// 静态工厂方法,用于创建GEP指令 (如果需要外部直接创建而非通过IRBuilder)
|
|
||||||
static GetElementPtrInst* create(Type *resultType, Value *basePointer,
|
|
||||||
const std::vector<Value *> &indices = {},
|
|
||||||
BasicBlock *parent = nullptr, const std::string &name = "") {
|
|
||||||
return new GetElementPtrInst(basePointer, indices, parent, name);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Load a value from memory address specified by a pointer value
|
//! Load a value from memory address specified by a pointer value
|
||||||
@ -1163,7 +1215,22 @@ public:
|
|||||||
return make_range(std::next(operand_begin()), operand_end());
|
return make_range(std::next(operand_begin()), operand_end());
|
||||||
}
|
}
|
||||||
Value* getIndex(int index) const { return getOperand(index + 1); }
|
Value* getIndex(int index) const { return getOperand(index + 1); }
|
||||||
|
std::list<Value *> getAncestorIndices() const {
|
||||||
|
std::list<Value *> indices;
|
||||||
|
for (const auto &index : getIndices()) {
|
||||||
|
indices.emplace_back(index->getValue());
|
||||||
|
}
|
||||||
|
auto curPointer = dynamic_cast<LVal *>(getPointer());
|
||||||
|
while (curPointer->getFatherLVal() != nullptr) {
|
||||||
|
auto inserter = std::next(indices.begin());
|
||||||
|
for (const auto &index : curPointer->getDefineInst()->getIndices()) {
|
||||||
|
indices.insert(inserter, index->getValue());
|
||||||
|
}
|
||||||
|
curPointer = curPointer->getFatherLVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
} ///< 获取相对于祖先数组的索引列表
|
||||||
}; // class LoadInst
|
}; // class LoadInst
|
||||||
|
|
||||||
//! Store a value to memory address specified by a pointer value
|
//! Store a value to memory address specified by a pointer value
|
||||||
@ -1189,6 +1256,22 @@ public:
|
|||||||
return make_range(std::next(operand_begin(), 2), operand_end());
|
return make_range(std::next(operand_begin(), 2), operand_end());
|
||||||
}
|
}
|
||||||
Value* getIndex(int index) const { return getOperand(index + 2); }
|
Value* getIndex(int index) const { return getOperand(index + 2); }
|
||||||
|
std::list<Value *> getAncestorIndices() const {
|
||||||
|
std::list<Value *> indices;
|
||||||
|
for (const auto &index : getIndices()) {
|
||||||
|
indices.emplace_back(index->getValue());
|
||||||
|
}
|
||||||
|
auto curPointer = dynamic_cast<LVal *>(getPointer());
|
||||||
|
while (curPointer->getFatherLVal() != nullptr) {
|
||||||
|
auto inserter = std::next(indices.begin());
|
||||||
|
for (const auto &index : curPointer->getDefineInst()->getIndices()) {
|
||||||
|
indices.insert(inserter, index->getValue());
|
||||||
|
}
|
||||||
|
curPointer = curPointer->getFatherLVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
} ///< 获取相对于祖先数组的索引列表
|
||||||
|
|
||||||
}; // class StoreInst
|
}; // class StoreInst
|
||||||
|
|
||||||
@ -1290,7 +1373,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//! Global value declared at file scope
|
//! Global value declared at file scope
|
||||||
class GlobalValue : public User {
|
class GlobalValue : public User, public LVal {
|
||||||
friend class Module;
|
friend class Module;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -1324,6 +1407,16 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
unsigned getLValNumDims() const override { return numDims; } ///< 获取作为左值的维度数量
|
||||||
|
std::vector<Value *> getLValDims() const override {
|
||||||
|
std::vector<Value *> dims;
|
||||||
|
for (const auto &dim : getOperands()) {
|
||||||
|
dims.emplace_back(dim->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return dims;
|
||||||
|
} ///< 获取作为左值的维度列表
|
||||||
|
|
||||||
unsigned getNumDims() const { return numDims; } ///< 获取维度数量
|
unsigned getNumDims() const { return numDims; } ///< 获取维度数量
|
||||||
Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
|
Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
|
||||||
auto getDims() const { return getOperands(); } ///< 获取维度列表
|
auto getDims() const { return getOperands(); } ///< 获取维度列表
|
||||||
@ -1345,7 +1438,7 @@ public:
|
|||||||
}; // class GlobalValue
|
}; // class GlobalValue
|
||||||
|
|
||||||
|
|
||||||
class ConstantVariable : public User {
|
class ConstantVariable : public User, public LVal {
|
||||||
friend class Module;
|
friend class Module;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -1364,6 +1457,15 @@ class ConstantVariable : public User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
unsigned getLValNumDims() const override { return numDims; } ///< 获取作为左值的维度数量
|
||||||
|
std::vector<Value *> getLValDims() const override {
|
||||||
|
std::vector<Value *> dims;
|
||||||
|
for (const auto &dim : getOperands()) {
|
||||||
|
dims.emplace_back(dim->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return dims;
|
||||||
|
} ///< 获取作为左值的维度列表
|
||||||
Value* getByIndex(unsigned index) const { return initValues.getValue(index); } ///< 通过一维位置index获取值
|
Value* getByIndex(unsigned index) const { return initValues.getValue(index); } ///< 通过一维位置index获取值
|
||||||
Value* getByIndices(const std::vector<Value *> &indices) const {
|
Value* getByIndices(const std::vector<Value *> &indices) const {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|||||||
@ -280,6 +280,46 @@ class IRBuilder {
|
|||||||
block->getInstructions().emplace(position, inst);
|
block->getInstructions().emplace(position, inst);
|
||||||
return inst;
|
return inst;
|
||||||
} ///< 创建load指令
|
} ///< 创建load指令
|
||||||
|
LaInst * createLaInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
|
||||||
|
std::string newName;
|
||||||
|
if (name.empty()) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << tmpIndex;
|
||||||
|
newName = ss.str();
|
||||||
|
tmpIndex++;
|
||||||
|
} else {
|
||||||
|
newName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto inst = new LaInst(pointer, indices, block, newName);
|
||||||
|
assert(inst);
|
||||||
|
block->getInstructions().emplace(position, inst);
|
||||||
|
return inst;
|
||||||
|
} ///< 创建la指令
|
||||||
|
GetSubArrayInst * createGetSubArray(LVal *fatherArray, const std::vector<Value *> &indices, const std::string &name = "") {
|
||||||
|
assert(fatherArray->getLValNumDims() > indices.size());
|
||||||
|
std::vector<Value *> subDims;
|
||||||
|
auto dims = fatherArray->getLValDims();
|
||||||
|
auto iter = std::next(dims.begin(), indices.size());
|
||||||
|
while (iter != dims.end()) {
|
||||||
|
subDims.emplace_back(*iter);
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string childArrayName;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "A"
|
||||||
|
<< "%" << tmpIndex;
|
||||||
|
childArrayName = ss.str();
|
||||||
|
tmpIndex++;
|
||||||
|
|
||||||
|
auto fatherArrayValue = dynamic_cast<Value *>(fatherArray);
|
||||||
|
auto childArray = new AllocaInst(fatherArrayValue->getType(), subDims, block, childArrayName);
|
||||||
|
auto inst = new GetSubArrayInst(fatherArray, childArray, indices, block, childArrayName);
|
||||||
|
assert(inst);
|
||||||
|
block->getInstructions().emplace(position, inst);
|
||||||
|
return inst;
|
||||||
|
} ///< 创建获取部分数组指令
|
||||||
MemsetInst * createMemsetInst(Value *pointer, Value *begin, Value *size, Value *value, const std::string &name = "") {
|
MemsetInst * createMemsetInst(Value *pointer, Value *begin, Value *size, Value *value, const std::string &name = "") {
|
||||||
auto inst = new MemsetInst(pointer, begin, size, value, block, name);
|
auto inst = new MemsetInst(pointer, begin, size, value, block, name);
|
||||||
assert(inst);
|
assert(inst);
|
||||||
@ -300,24 +340,6 @@ class IRBuilder {
|
|||||||
block->getInstructions().emplace(block->begin(), inst);
|
block->getInstructions().emplace(block->begin(), inst);
|
||||||
return inst;
|
return inst;
|
||||||
} ///< 创建Phi指令
|
} ///< 创建Phi指令
|
||||||
GetElementPtrInst* createGetElementPtrInst(Value *basePointer,
|
|
||||||
const std::vector<Value *> &indices = {},
|
|
||||||
const std::string &name = "") {
|
|
||||||
std::string newName;
|
|
||||||
if (name.empty()) {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << tmpIndex;
|
|
||||||
newName = ss.str();
|
|
||||||
tmpIndex++;
|
|
||||||
} else {
|
|
||||||
newName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto inst = new GetElementPtrInst(basePointer, indices, block, newName);
|
|
||||||
assert(inst);
|
|
||||||
block->getInstructions().emplace(position, inst);
|
|
||||||
return inst;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|||||||
@ -1,79 +1,59 @@
|
|||||||
// 假设 Mem2Reg.h 看起来像这样 (你需要根据实际情况调整)
|
#pragma once
|
||||||
#ifndef SYSY_MEM2REG_H
|
|
||||||
#define SYSY_MEM2REG_H
|
|
||||||
|
|
||||||
#include <vector>
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <stack>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <stack>
|
|
||||||
#include <queue> // For computeIteratedDomFrontiers
|
|
||||||
|
|
||||||
// Include your IR and analysis headers
|
|
||||||
#include "IR.h"
|
#include "IR.h"
|
||||||
#include "IRBuilder.h"
|
#include "IRBuilder.h"
|
||||||
#include "SysYIRAnalyser.h"
|
#include "SysYIRAnalyser.h"
|
||||||
#include "SysYIROptUtils.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
/**
|
||||||
|
* 实现静态单变量赋值核心类 mem2reg
|
||||||
|
*/
|
||||||
class Mem2Reg {
|
class Mem2Reg {
|
||||||
private:
|
private:
|
||||||
Module* pModule;
|
Module *pModule;
|
||||||
IRBuilder* pBuilder;
|
IRBuilder *pBuilder;
|
||||||
ControlFlowAnalysis* controlFlowAnalysis;
|
ControlFlowAnalysis *controlFlowAnalysis; // 控制流分析
|
||||||
ActiveVarAnalysis* activeVarAnalysis;
|
ActiveVarAnalysis *activeVarAnalysis; // 活跃变量分析
|
||||||
DataFlowAnalysisUtils dataFlowAnalysisUtils; // If this is part of Mem2Reg or an external helper
|
DataFlowAnalysisUtils dataFlowAnalysisUtils;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Mem2Reg(Module* module, IRBuilder* builder, ControlFlowAnalysis* cfa, ActiveVarAnalysis* ava)
|
Mem2Reg(Module *pMoudle, IRBuilder *pBuilder,
|
||||||
: pModule(module), pBuilder(builder), controlFlowAnalysis(cfa), activeVarAnalysis(ava) {}
|
ControlFlowAnalysis *pCFA = nullptr, ActiveVarAnalysis *pAVA = nullptr) :
|
||||||
// Constructor initializes members
|
pModule(pMoudle), pBuilder(pBuilder), controlFlowAnalysis(pCFA), activeVarAnalysis(pAVA), dataFlowAnalysisUtils()
|
||||||
void run();
|
{} // 初始化函数
|
||||||
|
|
||||||
// --- 新增的私有成员变量和方法,用于SSA转换上下文 ---
|
void mem2regPipeline(); ///< mem2reg
|
||||||
// 这是核心,用于存储 SSA 转换过程中的状态
|
|
||||||
std::vector<AllocaInst*> currentFunctionAllocas; // 当前函数中所有可提升的 alloca
|
|
||||||
// alloca -> set of BasicBlocks where it's defined (stored into)
|
|
||||||
std::unordered_map<AllocaInst*, std::unordered_set<BasicBlock*>> allocaDefsBlock;
|
|
||||||
// alloca -> set of BasicBlocks where it's used (loaded from)
|
|
||||||
std::unordered_map<AllocaInst*, std::unordered_set<BasicBlock*>> allocaUsesBlock;
|
|
||||||
|
|
||||||
// BasicBlock -> Map of (PhiInst, Original AllocaInst)
|
private:
|
||||||
// 用于在 rename 阶段通过 phi 指令找到它代表的原始 alloca
|
|
||||||
std::unordered_map<BasicBlock*, std::unordered_map<PhiInst*, AllocaInst*>> phiMap;
|
|
||||||
std::vector<PhiInst*> allPhiInstructions; // 收集所有创建的 Phi 指令以便后续简化和清理
|
|
||||||
|
|
||||||
// --- 核心 SSA 转换辅助函数 ---
|
// phi节点的插入需要计算IDF
|
||||||
// 计算给定定义块集合的迭代支配边界
|
std::unordered_set<BasicBlock *> computeIterDf(const std::unordered_set<BasicBlock *> &blocks); ///< 计算定义块集合的迭代支配边界
|
||||||
std::unordered_set<BasicBlock*> computeIteratedDomFrontiers(const std::unordered_set<BasicBlock*>& blocks);
|
|
||||||
|
|
||||||
// 分析一个 alloca 的所有 uses,填充 allocaDefsBlock 和 allocaUsesBlock
|
auto computeValue2Blocks() -> void; ///< 计算value2block的映射(不包括数组和global)
|
||||||
void allocaAnalysis(AllocaInst* alloca);
|
|
||||||
|
|
||||||
// 判断一个 alloca 是否可以被提升为寄存器 (无地址逃逸,标量类型)
|
auto preOptimize1() -> void; ///< llvm memtoreg预优化1: 删除不含load的alloc和store
|
||||||
bool is_promoted(AllocaInst* alloca);
|
auto preOptimize2() -> void; ///< llvm memtoreg预优化2: 针对某个变量的Defblocks只有一个块的情况
|
||||||
|
auto preOptimize3() -> void; ///< llvm memtoreg预优化3: 针对某个变量的所有读写都在同一个块中的情况
|
||||||
|
|
||||||
// 在迭代支配边界处插入 Phi 指令
|
auto insertPhi() -> void; ///< 为所有变量的迭代支配边界插入phi结点
|
||||||
void insertPhiNodes(Function* func);
|
|
||||||
|
|
||||||
// 递归地重命名基本块中的变量并填充 Phi 指令
|
auto rename(BasicBlock *block, std::unordered_map<Value *, int> &count,
|
||||||
// 这里的 `count` 和 `stacks` 是临时的,用于 DFS 过程中传递状态
|
std::unordered_map<Value *, std::stack<Instruction *>> &stacks) -> void; ///< 单个块的重命名
|
||||||
void renameBlock(BasicBlock* block,
|
auto renameAll() -> void; ///< 重命名所有块
|
||||||
std::unordered_map<AllocaInst*, Value*>& currentIncomings,
|
|
||||||
std::unordered_set<BasicBlock*>& visitedBlocks); // 修改为传递 map 和 set
|
|
||||||
|
|
||||||
// 简化冗余的 Phi 指令 (当所有输入都相同时)
|
// private helper function.
|
||||||
void simplifyphi(PhiInst* phi);
|
private:
|
||||||
|
auto getPredIndex(BasicBlock *n, BasicBlock *s) -> int; ///< 获取前驱索引
|
||||||
// 获取前驱块在后继块前驱列表中的索引,用于 Phi 指令入边
|
auto cascade(Instruction *instr, bool &changed, Function *func, BasicBlock *block,
|
||||||
int getPredIndex(BasicBlock* pred, BasicBlock* succ);
|
std::list<std::unique_ptr<Instruction>> &instrs) -> void; ///< 消除级联关系
|
||||||
|
auto isGlobal(Value *val) -> bool; ///< 判断是否是全局变量
|
||||||
// --- Mem2Reg 的主要工作流函数 ---
|
auto isArr(Value *val) -> bool; ///< 判断是否是数组
|
||||||
// 对单个函数执行内存到寄存器的提升
|
auto usedelete(Instruction *instr) -> void; ///< 删除指令相关的value-use-user关系
|
||||||
bool promoteMemoryToRegisters(Function* func);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
} // namespace sysy
|
||||||
} // namespace sysy
|
|
||||||
|
|
||||||
#endif // SYSY_MEM2REG_H
|
|
||||||
|
|||||||
@ -4,20 +4,23 @@
|
|||||||
#include "RISCv64LLIR.h"
|
#include "RISCv64LLIR.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
extern int DEBUG;
|
||||||
|
extern int DEEPDEBUG;
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
class RISCv64AsmPrinter {
|
class RISCv64AsmPrinter {
|
||||||
public:
|
public:
|
||||||
RISCv64AsmPrinter(MachineFunction* mfunc);
|
RISCv64AsmPrinter(MachineFunction* mfunc);
|
||||||
// 主入口
|
// 主入口
|
||||||
void run(std::ostream& os);
|
void run(std::ostream& os, bool debug = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 打印各个部分
|
// 打印各个部分
|
||||||
void printPrologue();
|
void printPrologue();
|
||||||
void printEpilogue();
|
void printEpilogue();
|
||||||
void printBasicBlock(MachineBasicBlock* mbb);
|
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
||||||
void printInstruction(MachineInstr* instr);
|
void printInstruction(MachineInstr* instr, bool debug = false);
|
||||||
|
|
||||||
// 辅助函数
|
// 辅助函数
|
||||||
std::string regToString(PhysicalReg reg);
|
std::string regToString(PhysicalReg reg);
|
||||||
|
|||||||
@ -4,6 +4,9 @@
|
|||||||
#include "IR.h"
|
#include "IR.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
extern int DEBUG;
|
||||||
|
extern int DEEPDEBUG;
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
// RISCv64CodeGen 现在是一个高层驱动器
|
// RISCv64CodeGen 现在是一个高层驱动器
|
||||||
|
|||||||
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include "RISCv64LLIR.h"
|
#include "RISCv64LLIR.h"
|
||||||
|
|
||||||
|
extern int DEBUG;
|
||||||
|
extern int DEEPDEBUG;
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
class RISCv64ISel {
|
class RISCv64ISel {
|
||||||
@ -31,6 +34,8 @@ private:
|
|||||||
DAGNode* get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
|
DAGNode* get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
|
||||||
DAGNode* create_node(int kind, Value* val, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
|
DAGNode* create_node(int kind, Value* val, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
|
||||||
|
|
||||||
|
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
|
||||||
|
|
||||||
// 状态
|
// 状态
|
||||||
Function* F; // 当前处理的高层IR函数
|
Function* F; // 当前处理的高层IR函数
|
||||||
std::unique_ptr<MachineFunction> MFunc; // 正在构建的底层LLIR函数
|
std::unique_ptr<MachineFunction> MFunc; // 正在构建的底层LLIR函数
|
||||||
|
|||||||
@ -46,6 +46,7 @@ enum class RVOpcodes {
|
|||||||
// 新增伪指令,用于解耦栈帧处理
|
// 新增伪指令,用于解耦栈帧处理
|
||||||
FRAME_LOAD, // 从栈帧加载 (AllocaInst)
|
FRAME_LOAD, // 从栈帧加载 (AllocaInst)
|
||||||
FRAME_STORE, // 保存到栈帧 (AllocaInst)
|
FRAME_STORE, // 保存到栈帧 (AllocaInst)
|
||||||
|
FRAME_ADDR, // [新] 获取栈帧变量的地址
|
||||||
};
|
};
|
||||||
|
|
||||||
class MachineOperand;
|
class MachineOperand;
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "IR.h"
|
#include "IR.h"
|
||||||
#include "IRBuilder.h"
|
#include "IRBuilder.h"
|
||||||
#include "SysYIROptUtils.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
/**
|
/**
|
||||||
@ -17,6 +16,8 @@ public:
|
|||||||
Reg2Mem(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
|
Reg2Mem(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
|
||||||
|
|
||||||
void DeletePhiInst();
|
void DeletePhiInst();
|
||||||
|
// 删除UD关系, 因为删除了phi指令会修改ud关系
|
||||||
|
void usedelete(Instruction *instr);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
@ -1,196 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IR.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
// 稀疏条件常量传播类
|
|
||||||
// Sparse Conditional Constant Propagation
|
|
||||||
/*
|
|
||||||
伪代码
|
|
||||||
function SCCP_Optimization(Module):
|
|
||||||
for each Function in Module:
|
|
||||||
changed = true
|
|
||||||
while changed:
|
|
||||||
changed = false
|
|
||||||
// 阶段1: 常量传播与折叠
|
|
||||||
changed |= PropagateConstants(Function)
|
|
||||||
// 阶段2: 控制流简化
|
|
||||||
changed |= SimplifyControlFlow(Function)
|
|
||||||
end while
|
|
||||||
end for
|
|
||||||
|
|
||||||
function PropagateConstants(Function):
|
|
||||||
// 初始化
|
|
||||||
executableBlocks = {entryBlock}
|
|
||||||
valueState = map<Value, State> // 值->状态映射
|
|
||||||
instWorkList = Queue()
|
|
||||||
edgeWorkList = Queue()
|
|
||||||
|
|
||||||
// 初始化工作列表
|
|
||||||
for each inst in entryBlock:
|
|
||||||
instWorkList.push(inst)
|
|
||||||
|
|
||||||
// 迭代处理
|
|
||||||
while !instWorkList.empty() || !edgeWorkList.empty():
|
|
||||||
// 处理指令工作列表
|
|
||||||
while !instWorkList.empty():
|
|
||||||
inst = instWorkList.pop()
|
|
||||||
// 如果指令是可执行基本块中的
|
|
||||||
if executableBlocks.contains(inst.parent):
|
|
||||||
ProcessInstruction(inst)
|
|
||||||
|
|
||||||
// 处理边工作列表
|
|
||||||
while !edgeWorkList.empty():
|
|
||||||
edge = edgeWorkList.pop()
|
|
||||||
ProcessEdge(edge)
|
|
||||||
|
|
||||||
// 应用常量替换
|
|
||||||
for each inst in Function:
|
|
||||||
if valueState[inst] == CONSTANT:
|
|
||||||
ReplaceWithConstant(inst, valueState[inst].constant)
|
|
||||||
changed = true
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
function ProcessInstruction(Instruction inst):
|
|
||||||
switch inst.type:
|
|
||||||
//二元操作
|
|
||||||
case BINARY_OP:
|
|
||||||
lhs = GetValueState(inst.operands[0])
|
|
||||||
rhs = GetValueState(inst.operands[1])
|
|
||||||
if lhs == CONSTANT && rhs == CONSTANT:
|
|
||||||
newState = ComputeConstant(inst.op, lhs.value, rhs.value)
|
|
||||||
UpdateState(inst, newState)
|
|
||||||
else if lhs == BOTTOM || rhs == BOTTOM:
|
|
||||||
UpdateState(inst, BOTTOM)
|
|
||||||
//phi
|
|
||||||
case PHI:
|
|
||||||
mergedState = ⊤
|
|
||||||
for each incoming in inst.incomings:
|
|
||||||
// 检查每个输入的状态
|
|
||||||
if executableBlocks.contains(incoming.block):
|
|
||||||
incomingState = GetValueState(incoming.value)
|
|
||||||
mergedState = Meet(mergedState, incomingState)
|
|
||||||
UpdateState(inst, mergedState)
|
|
||||||
// 条件分支
|
|
||||||
case COND_BRANCH:
|
|
||||||
cond = GetValueState(inst.condition)
|
|
||||||
if cond == CONSTANT:
|
|
||||||
// 判断条件分支
|
|
||||||
if cond.value == true:
|
|
||||||
AddEdgeToWorkList(inst.parent, inst.trueTarget)
|
|
||||||
else:
|
|
||||||
AddEdgeToWorkList(inst.parent, inst.falseTarget)
|
|
||||||
else if cond == BOTTOM:
|
|
||||||
AddEdgeToWorkList(inst.parent, inst.trueTarget)
|
|
||||||
AddEdgeToWorkList(inst.parent, inst.falseTarget)
|
|
||||||
|
|
||||||
case UNCOND_BRANCH:
|
|
||||||
AddEdgeToWorkList(inst.parent, inst.target)
|
|
||||||
|
|
||||||
// 其他指令处理...
|
|
||||||
|
|
||||||
function ProcessEdge(Edge edge):
|
|
||||||
fromBB, toBB = edge
|
|
||||||
if !executableBlocks.contains(toBB):
|
|
||||||
executableBlocks.add(toBB)
|
|
||||||
for each inst in toBB:
|
|
||||||
if inst is PHI:
|
|
||||||
instWorkList.push(inst)
|
|
||||||
else:
|
|
||||||
instWorkList.push(inst) // 非PHI指令
|
|
||||||
|
|
||||||
// 更新PHI节点的输入
|
|
||||||
for each phi in toBB.phis:
|
|
||||||
instWorkList.push(phi)
|
|
||||||
|
|
||||||
function SimplifyControlFlow(Function):
|
|
||||||
changed = false
|
|
||||||
// 标记可达基本块
|
|
||||||
ReachableBBs = FindReachableBlocks(Function.entry)
|
|
||||||
|
|
||||||
// 删除不可达块
|
|
||||||
for each bb in Function.blocks:
|
|
||||||
if !ReachableBBs.contains(bb):
|
|
||||||
RemoveDeadBlock(bb)
|
|
||||||
changed = true
|
|
||||||
|
|
||||||
// 简化条件分支
|
|
||||||
for each bb in Function.blocks:
|
|
||||||
terminator = bb.terminator
|
|
||||||
if terminator is COND_BRANCH:
|
|
||||||
cond = GetValueState(terminator.condition)
|
|
||||||
if cond == CONSTANT:
|
|
||||||
SimplifyBranch(terminator, cond.value)
|
|
||||||
changed = true
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
function RemoveDeadBlock(BasicBlock bb):
|
|
||||||
// 1. 更新前驱块的分支指令
|
|
||||||
for each pred in bb.predecessors:
|
|
||||||
UpdateTerminator(pred, bb)
|
|
||||||
|
|
||||||
// 2. 更新后继块的PHI节点
|
|
||||||
for each succ in bb.successors:
|
|
||||||
RemovePhiIncoming(succ, bb)
|
|
||||||
|
|
||||||
// 3. 删除块内所有指令
|
|
||||||
for each inst in bb.instructions:
|
|
||||||
inst.remove()
|
|
||||||
|
|
||||||
// 4. 从函数中移除基本块
|
|
||||||
Function.removeBlock(bb)
|
|
||||||
|
|
||||||
function Meet(State a, State b):
|
|
||||||
if a == ⊤: return b
|
|
||||||
if b == ⊤: return a
|
|
||||||
if a == ⊥ || b == ⊥: return ⊥
|
|
||||||
if a.value == b.value: return a
|
|
||||||
return ⊥
|
|
||||||
|
|
||||||
function UpdateState(Value v, State newState):
|
|
||||||
oldState = valueState.get(v, ⊤)
|
|
||||||
if newState != oldState:
|
|
||||||
valueState[v] = newState
|
|
||||||
for each user in v.users:
|
|
||||||
if user is Instruction:
|
|
||||||
instWorkList.push(user)
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum class LatticeValue {
|
|
||||||
Top, // ⊤ (Unknown)
|
|
||||||
Constant, // c (Constant)
|
|
||||||
Bottom // ⊥ (Undefined / Varying)
|
|
||||||
};
|
|
||||||
// LatticeValue: 用于表示值的状态,Top表示未知,Constant表示常量,Bottom表示未定义或变化的值。
|
|
||||||
// 这里的LatticeValue用于跟踪每个SSA值(变量、指令结果)的状态,
|
|
||||||
// 以便在SCCP过程中进行常量传播和控制流简化。
|
|
||||||
|
|
||||||
//TODO: 下列数据结构考虑集成到类中,避免重命名问题
|
|
||||||
static std::set<Instruction *> Worklist;
|
|
||||||
static std::unordered_set<BasicBlock*> Executable_Blocks;
|
|
||||||
static std::queue<std::pair<BasicBlock *, BasicBlock *> > Executable_Edges;
|
|
||||||
static std::map<Value*, LatticeValue> valueState;
|
|
||||||
|
|
||||||
class SCCP {
|
|
||||||
private:
|
|
||||||
Module *pModule;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SCCP(Module *pMoudle) : pModule(pMoudle) {}
|
|
||||||
|
|
||||||
void run();
|
|
||||||
bool PropagateConstants(Function *function);
|
|
||||||
bool SimplifyControlFlow(Function *function);
|
|
||||||
void ProcessInstruction(Instruction *inst);
|
|
||||||
void ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge);
|
|
||||||
void RemoveDeadBlock(BasicBlock *bb);
|
|
||||||
void UpdateState(Value *v, LatticeValue newState);
|
|
||||||
LatticeValue Meet(LatticeValue a, LatticeValue b);
|
|
||||||
LatticeValue GetValueState(Value *v);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
340
src/include/SysYFormatter.h
Normal file
340
src/include/SysYFormatter.h
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SysYBaseVisitor.h"
|
||||||
|
#include "SysYParser.h"
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
class SysYFormatter : public SysYBaseVisitor {
|
||||||
|
protected:
|
||||||
|
std::ostream &os;
|
||||||
|
int indent = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SysYFormatter(std::ostream &os) : os(os), indent(0) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct Indentor {
|
||||||
|
static constexpr int TabSize = 2;
|
||||||
|
int &indent;
|
||||||
|
Indentor(int &indent) : indent(indent) { indent += TabSize; }
|
||||||
|
~Indentor() { indent -= TabSize; }
|
||||||
|
};
|
||||||
|
std::ostream &space() { return os << std::string(indent, ' '); }
|
||||||
|
template <typename T>
|
||||||
|
std::ostream &interleave(const T &container, const std::string sep = ", ") {
|
||||||
|
auto b = container.begin(), e = container.end();
|
||||||
|
(*b)->accept(this);
|
||||||
|
for (b = std::next(b); b != e; b = std::next(b)) {
|
||||||
|
os << sep;
|
||||||
|
(*b)->accept(this);
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// virtual std::any visitModule(SysYParser::ModuleContext *ctx) override {
|
||||||
|
// return visitChildren(ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
virtual std::any visitBtype(SysYParser::BtypeContext *ctx) override {
|
||||||
|
os << ctx->getText();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitDecl(SysYParser::DeclContext *ctx) override {
|
||||||
|
space();
|
||||||
|
if (ctx->CONST())
|
||||||
|
os << ctx->CONST()->getText() << ' ';
|
||||||
|
ctx->btype()->accept(this);
|
||||||
|
os << ' ';
|
||||||
|
interleave(ctx->varDef(), ", ") << ';' << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitVarDef(SysYParser::VarDefContext *ctx) override {
|
||||||
|
ctx->lValue()->accept(this);
|
||||||
|
if (ctx->initValue()) {
|
||||||
|
os << ' ' << '=' << ' ';
|
||||||
|
ctx->initValue()->accept(this);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitInitValue(SysYParser::InitValueContext *ctx) override {
|
||||||
|
if (not ctx->exp()) {
|
||||||
|
os << '{';
|
||||||
|
auto values = ctx->initValue();
|
||||||
|
if (values.size())
|
||||||
|
interleave(values, ", ");
|
||||||
|
os << '}';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitFunc(SysYParser::FuncContext *ctx) override {
|
||||||
|
ctx->funcType()->accept(this);
|
||||||
|
os << ' ' << ctx->ID()->getText() << '(';
|
||||||
|
if (ctx->funcFParams())
|
||||||
|
ctx->funcFParams()->accept(this);
|
||||||
|
os << ')' << ' ';
|
||||||
|
ctx->blockStmt()->accept(this);
|
||||||
|
os << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitFuncType(SysYParser::FuncTypeContext *ctx) override {
|
||||||
|
os << ctx->getText();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitFuncFParams(SysYParser::FuncFParamsContext *ctx) override {
|
||||||
|
interleave(ctx->funcFParam(), ", ");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitFuncFParam(SysYParser::FuncFParamContext *ctx) override {
|
||||||
|
ctx->btype()->accept(this);
|
||||||
|
os << ' ' << ctx->ID()->getText();
|
||||||
|
if (not ctx->LBRACKET().empty()) {
|
||||||
|
os << '[';
|
||||||
|
auto exp = ctx->exp();
|
||||||
|
if (not exp.empty()) {
|
||||||
|
os << '[';
|
||||||
|
interleave(exp, "][") << ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitBlockStmt(SysYParser::BlockStmtContext *ctx) override {
|
||||||
|
os << '{' << '\n';
|
||||||
|
{
|
||||||
|
Indentor indentor(indent);
|
||||||
|
auto items = ctx->blockItem();
|
||||||
|
if (not items.empty())
|
||||||
|
interleave(items, "");
|
||||||
|
}
|
||||||
|
space() << ctx->RBRACE()->getText() << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// virtual std::any visitBlockItem(SysYParser::BlockItemContext *ctx)
|
||||||
|
// override {
|
||||||
|
// return visitChildren(ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// virtual std::any visitStmt(SysYParser::StmtContext *ctx) override {
|
||||||
|
// return visitChildren(ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitAssignStmt(SysYParser::AssignStmtContext *ctx) override {
|
||||||
|
space();
|
||||||
|
ctx->lValue()->accept(this);
|
||||||
|
os << " = ";
|
||||||
|
ctx->exp()->accept(this);
|
||||||
|
os << ';' << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override {
|
||||||
|
space();
|
||||||
|
ctx->exp()->accept(this);
|
||||||
|
os << ';' << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrapBlock(SysYParser::StmtContext *stmt) {
|
||||||
|
bool isBlock = stmt->blockStmt();
|
||||||
|
if (isBlock) {
|
||||||
|
stmt->accept(this);
|
||||||
|
} else {
|
||||||
|
os << "{\n";
|
||||||
|
{
|
||||||
|
Indentor indentor(indent);
|
||||||
|
stmt->accept(this);
|
||||||
|
}
|
||||||
|
space() << "}\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
virtual std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override {
|
||||||
|
space();
|
||||||
|
os << ctx->IF()->getText() << " (";
|
||||||
|
ctx->exp()->accept(this);
|
||||||
|
os << ") ";
|
||||||
|
auto stmt = ctx->stmt();
|
||||||
|
auto ifStmt = stmt[0];
|
||||||
|
wrapBlock(ifStmt);
|
||||||
|
if (stmt.size() == 2) {
|
||||||
|
auto elseStmt = stmt[1];
|
||||||
|
wrapBlock(elseStmt);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override {
|
||||||
|
space();
|
||||||
|
os << ctx->WHILE()->getText() << " (";
|
||||||
|
ctx->exp()->accept(this);
|
||||||
|
os << ") ";
|
||||||
|
wrapBlock(ctx->stmt());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitBreakStmt(SysYParser::BreakStmtContext *ctx) override {
|
||||||
|
space() << ctx->BREAK()->getText() << ';' << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitContinueStmt(SysYParser::ContinueStmtContext *ctx) override {
|
||||||
|
space() << ctx->CONTINUE()->getText() << ';' << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitReturnStmt(SysYParser::ReturnStmtContext *ctx) override {
|
||||||
|
space() << ctx->RETURN()->getText();
|
||||||
|
if (ctx->exp()) {
|
||||||
|
os << ' ';
|
||||||
|
ctx->exp()->accept(this);
|
||||||
|
}
|
||||||
|
os << ';' << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// virtual std::any visitEmptyStmt(SysYParser::EmptyStmtContext *ctx)
|
||||||
|
// override {
|
||||||
|
// return visitChildren(ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitRelationExp(SysYParser::RelationExpContext *ctx) override {
|
||||||
|
auto lhs = ctx->exp(0);
|
||||||
|
auto rhs = ctx->exp(1);
|
||||||
|
std::string op =
|
||||||
|
ctx->LT() ? "<" : (ctx->LE() ? "<=" : (ctx->GT() ? ">" : ">="));
|
||||||
|
lhs->accept(this);
|
||||||
|
os << ' ' << op << ' ';
|
||||||
|
rhs->accept(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitMultiplicativeExp(SysYParser::MultiplicativeExpContext *ctx) override {
|
||||||
|
auto lhs = ctx->exp(0);
|
||||||
|
auto rhs = ctx->exp(1);
|
||||||
|
std::string op = ctx->MUL() ? "*" : (ctx->DIV() ? "/" : "%");
|
||||||
|
lhs->accept(this);
|
||||||
|
os << ' ' << op << ' ';
|
||||||
|
rhs->accept(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// virtual std::any visitLValueExp(SysYParser::LValueExpContext *ctx)
|
||||||
|
// override {
|
||||||
|
// return visitChildren(ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// virtual std::any visitNumberExp(SysYParser::NumberExpContext *ctx)
|
||||||
|
// override {
|
||||||
|
// return visitChildren(ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
virtual std::any visitAndExp(SysYParser::AndExpContext *ctx) override {
|
||||||
|
ctx->exp(0)->accept(this);
|
||||||
|
os << " && ";
|
||||||
|
ctx->exp(1)->accept(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitUnaryExp(SysYParser::UnaryExpContext *ctx) override {
|
||||||
|
std::string op = ctx->ADD() ? "+" : (ctx->SUB() ? "-" : "!");
|
||||||
|
os << op;
|
||||||
|
ctx->exp()->accept(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitParenExp(SysYParser::ParenExpContext *ctx) override {
|
||||||
|
os << '(';
|
||||||
|
ctx->exp()->accept(this);
|
||||||
|
os << ')';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitStringExp(SysYParser::StringExpContext *ctx) override {
|
||||||
|
return visitChildren(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitOrExp(SysYParser::OrExpContext *ctx) override {
|
||||||
|
ctx->exp(0)->accept(this);
|
||||||
|
os << " || ";
|
||||||
|
ctx->exp(1)->accept(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// virtual std::any visitCallExp(SysYParser::CallExpContext *ctx) override {
|
||||||
|
// return visitChildren(ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitAdditiveExp(SysYParser::AdditiveExpContext *ctx) override {
|
||||||
|
auto lhs = ctx->exp(0);
|
||||||
|
auto rhs = ctx->exp(1);
|
||||||
|
std::string op = ctx->ADD() ? "+" : "-";
|
||||||
|
lhs->accept(this);
|
||||||
|
os << ' ' << op << ' ';
|
||||||
|
rhs->accept(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitEqualExp(SysYParser::EqualExpContext *ctx) override {
|
||||||
|
auto lhs = ctx->exp(0);
|
||||||
|
auto rhs = ctx->exp(1);
|
||||||
|
std::string op = ctx->EQ() ? "==" : "!=";
|
||||||
|
lhs->accept(this);
|
||||||
|
os << ' ' << op << ' ';
|
||||||
|
rhs->accept(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitCall(SysYParser::CallContext *ctx) override {
|
||||||
|
os << ctx->ID()->getText() << '(';
|
||||||
|
if (ctx->funcRParams())
|
||||||
|
ctx->funcRParams()->accept(this);
|
||||||
|
os << ')';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitLValue(SysYParser::LValueContext *ctx) override {
|
||||||
|
os << ctx->ID()->getText();
|
||||||
|
auto exp = ctx->exp();
|
||||||
|
if (not exp.empty()) {
|
||||||
|
os << '[';
|
||||||
|
interleave(exp, "][") << ']';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitNumber(SysYParser::NumberContext *ctx) override {
|
||||||
|
os << ctx->getText();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any visitString(SysYParser::StringContext *ctx) override {
|
||||||
|
os << ctx->getText();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::any
|
||||||
|
visitFuncRParams(SysYParser::FuncRParamsContext *ctx) override {
|
||||||
|
interleave(ctx->exp(), ", ");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@ -1,60 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IR.h"
|
|
||||||
#include "IRBuilder.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
// 优化前对SysY IR的预处理,也可以视作部分CFG优化
|
|
||||||
// 主要包括删除无用指令、合并基本块、删除空块等
|
|
||||||
// 这些操作可以在SysY IR生成时就完成,但为了简化IR生成过程,
|
|
||||||
// 这里将其放在SysY IR生成后进行预处理
|
|
||||||
// 同时兼容phi节点的处理,可以再mem2reg后再次调用优化
|
|
||||||
|
|
||||||
//TODO: 可增加的CFG优化和方法
|
|
||||||
// - 检查基本块跳转关系正确性
|
|
||||||
// - 简化条件分支(Branch Simplification),如条件恒真/恒假转为直接跳转
|
|
||||||
// - 合并连续的跳转指令(Jump Threading)在合并不可达块中似乎已经实现了
|
|
||||||
// - 基本块重排序(Block Reordering),提升局部性
|
|
||||||
|
|
||||||
class SysYCFGOpt {
|
|
||||||
private:
|
|
||||||
Module *pModule;
|
|
||||||
IRBuilder *pBuilder;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SysYCFGOpt(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
|
|
||||||
|
|
||||||
void SysYOptimizateAfterIR(){
|
|
||||||
|
|
||||||
auto &functions = pModule->getFunctions();
|
|
||||||
for (auto &function : functions) {
|
|
||||||
bool changed = false;
|
|
||||||
while(changed){
|
|
||||||
changed = false;
|
|
||||||
changed |= SysYCondBr2Br(function.second.get(), pBuilder);
|
|
||||||
// 删除br后面的无用指令
|
|
||||||
changed |= SysYDelInstAfterBr(function.second.get());
|
|
||||||
// 合并空基本块
|
|
||||||
changed |= SysYBlockMerge(function.second.get());
|
|
||||||
// 删除无前驱块
|
|
||||||
changed |= SysYDelNoPreBLock(function.second.get());
|
|
||||||
// 删除空块
|
|
||||||
changed |= SysYDelEmptyBlock(function.second.get(), pBuilder);
|
|
||||||
// 添加return指令
|
|
||||||
changed |= SysYAddReturn(function.second.get(), pBuilder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
static bool SysYDelInstAfterBr(Function *func); // 删除br后面的指令
|
|
||||||
static bool SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder); // 空块删除
|
|
||||||
static bool SysYDelNoPreBLock(Function *func); // 删除无前驱块(不可达块)
|
|
||||||
static bool SysYBlockMerge(Function *func); // 合并基本块(主要针对嵌套if while的exit块,
|
|
||||||
// 也可以修改IR生成实现回填机制
|
|
||||||
static bool SysYAddReturn(Function *func, IRBuilder* pBuilder); // 添加return指令(主要针对Void函数)
|
|
||||||
static bool SysYCondBr2Br(Function *func, IRBuilder* pBuilder); // 条件分支(已知cond的值)转换为无条件分支
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@ -62,11 +62,12 @@ private:
|
|||||||
public:
|
public:
|
||||||
SysYIRGenerator() = default;
|
SysYIRGenerator() = default;
|
||||||
|
|
||||||
|
bool HasReturnInst;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Module *get() const { return module.get(); }
|
Module *get() const { return module.get(); }
|
||||||
IRBuilder *getBuilder(){ return &builder; }
|
IRBuilder *getBuilder(){ return &builder; }
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::any visitCompUnit(SysYParser::CompUnitContext *ctx) override;
|
std::any visitCompUnit(SysYParser::CompUnitContext *ctx) override;
|
||||||
|
|
||||||
std::any visitGlobalConstDecl(SysYParser::GlobalConstDeclContext *ctx) override;
|
std::any visitGlobalConstDecl(SysYParser::GlobalConstDeclContext *ctx) override;
|
||||||
@ -133,11 +134,6 @@ public:
|
|||||||
|
|
||||||
// std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
// std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
||||||
|
|
||||||
public:
|
|
||||||
// 获取GEP指令的地址
|
|
||||||
Value* getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices);
|
|
||||||
// 构建数组类型
|
|
||||||
Type* buildArrayType(Type* baseType, const std::vector<Value*>& dims);
|
|
||||||
|
|
||||||
}; // class SysYIRGenerator
|
}; // class SysYIRGenerator
|
||||||
|
|
||||||
|
|||||||
37
src/include/SysYIROptPre.h
Normal file
37
src/include/SysYIROptPre.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IR.h"
|
||||||
|
#include "IRBuilder.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
// 优化前对SysY IR的预处理,也可以视作部分CFG优化
|
||||||
|
// 主要包括删除无用指令、合并基本块、删除空块等
|
||||||
|
// 这些操作可以在SysY IR生成时就完成,但为了简化IR生成过程,
|
||||||
|
// 这里将其放在SysY IR生成后进行预处理
|
||||||
|
// 同时兼容phi节点的处理,可以再mem2reg后再次调用优化
|
||||||
|
class SysYOptPre {
|
||||||
|
private:
|
||||||
|
Module *pModule;
|
||||||
|
IRBuilder *pBuilder;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SysYOptPre(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
|
||||||
|
|
||||||
|
void SysYOptimizateAfterIR(){
|
||||||
|
SysYDelInstAfterBr();
|
||||||
|
SysYBlockMerge();
|
||||||
|
SysYDelNoPreBLock();
|
||||||
|
SysYDelEmptyBlock();
|
||||||
|
SysYAddReturn();
|
||||||
|
}
|
||||||
|
void SysYDelInstAfterBr(); // 删除br后面的指令
|
||||||
|
void SysYDelEmptyBlock(); // 空块删除
|
||||||
|
void SysYDelNoPreBLock(); // 删除无前驱块
|
||||||
|
void SysYBlockMerge(); // 合并基本块(主要针对嵌套if while的exit块,
|
||||||
|
// 也可以修改IR生成实现回填机制
|
||||||
|
void SysYAddReturn(); // 添加return指令(主要针对Void函数)
|
||||||
|
void usedelete(Instruction *instr); // use删除
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@ -1,33 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IR.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
// 优化工具类,包含一些通用的优化方法
|
|
||||||
// 这些方法可以在不同的优化 pass 中复用
|
|
||||||
// 例如:删除use关系,判断是否是全局变量等
|
|
||||||
class SysYIROptUtils{
|
|
||||||
|
|
||||||
public:
|
|
||||||
// 删除use关系
|
|
||||||
static void usedelete(Instruction *instr) {
|
|
||||||
for (auto &use : instr->getOperands()) {
|
|
||||||
Value* val = use->getValue();
|
|
||||||
val->removeUse(use);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否是全局变量
|
|
||||||
static bool isGlobal(Value *val) {
|
|
||||||
auto gval = dynamic_cast<GlobalValue *>(val);
|
|
||||||
return gval != nullptr;
|
|
||||||
}
|
|
||||||
// 判断是否是数组
|
|
||||||
static bool isArr(Value *val) {
|
|
||||||
auto aval = dynamic_cast<AllocaInst *>(val);
|
|
||||||
return aval != nullptr && aval->getNumDims() != 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}// namespace sysy
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IR.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
// 前置声明
|
|
||||||
class FunctionPass;
|
|
||||||
class ModulePass;
|
|
||||||
class AnalysisPass;
|
|
||||||
class PassManager;
|
|
||||||
|
|
||||||
// 抽象基类 Pass
|
|
||||||
class Pass {
|
|
||||||
public:
|
|
||||||
enum PassKind {
|
|
||||||
PK_Function,
|
|
||||||
PK_Module,
|
|
||||||
PK_Analysis
|
|
||||||
};
|
|
||||||
|
|
||||||
Pass(PassKind kind, const std::string& name) : Kind(kind), Name(name) {}
|
|
||||||
virtual ~Pass() = default;
|
|
||||||
|
|
||||||
PassKind getPassKind() const { return Kind; }
|
|
||||||
const std::string& getPassName() const { return Name; }
|
|
||||||
|
|
||||||
// 每个Pass需要实现此方法来执行其逻辑
|
|
||||||
// 具体的run方法将根据Pass类型在FunctionPass和ModulePass中定义
|
|
||||||
protected:
|
|
||||||
PassKind Kind;
|
|
||||||
std::string Name;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 针对函数的优化遍
|
|
||||||
class FunctionPass : public Pass {
|
|
||||||
public:
|
|
||||||
FunctionPass(const std::string& name) : Pass(PK_Function, name) {}
|
|
||||||
// 真正的优化逻辑将在此方法中实现
|
|
||||||
virtual bool runOnFunction(Function& F) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 针对模块的优化遍
|
|
||||||
class ModulePass : public Pass {
|
|
||||||
public:
|
|
||||||
ModulePass(const std::string& name) : Pass(PK_Module, name) {}
|
|
||||||
// 真正的优化逻辑将在此方法中实现
|
|
||||||
virtual bool runOnModule(Module& M) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 分析遍
|
|
||||||
class AnalysisPass : public Pass {
|
|
||||||
public:
|
|
||||||
AnalysisPass(const std::string& name) : Pass(PK_Analysis, name) {}
|
|
||||||
// 分析遍通常需要一个模块或函数作为输入,并计算出分析结果
|
|
||||||
// 具体分析结果的存储和访问方式需要设计
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
// PassManager.h
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <typeindex> // For std::type_index
|
|
||||||
#include <unordered_map>
|
|
||||||
#include "SysYIRPass.h"
|
|
||||||
#include "IR.h" // 假设你的IR.h定义了Module, Function等
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
class PassManager {
|
|
||||||
public:
|
|
||||||
PassManager() = default;
|
|
||||||
|
|
||||||
// 添加一个FunctionPass
|
|
||||||
void addPass(std::unique_ptr<FunctionPass> pass) {
|
|
||||||
functionPasses.push_back(std::move(pass));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加一个ModulePass
|
|
||||||
void addPass(std::unique_ptr<ModulePass> pass) {
|
|
||||||
modulePasses.push_back(std::move(pass));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加一个AnalysisPass
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
T* addAnalysisPass(Args&&... args) {
|
|
||||||
static_assert(std::is_base_of<AnalysisPass, T>::value, "T must derive from AnalysisPass");
|
|
||||||
auto analysis = std::make_unique<T>(std::forward<Args>(args)...);
|
|
||||||
T* rawPtr = analysis.get();
|
|
||||||
analysisPasses[std::type_index(typeid(T))] = std::move(analysis);
|
|
||||||
return rawPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取分析结果(用于其他Pass访问)
|
|
||||||
template<typename T>
|
|
||||||
T* getAnalysis() {
|
|
||||||
static_assert(std::is_base_of<AnalysisPass, T>::value, "T must derive from AnalysisPass");
|
|
||||||
auto it = analysisPasses.find(std::type_index(typeid(T)));
|
|
||||||
if (it != analysisPasses.end()) {
|
|
||||||
return static_cast<T*>(it->second.get());
|
|
||||||
}
|
|
||||||
return nullptr; // 或者抛出异常
|
|
||||||
}
|
|
||||||
|
|
||||||
// 运行所有注册的遍
|
|
||||||
void run(Module& M);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<std::unique_ptr<FunctionPass>> functionPasses;
|
|
||||||
std::vector<std::unique_ptr<ModulePass>> modulePasses;
|
|
||||||
std::unordered_map<std::type_index, std::unique_ptr<AnalysisPass>> analysisPasses;
|
|
||||||
// 未来可以添加AnalysisPass的缓存机制
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@ -13,9 +13,9 @@ using namespace antlr4;
|
|||||||
|
|
||||||
#include "SysYIRGenerator.h"
|
#include "SysYIRGenerator.h"
|
||||||
#include "SysYIRPrinter.h"
|
#include "SysYIRPrinter.h"
|
||||||
#include "SysYIRCFGOpt.h"
|
#include "SysYIROptPre.h"
|
||||||
#include "RISCv64Backend.h"
|
#include "RISCv64Backend.h"
|
||||||
// #include "SysYIRAnalyser.h"
|
#include "SysYIRAnalyser.h"
|
||||||
// #include "DeadCodeElimination.h"
|
// #include "DeadCodeElimination.h"
|
||||||
#include "AddressCalculationExpansion.h"
|
#include "AddressCalculationExpansion.h"
|
||||||
// #include "Mem2Reg.h"
|
// #include "Mem2Reg.h"
|
||||||
@ -132,13 +132,13 @@ int main(int argc, char **argv) {
|
|||||||
DEBUG = 1; // 这里可能需要更精细地控制 DEBUG 的开启时机和范围
|
DEBUG = 1; // 这里可能需要更精细地控制 DEBUG 的开启时机和范围
|
||||||
}
|
}
|
||||||
// 默认优化 pass (在所有优化级别都会执行)
|
// 默认优化 pass (在所有优化级别都会执行)
|
||||||
SysYCFGOpt cfgopt(moduleIR, builder);
|
SysYOptPre optPre(moduleIR, builder);
|
||||||
cfgopt.SysYOptimizateAfterIR();
|
optPre.SysYOptimizateAfterIR();
|
||||||
|
|
||||||
// ControlFlowAnalysis cfa(moduleIR);
|
ControlFlowAnalysis cfa(moduleIR);
|
||||||
// cfa.init();
|
cfa.init();
|
||||||
// ActiveVarAnalysis ava;
|
ActiveVarAnalysis ava;
|
||||||
// ava.init(moduleIR);
|
ava.init(moduleIR);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
cout << "=== After CFA & AVA (Default) ===\n";
|
cout << "=== After CFA & AVA (Default) ===\n";
|
||||||
@ -218,7 +218,7 @@ int main(int argc, char **argv) {
|
|||||||
// 设置 DEBUG 模式(如果指定了 'asmd')
|
// 设置 DEBUG 模式(如果指定了 'asmd')
|
||||||
if (argStopAfter == "asmd") {
|
if (argStopAfter == "asmd") {
|
||||||
DEBUG = 1;
|
DEBUG = 1;
|
||||||
// DEEPDEBUG = 1;
|
DEEPDEBUG = 1;
|
||||||
}
|
}
|
||||||
sysy::RISCv64CodeGen codegen(moduleIR); // 传入优化后的 moduleIR
|
sysy::RISCv64CodeGen codegen(moduleIR); // 传入优化后的 moduleIR
|
||||||
string asmCode = codegen.code_gen();
|
string asmCode = codegen.code_gen();
|
||||||
|
|||||||
227
test_script/runit-riscv64-single.sh
Normal file
227
test_script/runit-riscv64-single.sh
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# runit-riscv64-single.sh - 用于在 RISC-V 虚拟机内部测试单个或少量 .s 文件的脚本
|
||||||
|
# 模仿 runit-riscv64.sh 的功能,但以具体文件路径作为输入。
|
||||||
|
|
||||||
|
# --- 配置区 ---
|
||||||
|
# 假设此脚本位于项目根目录 (例如 /home/ubuntu/debug)
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||||
|
LIB_DIR="${SCRIPT_DIR}/lib"
|
||||||
|
TMP_DIR="${SCRIPT_DIR}/tmp" # 临时可执行文件将存放在这里
|
||||||
|
TESTDATA_DIR="${SCRIPT_DIR}/testdata" # 用于查找 .in/.out 文件
|
||||||
|
|
||||||
|
# 定义编译器
|
||||||
|
GCC_NATIVE="gcc" # VM 内部的原生 gcc
|
||||||
|
|
||||||
|
# --- 初始化变量 ---
|
||||||
|
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||||
|
EXEC_TIMEOUT=5 # 程序自动化执行超时 (秒)
|
||||||
|
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||||
|
S_FILES=() # 存储用户提供的 .s 文件列表
|
||||||
|
PASSED_CASES=0
|
||||||
|
FAILED_CASES_LIST=""
|
||||||
|
|
||||||
|
# --- 函数定义 ---
|
||||||
|
show_help() {
|
||||||
|
echo "用法: $0 [文件1.s] [文件2.s] ... [选项]"
|
||||||
|
echo "在 VM 内部编译并测试指定的 .s 文件。"
|
||||||
|
echo ""
|
||||||
|
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
|
||||||
|
echo ""
|
||||||
|
echo "选项:"
|
||||||
|
echo " -ct N 设置 gcc 编译超时为 N 秒 (默认: 10)。"
|
||||||
|
echo " -t N 设置程序自动化执行超时为 N 秒 (默认: 5)。"
|
||||||
|
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
||||||
|
echo " -h, --help 显示此帮助信息并退出。"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 显示文件内容并根据行数截断的函数
|
||||||
|
display_file_content() {
|
||||||
|
local file_path="$1"
|
||||||
|
local title="$2"
|
||||||
|
local max_lines="$3"
|
||||||
|
|
||||||
|
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"
|
||||||
|
else
|
||||||
|
cat "$file_path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 参数解析 ---
|
||||||
|
# 从参数中分离出 .s 文件和选项
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
-ct|-t|-ml|--max-lines)
|
||||||
|
# 选项和其值将在下一个循环中处理
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
# 检查是否是带值的选项
|
||||||
|
if ! [[ ${args_processed+x} ]]; then
|
||||||
|
args_processed=true # 标记已处理过参数
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-ct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -ct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-t) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -t 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
*.s) S_FILES+=("$1") ;;
|
||||||
|
*) if ! [[ "$1" =~ ^[0-9]+$ ]]; then echo "未知选项或无效文件: $1"; show_help; exit 1; fi ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*.s)
|
||||||
|
if [[ -f "$arg" ]]; then
|
||||||
|
S_FILES+=("$arg")
|
||||||
|
else
|
||||||
|
echo "警告: 文件不存在,已忽略: $arg"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- 主逻辑开始 ---
|
||||||
|
if [ ${#S_FILES[@]} -eq 0 ]; then
|
||||||
|
echo "错误: 未提供任何 .s 文件作为输入。"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${TMP_DIR}"
|
||||||
|
TOTAL_CASES=${#S_FILES[@]}
|
||||||
|
|
||||||
|
echo "SysY VM 内单例测试运行器启动..."
|
||||||
|
echo "超时设置: gcc=${GCC_TIMEOUT}s, 运行=${EXEC_TIMEOUT}s"
|
||||||
|
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
for s_file in "${S_FILES[@]}"; do
|
||||||
|
is_passed=1
|
||||||
|
|
||||||
|
# 从 .s 文件名反向推导原始测试用例路径
|
||||||
|
base_name_from_s_file=$(basename "$s_file" .s)
|
||||||
|
original_test_name_underscored=$(echo "$base_name_from_s_file" | sed 's/_sysyc_riscv64$//')
|
||||||
|
category=$(echo "$original_test_name_underscored" | cut -d'_' -f1)
|
||||||
|
test_file_base=$(echo "$original_test_name_underscored" | cut -d'_' -f2-)
|
||||||
|
original_relative_path="${category}/${test_file_base}"
|
||||||
|
|
||||||
|
executable_file="${TMP_DIR}/${base_name_from_s_file}"
|
||||||
|
input_file="${TESTDATA_DIR}/${original_relative_path}.in"
|
||||||
|
output_reference_file="${TESTDATA_DIR}/${original_relative_path}.out"
|
||||||
|
output_actual_file="${TMP_DIR}/${base_name_from_s_file}.actual_out"
|
||||||
|
|
||||||
|
echo "======================================================================"
|
||||||
|
echo "正在处理: ${s_file}"
|
||||||
|
echo " (关联测试用例: ${original_relative_path}.sy)"
|
||||||
|
|
||||||
|
# 步骤 1: GCC 编译
|
||||||
|
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${GCC_TIMEOUT} "${GCC_NATIVE}" "${s_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static -g
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"
|
||||||
|
is_passed=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 步骤 2: 执行与测试
|
||||||
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
|
# 检查是自动化测试还是交互模式
|
||||||
|
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
|
||||||
|
# --- 自动化测试模式 ---
|
||||||
|
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
|
||||||
|
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||||
|
|
||||||
|
exec_cmd="\"${executable_file}\""
|
||||||
|
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||||
|
exec_cmd+=" > \"${output_actual_file}\""
|
||||||
|
|
||||||
|
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||||
|
ACTUAL_RETURN_CODE=$?
|
||||||
|
|
||||||
|
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||||
|
echo -e "\e[31m 执行超时。\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}/${base_name_from_s_file}.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
|
||||||
|
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||||
|
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
||||||
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
echo -e " \e[36m----------------\e[0m"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
||||||
|
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
||||||
|
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
echo -e " \e[36m----------------\e[0m"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# --- 交互模式 ---
|
||||||
|
echo -e "\e[33m"
|
||||||
|
echo " **********************************************************"
|
||||||
|
echo " ** 未找到 .in 或 .out 文件,进入交互模式。 **"
|
||||||
|
echo " ** 程序即将运行,你可以直接在终端中输入。 **"
|
||||||
|
echo " ** 按下 Ctrl+D (EOF) 或以其他方式结束程序以继续。 **"
|
||||||
|
echo " **********************************************************"
|
||||||
|
echo -e "\e[0m"
|
||||||
|
"${executable_file}"
|
||||||
|
INTERACTIVE_RET_CODE=$?
|
||||||
|
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE}\e[0m"
|
||||||
|
echo " 注意: 交互模式的结果未经验证。"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
|
echo -e "\e[32m状态: 通过\e[0m"
|
||||||
|
((PASSED_CASES++))
|
||||||
|
else
|
||||||
|
echo -e "\e[31m状态: 失败\e[0m"
|
||||||
|
FAILED_CASES_LIST+="${original_relative_path}.sy\n"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- 打印最终总结 ---
|
||||||
|
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
|
||||||
@ -1,16 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# run_vm_tests.sh - 用于在 RISC-V 虚拟机内部汇编、链接和测试 SysY 程序的脚本
|
# runit-riscv64.sh - 用于在 RISC-V 虚拟机内部汇编、链接和测试 SysY 程序的脚本
|
||||||
# 此脚本应位于您的项目根目录 (例如 /home/ubuntu/debug)
|
# 此脚本应位于您的项目根目录 (例如 /home/ubuntu/debug)
|
||||||
# 假设当前运行环境已经是 RISC-V 64 位架构,可以直接执行编译后的程序。
|
# 假设当前运行环境已经是 RISC-V 64 位架构,可以直接执行编译后的程序。
|
||||||
# 脚本的目录结构应该为:
|
|
||||||
# .
|
|
||||||
# ├── runit.sh
|
|
||||||
# ├── lib
|
|
||||||
# │ └── libsysy_riscv.a
|
|
||||||
# └── testdata
|
|
||||||
# ├── functional
|
|
||||||
# └── performance
|
|
||||||
|
|
||||||
# 定义相对于脚本位置的目录
|
# 定义相对于脚本位置的目录
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||||
@ -22,30 +14,47 @@ TESTDATA_DIR="${SCRIPT_DIR}/testdata"
|
|||||||
GCC_NATIVE="gcc" # VM 内部的 gcc
|
GCC_NATIVE="gcc" # VM 内部的 gcc
|
||||||
|
|
||||||
# --- 新增功能: 初始化变量 ---
|
# --- 新增功能: 初始化变量 ---
|
||||||
TIMEOUT_SECONDS=5 # 默认运行时超时时间为 5 秒
|
GCC_TIMEOUT=10 # 默认 gcc 编译超时 (秒)
|
||||||
COMPILE_TIMEOUT_SECONDS=10 # 默认编译超时时间为 10 秒
|
EXEC_TIMEOUT=5 # 默认运行时超时 (秒)
|
||||||
|
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||||
TOTAL_CASES=0
|
TOTAL_CASES=0
|
||||||
PASSED_CASES=0
|
PASSED_CASES=0
|
||||||
|
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
|
||||||
|
|
||||||
# 显示帮助信息的函数
|
# 显示帮助信息的函数
|
||||||
show_help() {
|
show_help() {
|
||||||
echo "用法: $0 [选项]"
|
echo "用法: $0 [选项]"
|
||||||
echo "此脚本用于在 RISC-V 虚拟机内部,对之前生成的 .s 汇编文件进行汇编、链接和测试。"
|
echo "此脚本用于在 RISC-V 虚拟机内部,对之前生成的 .s 汇编文件进行汇编、链接和测试。"
|
||||||
echo "假设当前运行环境已经是 RISC-V 64 位架构,可以直接执行编译后的程序。"
|
echo "测试会按文件名升序进行。"
|
||||||
echo ""
|
echo ""
|
||||||
echo "选项:"
|
echo "选项:"
|
||||||
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
||||||
echo " -t, --timeout N 设置每个测试用例的运行时超时为 N 秒 (默认: 5)。"
|
echo " -ct M 设置 gcc 编译的超时时间为 M 秒 (默认: 10)。"
|
||||||
echo " -ct, --compile-timeout M 设置 gcc 编译的超时时间为 M 秒 (默认: 10)。"
|
echo " -t N 设置每个测试用例的运行时超时为 N 秒 (默认: 5)。"
|
||||||
|
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
||||||
echo " -h, --help 显示此帮助信息并退出。"
|
echo " -h, --help 显示此帮助信息并退出。"
|
||||||
echo ""
|
}
|
||||||
echo "执行步骤:"
|
|
||||||
echo "1. 遍历 'tmp/' 目录下的所有 .s 汇编文件。"
|
# 显示文件内容并根据行数截断的函数
|
||||||
echo "2. 在指定的超时时间内使用 VM 内部的 gcc 将 .s 文件汇编并链接为可执行文件。"
|
display_file_content() {
|
||||||
echo "3. 在指定的超时时间内运行编译后的可执行文件。"
|
local file_path="$1"
|
||||||
echo "4. 根据对应的 .out 文件内容进行返回值和/或标准输出的比较。"
|
local title="$2"
|
||||||
echo "5. 输出比较时会忽略行尾多余的换行符。"
|
local max_lines="$3"
|
||||||
echo "6. 所有测试结束后,报告总通过率。"
|
|
||||||
|
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"
|
||||||
|
else
|
||||||
|
cat "$file_path"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 清理临时文件的函数
|
# 清理临时文件的函数
|
||||||
@ -69,23 +78,14 @@ while [[ "$#" -gt 0 ]]; do
|
|||||||
clean_tmp
|
clean_tmp
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
-t|--timeout)
|
-t)
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then
|
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -t 需要一个正整数参数。" >&2; exit 1; fi
|
||||||
TIMEOUT_SECONDS="$2"
|
|
||||||
shift # 移过参数值
|
|
||||||
else
|
|
||||||
echo "错误: --timeout 需要一个正整数参数。" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
-ct|--compile-timeout)
|
-ct)
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then
|
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -ct 需要一个正整数参数。" >&2; exit 1; fi
|
||||||
COMPILE_TIMEOUT_SECONDS="$2"
|
;;
|
||||||
shift # 移过参数值
|
-ml|--max-lines)
|
||||||
else
|
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
|
||||||
echo "错误: --compile-timeout 需要一个正整数参数。" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
show_help
|
show_help
|
||||||
@ -101,32 +101,27 @@ while [[ "$#" -gt 0 ]]; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
echo "SysY VM 内部测试运行器启动..."
|
echo "SysY VM 内部测试运行器启动..."
|
||||||
echo "编译超时设置为: ${COMPILE_TIMEOUT_SECONDS} 秒"
|
echo "GCC 编译超时设置为: ${GCC_TIMEOUT} 秒"
|
||||||
echo "运行时超时设置为: ${TIMEOUT_SECONDS} 秒"
|
echo "运行时超时设置为: ${EXEC_TIMEOUT} 秒"
|
||||||
|
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||||
echo "汇编文件目录: ${TMP_DIR}"
|
echo "汇编文件目录: ${TMP_DIR}"
|
||||||
echo "库文件目录: ${LIB_DIR}"
|
|
||||||
echo "测试数据目录: ${TESTDATA_DIR}"
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 查找 tmp 目录下的所有 .s 汇编文件
|
# 查找 tmp 目录下的所有 .s 汇编文件并排序
|
||||||
s_files=$(find "${TMP_DIR}" -maxdepth 1 -name "*.s")
|
s_files=$(find "${TMP_DIR}" -maxdepth 1 -name "*.s" | sort -V)
|
||||||
TOTAL_CASES=$(echo "$s_files" | wc -w)
|
TOTAL_CASES=$(echo "$s_files" | wc -w)
|
||||||
|
|
||||||
# 遍历找到的每个 .s 文件
|
# 使用 here-string (<<<) 避免子 shell 问题
|
||||||
echo "$s_files" | while read s_file; do
|
while IFS= read -r s_file; do
|
||||||
# --- 新增功能: 初始化用例通过状态 ---
|
|
||||||
is_passed=1 # 1 表示通过, 0 表示失败
|
is_passed=1 # 1 表示通过, 0 表示失败
|
||||||
|
|
||||||
# 从 .s 文件名中提取原始的测试用例名称部分
|
|
||||||
base_name_from_s_file=$(basename "$s_file" .s)
|
base_name_from_s_file=$(basename "$s_file" .s)
|
||||||
original_test_name_underscored=$(echo "$base_name_from_s_file" | sed 's/_sysyc_riscv64$//')
|
original_test_name_underscored=$(echo "$base_name_from_s_file" | sed 's/_sysyc_riscv64$//')
|
||||||
|
|
||||||
# 将 `original_test_name_underscored` 分割成类别和文件名
|
|
||||||
category=$(echo "$original_test_name_underscored" | cut -d'_' -f1)
|
category=$(echo "$original_test_name_underscored" | cut -d'_' -f1)
|
||||||
test_file_base=$(echo "$original_test_name_underscored" | cut -d'_' -f2-)
|
test_file_base=$(echo "$original_test_name_underscored" | cut -d'_' -f2-)
|
||||||
original_relative_path="${category}/${test_file_base}"
|
original_relative_path="${category}/${test_file_base}"
|
||||||
|
|
||||||
# 定义可执行文件、输入文件、参考输出文件和实际输出文件的路径
|
|
||||||
executable_file="${TMP_DIR}/${base_name_from_s_file}"
|
executable_file="${TMP_DIR}/${base_name_from_s_file}"
|
||||||
input_file="${TESTDATA_DIR}/${original_relative_path}.in"
|
input_file="${TESTDATA_DIR}/${original_relative_path}.in"
|
||||||
output_reference_file="${TESTDATA_DIR}/${original_relative_path}.out"
|
output_reference_file="${TESTDATA_DIR}/${original_relative_path}.out"
|
||||||
@ -136,42 +131,43 @@ echo "$s_files" | while read s_file; do
|
|||||||
echo " 对应的测试用例路径: ${original_relative_path}"
|
echo " 对应的测试用例路径: ${original_relative_path}"
|
||||||
|
|
||||||
# 步骤 1: 使用 VM 内部的 gcc 编译 .s 到可执行文件
|
# 步骤 1: 使用 VM 内部的 gcc 编译 .s 到可执行文件
|
||||||
echo " 使用 gcc 汇编并链接 (超时 ${COMPILE_TIMEOUT_SECONDS}s)..."
|
echo " 使用 gcc 汇编并链接 (超时 ${GCC_TIMEOUT}s)..."
|
||||||
# --- 修改点: 为 gcc 增加 timeout ---
|
timeout -s KILL ${GCC_TIMEOUT} "${GCC_NATIVE}" "${s_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static -g
|
||||||
timeout ${COMPILE_TIMEOUT_SECONDS} "${GCC_NATIVE}" "${s_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static -g
|
|
||||||
GCC_STATUS=$?
|
GCC_STATUS=$?
|
||||||
if [ $GCC_STATUS -eq 124 ]; then
|
if [ $GCC_STATUS -eq 124 ]; then
|
||||||
echo -e "\e[31m错误: GCC 编译/链接 ${s_file} 超时 (超过 ${COMPILE_TIMEOUT_SECONDS} 秒)\e[0m"
|
echo -e "\e[31m错误: GCC 编译/链接 ${s_file} 超时\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
elif [ $GCC_STATUS -ne 0 ]; then
|
elif [ $GCC_STATUS -ne 0 ]; then
|
||||||
echo -e "\e[31m错误: GCC 汇编/链接 ${s_file} 失败,退出码: ${GCC_STATUS}\e[0m"
|
echo -e "\e[31m错误: GCC 汇编/链接 ${s_file} 失败,退出码: ${GCC_STATUS}\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
else
|
fi
|
||||||
|
|
||||||
|
# 步骤 2: 只有当编译成功时才执行
|
||||||
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
echo " 生成的可执行文件: ${executable_file}"
|
echo " 生成的可执行文件: ${executable_file}"
|
||||||
echo " 正在执行 (超时 ${TIMEOUT_SECONDS}s): \"${executable_file}\""
|
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||||
|
|
||||||
# 步骤 2: 执行编译后的文件并比较/报告结果
|
exec_cmd="\"${executable_file}\""
|
||||||
if [ -f "${output_reference_file}" ]; then
|
if [ -f "${input_file}" ]; then
|
||||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
exec_cmd+=" < \"${input_file}\""
|
||||||
|
fi
|
||||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
exec_cmd+=" > \"${output_actual_file}\""
|
||||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
|
||||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name_from_s_file}.expected_stdout"
|
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
ACTUAL_RETURN_CODE=$?
|
||||||
echo " 检测到 .out 文件同时包含标准输出和期望的返回码。"
|
|
||||||
echo " 期望返回码: ${EXPECTED_RETURN_CODE}"
|
|
||||||
|
|
||||||
if [ -f "${input_file}" ]; then
|
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||||
timeout ${TIMEOUT_SECONDS} "${executable_file}" < "${input_file}" > "${output_actual_file}"
|
echo -e "\e[31m 执行超时: ${original_relative_path}.sy 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||||
else
|
is_passed=0
|
||||||
timeout ${TIMEOUT_SECONDS} "${executable_file}" > "${output_actual_file}"
|
else
|
||||||
fi
|
if [ -f "${output_reference_file}" ]; then
|
||||||
ACTUAL_RETURN_CODE=$?
|
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}/${base_name_from_s_file}.expected_stdout"
|
||||||
|
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||||
|
|
||||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
|
||||||
echo -e "\e[31m 执行超时: ${original_relative_path}.sy 运行超过 ${TIMEOUT_SECONDS} 秒\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
else
|
|
||||||
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||||
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||||
else
|
else
|
||||||
@ -179,65 +175,51 @@ echo "$s_files" | while read s_file; do
|
|||||||
is_passed=0
|
is_passed=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||||
echo -e "\e[32m 标准输出测试成功\e[0m"
|
|
||||||
else
|
|
||||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||||
echo " 差异:"
|
|
||||||
diff "${output_actual_file}" "${EXPECTED_STDOUT_FILE}"
|
|
||||||
is_passed=0
|
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
|
fi
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo " 检测到 .out 文件为纯标准输出参考。"
|
|
||||||
if [ -f "${input_file}" ]; then
|
|
||||||
timeout ${TIMEOUT_SECONDS} "${executable_file}" < "${input_file}" > "${output_actual_file}"
|
|
||||||
else
|
else
|
||||||
timeout ${TIMEOUT_SECONDS} "${executable_file}" > "${output_actual_file}"
|
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
|
||||||
fi
|
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
|
||||||
EXEC_STATUS=$?
|
|
||||||
|
|
||||||
if [ $EXEC_STATUS -eq 124 ]; then
|
|
||||||
echo -e "\e[31m 执行超时: ${original_relative_path}.sy 运行超过 ${TIMEOUT_SECONDS} 秒\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
else
|
|
||||||
if [ $EXEC_STATUS -ne 0 ]; then
|
|
||||||
echo -e "\e[33m警告: 程序以非零状态 ${EXEC_STATUS} 退出 (纯输出比较模式)。\e[0m"
|
|
||||||
fi
|
fi
|
||||||
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
||||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||||
echo " 差异:"
|
|
||||||
diff "${output_actual_file}" "${output_reference_file}"
|
|
||||||
is_passed=0
|
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
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo " 未找到 .out 文件。正在运行并报告返回码。"
|
|
||||||
timeout ${TIMEOUT_SECONDS} "${executable_file}"
|
|
||||||
EXEC_STATUS=$?
|
|
||||||
if [ $EXEC_STATUS -eq 124 ]; then
|
|
||||||
echo -e "\e[31m 执行超时: ${original_relative_path}.sy 运行超过 ${TIMEOUT_SECONDS} 秒\e[0m"
|
|
||||||
is_passed=0
|
|
||||||
else
|
else
|
||||||
echo " ${original_relative_path}.sy 的返回码: ${EXEC_STATUS}"
|
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 新增功能: 更新通过用例计数 ---
|
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
((PASSED_CASES++))
|
((PASSED_CASES++))
|
||||||
|
else
|
||||||
|
FAILED_CASES_LIST+="${original_relative_path}.sy\n"
|
||||||
fi
|
fi
|
||||||
echo "" # 为测试用例之间添加一个空行
|
echo ""
|
||||||
done
|
done <<< "$s_files"
|
||||||
|
|
||||||
# --- 新增功能: 打印最终总结 ---
|
|
||||||
echo "========================================"
|
echo "========================================"
|
||||||
echo "测试完成"
|
echo "测试完成"
|
||||||
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
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 "========================================"
|
echo "========================================"
|
||||||
|
|
||||||
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
|
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
|
||||||
|
|||||||
270
test_script/runit-single.sh
Normal file
270
test_script/runit-single.sh
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# runit-single.sh - 用于编译和测试单个或少量 SysY 程序的脚本
|
||||||
|
# 模仿 runit.sh 的功能,但以具体文件路径作为输入。
|
||||||
|
|
||||||
|
# --- 配置区 ---
|
||||||
|
# 请根据你的环境修改这些路径
|
||||||
|
# 假设此脚本位于你的项目根目录或一个脚本目录中
|
||||||
|
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"
|
||||||
|
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
||||||
|
QEMU_RISCV64="qemu-riscv64"
|
||||||
|
|
||||||
|
# --- 初始化变量 ---
|
||||||
|
EXECUTE_MODE=false
|
||||||
|
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=""
|
||||||
|
|
||||||
|
# --- 函数定义 ---
|
||||||
|
show_help() {
|
||||||
|
echo "用法: $0 [文件1.sy] [文件2.sy] ... [选项]"
|
||||||
|
echo "编译并测试指定的 .sy 文件。"
|
||||||
|
echo ""
|
||||||
|
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
|
||||||
|
echo ""
|
||||||
|
echo "选项:"
|
||||||
|
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
|
||||||
|
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
||||||
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
|
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
|
||||||
|
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
||||||
|
echo " -h, --help 显示此帮助信息并退出。"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 新增功能: 显示文件内容并根据行数截断 ---
|
||||||
|
display_file_content() {
|
||||||
|
local file_path="$1"
|
||||||
|
local title="$2"
|
||||||
|
local max_lines="$3"
|
||||||
|
|
||||||
|
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"
|
||||||
|
else
|
||||||
|
cat "$file_path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# --- 参数解析 ---
|
||||||
|
# 从参数中分离出 .sy 文件和选项
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
-e|--executable)
|
||||||
|
EXECUTE_MODE=true
|
||||||
|
;;
|
||||||
|
-sct|-gct|-et|-ml|--max-lines)
|
||||||
|
# 选项和其值将在下一个循环中处理
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
# 检查是否是带值的选项
|
||||||
|
if ! [[ ${args_processed+x} ]]; then
|
||||||
|
args_processed=true # 标记已处理过参数
|
||||||
|
# 重新处理所有参数
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
*.sy) SY_FILES+=("$1") ;;
|
||||||
|
-e|--executable) ;; # 已在外部处理
|
||||||
|
*) if ! [[ "$1" =~ ^[0-9]+$ ]]; then echo "未知选项或无效文件: $1"; show_help; exit 1; fi ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*.sy)
|
||||||
|
if [[ -f "$arg" ]]; then
|
||||||
|
SY_FILES+=("$arg")
|
||||||
|
else
|
||||||
|
echo "警告: 文件不存在,已忽略: $arg"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- 主逻辑开始 ---
|
||||||
|
if ! ${EXECUTE_MODE}; then
|
||||||
|
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#SY_FILES[@]} -eq 0 ]; then
|
||||||
|
echo "错误: 未提供任何 .sy 文件作为输入。"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${TMP_DIR}"
|
||||||
|
TOTAL_CASES=${#SY_FILES[@]}
|
||||||
|
|
||||||
|
echo "SysY 单例测试运行器启动..."
|
||||||
|
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
|
||||||
|
base_name=$(basename "${sy_file}" .sy)
|
||||||
|
source_dir=$(dirname "${sy_file}")
|
||||||
|
|
||||||
|
ir_file="${TMP_DIR}/${base_name}_sysyc_riscv64.ll"
|
||||||
|
assembly_file="${TMP_DIR}/${base_name}.s"
|
||||||
|
executable_file="${TMP_DIR}/${base_name}"
|
||||||
|
input_file="${source_dir}/${base_name}.in"
|
||||||
|
output_reference_file="${source_dir}/${base_name}.out"
|
||||||
|
output_actual_file="${TMP_DIR}/${base_name}.actual_out"
|
||||||
|
|
||||||
|
echo "======================================================================"
|
||||||
|
echo "正在处理: ${sy_file}"
|
||||||
|
|
||||||
|
# 步骤 1: sysyc 编译
|
||||||
|
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" > "${ir_file}"
|
||||||
|
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
|
||||||
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
|
||||||
|
is_passed=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
|
||||||
|
|
||||||
|
# 步骤 3: 执行与测试
|
||||||
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
|
# 检查是自动化测试还是交互模式
|
||||||
|
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
|
||||||
|
# --- 自动化测试模式 ---
|
||||||
|
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
|
||||||
|
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||||
|
|
||||||
|
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
|
||||||
|
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||||
|
exec_cmd+=" > \"${output_actual_file}\""
|
||||||
|
|
||||||
|
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||||
|
ACTUAL_RETURN_CODE=$?
|
||||||
|
|
||||||
|
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||||
|
echo -e "\e[31m 执行超时。\e[0m"
|
||||||
|
is_passed=0
|
||||||
|
else
|
||||||
|
if [ -f "${output_reference_file}" ]; then
|
||||||
|
# 此处逻辑与 runit.sh 相同
|
||||||
|
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}/${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
|
||||||
|
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||||
|
echo -e "\e[31m 标准输出测试失败。\e[0m"
|
||||||
|
is_passed=0
|
||||||
|
# --- 本次修改点: 使用新函数显示输出 ---
|
||||||
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
echo -e " \e[36m----------------\e[0m"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
||||||
|
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31m 标准输出测试失败。\e[0m"
|
||||||
|
is_passed=0
|
||||||
|
# --- 本次修改点: 使用新函数显示输出 ---
|
||||||
|
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
|
echo -e " \e[36m----------------\e[0m"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# --- 交互模式 ---
|
||||||
|
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 " 注意: 交互模式的结果未经验证。"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
|
echo -e "\e[32m状态: 通过\e[0m"
|
||||||
|
((PASSED_CASES++))
|
||||||
|
else
|
||||||
|
echo -e "\e[31m状态: 失败\e[0m"
|
||||||
|
FAILED_CASES_LIST+="${sy_file}\n"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- 打印最终总结 ---
|
||||||
|
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
|
||||||
@ -21,6 +21,7 @@ EXECUTE_MODE=false
|
|||||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||||
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
|
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
|
||||||
|
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||||
TOTAL_CASES=0
|
TOTAL_CASES=0
|
||||||
PASSED_CASES=0
|
PASSED_CASES=0
|
||||||
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
|
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
|
||||||
@ -36,9 +37,32 @@ show_help() {
|
|||||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 5)。"
|
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 5)。"
|
||||||
|
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
||||||
echo " -h, --help 显示此帮助信息并退出。"
|
echo " -h, --help 显示此帮助信息并退出。"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 显示文件内容并根据行数截断的函数
|
||||||
|
display_file_content() {
|
||||||
|
local file_path="$1"
|
||||||
|
local title="$2"
|
||||||
|
local max_lines="$3"
|
||||||
|
|
||||||
|
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"
|
||||||
|
else
|
||||||
|
cat "$file_path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# 清理临时文件的函数
|
# 清理临时文件的函数
|
||||||
clean_tmp() {
|
clean_tmp() {
|
||||||
echo "正在清理临时目录: ${TMP_DIR}"
|
echo "正在清理临时目录: ${TMP_DIR}"
|
||||||
@ -67,6 +91,9 @@ while [[ "$#" -gt 0 ]]; do
|
|||||||
-et)
|
-et)
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
|
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
|
||||||
;;
|
;;
|
||||||
|
-ml|--max-lines)
|
||||||
|
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
show_help
|
show_help
|
||||||
exit 0
|
exit 0
|
||||||
@ -86,6 +113,7 @@ echo "临时目录: ${TMP_DIR}"
|
|||||||
echo "执行模式: ${EXECUTE_MODE}"
|
echo "执行模式: ${EXECUTE_MODE}"
|
||||||
if ${EXECUTE_MODE}; then
|
if ${EXECUTE_MODE}; then
|
||||||
echo "超时设置: sysyc=${SYSYC_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}"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
@ -93,8 +121,7 @@ echo ""
|
|||||||
sy_files=$(find "${TESTDATA_DIR}" -name "*.sy" | sort -V)
|
sy_files=$(find "${TESTDATA_DIR}" -name "*.sy" | sort -V)
|
||||||
TOTAL_CASES=$(echo "$sy_files" | wc -w)
|
TOTAL_CASES=$(echo "$sy_files" | wc -w)
|
||||||
|
|
||||||
# --- 本次修复: 使用 here-string (<<<) 代替管道 (|) 来避免子 shell 问题 ---
|
# --- 修复: 使用 here-string (<<<) 代替管道 (|) 来避免子 shell 问题 ---
|
||||||
# 这样可以确保循环内的 PASSED_CASES 变量修改在循环结束后依然有效
|
|
||||||
while IFS= read -r sy_file; do
|
while IFS= read -r sy_file; do
|
||||||
is_passed=1 # 1 表示通过, 0 表示失败
|
is_passed=1 # 1 表示通过, 0 表示失败
|
||||||
|
|
||||||
@ -111,7 +138,7 @@ while IFS= read -r sy_file; do
|
|||||||
|
|
||||||
# 步骤 1: 使用 sysyc 编译 .sy 到 .s
|
# 步骤 1: 使用 sysyc 编译 .sy 到 .s
|
||||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
timeout ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
||||||
SYSYC_STATUS=$?
|
SYSYC_STATUS=$?
|
||||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
if [ $SYSYC_STATUS -eq 124 ]; then
|
||||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
|
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
|
||||||
@ -125,7 +152,7 @@ while IFS= read -r sy_file; do
|
|||||||
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
|
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
|
||||||
# 步骤 2: 使用 riscv64-linux-gnu-gcc 编译 .s 到可执行文件
|
# 步骤 2: 使用 riscv64-linux-gnu-gcc 编译 .s 到可执行文件
|
||||||
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||||
timeout ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||||
GCC_STATUS=$?
|
GCC_STATUS=$?
|
||||||
if [ $GCC_STATUS -eq 124 ]; then
|
if [ $GCC_STATUS -eq 124 ]; then
|
||||||
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 超时\e[0m"
|
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 超时\e[0m"
|
||||||
@ -136,11 +163,9 @@ while IFS= read -r sy_file; do
|
|||||||
fi
|
fi
|
||||||
elif ! ${EXECUTE_MODE}; then
|
elif ! ${EXECUTE_MODE}; then
|
||||||
echo " 跳过执行模式。仅生成汇编文件。"
|
echo " 跳过执行模式。仅生成汇编文件。"
|
||||||
# 如果只编译不执行,只要编译成功就算通过
|
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
((PASSED_CASES++))
|
((PASSED_CASES++))
|
||||||
else
|
else
|
||||||
# --- 本次修改点 ---
|
|
||||||
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
@ -151,22 +176,19 @@ while IFS= read -r sy_file; do
|
|||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||||
|
|
||||||
# 准备执行命令
|
|
||||||
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
|
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
|
||||||
if [ -f "${input_file}" ]; then
|
if [ -f "${input_file}" ]; then
|
||||||
exec_cmd+=" < \"${input_file}\""
|
exec_cmd+=" < \"${input_file}\""
|
||||||
fi
|
fi
|
||||||
exec_cmd+=" > \"${output_actual_file}\""
|
exec_cmd+=" > \"${output_actual_file}\""
|
||||||
|
|
||||||
# 执行并捕获返回码
|
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||||
eval "timeout ${EXEC_TIMEOUT} ${exec_cmd}"
|
|
||||||
ACTUAL_RETURN_CODE=$?
|
ACTUAL_RETURN_CODE=$?
|
||||||
|
|
||||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||||
echo -e "\e[31m 执行超时: ${sy_file} 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
echo -e "\e[31m 执行超时: ${sy_file} 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
else
|
else
|
||||||
# 检查是否存在 .out 文件以进行比较
|
|
||||||
if [ -f "${output_reference_file}" ]; then
|
if [ -f "${output_reference_file}" ]; then
|
||||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||||
|
|
||||||
@ -175,70 +197,54 @@ while IFS= read -r sy_file; do
|
|||||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_riscv64.expected_stdout"
|
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_riscv64.expected_stdout"
|
||||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||||
|
|
||||||
# 比较返回码
|
|
||||||
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||||
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
fi
|
fi
|
||||||
# 比较标准输出
|
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||||
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
|
||||||
echo -e "\e[32m 标准输出测试成功\e[0m"
|
|
||||||
else
|
|
||||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
echo -e " \e[36m---------- 期望输出 ----------\e[0m"
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
cat "${EXPECTED_STDOUT_FILE}"
|
display_file_content "${output_actual_file}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
echo -e " \e[36m---------- 实际输出 ----------\e[0m"
|
|
||||||
cat "${output_actual_file}"
|
|
||||||
echo -e " \e[36m------------------------------\e[0m"
|
echo -e " \e[36m------------------------------\e[0m"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# 纯标准输出比较
|
|
||||||
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
|
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
|
||||||
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
|
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
|
||||||
fi
|
fi
|
||||||
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
||||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
echo -e " \e[36m---------- 期望输出 ----------\e[0m"
|
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
cat "${output_reference_file}"
|
display_file_content "${output_actual_file}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||||
echo -e " \e[36m---------- 实际输出 ----------\e[0m"
|
|
||||||
cat "${output_actual_file}"
|
|
||||||
echo -e " \e[36m------------------------------\e[0m"
|
echo -e " \e[36m------------------------------\e[0m"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# 没有 .out 文件,只报告返回码
|
|
||||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 更新通过用例计数
|
|
||||||
# --- 本次修改点 ---
|
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
((PASSED_CASES++))
|
((PASSED_CASES++))
|
||||||
else
|
else
|
||||||
# 将失败的用例名称添加到列表中
|
|
||||||
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
||||||
fi
|
fi
|
||||||
echo "" # 添加空行以提高可读性
|
echo ""
|
||||||
done <<< "$sy_files"
|
done <<< "$sy_files"
|
||||||
|
|
||||||
# --- 新增功能: 打印最终总结 ---
|
|
||||||
echo "========================================"
|
echo "========================================"
|
||||||
echo "测试完成"
|
echo "测试完成"
|
||||||
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
||||||
|
|
||||||
# --- 本次修改点: 打印未通过的测例列表 ---
|
|
||||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "\e[31m未通过的测例:\e[0m"
|
echo -e "\e[31m未通过的测例:\e[0m"
|
||||||
# 使用 -e 来解释换行符 \n
|
|
||||||
echo -e "${FAILED_CASES_LIST}"
|
echo -e "${FAILED_CASES_LIST}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user