Skip to content

Commit

Permalink
[X86][Disassembler] Optimize argument passing and immediate reading
Browse files Browse the repository at this point in the history
  • Loading branch information
MaskRay committed Jan 11, 2020
1 parent 6fdd6a7 commit 1e8ce74
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 74 deletions.
32 changes: 17 additions & 15 deletions llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,33 +177,35 @@ MCDisassembler::DecodeStatus X86GenericDisassembler::getInstruction(
raw_ostream &CStream) const {
CommentStream = &CStream;

InternalInstruction InternalInstr;
InternalInstruction Insn;
memset(&Insn, 0, sizeof(InternalInstruction));
Insn.bytes = Bytes;
Insn.startLocation = Address;
Insn.readerCursor = Address;
Insn.mode = fMode;

std::pair<ArrayRef<uint8_t>, uint64_t> R(Bytes, Address);

int Ret = decodeInstruction(&InternalInstr, &R, (const void *)MII.get(),
Address, fMode);
int Ret = decodeInstruction(&Insn, MII.get());

if (Ret) {
Size = InternalInstr.readerCursor - Address;
Size = Insn.readerCursor - Address;
return Fail;
} else {
Size = InternalInstr.length;
bool Ret = translateInstruction(Instr, InternalInstr, this);
Size = Insn.length;
bool Ret = translateInstruction(Instr, Insn, this);
if (!Ret) {
unsigned Flags = X86::IP_NO_PREFIX;
if (InternalInstr.hasAdSize)
if (Insn.hasAdSize)
Flags |= X86::IP_HAS_AD_SIZE;
if (!InternalInstr.mandatoryPrefix) {
if (InternalInstr.hasOpSize)
if (!Insn.mandatoryPrefix) {
if (Insn.hasOpSize)
Flags |= X86::IP_HAS_OP_SIZE;
if (InternalInstr.repeatPrefix == 0xf2)
if (Insn.repeatPrefix == 0xf2)
Flags |= X86::IP_HAS_REPEAT_NE;
else if (InternalInstr.repeatPrefix == 0xf3 &&
else if (Insn.repeatPrefix == 0xf3 &&
// It should not be 'pause' f3 90
InternalInstr.opcode != 0x90)
Insn.opcode != 0x90)
Flags |= X86::IP_HAS_REPEAT;
if (InternalInstr.hasLockPrefix)
if (Insn.hasLockPrefix)
Flags |= X86::IP_HAS_LOCK;
}
Instr.setFlags(Flags);
Expand Down
65 changes: 19 additions & 46 deletions llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

#include <cassert>
#include <cstdarg> /* for va_*() */
#include <cstdio> /* for vsnprintf() */
#include <cstdlib> /* for exit() */
#include <cstring> /* for memset() */

using namespace llvm;
using namespace llvm::X86Disassembler;

#define DEBUG_TYPE "x86-disassembler"
Expand Down Expand Up @@ -196,12 +198,11 @@ static const struct InstructionSpecifier *specifierForUID(InstrUID uid) {
}

static bool peek(struct InternalInstruction *insn, uint8_t &byte) {
auto *r = static_cast<const std::pair<llvm::ArrayRef<uint8_t>, uint64_t> *>(
insn->readerArg);
uint64_t offset = insn->readerCursor - r->second;
if (offset >= r->first.size())
auto r = insn->bytes;
uint64_t offset = insn->readerCursor - insn->startLocation;
if (offset >= r.size())
return true;
byte = r->first[offset];
byte = r[offset];
return false;
}

Expand All @@ -211,14 +212,13 @@ static void unconsumeByte(struct InternalInstruction* insn) {

template <typename T>
static bool consume(InternalInstruction *insn, T &ptr) {
auto *r = static_cast<const std::pair<llvm::ArrayRef<uint8_t>, uint64_t> *>(
insn->readerArg);
uint64_t offset = insn->readerCursor - r->second;
if (offset + sizeof(T) > r->first.size())
auto r = insn->bytes;
uint64_t offset = insn->readerCursor - insn->startLocation;
if (offset + sizeof(T) > r.size())
return true;
T ret = 0;
for (unsigned i = 0; i < sizeof(T); ++i)
ret |= (uint64_t)r->first[offset + i] << (i * 8);
ret |= (uint64_t)r[offset + i] << (i * 8);
ptr = ret;
insn->readerCursor += sizeof(T);
return false;
Expand Down Expand Up @@ -774,7 +774,7 @@ static bool is64Bit(const char *name) {
* @return - 0 if the ModR/M could be read when needed or was not needed;
* nonzero otherwise.
*/
static int getID(struct InternalInstruction* insn, const void *miiArg) {
static int getID(struct InternalInstruction* insn, const MCInstrInfo *miiArg) {
uint16_t attrMask;
uint16_t instructionID;

Expand Down Expand Up @@ -1553,15 +1553,9 @@ static int readImmediate(struct InternalInstruction* insn, uint8_t size) {

dbgprintf(insn, "readImmediate()");

if (insn->numImmediatesConsumed == 2) {
debug("Already consumed two immediates");
return -1;
}
assert(insn->numImmediatesConsumed < 2 && "Already consumed two immediates");

if (size == 0)
size = insn->immediateSize;
else
insn->immediateSize = size;
insn->immediateSize = size;
insn->immediateOffset = insn->readerCursor - insn->startLocation;

switch (size) {
Expand All @@ -1585,6 +1579,8 @@ static int readImmediate(struct InternalInstruction* insn, uint8_t size) {
return -1;
insn->immediates[insn->numImmediatesConsumed] = imm64;
break;
default:
llvm_unreachable("invalid size");
}

insn->numImmediatesConsumed++;
Expand Down Expand Up @@ -1811,44 +1807,21 @@ static int readOperands(struct InternalInstruction* insn) {
* decodeInstruction - Reads and interprets a full instruction provided by the
* user.
*
* @param insn - A pointer to the instruction to be populated. Must be
* pre-allocated.
* @param reader - The function to be used to read the instruction's bytes.
* @param readerArg - A generic argument to be passed to the reader to store
* any internal state.
* @param startLoc - The address (in the reader's address space) of the first
* byte in the instruction.
* @param mode - The mode (real mode, IA-32e, or IA-32e in 64-bit mode) to
* decode the instruction in.
* @return - 0 if the instruction's memory could be read; nonzero if
* not.
*/
int llvm::X86Disassembler::decodeInstruction(struct InternalInstruction *insn,
const void *readerArg,
const void *miiArg,
uint64_t startLoc,
DisassemblerMode mode) {
memset(insn, 0, sizeof(struct InternalInstruction));

insn->readerArg = readerArg;
insn->startLocation = startLoc;
insn->readerCursor = startLoc;
insn->mode = mode;
insn->numImmediatesConsumed = 0;

if (readPrefixes(insn) ||
readOpcode(insn) ||
getID(insn, miiArg) ||
insn->instructionID == 0 ||
readOperands(insn))
const MCInstrInfo *mii) {
if (readPrefixes(insn) || readOpcode(insn) || getID(insn, mii) ||
insn->instructionID == 0 || readOperands(insn))
return -1;

insn->operands = x86OperandSets[insn->spec->operands];

insn->length = insn->readerCursor - insn->startLocation;

dbgprintf(insn, "Read from 0x%llx to 0x%llx: length %zu",
startLoc, insn->readerCursor, insn->length);
insn->startLocation, insn->readerCursor, insn->length);

if (insn->length > 15)
dbgprintf(insn, "Instruction exceeds 15-byte limit");
Expand Down
18 changes: 5 additions & 13 deletions llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include "llvm/Support/X86DisassemblerDecoderCommon.h"

namespace llvm {

class MCInstrInfo;

namespace X86Disassembler {

// Accessor functions for various fields of an Intel instruction
Expand Down Expand Up @@ -530,7 +533,7 @@ struct InstructionSpecifier {
/// The x86 internal instruction, which is produced by the decoder.
struct InternalInstruction {
// Opaque value passed to the reader
const void* readerArg;
llvm::ArrayRef<uint8_t> bytes;
// The address of the next byte to read via the reader
uint64_t readerCursor;

Expand Down Expand Up @@ -652,19 +655,8 @@ struct InternalInstruction {

/// Decode one instruction and store the decoding results in
/// a buffer provided by the consumer.
/// \param insn The buffer to store the instruction in. Allocated by the
/// consumer.
/// \param readerArg An argument to pass to the reader for storing context
/// specific to the consumer. May be NULL.
/// \param startLoc The address (in the reader's address space) of the first
/// byte in the instruction.
/// \param mode The mode (16-bit, 32-bit, 64-bit) to decode in.
/// \return Nonzero if there was an error during decode, 0 otherwise.
int decodeInstruction(InternalInstruction *insn,
const void *readerArg,
const void *miiArg,
uint64_t startLoc,
DisassemblerMode mode);
int decodeInstruction(InternalInstruction *insn, const MCInstrInfo *mii);

/// Print a message to debugs()
/// \param file The name of the file printing the debug message.
Expand Down

0 comments on commit 1e8ce74

Please sign in to comment.