@@ -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 & param : 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 , paramActual Types ) ;
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 < paramActual Types . size ( ) ; + + i ) {
AllocaInst * alloca = builder . createAllocaInst ( Type : : getPointerType ( paramActual Types [ 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,54 @@ 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)
// 那么 GEP 的基指针是加载这个指针变量的值。
gepBasePointer = builder . createLoadInst ( alloc ) ; // 加载出实际的指针值 (e.g., [20 x i32]*)
// 对于这种参数指针,用户提供的索引直接作用于它。不需要额外的 0。
gepIndices = dims ;
} else {
// 如果 AllocaInst 分配的是实际的数组数据 (例如, int b[10][20] 中的 b)
// 那么 AllocaInst 本身就是 GEP 的基指针。
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 ( f als e & & " 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 < V alu e * > ( nullptr ) ;
}
// 现在 targetAddress 持有元素或子数组的地址。
// 需要判断是加载值,还是返回子数组的地址。
// 现在调用 getGEPAddressInst, 传入正确准备的基指针和索引列表
Value * targetAddress = getGEPAddressInst ( gepBasePointer , gepIndices ) ;
// 如果提供的索引数量少于声明的维度数量,则表示访问的是子数组,返回其地址
if ( dims . size ( ) < declaredNumDims ) {
@@ -1264,7 +1355,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);
}