You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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(溢出跳转)指令。

有两种修复方式:

  1. 直接使用特定的JNE指令
    替换原来的通用跳转代码,直接调用X86架构中对应JNE的专用指令X86::JNE_1,无需手动指定条件码:

    // 替换原JCC_1相关代码
    llvm::BuildMI(MBB, FirstMI, DL, TII->get(llvm::X86::JNE_1))
            .addMBB(TrueBB);
    
  2. 正确转换条件码为位掩码
    如果坚持使用通用的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 23:54:55