Merge branch 'midend' of gitee.com:lixuanwang/mysysy into midend
This commit is contained in:
13
src/IR.cpp
13
src/IR.cpp
@ -105,8 +105,17 @@ FunctionType*FunctionType::get(Type *returnType, const std::vector<Type *> ¶
|
||||
}
|
||||
|
||||
ArrayType *ArrayType::get(Type *elementType, unsigned numElements) {
|
||||
// TODO:可以考虑在这里添加缓存,避免重复创建相同的数组类型
|
||||
return new ArrayType(elementType, numElements);
|
||||
static std::set<std::unique_ptr<ArrayType>> arrayTypes;
|
||||
auto iter = std::find_if(arrayTypes.begin(), arrayTypes.end(), [&](const std::unique_ptr<ArrayType> &type) -> bool {
|
||||
return elementType == type->getElementType() && numElements == type->getNumElements();
|
||||
});
|
||||
if (iter != arrayTypes.end()) {
|
||||
return iter->get();
|
||||
}
|
||||
auto type = new ArrayType(elementType, numElements);
|
||||
assert(type);
|
||||
auto result = arrayTypes.emplace(type);
|
||||
return result.first->get();
|
||||
}
|
||||
|
||||
void Value::replaceAllUsesWith(Value *value) {
|
||||
|
||||
@ -40,19 +40,21 @@ Type* SysYIRGenerator::buildArrayType(Type* baseType, const std::vector<Value*>&
|
||||
return currentType;
|
||||
}
|
||||
|
||||
// @brief: 获取 GEP 指令的地址
|
||||
// @param basePointer: GEP 的基指针,已经过适当的加载/处理,类型为 LLVM IR 中的指针类型。
|
||||
// 例如,对于局部数组,它是 AllocaInst;对于参数数组,它是 LoadInst 的结果。
|
||||
// @param indices: 已经包含了所有必要的偏移索引 (包括可能的初始 0 索引,由 visitLValue 准备)。
|
||||
// @return: 计算得到的地址值 (也是一个指针类型)
|
||||
Value* SysYIRGenerator::getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices) {
|
||||
// 检查 basePointer 是否为指针类型
|
||||
assert(basePointer->getType()->isPointer());
|
||||
assert(basePointer->getType()->isPointer() && "Base pointer must be a pointer type!");
|
||||
|
||||
// GEP 的第一个索引通常是0,用于“步过”指针本身,访问其指向的对象。
|
||||
// 例如,对于全局数组 @arr,其类型为 [6 x i32]*,第一个0索引是必需的步过偏移。
|
||||
std::vector<Value*> actualGEPIndices;
|
||||
actualGEPIndices.push_back(ConstantInteger::get(0));
|
||||
actualGEPIndices.insert(actualGEPIndices.end(), indices.begin(), indices.end());
|
||||
|
||||
// 直接调用 builder 的方法,无需再关心类型推断的细节
|
||||
return builder.createGetElementPtrInst(basePointer, actualGEPIndices);
|
||||
// `indices` 向量现在由调用方(如 visitLValue, visitVarDecl, visitAssignStmt)负责完整准备,
|
||||
// 包括是否需要添加初始的 `0` 索引。
|
||||
// 所以这里直接将其传递给 `builder.createGetElementPtrInst`。
|
||||
return builder.createGetElementPtrInst(basePointer, indices);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: visit compUnit
|
||||
* @details:
|
||||
@ -168,7 +170,7 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
|
||||
// 对于数组,alloca 的类型将是指针指向数组类型,例如 `int[2][3]*`
|
||||
// 对于标量,alloca 的类型将是指针指向标量类型,例如 `int*`
|
||||
AllocaInst* alloca =
|
||||
builder.createAllocaInst(Type::getPointerType(variableType), dims, name);
|
||||
builder.createAllocaInst(Type::getPointerType(variableType), {}, name);
|
||||
|
||||
if (varDef->initVal() != nullptr) {
|
||||
ValueCounter values;
|
||||
@ -239,9 +241,15 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
|
||||
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, currentIndices);
|
||||
Value* elementAddress = getGEPAddressInst(alloca, gepIndicesForInit);
|
||||
// 生成 store 指令
|
||||
builder.createStoreInst(currentValue, elementAddress);
|
||||
}
|
||||
@ -328,34 +336,72 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
|
||||
|
||||
auto name = ctx->Ident()->getText();
|
||||
std::vector<Type *> paramTypes;
|
||||
std::vector<Type *> paramActualTypes;
|
||||
std::vector<std::string> paramNames;
|
||||
std::vector<std::vector<Value *>> paramDims;
|
||||
|
||||
if (ctx->funcFParams() != nullptr) {
|
||||
auto params = ctx->funcFParams()->funcFParam();
|
||||
for (const auto ¶m : params) {
|
||||
paramTypes.push_back(std::any_cast<Type *>(visitBType(param->bType())));
|
||||
paramNames.push_back(param->Ident()->getText());
|
||||
std::vector<Value *> dims = {};
|
||||
if (!param->LBRACK().empty()) {
|
||||
dims.push_back(ConstantInteger::get(-1)); // 第一个维度不确定
|
||||
Type* baseBType = std::any_cast<Type *>(visitBType(param->bType()));
|
||||
std::string paramName = param->Ident()->getText();
|
||||
|
||||
// 用于收集当前参数的维度信息(如果它是数组)
|
||||
std::vector<Value *> currentParamDims;
|
||||
if (!param->LBRACK().empty()) { // 如果参数声明中有方括号,说明是数组
|
||||
// SysY 数组参数的第一个维度可以是未知的(例如 int arr[] 或 int arr[][10])
|
||||
// 这里的 ConstantInteger::get(-1) 表示未知维度,但对于 LLVM 类型构建,我们主要关注已知维度
|
||||
currentParamDims.push_back(ConstantInteger::get(-1)); // 标记第一个维度为未知
|
||||
for (const auto &exp : param->exp()) {
|
||||
dims.push_back(std::any_cast<Value *>(visitExp(exp)));
|
||||
// 访问表达式以获取维度大小,这些维度必须是常量
|
||||
Value* dimVal = std::any_cast<Value *>(visitExp(exp));
|
||||
// 确保维度是常量整数,否则 buildArrayType 会断言失败
|
||||
assert(dynamic_cast<ConstantInteger*>(dimVal) && "Array dimension in parameter must be a constant integer!");
|
||||
currentParamDims.push_back(dimVal);
|
||||
}
|
||||
}
|
||||
paramDims.emplace_back(dims);
|
||||
|
||||
// 根据解析出的信息,确定参数在 LLVM IR 中的实际类型
|
||||
Type* actualParamType;
|
||||
if (currentParamDims.empty()) { // 情况1:标量参数 (e.g., int x)
|
||||
actualParamType = baseBType; // 实际类型就是基本类型
|
||||
} else { // 情况2&3:数组参数 (e.g., int arr[] 或 int arr[][10])
|
||||
// 数组参数在函数传递时会退化为指针。
|
||||
// 这个指针指向的类型是除第一维外,由后续维度构成的数组类型。
|
||||
|
||||
// 从 currentParamDims 中移除第一个标记未知维度的 -1
|
||||
std::vector<Value*> fixedDimsForTypeBuilding;
|
||||
if (currentParamDims.size() > 1) { // 如果有固定维度 (e.g., int arr[][10])
|
||||
// 复制除第一个 -1 之外的所有维度
|
||||
fixedDimsForTypeBuilding.assign(currentParamDims.begin() + 1, currentParamDims.end());
|
||||
}
|
||||
|
||||
Type* pointedToArrayType = baseBType; // 从基本类型开始构建
|
||||
// 从最内层维度向外层构建数组类型
|
||||
// buildArrayType 期望 dims 是从最外层到最内层,但它内部反向迭代,所以这里直接传入
|
||||
// 例如,对于 int arr[][10],fixedDimsForTypeBuilding 包含 [10],构建出 [10 x i32]
|
||||
if (!fixedDimsForTypeBuilding.empty()) {
|
||||
pointedToArrayType = buildArrayType(baseBType, fixedDimsForTypeBuilding);
|
||||
}
|
||||
|
||||
// 实际参数类型是指向这个构建好的数组类型的指针
|
||||
actualParamType = Type::getPointerType(pointedToArrayType); // e.g., i32* 或 [10 x i32]*
|
||||
}
|
||||
|
||||
paramActualTypes.push_back(actualParamType); // 存储参数的实际 LLVM IR 类型
|
||||
paramNames.push_back(paramName); // 存储参数名称
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Type* returnType = std::any_cast<Type *>(visitFuncType(ctx->funcType()));
|
||||
Type* funcType = Type::getFunctionType(returnType, paramTypes);
|
||||
Type* funcType = Type::getFunctionType(returnType, paramActualTypes);
|
||||
Function* function = module->createFunction(name, funcType);
|
||||
BasicBlock* entry = function->getEntryBlock();
|
||||
builder.setPosition(entry, entry->end());
|
||||
|
||||
for (int i = 0; i < paramTypes.size(); ++i) {
|
||||
AllocaInst* alloca = builder.createAllocaInst(Type::getPointerType(paramTypes[i]),
|
||||
paramDims[i], paramNames[i]);
|
||||
for (int i = 0; i < paramActualTypes.size(); ++i) {
|
||||
AllocaInst* alloca = builder.createAllocaInst(Type::getPointerType(paramActualTypes[i]), {},paramNames[i]);
|
||||
entry->insertArgument(alloca);
|
||||
module->addVariable(paramNames[i], alloca);
|
||||
}
|
||||
@ -641,30 +687,41 @@ std::any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx) {
|
||||
}
|
||||
|
||||
|
||||
// SysYIRGenerator.cpp (修改部分)
|
||||
// 辅助函数:计算给定类型中嵌套的数组维度数量
|
||||
// 例如:
|
||||
// - 对于 i32* 类型,它指向 i32,维度为 0。
|
||||
// - 对于 [10 x i32]* 类型,它指向 [10 x i32],维度为 1。
|
||||
// - 对于 [20 x [10 x i32]]* 类型,它指向 [20 x [10 x i32]],维度为 2。
|
||||
unsigned SysYIRGenerator::countArrayDimensions(Type* type) {
|
||||
unsigned dims = 0;
|
||||
Type* currentType = type;
|
||||
|
||||
// 如果是指针类型,先获取它指向的基础类型
|
||||
if (currentType->isPointer()) {
|
||||
currentType = currentType->as<PointerType>()->getBaseType();
|
||||
}
|
||||
|
||||
// 递归地计算数组的维度层数
|
||||
while (currentType && currentType->isArray()) {
|
||||
dims++;
|
||||
currentType = currentType->as<ArrayType>()->getElementType();
|
||||
}
|
||||
return dims;
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
unsigned declaredNumDims = countArrayDimensions(variable->getType());
|
||||
|
||||
// 2. 处理常量变量 (ConstantVariable) 且所有索引都是常量的情况
|
||||
ConstantVariable* constVar = dynamic_cast<ConstantVariable *>(variable);
|
||||
@ -700,20 +757,56 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
|
||||
}
|
||||
} else {
|
||||
// 访问数组元素或子数组(有索引,或变量本身是数组/多维指针)
|
||||
Value* targetAddress = nullptr;
|
||||
|
||||
Value* gepBasePointer = nullptr;
|
||||
std::vector<Value*> gepIndices; // 准备传递给 getGEPAddressInst 的索引列表
|
||||
// GEP 的基指针就是变量本身(它是一个指向内存的指针)
|
||||
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable) || (constVar != nullptr)) {
|
||||
// 允许对 ConstantVariable (如果它代表全局数组常量) 进行 GEP
|
||||
targetAddress = getGEPAddressInst(variable, dims);
|
||||
if (AllocaInst *alloc = dynamic_cast<AllocaInst *>(variable)) {
|
||||
// 情况 A: 局部变量 (AllocaInst)
|
||||
// 获取 AllocaInst 分配的内存的实际类型。
|
||||
// 例如:对于 `int b[10][20];`,`allocatedType` 是 `[10 x [20 x i32]]`。
|
||||
// 对于 `int b[][20]` 的函数参数,其 AllocaInst 存储的是一个指针,
|
||||
// 此时 `allocatedType` 是 `[20 x i32]*`。
|
||||
Type* allocatedType = alloc->getType()->as<PointerType>()->getBaseType();
|
||||
|
||||
if (allocatedType->isPointer()) {
|
||||
// 如果 AllocaInst 分配的是一个指针类型 (例如,用于存储函数参数的指针,如 int b[][20] 中的 b)
|
||||
// 即 `allocatedType` 是一个指向数组指针的指针 (e.g., [20 x i32]**)
|
||||
// 那么 GEP 的基指针是加载这个指针变量的值。
|
||||
gepBasePointer = builder.createLoadInst(alloc); // 加载出实际的指针值 (e.g., [20 x i32]*)
|
||||
// 对于这种参数指针,用户提供的索引直接作用于它。不需要额外的 0。
|
||||
gepIndices = dims;
|
||||
} else {
|
||||
// 如果 AllocaInst 分配的是实际的数组数据 (例如,int b[10][20] 中的 b)
|
||||
// 那么 AllocaInst 本身就是 GEP 的基指针。
|
||||
// 这里的 `alloc` 是指向数组的指针 (e.g., [10 x [20 x i32]]*)
|
||||
gepBasePointer = alloc; // 类型是 [10 x [20 x i32]]*
|
||||
// 对于这种完整的数组分配,GEP 的第一个索引必须是 0,用于“步过”整个数组。
|
||||
gepIndices.push_back(ConstantInteger::get(0));
|
||||
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
||||
}
|
||||
} else if (GlobalValue *glob = dynamic_cast<GlobalValue *>(variable)) {
|
||||
// 情况 B: 全局变量 (GlobalValue)
|
||||
// GlobalValue 总是指向全局数据的指针。
|
||||
gepBasePointer = glob; // 类型是 [61 x [67 x i32]]*
|
||||
// 对于全局数组,GEP 的第一个索引必须是 0,用于“步过”整个数组。
|
||||
gepIndices.push_back(ConstantInteger::get(0));
|
||||
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
||||
} else if (ConstantVariable *constV = dynamic_cast<ConstantVariable *>(variable)) {
|
||||
// 情况 C: 常量变量 (ConstantVariable),如果它代表全局数组常量
|
||||
// 假设 ConstantVariable 可以直接作为 GEP 的基指针。
|
||||
gepBasePointer = constV;
|
||||
// 对于常量数组,也需要 0 索引来“步过”整个数组。
|
||||
// 这里可以进一步检查 constV->getType()->as<PointerType>()->getBaseType()->isArray()
|
||||
// 但为了简洁,假设所有 ConstantVariable 作为 GEP 基指针时都需要此 0。
|
||||
gepIndices.push_back(ConstantInteger::get(0));
|
||||
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
|
||||
} else {
|
||||
// 其他情况(例如尝试对非指针类型或不支持的 LValue 进行 GEP)应报错
|
||||
assert(false && "LValue variable type not supported for GEP or dynamic load.");
|
||||
return static_cast<Value*>(nullptr);
|
||||
assert(false && "LValue variable type not supported for GEP base pointer.");
|
||||
return static_cast<Value *>(nullptr);
|
||||
}
|
||||
|
||||
// 现在 targetAddress 持有元素或子数组的地址。
|
||||
// 需要判断是加载值,还是返回子数组的地址。
|
||||
// 现在调用 getGEPAddressInst,传入正确准备的基指针和索引列表
|
||||
Value *targetAddress = getGEPAddressInst(gepBasePointer, gepIndices);
|
||||
|
||||
// 如果提供的索引数量少于声明的维度数量,则表示访问的是子数组,返回其地址
|
||||
if (dims.size() < declaredNumDims) {
|
||||
@ -765,32 +858,63 @@ std::any SysYIRGenerator::visitCall(SysYParser::CallContext *ctx) {
|
||||
|
||||
std::vector<Value *> args = {};
|
||||
if (funcName == "starttime" || funcName == "stoptime") {
|
||||
// 如果是starttime或stoptime函数
|
||||
// TODO: 这里需要处理starttime和stoptime函数的参数
|
||||
// args.emplace_back()
|
||||
args.emplace_back(
|
||||
ConstantInteger::get(static_cast<int>(ctx->getStart()->getLine())));
|
||||
} else {
|
||||
if (ctx->funcRParams() != nullptr) {
|
||||
args = std::any_cast<std::vector<Value *>>(visitFuncRParams(ctx->funcRParams()));
|
||||
}
|
||||
|
||||
auto params = function->getEntryBlock()->getArguments();
|
||||
// 获取形参列表。`getArguments()` 返回的是 `Argument*` 的集合,
|
||||
// 每个 `Argument` 代表一个函数形参,其 `getType()` 就是指向形参的类型的指针类型。
|
||||
auto formalParamsAlloca = function->getEntryBlock()->getArguments();
|
||||
|
||||
// 检查实参和形参数量是否匹配。
|
||||
if (args.size() != formalParamsAlloca.size()) {
|
||||
std::cerr << "Error: Function call argument count mismatch for function '" << funcName << "'." << std::endl;
|
||||
assert(false && "Function call argument count mismatch!");
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
// 参数类型转换
|
||||
if (params[i]->getType() != args[i]->getType() &&
|
||||
(params[i]->getNumDims() != 0 ||
|
||||
params[i]->getType()->as<PointerType>()->getBaseType() != args[i]->getType())) {
|
||||
ConstantValue * constValue = dynamic_cast<ConstantValue *>(args[i]);
|
||||
// 形参的类型 (e.g., i32, float, i32*, [10 x i32]*)
|
||||
Type* formalParamExpectedValueType = formalParamsAlloca[i]->getType()->as<PointerType>()->getBaseType();
|
||||
// 实参的实际类型 (e.g., i32, float, i32*, [67 x i32]*)
|
||||
Type* actualArgType = args[i]->getType();
|
||||
// 如果实参类型与形参类型不匹配,则尝试进行类型转换
|
||||
if (formalParamExpectedValueType != actualArgType) {
|
||||
ConstantValue *constValue = dynamic_cast<ConstantValue *>(args[i]);
|
||||
if (constValue != nullptr) {
|
||||
if (params[i]->getType() == Type::getPointerType(Type::getFloatType())) {
|
||||
args[i] = ConstantInteger::get(static_cast<float>(constValue->getInt()));
|
||||
if (formalParamExpectedValueType->isInt() && actualArgType->isFloat()) {
|
||||
args[i] = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
|
||||
} else if (formalParamExpectedValueType->isFloat() && actualArgType->isInt()) {
|
||||
args[i] = ConstantFloating::get(static_cast<float>(constValue->getInt()));
|
||||
} else {
|
||||
args[i] = ConstantFloating::get(static_cast<int>(constValue->getFloat()));
|
||||
// 如果是常量但不是简单的 int/float 标量转换,
|
||||
// 或者是指针常量需要 bitcast,则让它进入非常量转换逻辑。
|
||||
// 例如,一个常量数组的地址,需要 bitcast 成另一种指针类型。
|
||||
// 目前不知道样例有没有这种情况,所以这里不做处理。
|
||||
}
|
||||
} else {
|
||||
if (params[i]->getType() == Type::getPointerType(Type::getFloatType())) {
|
||||
args[i] = builder.createIToFInst(args[i]);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// 1. 标量值类型转换 (例如:int_reg 到 float_reg,float_reg 到 int_reg)
|
||||
if (formalParamExpectedValueType->isInt() && actualArgType->isFloat()) {
|
||||
args[i] = builder.createFtoIInst(args[i]);
|
||||
} else if (formalParamExpectedValueType->isFloat() && actualArgType->isInt()) {
|
||||
args[i] = builder.createIToFInst(args[i]);
|
||||
}
|
||||
// 2. 指针类型转换 (例如数组退化:`[N x T]*` 到 `T*`,或兼容指针类型之间) TODO:不清楚有没有这种样例
|
||||
// 这种情况常见于数组参数,实参可能是一个更具体的数组指针类型,
|
||||
// 而形参是其退化后的基础指针类型。LLVM 的 `bitcast` 指令可以用于
|
||||
// 在相同大小的指针类型之间进行转换,这对于数组退化至关重要。
|
||||
// else if (formalParamType->isPointer() && actualArgType->isPointer()) {
|
||||
// 检查指针基类型是否兼容,或者是否是数组退化导致的类型不同。
|
||||
// 使用 bitcast,
|
||||
// args[i] = builder.createBitCastInst(args[i], formalParamType);
|
||||
// }
|
||||
// 3. 其他未预期的类型不匹配
|
||||
// 如果代码执行到这里,说明存在编译器前端未处理的类型不兼容或错误。
|
||||
else {
|
||||
// assert(false && "Unhandled type mismatch for function call argument.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1264,7 +1388,7 @@ void Utils::createExternalFunction(
|
||||
|
||||
for (int i = 0; i < paramTypes.size(); ++i) {
|
||||
auto alloca = pBuilder->createAllocaInst(
|
||||
Type::getPointerType(paramTypes[i]), paramDims[i], paramNames[i]);
|
||||
Type::getPointerType(paramTypes[i]), {}, paramNames[i]);
|
||||
entry->insertArgument(alloca);
|
||||
// pModule->addVariable(paramNames[i], alloca);
|
||||
}
|
||||
|
||||
@ -347,22 +347,48 @@ class IRBuilder {
|
||||
|
||||
static Type *getIndexedType(Type *pointerType, const std::vector<Value *> &indices) {
|
||||
assert(pointerType->isPointer() && "base must be a pointer type!");
|
||||
Type *CurrentType = pointerType;
|
||||
// 遍历所有索引来深入类型层次结构Sysy只支持数组
|
||||
// GEP 的类型推断从基指针所指向的类型开始。
|
||||
// 例如:
|
||||
// - 如果 pointerType 是 `[20 x [10 x i32]]*`,`currentWalkType` 初始为 `[20 x [10 x i32]]`。
|
||||
// - 如果 pointerType 是 `i32*`,`currentWalkType` 初始为 `i32`。
|
||||
// - 如果 pointerType 是 `i32**`,`currentWalkType` 初始为 `i32*`。
|
||||
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
|
||||
|
||||
// 遍历所有索引来深入类型层次结构。
|
||||
// `indices` 向量包含了所有 GEP 索引,包括由 `visitLValue` 等函数添加的初始 `0` 索引。
|
||||
for (int i = 0; i < indices.size(); ++i) {
|
||||
if(i == 0) {
|
||||
// 第一个索引是指针类型的元素类型
|
||||
CurrentType = pointerType->as<PointerType>()->getBaseType();
|
||||
} else
|
||||
if (CurrentType->isArray()) {
|
||||
CurrentType = CurrentType->as<ArrayType>()->getElementType();
|
||||
}
|
||||
else {
|
||||
// 如果类型不是聚合类型但仍有索引,说明索引过多,这是错误的
|
||||
CurrentType = nullptr;
|
||||
}
|
||||
if (currentWalkType->isArray()) {
|
||||
// 情况一:当前遍历类型是 `ArrayType`。
|
||||
// 索引用于选择数组元素,`currentWalkType` 更新为数组的元素类型。
|
||||
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
|
||||
} else if (currentWalkType->isPointer()) {
|
||||
// 情况二:当前遍历类型是 `PointerType`。
|
||||
// 这意味着我们正在通过一个指针来访问其指向的内存。
|
||||
// 索引用于选择该指针所指向的“数组”的元素。
|
||||
// `currentWalkType` 更新为该指针所指向的基础类型。
|
||||
// 例如:如果 `currentWalkType` 是 `i32*`,它将变为 `i32`。
|
||||
// 如果 `currentWalkType` 是 `[10 x i32]*`,它将变为 `[10 x i32]`。
|
||||
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
|
||||
} else {
|
||||
// 情况三:当前遍历类型是标量类型 (例如 `i32`, `float` 等非聚合、非指针类型)。
|
||||
//
|
||||
// 如果 `currentWalkType` 是标量,并且当前索引 `i` **不是** `indices` 向量中的最后一个索引,
|
||||
// 这意味着尝试对一个标量类型进行进一步的结构性索引,这是**无效的**。
|
||||
// 例如:`int x; x[0];` 对应的 GEP 链中,`x` 的类型是 `i32`,再加 `[0]` 索引就是错误。
|
||||
//
|
||||
// 如果 `currentWalkType` 是标量,且这是**最后一个索引** (`i == indices.size() - 1`),
|
||||
// 那么 GEP 是合法的,它只是计算一个偏移地址,最终的类型就是这个标量类型。
|
||||
// 此时 `currentWalkType` 保持不变,循环结束。
|
||||
if (i < indices.size() - 1) {
|
||||
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
|
||||
return nullptr; // 返回空指针表示类型推断失败
|
||||
}
|
||||
// 如果是最后一个索引,且当前类型是标量,则类型保持不变,这是合法的。
|
||||
// 循环会自然结束,返回正确的 `currentWalkType`。
|
||||
}
|
||||
}
|
||||
return CurrentType;
|
||||
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
|
||||
return currentWalkType;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -139,6 +139,8 @@ public:
|
||||
// 构建数组类型
|
||||
Type* buildArrayType(Type* baseType, const std::vector<Value*>& dims);
|
||||
|
||||
unsigned countArrayDimensions(Type* type);
|
||||
|
||||
}; // class SysYIRGenerator
|
||||
|
||||
} // namespace sysy
|
||||
Reference in New Issue
Block a user