[midend]修改constdecl的逻辑区分局部常量和全局常量声明逻辑,提供方法访问全局变量,常量的维度信息,修改GlobalValue,ConstantVariable的继承父类(User->Value)维度信息保存在Type中。

This commit is contained in:
rain2133
2025-07-30 14:40:10 +08:00
parent 507096a0f6
commit 98511efd91
3 changed files with 153 additions and 30 deletions

View File

@@ -132,8 +132,8 @@ std::any SysYIRGenerator::visitGlobalVarDecl(SysYParser::GlobalVarDeclContext *c
return std::any();
}
std::any SysYIRGenerator::visitConstDecl(SysYParser::ConstDeclContext *ctx){
Type* type = std::any_cast<Type *>(visitBType(ctx->bType()));
std::any SysYIRGenerator::visitConstDecl(SysYParser::ConstDeclContext *ctx) {
Type *type = std::any_cast<Type *>(visitBType(ctx->bType()));
for (const auto constDef : ctx->constDef()) {
std::vector<Value *> dims = {};
std::string name = constDef->Ident()->getText();
@@ -144,19 +144,112 @@ std::any SysYIRGenerator::visitConstDecl(SysYParser::ConstDeclContext *ctx){
}
}
ArrayValueTree* root = std::any_cast<ArrayValueTree *>(constDef->constInitVal()->accept(this));
Type *variableType = type;
if (!dims.empty()) {
variableType = buildArrayType(type, dims); // 构建完整的 ArrayType
}
// 显式地为局部常量在栈上分配空间
// alloca 的类型将是指针指向常量类型,例如 `int*` 或 `int[2][3]*`
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(variableType), {}, name);
ArrayValueTree *root = std::any_cast<ArrayValueTree *>(constDef->constInitVal()->accept(this));
ValueCounter values;
Utils::tree2Array(type, root, dims, dims.size(), values, &builder);
delete root;
// 创建局部常量,并更新符号表
Type* variableType = type;
if (!dims.empty()) {
variableType = buildArrayType(type, dims); // 构建完整的 ArrayType
// 根据维度信息进行 store 初始化
if (dims.empty()) { // 标量常量初始化
// 局部常量必须有初始值,且通常是单个值
if (!values.getValues().empty()) {
builder.createStoreInst(values.getValue(0), alloca);
} else {
// 错误处理:局部标量常量缺少初始化值
// 或者可以考虑默认初始化为0但这通常不符合常量的语义
assert(false && "Local scalar constant must have an initialization value!");
return std::any(); // 直接返回,避免继续执行
}
} else { // 数组常量初始化
const std::vector<sysy::Value *> &counterValues = values.getValues();
const std::vector<unsigned> &counterNumbers = values.getNumbers();
int numElements = 1;
std::vector<int> dimSizes;
for (Value *dimVal : dims) {
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal)) {
int dimSize = constInt->getInt();
numElements *= dimSize;
dimSizes.push_back(dimSize);
}
// TODO else 错误处理:数组维度必须是常量(对于静态分配)
else {
assert(false && "Array dimension must be a constant integer!");
return std::any(); // 直接返回,避免继续执行
}
}
unsigned int elementSizeInBytes = type->getSize();
unsigned int totalSizeInBytes = numElements * elementSizeInBytes;
// 检查是否所有初始化值都是零
bool allValuesAreZero = false;
if (counterValues.empty()) { // 如果没有提供初始化值,通常视为全零初始化
allValuesAreZero = true;
} else {
allValuesAreZero = true;
for (Value *val : counterValues) {
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(val)) {
if (constInt->getInt() != 0) {
allValuesAreZero = false;
break;
}
} else { // 如果不是常量整数,则不能确定是零
allValuesAreZero = false;
break;
}
}
}
if (allValuesAreZero) {
builder.createMemsetInst(alloca, ConstantInteger::get(0), ConstantInteger::get(totalSizeInBytes),
ConstantInteger::get(0));
} else {
int linearIndexOffset = 0; // 用于追踪当前处理的线性索引的偏移量
for (int k = 0; k < counterValues.size(); ++k) {
// 当前 Value 的值和重复次数
Value *currentValue = counterValues[k];
unsigned currentRepeatNum = counterNumbers[k];
for (unsigned i = 0; i < currentRepeatNum; ++i) {
std::vector<Value *> currentIndices;
int tempLinearIndex = linearIndexOffset + i; // 使用偏移量和当前重复次数内的索引
// 将线性索引转换为多维索引
for (int dimIdx = dimSizes.size() - 1; dimIdx >= 0; --dimIdx) {
currentIndices.insert(currentIndices.begin(),
ConstantInteger::get(static_cast<int>(tempLinearIndex % dimSizes[dimIdx])));
tempLinearIndex /= dimSizes[dimIdx];
}
// 对于局部数组alloca 本身就是 GEP 的基指针。
// GEP 的第一个索引必须是 0用于“步过”整个数组。
std::vector<Value *> gepIndicesForInit;
gepIndicesForInit.push_back(ConstantInteger::get(0));
gepIndicesForInit.insert(gepIndicesForInit.end(), currentIndices.begin(), currentIndices.end());
// 计算元素的地址
Value *elementAddress = getGEPAddressInst(alloca, gepIndicesForInit);
// 生成 store 指令
builder.createStoreInst(currentValue, elementAddress);
}
// 更新线性索引偏移量,以便下一次迭代从正确的位置开始
linearIndexOffset += currentRepeatNum;
}
}
}
module->createConstVar(name, Type::getPointerType(variableType), values, dims);
// 更新符号表,将常量名称与 AllocaInst 关联起来
module->addVariable(name, alloca);
}
return 0;
return std::any();
}
std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {