在LLVM代码生成器部分的MCInstrDesc
或MachineInstr
类中,函数getOpcode()
返回什么?我不能联系到机器的实际操作码。
例如,对于x86
中的RET
指令,getOpcode()
函数返回2515
。但是,x86中的实际操作码是C3
(十进制的195
)。
这是什么关系?
发布于 2018-02-26 02:54:12
MCInstrDesc
和MachineInstr
上的getOpcode()
成员函数返回枚举值,该枚举值标识指令表示X86InstrInfo.td
中的哪个操作码。在其他后端中,编号对应于该后端的instr信息,通常是一个名为[BACKEND]InstrInfo.td
的文件。
您可以在许多X86后端传递中找到使用这种方法的示例,例如X86ExpandPseudo.cpp
中处理尾部调用返回的代码。
switch (MI.getOpcode()) {
default:
return false;
case X86::TCRETURNdi:
case X86::TCRETURNdicc:
case X86::TCRETURNri:
case X86::TCRETURNmi:
case X86::TCRETURNdi64:
case X86::TCRETURNdi64cc:
case X86::TCRETURNri64:
case X86::TCRETURNmi64: {
/* ... */
}
/* ... */
}
发布于 2021-06-27 09:29:56
最近,我一直在为同样的问题而苦苦挣扎,最终得到了答案。你的问题已经有很长一段时间了,但我写这篇文章是为了如果有人仍然感到困惑。
正如你所说的,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
例如,在我的pc中为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时,不应将它们用作编号,而应使用枚举名称调用它们。例如:
#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 ...
https://stackoverflow.com/questions/48894012
复制相似问题