LLVM X86机器函数Pass中用BuildMI插入JNE指令失败求助
问题描述
我正在编写一个LLVM机器函数Pass,需要在每个基本块的开头插入一系列指令:从指定位置加载值,与数值比较,若比较结果不等则跳转到指定基本块。尝试插入JNE(jump not equal)指令,但未能成功。
我的代码如下:
void SomeFunction(llvm::MachineFunction &MF) { const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); // MachineRegisterInfo &MRI = MF.getRegInfo(); MachineBasicBlock *TrueBB = MF.CreateMachineBasicBlock(); MF.insert(MF.end(),TrueBB); // get the false basic block ready // this is stored at the end of the function that if in the previous block, if any of the jne actually jump into this block, it should terminate // Location testing llvm::BuildMI(*TrueBB, TrueBB->begin(), TrueBB->begin()->getDebugLoc(), TII->get(X86::MOV64mr)) .addReg(X86::RAX) // Base register for the destination address .addImm(1) // Scale factor .addReg(0) // Index register, none in this case .addImm(0) // Displacement .addReg(0) // Segment register, not used here .addImm(0); // Immediate value to store llvm::BuildMI(*TrueBB, TrueBB->begin(), TrueBB->begin()->getDebugLoc(), TII->get(X86::MOV64ri), X86::RAX).addImm(0); llvm::BuildMI(*TrueBB, TrueBB->begin(), TrueBB->begin()->getDebugLoc(), TII->get(X86::NOOP)); // then for other basic blocks that are not the first and last for (llvm::MachineFunction::iterator MBBItr = MF.begin(), MBBEnd = MF.end(); MBBItr != MBBEnd; MBBItr++){ llvm::MachineBasicBlock &MBB = *MBBItr; if (&MBB != &MF.front() && &MBB != &MF.front()) { MachineBasicBlock::iterator FirstMI = MBB.begin(); DebugLoc DL = FirstMI->getDebugLoc(); // Location indicator for debug purpose BuildMI(MBB, FirstMI, DL, TII->get(X86::NOOP)); // Both way works // Firstly load value from address stored in R14 // addRegOffset(llvm::BuildMI(MBB, FirstMI, DL, TII->get(llvm::X86::MOV64rm),llvm::X86::RAX), // llvm::X86::R14, false, 0); llvm::BuildMI(MBB, FirstMI, DL, TII->get(llvm::X86::MOV64rm),llvm::X86::RAX) .addReg(llvm::X86::R14) .addImm(1) .addReg(llvm::X86::NoRegister) .addImm(0) .addReg(llvm::X86::NoRegister); // Then Compare it with our value llvm::BuildMI(MBB,FirstMI,DL,TII->get(llvm::X86::CMP64ri32)) .addReg(llvm::X86::RAX) .addImm(0x11111111); // if the value isn't the same, means interrupt happened, jump to terminate block // This is the code that I couldn't get it to work llvm::BuildMI(MBB, FirstMI, DL, TII->get(llvm::X86::JCC_1)) .addImm(llvm::X86::COND_NE) .addMBB(TrueBB); } } return; }
LLVM编译成功,但编译测试代码时生成了如下结果:
# %bb.3: # in Loop: Header=BB25_1 Depth=1 nop movq (%r14), %rax cmpq $286331153, %rax # imm = 0x11111111 jo 5
生成的不是JNE而是JO指令,不清楚问题出在哪。这是学术用途,希望能解决该问题。
问题分析与解决
问题出在X86::JCC_1指令的条件码参数传递方式上:
- X86通用条件跳转指令
JCC_1期望接收的是条件码的位掩码值,而非直接使用X86::COND_*枚举的原始数值,直接传递X86::COND_NE会被解析为错误的条件,从而生成jo(溢出跳转)指令。
有两种修复方式:
直接使用特定的JNE指令
替换原来的通用跳转代码,直接调用X86架构中对应JNE的专用指令X86::JNE_1,无需手动指定条件码:// 替换原JCC_1相关代码 llvm::BuildMI(MBB, FirstMI, DL, TII->get(llvm::X86::JNE_1)) .addMBB(TrueBB);正确转换条件码为位掩码
如果坚持使用通用的JCC_1,需要调用X86::CondCodeToCondMask函数将枚举值转换为正确的位掩码:#include "X86InstrInfo.h" // ... llvm::BuildMI(MBB, FirstMI, DL, TII->get(llvm::X86::JCC_1)) .addImm(X86::CondCodeToCondMask(X86::COND_NE)) .addMBB(TrueBB);
另外,代码中存在一个逻辑小错误:循环内的判断条件&MBB != &MF.front() && &MBB != &MF.front()重复检查了同一个条件,应该改为排除你创建的TrueBB:
if (&MBB != &MF.front() && &MBB != TrueBB) {
修改后,生成的汇编代码中就会出现预期的jne指令。
内容的提问来源于stack exchange,提问作者Nelly
相关产品推荐
相关产品推荐

