[IR]重构数组地址相关指令

增加GEP指令以及相关方法
新增数组Array Type
删除无用指令(GetSubArray,LA)
删除冗余类定义(Lval)
修复中间代码生成逻辑
测试通过所以test目录下的文件
TODO:后端展开数组计算地址仅需要针对GEP指令展开
This commit is contained in:
rain2133
2025-07-20 15:33:58 +08:00
parent 18e7cbd413
commit de696b2b53
8 changed files with 455 additions and 467 deletions

View File

@@ -15,6 +15,73 @@
using namespace std;
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
* @details:
@@ -118,24 +185,28 @@ 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 =
builder.createAllocaInst(Type::getPointerType(type), dims, name);
if (varDef->initVal() != nullptr) {
ValueCounter values;
// 这里的varDef->initVal()可能是ScalarInitValue或ArrayInitValue
ArrayValueTree* root = std::any_cast<ArrayValueTree *>(varDef->initVal()->accept(this));
Utils::tree2Array(type, root, dims, dims.size(), values, &builder);
delete root;
if (dims.empty()) {
if (dims.empty()) { // 标量变量初始化
builder.createStoreInst(values.getValue(0), alloca);
} else{
// **数组变量初始化**
} else { // 数组变量初始化
const std::vector<sysy::Value *> &counterValues = values.getValues();
// 计算数组的**总元素数量**和**总字节大小**
int numElements = 1;
// 存储每个维度的实际整数大小,用于索引计算
std::vector<int> dimSizes;
for (Value *dimVal : dims) {
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal)) {
@@ -145,12 +216,11 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
}
// TODO else 错误处理:数组维度必须是常量(对于静态分配)
}
unsigned int elementSizeInBytes = type->getSize(); // 获取单个元素的大小(字节)
unsigned int elementSizeInBytes = type->getSize();
unsigned int totalSizeInBytes = numElements * elementSizeInBytes;
// **判断是否可以进行全零初始化优化**
bool allValuesAreZero = false;
if (counterValues.empty()) { // 例如 int arr[3] = {}; 或 int arr[3][4] = {};
if (counterValues.empty()) {
allValuesAreZero = true;
}
else {
@@ -163,7 +233,6 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
}
}
else{
// 如果值不是常量,我们通常不能确定它是否为零,所以不进行 memset 优化
allValuesAreZero = false;
break;
}
@@ -171,64 +240,51 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
}
if (allValuesAreZero) {
// 如果所有初始化值都是零(或没有明确初始化但语法允许),使用 memset 优化
builder.createMemsetInst(
alloca, // 目标数组的起始地址
ConstantInteger::get(0), // 偏移量通常为0后续删除
alloca,
ConstantInteger::get(0),
ConstantInteger::get(totalSizeInBytes),
ConstantInteger::get(0)); // 填充的总字节数
ConstantInteger::get(0));
}
else {
// **逐元素存储:遍历所有初始值,并为每个值生成一个 store 指令**
for (size_t k = 0; k < counterValues.size(); ++k) {
// 用于存储当前元素的索引列表
std::vector<Value *> currentIndices;
int tempLinearIndex = k; // 临时线性索引,用于计算多维索引
int tempLinearIndex = k;
// **将线性索引转换为多维索引**
// 这个循环从最内层维度开始倒推,计算每个维度的索引
// 假设是行主序row-major order这是 C/C++ 数组的标准存储方式
// 将线性索引转换为多维索引
for (int dimIdx = dimSizes.size() - 1; dimIdx >= 0; --dimIdx)
{
// 计算当前维度的索引,并插入到列表的最前面
currentIndices.insert(currentIndices.begin(),
ConstantInteger::get(static_cast<int>(tempLinearIndex % dimSizes[dimIdx])));
// 更新线性索引,用于计算下一个更高维度的索引
tempLinearIndex /= dimSizes[dimIdx];
}
// **生成 store 指令,传入值、基指针和计算出的索引列表**
// 你的 builder.createStoreInst 签名需要能够接受这些参数
// 假设你的 builder.createStoreInst(Value *val, Value *ptr, const std::vector<Value *> &indices, ...)
builder.createStoreInst(counterValues[k], alloca, currentIndices);
// 计算元素的地址
Value* elementAddress = getGEPAddressInst(alloca, currentIndices);
// 生成 store 指令 (假设 createStoreInst 接受 Value* value, Value* pointer)
builder.createStoreInst(counterValues[k], elementAddress);
}
}
}
}
else
{ // **如果没有显式初始化值,默认对数组进行零初始化**
if (!dims.empty())
{ // 只有数组才需要默认的零初始化
else { // 如果没有显式初始化值,默认对数组进行零初始化
if (!dims.empty()) { // 只有数组才需要默认的零初始化
int numElements = 1;
for (Value *dimVal : dims)
{
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal))
{
for (Value *dimVal : dims) {
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal)) {
numElements *= constInt->getInt();
}
}
unsigned int elementSizeInBytes = type->getSize();
unsigned int totalSizeInBytes = numElements * elementSizeInBytes;
// 使用 memset 将整个数组清零
builder.createMemsetInst(
alloca,
ConstantInteger::get(0),
ConstantInteger::get(totalSizeInBytes),
ConstantInteger::get(0)
); // 填充的总字节数
);
}
// 标量变量如果没有初始化值,通常不生成额外的初始化指令,因为其内存已分配但未赋值。
}
module->addVariable(name, alloca);
@@ -356,29 +412,56 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
for (const auto &exp : lVal->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())); // 右值
auto variable = module->getVariable(name);
Value* value = std::any_cast<Value *>(visitExp(ctx->exp()));
Type* variableType = dynamic_cast<PointerType *>(variable->getType())->getBaseType();
if (variable == nullptr) {
throw std::runtime_error("Variable " + name + " not found in assignment.");
}
// 左值右值类型不同处理
if (variableType != value->getType()) {
// 计算最终赋值目标元素的类型
// variable 本身应该是一个指针类型 (例如 int* 或 int[2][3]*)
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);
if (constValue != nullptr) {
if (variableType == Type::getFloatType()) {
value = ConstantInteger::get(static_cast<float>(constValue->getInt()));
} else {
value = ConstantFloating::get(static_cast<int>(constValue->getFloat()));
if (targetElementType == Type::getFloatType()) {
value = ConstantFloating::get(static_cast<float>(constValue->getInt()));
} else { // 假设如果不是浮点型,就是整型
value = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
}
} else {
if (variableType == Type::getFloatType()) {
if (targetElementType == Type::getFloatType()) {
value = builder.createIToFInst(value);
} else {
} else { // 假设如果不是浮点型,就是整型
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();
}
@@ -576,51 +659,89 @@ std::any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx) {
}
// SysYIRGenerator.cpp (修改部分)
std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
std::string name = ctx->Ident()->getText();
User* variable = module->getVariable(name);
Value* value = nullptr;
if (variable == nullptr) {
throw std::runtime_error("Variable " + name + " not found.");
}
std::vector<Value *> dims;
for (const auto &exp : ctx->exp()) {
dims.push_back(std::any_cast<Value *>(visitExp(exp)));
}
if (variable == nullptr) {
throw std::runtime_error("Variable " + name + " not found.");
}
bool indicesConstant = true;
for (const auto &dim : dims) {
if (dynamic_cast<ConstantValue *>(dim) == nullptr) {
indicesConstant = false;
break;
}
// 1. 获取变量的声明维度数量
unsigned declaredNumDims = 0;
if (AllocaInst* alloc = dynamic_cast<AllocaInst*>(variable)) {
declaredNumDims = alloc->getNumDims();
} else if (GlobalValue* glob = dynamic_cast<GlobalValue*>(variable)) {
declaredNumDims = glob->getNumDims();
} else if (ConstantVariable* constV = dynamic_cast<ConstantVariable*>(variable)) {
declaredNumDims = constV->getNumDims();
}
// 2. 处理常量变量 (ConstantVariable) 且所有索引都是常量的情况
ConstantVariable* constVar = dynamic_cast<ConstantVariable *>(variable);
GlobalValue* globalVar = dynamic_cast<GlobalValue *>(variable);
AllocaInst* localVar = dynamic_cast<AllocaInst *>(variable);
if (constVar != nullptr && indicesConstant) {
// 如果是常量变量,且索引是常量,则直接获取子数组
value = constVar->getByIndices(dims);
} else if (module->isInGlobalArea() && (globalVar != nullptr)) {
assert(indicesConstant);
value = globalVar->getByIndices(dims);
} else {
if ((globalVar != nullptr && globalVar->getNumDims() > dims.size()) ||
(localVar != nullptr && localVar->getNumDims() > dims.size()) ||
(constVar != nullptr && constVar->getNumDims() > dims.size())) {
// value = builder.createLaInst(variable, indices);
// 如果变量是全局变量或局部变量且索引数量小于维度数量则创建createGetSubArray获取子数组
auto getArrayInst =
builder.createGetSubArray(dynamic_cast<LVal *>(variable), dims);
value = getArrayInst->getChildArray();
} else {
value = builder.createLoadInst(variable, dims);
if (constVar != nullptr) {
bool allIndicesConstant = true;
for (const auto &dim : dims) {
if (dynamic_cast<ConstantValue *>(dim) == nullptr) {
allIndicesConstant = false;
break;
}
}
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 {
// 访问数组元素或子数组(有索引,或变量本身是数组/多维指针)
Value* targetAddress = nullptr;
// GEP 的基指针就是变量本身(它是一个指向内存的指针)
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable) || (constVar != nullptr)) {
// 允许对 ConstantVariable (如果它代表全局数组常量) 进行 GEP
targetAddress = getGEPAddressInst(variable, dims);
} else {
// 其他情况(例如尝试对非指针类型或不支持的 LValue 进行 GEP应报错
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;
}