You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

LLVM类型合法化Pass实现:如何修改<6 x i3>加法指令的值与类型

实现LLVM向量类型拓宽的合法化Pass

针对你要做的<6 x i3><8 x i3>的类型拓宽需求,下面一步步拆解怎么在LLVM Pass里修改Value、替换指令:

核心思路:LLVM中修改Value的本质

LLVM的IR指令是不可变对象,没法直接修改现有指令的操作数或类型。正确的做法是:

  • 创建符合新类型要求的新指令/Value
  • 将原指令的所有使用点替换为新的Value
  • 标记原指令待删除(避免迭代时出错)

具体实现步骤(结合你的代码片段)

1. 识别目标Binary指令

首先要过滤出你需要处理的add指令,且操作数类型是<6 x i3>

for (auto &block : function) { 
    std::vector<BinaryOperator *> binInstsToErase; 
    for (auto &inst : block) { 
        BinaryOperator *binaryOpInst = dyn_cast<BinaryOperator>(&inst); 
        if (!binaryOpInst || binaryOpInst->getOpcode() != Instruction::Add) {
            continue; // 只处理add指令
        }

        // 检查操作数类型是否是<6 x i3>
        VectorType *origVecTy = dyn_cast<VectorType>(binaryOpInst->getType());
        if (!origVecTy || origVecTy->getNumElements() != 6 || 
            origVecTy->getElementType()->getBitWidth() != 3) {
            continue;
        }

        Value *vector1 = binaryOpInst->getOperand(0);
        Value *vector2 = binaryOpInst->getOperand(1);
        // 接下来处理类型拓宽
        // ...
    }
    // 批量删除标记的原指令(放在block遍历末尾)
    for (auto *inst : binInstsToErase) {
        inst->eraseFromParent();
    }
}

2. 创建目标拓宽类型<8 x i3>

用LLVM的VectorType工具类生成目标类型:

LLVMContext &ctx = function.getContext();
Type *elemTy = Type::getInt3Ty(ctx);
VectorType *targetVecTy = VectorType::get(elemTy, 8);

3. 生成向量拓宽的指令

要把<6 x i3>的向量扩展为<8 x i3>,我们可以通过插入两个i3类型的0元素来实现,这里提供两种方式:

方法1:循环插入0元素(直观易懂)

// 准备填充用的0常量
Constant *zero = ConstantInt::get(elemTy, 0);

// 拓宽vector1
Value *widenedVec1 = vector1;
for (unsigned i = 6; i < 8; ++i) {
    widenedVec1 = InsertElementInst::Create(widenedVec1, zero, 
                                            ConstantInt::get(Type::getInt32Ty(ctx), i),
                                            "widened.vec1", &inst);
}

// 同理拓宽vector2
Value *widenedVec2 = vector2;
for (unsigned i = 6; i < 8; ++i) {
    widenedVec2 = InsertElementInst::Create(widenedVec2, zero, 
                                            ConstantInt::get(Type::getInt32Ty(ctx), i),
                                            "widened.vec2", &inst);
}

方法2:用ShuffleVector一次性完成(更简洁高效)

// 创建一个mask:原6个元素留前6位,后两位用0填充
SmallVector<int, 8> mask;
for (int i = 0; i < 6; ++i) mask.push_back(i);
mask.push_back(-1); // -1表示取第二个操作数的对应位置(这里是全0向量)
mask.push_back(-1);

Constant *zeroVec = ConstantVector::getSplat(8, ConstantInt::get(elemTy, 0));
Value *widenedVec1 = ShuffleVectorInst::Create(vector1, zeroVec, 
                                               ConstantInt::getVector(Type::getInt32Ty(ctx), mask),
                                               "widened.vec1", &inst);
Value *widenedVec2 = ShuffleVectorInst::Create(vector2, zeroVec, 
                                               ConstantInt::getVector(Type::getInt32Ty(ctx), mask),
                                               "widened.vec2", &inst);

4. 创建新的add指令并替换原指令

用拓宽后的向量创建新的add指令,然后替换原指令的所有使用:

// 创建新的add指令,插入到原指令之前
BinaryOperator *newAddInst = BinaryOperator::CreateAdd(widenedVec1, widenedVec2, 
                                                       "widened.add", binaryOpInst);

// 替换原指令的所有使用点
binaryOpInst->replaceAllUsesWith(newAddInst);

// 标记原指令待删除
binInstsToErase.push_back(binaryOpInst);

关键注意事项

  • 绝对不要在遍历指令的过程中直接删除指令,一定要先收集到待删除列表,遍历结束后再统一删除,否则会破坏迭代器的有效性。
  • 如果后续还有其他处理逻辑(比如对拓宽后的向量做额外操作),可以在创建newAddInst之后继续添加。
  • 所有类型和常量都要基于同一个LLVMContext创建,避免出现上下文不匹配的错误。

内容的提问来源于stack exchange,提问作者matcha latte

火山引擎 最新活动