LLVM IR到RISC-V汇编映射:如何替换ADD与SUB指令行为
实现RISC-V ADD与SUB指令的逻辑互换
为什么不能直接改.td文件?
你说的没错,RISCVInstrInfo.td里的定义只是描述指令的编码、名称和操作数格式,LLVM的指令选择逻辑是把IR层的add/sub映射到对应的目标指令节点,改.td只会换指令名或编码,不会改变逻辑映射关系。要实现C加法变二进制减法,得在IR到机器指令的转换流程里动手。
两种可行的实现方式
方式一:在SelectionDAG Lowering阶段替换操作
直接在RISCVISelLowering.cpp里修改IR节点到目标指令节点的映射:
找到LowerOperation函数,对ISD::ADD和ISD::SUB节点做反向映射:
SDValue RISCVTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { case ISD::ADD: { // 把IR的ADD转换成RISC-V的SUB节点 SDValue lhs = Op.getOperand(0); SDValue rhs = Op.getOperand(1); return DAG.getNode(RISCVISD::SUB, SDLoc(Op), Op.getValueType(), lhs, rhs); } case ISD::SUB: { // 把IR的SUB转换成RISC-V的ADD节点 SDValue lhs = Op.getOperand(0); SDValue rhs = Op.getOperand(1); return DAG.getNode(RISCVISD::ADD, SDLoc(Op), Op.getValueType(), lhs, rhs); } // 其他case保持原样,不要动 default: return SDValue(); } }
这个方法是在指令选择的早期阶段修改,后续的优化和发射都会基于替换后的节点处理。
方式二:在MachineInstr阶段直接替换操作码
如果觉得SelectionDAG的逻辑太绕,可以等机器指令生成后,直接遍历替换操作码,更直观:
- 写一个自定义的MachineFunctionPass:
struct SwapAddSubPass : public MachineFunctionPass { static char ID; SwapAddSubPass() : MachineFunctionPass(ID) {} bool runOnMachineFunction(MachineFunction &MF) override { for (auto &MBB : MF) { for (auto &MI : MBB) { // 直接替换ADD和SUB的操作码 if (MI.getOpcode() == RISCV::ADD) { MI.setOpcode(RISCV::SUB); } else if (MI.getOpcode() == RISCV::SUB) { MI.setOpcode(RISCV::ADD); } } } return true; } }; char SwapAddSubPass::ID = 0; static RegisterPass<SwapAddSubPass> X("swap-add-sub", "Swap ADD/SUB instructions for RISC-V");
- 在
RISCVTargetMachine.cpp里把这个Pass加到后端的Pass序列中,确保在指令发射前执行(比如插在RISCVCodeGenPrepare之后)。
验证步骤
- 重新编译llvm-project,生成修改后的
clang和llc; - 写测试C代码:
int main() { int a = 10, b = 4; int c = a + b; // 实际会执行10-4=6 return c; }
- 用修改后的clang编译:
clang -target riscv64-unknown-linux-gnu test.c -o test; - 反编译看结果:
objdump -d test,main函数里的加法指令应该变成subw(RV64)或sub(RV32)。
注意点
- RISC-V的ADD和SUB都是R型指令,操作数顺序完全一致,所以直接替换操作码不会有问题;
- 如果需要区分有符号/无符号加法,可以在Lowering阶段针对
ISD::SADD/ISD::UADD分别处理; - 虽然CodeGen和SelectionDAG的文档确实难啃,但从这种小修改入手,跟着代码调用链走,慢慢就能摸清楚后端的流程。
内容的提问来源于stack exchange,提问作者Ilyass
相关产品推荐
相关产品推荐

