如何在LLVM中将RVV 1.0的vsetivli替换为RVV 0.7的vsetvli?
解决RVV 1.0指令在RVV 0.7硬件上的兼容问题:替换
vsetivli为vsetvli 针对你用LLVM从Halide生成的RVV1.0二进制无法在仅支持RVV0.7的全志D1 C906运行的问题,以下是LLVM源码层面替换vsetivli为RVV0.7vsetvli的具体操作步骤:
1. 理解指令差异
RVV1.0新增了立即数版本的向量长度设置指令vsetivli,而RVV0.7仅支持寄存器版本的vsetvli。例如你给出的指令vsetivli zero,4,e32,m1,ta,ma,需要转成**先将立即数4加载到寄存器,再调用vsetvli**的形式。
2. 定位LLVM RISCV后端核心文件
所有修改都集中在LLVM的RISCV后端目录llvm/lib/Target/RISCV/,关键文件包括:
RISCVInstrInfoV.td:RVV指令定义表RISCVISelLowering.cpp:指令选择与节点转换逻辑RISCVSubtarget.h/cpp:RVV版本判定相关代码
3. 限制vsetivli仅在RVV1.0+启用
编辑RISCVInstrInfoV.td,给vsetivli指令添加版本判定条件,确保RVV0.7目标不会生成该指令:
// 找到VSETIVLI的定义,添加IsRVV1_0谓词 let Predicates = [HasVInstructions, IsRVV1_0] in def VSETIVLI : RVVInst<0b101, 0b111, (outs GPR:$rd), (ins uimm5:$vl, VTypeImm:$vtype), "vsetivli", "$rd, $vl, $vtype", []>;
4. 实现vsetivli到vsetvli的转换逻辑
编辑RISCVISelLowering.cpp,找到LowerOperation函数中处理RISCVISD::VSETIVLI的分支,添加RVV0.7下的转换逻辑:
case RISCVISD::VSETIVLI: { SDLoc DL(N); // 检查目标RVV版本是否低于1.0 if (Subtarget->getRVVVersion() < RISCV::RVVVersion::RVV1_0) { // 将立即数vl转换为寄存器加载 uint64_t VLVal = N->getConstantOperandVal(0); SDValue VLConst = DAG.getTargetConstant(VLVal, DL, MVT::i32); SDValue VLReg = DAG.getNode(RISCVISD::LI, DL, MVT::GPR, VLConst); // 生成VSETVLI节点替代原VSETIVLI return DAG.getNode(RISCVISD::VSETVLI, DL, N->getValueType(0), N->getOperand(0), // rd(通常是zero) VLReg, // rs1(存储vl的寄存器) N->getOperand(2));// vtype参数 } // 保留原RVV1.0的处理逻辑 return SDValue(); }
5. 编译验证修改后的LLVM
- 编译修改后的LLVM项目,生成新的
clang和llc工具 - 用新工具编译Halide代码,指定RVV0.7目标架构:
clang -march=rv64gcv0.7.1 -O3 your_halide_code.cpp -o output - 用
objdump检查生成的二进制,确认vsetivli已被替换为:li x1, 4 vsetvli zero, x1, e32,m1,ta,ma
其他注意事项
- 这只是单个指令的替换,RVV1.0还有其他不兼容的intrinsics(如
vslideup.vx、vslidedown.vx等),需要类似方法逐一处理 - 全志D1的RVV0.7实现可能还有额外限制(如仅支持部分LMUL值),需结合硬件手册调整LLVM的目标参数
内容的提问来源于stack exchange,提问作者Dmitry Kurtaev
相关产品推荐
相关产品推荐

