编写LLVM Pass时如何从.ll文件获取零初始化GlobalVariable二维数组的维度
问题根因
- 多维数组的维度信息完全存储在LLVM的
ArrayType类型对象中,和初始化常量的具体值没有关系。尤其是zeroinitializer是表示全零值的共享单例标记,不持有数组结构的实体内容,不可能从常量实例的元素中拆解出嵌套维度;就算是从普通的聚合初始化常量上解析,拿到常量对应的类型后,仍然需要沿着类型链拆解嵌套结构,没有捷径。 - 现有代码存在几处逻辑错误:
- 变量名拼写不一致:定义的常量数组指针名为
constArrayd,后续取值时误写为constArraydd - 逻辑错位:
int firstdim = datafile << ...错误地将文件输出流的引用赋值给整数变量,根本无法拿到数组元素个数 - 没有沿着数组类型的嵌套结构逐层拆解:仅获取了最外层数组的元素总数,没有提取外层数组的元素类型、判断其是否为嵌套数组
- 变量名拼写不一致:定义的常量数组指针名为
修复方案
不需要对初始化常量做ConstantArray的类型转换,直接从全局变量的类型定义层逐层解析即可,具体实现逻辑:
- 通过
GlobalVariable::getValueType()拿到全局变量对应值的实际类型(会自动跳过GlobalVariable自身的指针类型) - 判断该类型是否为
ArrayType,每一层ArrayType的getNumElements()就是对应维度的大小 - 提取当前数组类型的元素类型,重复判断是否为嵌套
ArrayType,直到拆解到非数组的基础类型为止
示例代码
virtual bool runOnModule(Module &M) { // 遍历所有全局变量,使用范围for循环简化迭代逻辑 for (GlobalVariable &gv : M.globals()) { // 跳过非数组类型的全局变量 Type *valTy = gv.getValueType(); ArrayType *outerArrTy = dyn_cast<ArrayType>(valTy); if (!outerArrTy) continue; int firstdim = outerArrTy->getNumElements(); int seconddim = -1; // 提取外层数组的元素类型,判断是否为嵌套二维数组 Type *innerElemTy = outerArrTy->getElementType(); ArrayType *innerArrTy = dyn_cast<ArrayType>(innerElemTy); if (innerArrTy) { seconddim = innerArrTy->getNumElements(); } // 将获取到的维度写入输出文件(替换原有的错误流赋值逻辑) // datafile << "First dim: " << firstdim << ", Second dim: " << seconddim << "\n"; } return false; }
通用多维度支持
如果需要兼容任意维度的多维数组,可以写循环拆解逻辑,自动提取所有层级的维度值:
// 递归拆解数组类型,将每一层的维度值存入dims列表 void extractArrayDims(Type *arrRootTy, SmallVectorImpl<int> &dims) { Type *curTy = arrRootTy; while (ArrayType *curArrTy = dyn_cast<ArrayType>(curTy)) { dims.push_back(curArrTy->getNumElements()); curTy = curArrTy->getElementType(); } }
调用该函数传入全局变量的getValueType(),得到的dims列表就是从高维到低维的所有维度值——针对你给出的示例[5 x [10 x i32]],最终会得到维度列表[5, 10],完全符合需求。
注意事项
- 该方法不受全局变量初始化形式的影响:不管是
zeroinitializer初始化、还是填充了具体元素值的聚合初始化,都可以正确提取维度。 - 无需对
zeroinitializer做特殊判断,避免因为单例常量不持有元素结构导致的解析错误。
内容的提问来源于stack exchange,提问作者mohmsslk
相关产品推荐
相关产品推荐

