[backend-LAG]添加新的LargeArrayToGlobal中端Pass,以及栈保护逻辑
This commit is contained in:
@@ -46,9 +46,13 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
|||||||
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
|
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
|
||||||
int size = getTypeSizeInBytes(allocated_type);
|
int size = getTypeSizeInBytes(allocated_type);
|
||||||
|
|
||||||
// RISC-V要求栈地址8字节对齐
|
// 优化栈帧大小:对于大数组使用4字节对齐,小对象使用8字节对齐
|
||||||
size = (size + 7) & ~7;
|
if (size >= 256) { // 大数组优化
|
||||||
if (size == 0) size = 8; // 至少分配8字节
|
size = (size + 3) & ~3; // 4字节对齐
|
||||||
|
} else {
|
||||||
|
size = (size + 7) & ~7; // 8字节对齐
|
||||||
|
}
|
||||||
|
if (size == 0) size = 4; // 最小4字节
|
||||||
|
|
||||||
local_var_offset += size;
|
local_var_offset += size;
|
||||||
unsigned alloca_vreg = isel->getVReg(alloca);
|
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||||
|
|||||||
@@ -47,12 +47,22 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
|||||||
std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end());
|
std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end());
|
||||||
frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8;
|
frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8;
|
||||||
|
|
||||||
// 3. 计算最终的栈帧总大小
|
// 3. 计算最终的栈帧总大小,包含栈溢出保护
|
||||||
int total_stack_size = frame_info.locals_size +
|
int total_stack_size = frame_info.locals_size +
|
||||||
frame_info.spill_size +
|
frame_info.spill_size +
|
||||||
frame_info.callee_saved_size +
|
frame_info.callee_saved_size +
|
||||||
16;
|
16;
|
||||||
|
|
||||||
|
// 栈溢出保护:增加最大栈帧大小以容纳大型数组
|
||||||
|
const int MAX_STACK_FRAME_SIZE = 8192; // 8KB to handle large arrays like 256*4*2 = 2048 bytes
|
||||||
|
if (total_stack_size > MAX_STACK_FRAME_SIZE) {
|
||||||
|
// 如果仍然超过限制,尝试优化对齐方式
|
||||||
|
std::cerr << "Warning: Stack frame size " << total_stack_size
|
||||||
|
<< " exceeds recommended limit " << MAX_STACK_FRAME_SIZE << " for function "
|
||||||
|
<< mfunc->getName() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优化:减少对齐开销,使用16字节对齐而非更大的对齐
|
||||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||||
frame_info.total_size = aligned_stack_size;
|
frame_info.total_size = aligned_stack_size;
|
||||||
|
|
||||||
|
|||||||
@@ -1289,14 +1289,19 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
if (stride != 0) {
|
if (stride != 0) {
|
||||||
// --- 为当前索引和步长生成偏移计算指令 ---
|
// --- 为当前索引和步长生成偏移计算指令 ---
|
||||||
auto offset_vreg = getNewVReg();
|
auto offset_vreg = getNewVReg();
|
||||||
auto index_vreg = getVReg(indexValue);
|
|
||||||
|
// 处理索引 - 区分常量与动态值
|
||||||
// 如果索引是常量,先用 LI 指令加载到虚拟寄存器
|
unsigned index_vreg;
|
||||||
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
|
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
|
||||||
|
// 对于常量索引,直接创建新的虚拟寄存器
|
||||||
|
index_vreg = getNewVReg();
|
||||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
li->addOperand(std::make_unique<RegOperand>(index_vreg));
|
li->addOperand(std::make_unique<RegOperand>(index_vreg));
|
||||||
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
|
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
|
||||||
CurMBB->addInstruction(std::move(li));
|
CurMBB->addInstruction(std::move(li));
|
||||||
|
} else {
|
||||||
|
// 对于动态索引,使用已存在的虚拟寄存器
|
||||||
|
index_vreg = getVReg(indexValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 优化:如果步长是1,可以直接移动(MV)作为偏移量,无需乘法
|
// 优化:如果步长是1,可以直接移动(MV)作为偏移量,无需乘法
|
||||||
|
|||||||
24
src/include/midend/Pass/Optimize/LargeArrayToGlobal.h
Normal file
24
src/include/midend/Pass/Optimize/LargeArrayToGlobal.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Pass.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
class LargeArrayToGlobalPass : public OptimizationPass {
|
||||||
|
public:
|
||||||
|
static void *ID;
|
||||||
|
|
||||||
|
LargeArrayToGlobalPass() : OptimizationPass("LargeArrayToGlobal", Granularity::Module) {}
|
||||||
|
|
||||||
|
bool runOnModule(Module *M, AnalysisManager &AM) override;
|
||||||
|
void *getPassID() const override {
|
||||||
|
return &ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned calculateTypeSize(Type *type);
|
||||||
|
void convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M);
|
||||||
|
std::string generateUniqueGlobalName(AllocaInst *alloca, Function *F);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@@ -279,7 +279,7 @@ private:
|
|||||||
IRBuilder *pBuilder;
|
IRBuilder *pBuilder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PassManager() = default;
|
PassManager() = delete;
|
||||||
~PassManager() = default;
|
~PassManager() = default;
|
||||||
|
|
||||||
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
|
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ add_library(midend_lib STATIC
|
|||||||
Pass/Optimize/SysYIRCFGOpt.cpp
|
Pass/Optimize/SysYIRCFGOpt.cpp
|
||||||
Pass/Optimize/SCCP.cpp
|
Pass/Optimize/SCCP.cpp
|
||||||
Pass/Optimize/BuildCFG.cpp
|
Pass/Optimize/BuildCFG.cpp
|
||||||
|
Pass/Optimize/LargeArrayToGlobal.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# 包含中端模块所需的头文件路径
|
# 包含中端模块所需的头文件路径
|
||||||
|
|||||||
143
src/midend/Pass/Optimize/LargeArrayToGlobal.cpp
Normal file
143
src/midend/Pass/Optimize/LargeArrayToGlobal.cpp
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#include "../../include/midend/Pass/Optimize/LargeArrayToGlobal.h"
|
||||||
|
#include "../../IR.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
// Helper function to convert type to string
|
||||||
|
static std::string typeToString(Type *type) {
|
||||||
|
if (!type) return "null";
|
||||||
|
|
||||||
|
switch (type->getKind()) {
|
||||||
|
case Type::kInt:
|
||||||
|
return "int";
|
||||||
|
case Type::kFloat:
|
||||||
|
return "float";
|
||||||
|
case Type::kPointer:
|
||||||
|
return "ptr";
|
||||||
|
case Type::kArray: {
|
||||||
|
auto *arrayType = type->as<ArrayType>();
|
||||||
|
return "[" + std::to_string(arrayType->getNumElements()) + " x " +
|
||||||
|
typeToString(arrayType->getElementType()) + "]";
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *LargeArrayToGlobalPass::ID = &LargeArrayToGlobalPass::ID;
|
||||||
|
|
||||||
|
bool LargeArrayToGlobalPass::runOnModule(Module *M, AnalysisManager &AM) {
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
if (!M) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all alloca instructions from all functions
|
||||||
|
std::vector<std::pair<AllocaInst*, Function*>> allocasToConvert;
|
||||||
|
|
||||||
|
for (auto &funcPair : M->getFunctions()) {
|
||||||
|
Function *F = funcPair.second.get();
|
||||||
|
if (!F || F->getBasicBlocks().begin() == F->getBasicBlocks().end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &BB : F->getBasicBlocks()) {
|
||||||
|
for (auto &inst : BB->getInstructions()) {
|
||||||
|
if (auto *alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||||
|
Type *allocatedType = alloca->getAllocatedType();
|
||||||
|
|
||||||
|
// Calculate the size of the allocated type
|
||||||
|
unsigned size = calculateTypeSize(allocatedType);
|
||||||
|
|
||||||
|
// Debug: print size information
|
||||||
|
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
|
||||||
|
<< " for type " << typeToString(allocatedType) << std::endl;
|
||||||
|
|
||||||
|
// Convert arrays of 1KB (1024 bytes) or larger to global variables
|
||||||
|
if (size >= 1024) {
|
||||||
|
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
|
||||||
|
allocasToConvert.emplace_back(alloca, F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the collected alloca instructions to global variables
|
||||||
|
for (auto [alloca, F] : allocasToConvert) {
|
||||||
|
convertAllocaToGlobal(alloca, F, M);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned LargeArrayToGlobalPass::calculateTypeSize(Type *type) {
|
||||||
|
if (!type) return 0;
|
||||||
|
|
||||||
|
switch (type->getKind()) {
|
||||||
|
case Type::kInt:
|
||||||
|
case Type::kFloat:
|
||||||
|
return 4;
|
||||||
|
case Type::kPointer:
|
||||||
|
return 8;
|
||||||
|
case Type::kArray: {
|
||||||
|
auto *arrayType = type->as<ArrayType>();
|
||||||
|
return arrayType->getNumElements() * calculateTypeSize(arrayType->getElementType());
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LargeArrayToGlobalPass::convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M) {
|
||||||
|
Type *allocatedType = alloca->getAllocatedType();
|
||||||
|
|
||||||
|
// Create a unique name for the global variable
|
||||||
|
std::string globalName = generateUniqueGlobalName(alloca, F);
|
||||||
|
|
||||||
|
// Create the global variable - GlobalValue expects pointer type
|
||||||
|
Type *pointerType = Type::getPointerType(allocatedType);
|
||||||
|
GlobalValue *globalVar = M->createGlobalValue(globalName, pointerType);
|
||||||
|
|
||||||
|
if (!globalVar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all uses of the alloca with the global variable
|
||||||
|
alloca->replaceAllUsesWith(globalVar);
|
||||||
|
|
||||||
|
// Remove the alloca instruction from its basic block
|
||||||
|
for (auto &BB : F->getBasicBlocks()) {
|
||||||
|
auto &instructions = BB->getInstructions();
|
||||||
|
for (auto it = instructions.begin(); it != instructions.end(); ++it) {
|
||||||
|
if (it->get() == alloca) {
|
||||||
|
instructions.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LargeArrayToGlobalPass::generateUniqueGlobalName(AllocaInst *alloca, Function *F) {
|
||||||
|
std::string baseName = alloca->getName();
|
||||||
|
if (baseName.empty()) {
|
||||||
|
baseName = "array";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure uniqueness by appending function name and counter
|
||||||
|
static std::unordered_map<std::string, int> nameCounter;
|
||||||
|
std::string key = F->getName() + "." + baseName;
|
||||||
|
|
||||||
|
int counter = nameCounter[key]++;
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << key << "." << counter;
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Reg2Mem.h"
|
#include "Reg2Mem.h"
|
||||||
#include "SCCP.h"
|
#include "SCCP.h"
|
||||||
#include "BuildCFG.h"
|
#include "BuildCFG.h"
|
||||||
|
#include "LargeArrayToGlobal.h"
|
||||||
#include "Pass.h"
|
#include "Pass.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
@@ -41,6 +42,7 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
|||||||
|
|
||||||
// 注册优化遍
|
// 注册优化遍
|
||||||
registerOptimizationPass<BuildCFG>();
|
registerOptimizationPass<BuildCFG>();
|
||||||
|
registerOptimizationPass<LargeArrayToGlobalPass>();
|
||||||
|
|
||||||
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
||||||
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
||||||
@@ -68,6 +70,7 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
|||||||
|
|
||||||
this->clearPasses();
|
this->clearPasses();
|
||||||
this->addPass(&BuildCFG::ID);
|
this->addPass(&BuildCFG::ID);
|
||||||
|
this->addPass(&LargeArrayToGlobalPass::ID);
|
||||||
this->run();
|
this->run();
|
||||||
|
|
||||||
this->clearPasses();
|
this->clearPasses();
|
||||||
|
|||||||
Reference in New Issue
Block a user