我最近在为同样的问题而苦苦挣扎,终于明白了。很久没有提出你的问题了,但我写这个是为了如果有人仍然困惑。
正如你所说的getOpcode() 函数返回机器指令的枚举,而这些不是像@dtolnay 所说的那样持有{BackendArchName}InstrInfo.td。这些枚举将在 LLVM 库构建后生成,并且它与真正的十进制操作码编号无关,并且操作码的十进制枚举表示可能会因不同的 llvm 版本或库中有关后端的自定义更改而发生变化。这听起来很合理,因为它不会阻止自定义,您可以在后端添加或删除操作码,并且在库构建后,操作码的枚举会动态更改和生成。如果这些枚举在构建之前一直存在于库中的某个位置,例如,您可能无法为目标添加新的操作码或
这样的小细节可能很难改变。
因此,构建后您可以在此文件夹中找到具有这些操作码表示的文件:
{your-llvm-directory}/{your-llvm-build-directory}/lib/Target/{which-backend-target}
这个.inc 文件包含操作码的枚举:
{which-backend-target}GenInstrInfo.inc
例如,在我的电脑中为 riscv 目标构建后,我可以在这里找到枚举:
~/llvm/llvm-project/build/lib/Target/RISCV/RISCVGenInstrInfo.inc
这些枚举的一部分:
/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\
|* *|
|* Target Instruction Enum Values and Descriptors *|
|* *|
|* Automatically generated file, do not edit! *|
|* *|
\*===----------------------------------------------------------------------===*/
#ifdef GET_INSTRINFO_ENUM
#undef GET_INSTRINFO_ENUM
namespace llvm {
namespace RISCV {
enum {
// ........................................
AND = 323,
ANDI = 324,
ANDN = 325,
AUIPC = 326,
BDEP = 327,
BDEPW = 328,
BEQ = 329,
BEXT = 330,
BEXTW = 331,
BFP = 332,
BFPW = 333,
BGE = 334,
BGEU = 335,
BLT = 336,
BLTU = 337,
BMATFLIP = 338,
BMATOR = 339,
BMATXOR = 340,
BNE = 341,
CLMUL = 342,
CLMULH = 343,
CLMULHW = 344,
CLMULR = 345,
CLMULRW = 346,
CLMULW = 347,
CLZ = 348,
CLZW = 349,
CMIX = 350,
CMOV = 351,
CRC32B = 352,
// ........................................
CRC32H = 358,
CRC32W = 359,
CSRRC = 360,
CSRRCI = 361,
CSRRS = 362,
CSRRSI = 363,
CSRRW = 364,
CSRRWI = 365,
CTZ = 366,
CTZW = 367,
C_ADD = 368,
C_ADDI = 369,
C_ADDI16SP = 370,
C_ADDI4SPN = 371,
C_ADDIW = 372,
C_ADDI_HINT_IMM_ZERO = 373,
C_ADDI_HINT_X0 = 374,
C_ADDI_NOP = 375,
// ........................................
};
} // end namespace RISCV
} // end namespace llvm
我只是举了一个 RISCV 的例子,它与 X86 等其他目标的过程相同。在您的示例中,RET 的 2515 应该在 X86GenInstrInfo.inc 文件中作为枚举编号,如上所示。
因为这些枚举是在构建之后生成的,所以在任何未构建的llvm library 中都找不到这些枚举是很正常的,比如在 github 中。
额外信息:
因为枚举编号会因不同的场景而改变,所以在使用 LLVM C++ API 时不应将它们用作数字,而应使用枚举名称来调用它们。例如:
#include "RISCV.h" //You should include backend header for using enums.
#include "llvm/MC/MCInst.h"
//Some code here ...
if(MI->getOpcode() == RISCV::ADD){ // MI is machine instruction for example const MCInst *MI
//Some code here...
}
//Some code here...
上面的代码,你可以看到无论什么数字返回 getOpcode 函数,因为我可以用派生自(RISCV header->RISCV namespace->RISCV Opcode Enum Name)的名称来控制它。但是,如果您想直接获取返回的枚举编号的名称,您可以使用 getOpcodeName 函数,例如:
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/ADT/StringRef.h" //for llvm string variable
//Some code here ...
StringRef opcodeName = IP.getOpcodeName(MI->getOpcode()); // IP is instruction printer for example MCInstPrinter &IP
//Some code here ...