arch-x86: Let individual reg uops specialize their arguments.
Rather than force all x86 microops to have one destination and two sources, the second of which is a register or immediate, make it possible for these microops to pick any combination of those elements by modularizing the operand aspects of the base class. This prevents having a bunch of extra parameters and members of the classes, or having a lot of explicitly laid out classes with various combinations. This also improves the accuracy/usefulness of Exec traces since register types and therefore names will be determined correctly. Also, there was a branchTarget override added to all register uops which would be used when the macroop was an direct control transfer instruction. The assumption was that the immediate value of the whole instruction would be the PC offset, which is not necessarily correct but is probably a fairly safe assumption. This override was only provided for all *register* uops though, and there's nothing saying the last uop in a branch instruction has to be a a register uop. This change moves that override to the uop base class so that *any* uop can be last in the macroop and still support branchTarget correctly (or at least as correctly as a register uop would). Change-Id: I9d42d22609d511fa757a784c04a5a9874beca479 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/42343 Reviewed-by: Gabe Black <gabe.black@gmail.com> Maintainer: Gabe Black <gabe.black@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -119,4 +119,15 @@ X86MicroopBase::checkCondition(uint64_t flags, int condition) const
|
||||
return true;
|
||||
}
|
||||
|
||||
PCState
|
||||
X86MicroopBase::branchTarget(const PCState &branchPC) const
|
||||
{
|
||||
PCState pcs = branchPC;
|
||||
DPRINTF(X86, "branchTarget PC info: %s, Immediate: %lx\n", pcs,
|
||||
(int64_t)machInst.immediate);
|
||||
pcs.npc(pcs.npc() + (int64_t)machInst.immediate);
|
||||
pcs.uEnd();
|
||||
return pcs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -134,6 +134,11 @@ class X86MicroopBase : public X86StaticInst
|
||||
else
|
||||
pcState.uAdvance();
|
||||
}
|
||||
|
||||
PCState branchTarget(const PCState &branchPC) const override;
|
||||
|
||||
// Explicitly import the otherwise hidden branchTarget.
|
||||
using StaticInst::branchTarget;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -47,59 +47,32 @@ namespace X86ISA
|
||||
{
|
||||
|
||||
uint64_t
|
||||
RegOpBase::genFlags(uint64_t oldFlags, uint64_t flagMask,
|
||||
RegOpBase::genFlags(uint64_t old_flags, uint64_t flag_mask,
|
||||
uint64_t _dest, uint64_t _src1, uint64_t _src2, bool subtract) const
|
||||
{
|
||||
DPRINTF(X86, "flagMask = %#x\n", flagMask);
|
||||
uint64_t flags = oldFlags & ~flagMask;
|
||||
if (flagMask & (ECFBit | CFBit)) {
|
||||
DPRINTF(X86, "flag_mask = %#x\n", flag_mask);
|
||||
uint64_t flags = old_flags & ~flag_mask;
|
||||
if (flag_mask & (ECFBit | CFBit)) {
|
||||
if (findCarry(dataSize*8, _dest, _src1, _src2))
|
||||
flags |= (flagMask & (ECFBit | CFBit));
|
||||
flags |= (flag_mask & (ECFBit | CFBit));
|
||||
if (subtract)
|
||||
flags ^= (flagMask & (ECFBit | CFBit));
|
||||
flags ^= (flag_mask & (ECFBit | CFBit));
|
||||
}
|
||||
if (flagMask & PFBit && !findParity(8, _dest))
|
||||
if (flag_mask & PFBit && !findParity(8, _dest))
|
||||
flags |= PFBit;
|
||||
if (flagMask & AFBit) {
|
||||
if (flag_mask & AFBit) {
|
||||
if (findCarry(4, _dest, _src1, _src2))
|
||||
flags |= AFBit;
|
||||
if (subtract)
|
||||
flags ^= AFBit;
|
||||
}
|
||||
if (flagMask & (EZFBit | ZFBit) && findZero(dataSize*8, _dest))
|
||||
flags |= (flagMask & (EZFBit | ZFBit));
|
||||
if (flagMask & SFBit && findNegative(dataSize*8, _dest))
|
||||
if (flag_mask & (EZFBit | ZFBit) && findZero(dataSize * 8, _dest))
|
||||
flags |= (flag_mask & (EZFBit | ZFBit));
|
||||
if (flag_mask & SFBit && findNegative(dataSize * 8, _dest))
|
||||
flags |= SFBit;
|
||||
if (flagMask & OFBit && findOverflow(dataSize*8, _dest, _src1, _src2))
|
||||
if (flag_mask & OFBit && findOverflow(dataSize * 8, _dest, _src1, _src2))
|
||||
flags |= OFBit;
|
||||
return flags;
|
||||
}
|
||||
|
||||
std::string
|
||||
RegOp::generateDisassembly(Addr pc, const Loader::SymbolTable *symtab) const
|
||||
{
|
||||
std::stringstream response;
|
||||
|
||||
printMnemonic(response, instMnem, mnemonic);
|
||||
printDestReg(response, 0, dataSize);
|
||||
response << ", ";
|
||||
printSrcReg(response, 0, dataSize);
|
||||
response << ", ";
|
||||
printSrcReg(response, 1, dataSize);
|
||||
return response.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
RegOpImm::generateDisassembly(Addr pc, const Loader::SymbolTable *symtab) const
|
||||
{
|
||||
std::stringstream response;
|
||||
|
||||
printMnemonic(response, instMnem, mnemonic);
|
||||
printDestReg(response, 0, dataSize);
|
||||
response << ", ";
|
||||
printSrcReg(response, 0, dataSize);
|
||||
ccprintf(response, ", %#x", imm8);
|
||||
return response.str();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,80 +43,279 @@
|
||||
namespace X86ISA
|
||||
{
|
||||
|
||||
/**
|
||||
* Base classes for RegOps which provides a generateDisassembly method.
|
||||
*/
|
||||
struct RegOpDest
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex dest;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpDest(InstType *inst, ArgType idx) :
|
||||
dest(INTREG_FOLDED(idx.index(), inst->foldOBit)),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
X86StaticInst::printReg(os, RegId(IntRegClass, dest), size);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpDbgDest
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex dest;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpDbgDest(InstType *inst, ArgType idx) : dest(idx.index()),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
ccprintf(os, "dr%d", dest);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpCrDest
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex dest;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpCrDest(InstType *inst, ArgType idx) : dest(idx.index()),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
ccprintf(os, "cr%d", dest);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpSegDest
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex dest;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpSegDest(InstType *inst, ArgType idx) : dest(idx.index()),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
X86StaticInst::printSegment(os, dest);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpMiscDest
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex dest;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpMiscDest(InstType *inst, ArgType idx) : dest(idx.index()),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
X86StaticInst::printReg(os, RegId(MiscRegClass, dest), size);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpSrc1
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex src1;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpSrc1(InstType *inst, ArgType idx) :
|
||||
src1(INTREG_FOLDED(idx.index(), inst->foldOBit)),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
X86StaticInst::printReg(os, RegId(IntRegClass, src1), size);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpDbgSrc1
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex src1;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpDbgSrc1(InstType *inst, ArgType idx) : src1(idx.index()),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
ccprintf(os, "dr%d", src1);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpCrSrc1
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex src1;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpCrSrc1(InstType *inst, ArgType idx) : src1(idx.index()),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
ccprintf(os, "cr%d", src1);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpSegSrc1
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex src1;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpSegSrc1(InstType *inst, ArgType idx) : src1(idx.index()),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
X86StaticInst::printSegment(os, src1);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpMiscSrc1
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex src1;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpMiscSrc1(InstType *inst, ArgType idx) : src1(idx.index()),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
X86StaticInst::printReg(os, RegId(MiscRegClass, src1), size);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpSrc2
|
||||
{
|
||||
using ArgType = InstRegIndex;
|
||||
|
||||
RegIndex src2;
|
||||
size_t size;
|
||||
|
||||
template <class InstType>
|
||||
RegOpSrc2(InstType *inst, ArgType idx) :
|
||||
src2(INTREG_FOLDED(idx.index(), inst->foldOBit)),
|
||||
size(inst->dataSize)
|
||||
{}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
X86StaticInst::printReg(os, RegId(IntRegClass, src2), size);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegOpImm8
|
||||
{
|
||||
using ArgType = uint8_t;
|
||||
|
||||
uint8_t imm8;
|
||||
|
||||
template <class InstType>
|
||||
RegOpImm8(InstType *inst, ArgType _imm8) : imm8(_imm8) {}
|
||||
|
||||
void
|
||||
print(std::ostream &os) const
|
||||
{
|
||||
ccprintf(os, "%#x", imm8);
|
||||
}
|
||||
};
|
||||
|
||||
class RegOpBase : public X86MicroopBase
|
||||
{
|
||||
protected:
|
||||
const RegIndex src1;
|
||||
const RegIndex dest;
|
||||
const uint8_t dataSize;
|
||||
const uint16_t ext;
|
||||
RegIndex foldOBit;
|
||||
|
||||
// Constructor
|
||||
RegOpBase(ExtMachInst _machInst,
|
||||
const char *mnem, const char *_instMnem, uint64_t setFlags,
|
||||
InstRegIndex _src1, InstRegIndex _dest,
|
||||
uint8_t _dataSize, uint16_t _ext,
|
||||
OpClass __opClass) :
|
||||
X86MicroopBase(_machInst, mnem, _instMnem, setFlags,
|
||||
__opClass),
|
||||
src1(_src1.index()), dest(_dest.index()),
|
||||
dataSize(_dataSize), ext(_ext)
|
||||
{
|
||||
foldOBit = (dataSize == 1 && !_machInst.rex.present) ? 1 << 6 : 0;
|
||||
}
|
||||
RegOpBase(ExtMachInst mach_inst, const char *mnem, const char *inst_mnem,
|
||||
uint64_t set_flags, uint8_t data_size, uint16_t _ext,
|
||||
OpClass op_class) :
|
||||
X86MicroopBase(mach_inst, mnem, inst_mnem, set_flags, op_class),
|
||||
ext(_ext), dataSize(data_size),
|
||||
foldOBit((data_size == 1 && !mach_inst.rex.present) ? 1 << 6 : 0)
|
||||
{}
|
||||
|
||||
//Figure out what the condition code flags should be.
|
||||
uint64_t genFlags(uint64_t oldFlags, uint64_t flagMask,
|
||||
uint64_t genFlags(uint64_t old_flags, uint64_t flag_mask,
|
||||
uint64_t _dest, uint64_t _src1, uint64_t _src2,
|
||||
bool subtract = false) const;
|
||||
bool subtract=false)const ;
|
||||
|
||||
public:
|
||||
const uint8_t dataSize;
|
||||
const RegIndex foldOBit;
|
||||
};
|
||||
|
||||
class RegOp : public RegOpBase
|
||||
template <typename ...Operands>
|
||||
class RegOpT : public RegOpBase, public Operands...
|
||||
{
|
||||
protected:
|
||||
const RegIndex src2;
|
||||
RegOpT(ExtMachInst mach_inst, const char *mnem, const char *inst_mnem,
|
||||
uint64_t set_flags, uint8_t data_size, uint16_t _ext,
|
||||
OpClass op_class, typename Operands::ArgType... args) :
|
||||
RegOpBase(mach_inst, mnem, inst_mnem, set_flags, data_size, _ext,
|
||||
op_class), Operands(this, args)...
|
||||
{}
|
||||
|
||||
// Constructor
|
||||
RegOp(ExtMachInst _machInst,
|
||||
const char *mnem, const char *_instMnem, uint64_t setFlags,
|
||||
InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
|
||||
uint8_t _dataSize, uint16_t _ext,
|
||||
OpClass __opClass) :
|
||||
RegOpBase(_machInst, mnem, _instMnem, setFlags,
|
||||
_src1, _dest, _dataSize, _ext,
|
||||
__opClass),
|
||||
src2(_src2.index())
|
||||
std::string
|
||||
generateDisassembly(Addr pc,
|
||||
const Loader::SymbolTable *symtab) const override
|
||||
{
|
||||
std::stringstream response;
|
||||
printMnemonic(response, instMnem, mnemonic);
|
||||
int count = 0;
|
||||
M5_FOR_EACH_IN_PACK(ccprintf(response, count++ ? ", " : ""),
|
||||
Operands::print(response));
|
||||
return response.str();
|
||||
}
|
||||
|
||||
std::string generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const override;
|
||||
};
|
||||
|
||||
class RegOpImm : public RegOpBase
|
||||
{
|
||||
protected:
|
||||
const uint8_t imm8;
|
||||
|
||||
// Constructor
|
||||
RegOpImm(ExtMachInst _machInst,
|
||||
const char * mnem, const char *_instMnem, uint64_t setFlags,
|
||||
InstRegIndex _src1, uint8_t _imm8, InstRegIndex _dest,
|
||||
uint8_t _dataSize, uint16_t _ext,
|
||||
OpClass __opClass) :
|
||||
RegOpBase(_machInst, mnem, _instMnem, setFlags,
|
||||
_src1, _dest, _dataSize, _ext,
|
||||
__opClass),
|
||||
imm8(_imm8)
|
||||
{
|
||||
}
|
||||
|
||||
std::string generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -45,19 +45,19 @@ namespace X86ISA
|
||||
{
|
||||
|
||||
void
|
||||
X86StaticInst::printMnemonic(std::ostream &os, const char *mnemonic) const
|
||||
X86StaticInst::printMnemonic(std::ostream &os, const char *mnemonic)
|
||||
{
|
||||
ccprintf(os, " %s ", mnemonic);
|
||||
}
|
||||
|
||||
void
|
||||
X86StaticInst::printMnemonic(std::ostream &os, const char *instMnemonic,
|
||||
const char *mnemonic) const
|
||||
const char *mnemonic)
|
||||
{
|
||||
ccprintf(os, " %s : %s ", instMnemonic, mnemonic);
|
||||
}
|
||||
|
||||
void X86StaticInst::printSegment(std::ostream &os, int segment) const
|
||||
void X86StaticInst::printSegment(std::ostream &os, int segment)
|
||||
{
|
||||
switch (segment)
|
||||
{
|
||||
@@ -120,7 +120,7 @@ X86StaticInst::printDestReg(std::ostream &os, int reg, int size) const
|
||||
}
|
||||
|
||||
void
|
||||
X86StaticInst::printReg(std::ostream &os, RegId reg, int size) const
|
||||
X86StaticInst::printReg(std::ostream &os, RegId reg, int size)
|
||||
{
|
||||
assert(size == 1 || size == 2 || size == 4 || size == 8);
|
||||
static const char * abcdFormats[9] =
|
||||
@@ -231,7 +231,7 @@ X86StaticInst::printReg(std::ostream &os, RegId reg, int size) const
|
||||
void
|
||||
X86StaticInst::printMem(std::ostream &os, uint8_t segment,
|
||||
uint8_t scale, RegIndex index, RegIndex base,
|
||||
uint64_t disp, uint8_t addressSize, bool rip) const
|
||||
uint64_t disp, uint8_t addressSize, bool rip)
|
||||
{
|
||||
bool someAddr = false;
|
||||
printSegment(os, segment);
|
||||
|
||||
@@ -81,6 +81,18 @@ struct InstRegIndex : public RegId
|
||||
|
||||
class X86StaticInst : public StaticInst
|
||||
{
|
||||
public:
|
||||
static void printMnemonic(std::ostream &os, const char *mnemonic);
|
||||
static void printMnemonic(std::ostream &os, const char *instMnemonic,
|
||||
const char *mnemonic);
|
||||
static void printMem(std::ostream &os, uint8_t segment,
|
||||
uint8_t scale, RegIndex index, RegIndex base,
|
||||
uint64_t disp, uint8_t addressSize, bool rip);
|
||||
|
||||
static void printSegment(std::ostream &os, int segment);
|
||||
|
||||
static void printReg(std::ostream &os, RegId reg, int size);
|
||||
|
||||
protected:
|
||||
using ExtMachInst = X86ISA::ExtMachInst;
|
||||
|
||||
@@ -95,19 +107,8 @@ class X86StaticInst : public StaticInst
|
||||
|
||||
std::string generateDisassembly(
|
||||
Addr pc, const Loader::SymbolTable *symtab) const override;
|
||||
|
||||
void printMnemonic(std::ostream &os, const char * mnemonic) const;
|
||||
void printMnemonic(std::ostream &os, const char * instMnemonic,
|
||||
const char * mnemonic) const;
|
||||
|
||||
void printSegment(std::ostream &os, int segment) const;
|
||||
|
||||
void printReg(std::ostream &os, RegId reg, int size) const;
|
||||
void printSrcReg(std::ostream &os, int reg, int size) const;
|
||||
void printDestReg(std::ostream &os, int reg, int size) const;
|
||||
void printMem(std::ostream &os, uint8_t segment,
|
||||
uint8_t scale, RegIndex index, RegIndex base,
|
||||
uint64_t disp, uint8_t addressSize, bool rip) const;
|
||||
|
||||
inline uint64_t
|
||||
merge(uint64_t into, uint64_t val, int size) const
|
||||
|
||||
@@ -77,6 +77,7 @@ output decoder {{
|
||||
#include "arch/x86/faults.hh"
|
||||
#include "arch/x86/microcode_rom.hh"
|
||||
#include "arch/x86/regs/float.hh"
|
||||
#include "arch/x86/regs/int.hh"
|
||||
#include "arch/x86/regs/misc.hh"
|
||||
#include "arch/x86/regs/segment.hh"
|
||||
#include "arch/x86/tlb.hh"
|
||||
|
||||
@@ -135,7 +135,8 @@ let {{
|
||||
|
||||
for reg in ('ah', 'bh', 'ch', 'dh'):
|
||||
assembler.symbols[reg] = \
|
||||
regIdx("INTREG_FOLDED(INTREG_%s, IntFoldBit)" % reg.upper())
|
||||
regIdx("X86ISA::INTREG_FOLDED(INTREG_%s, IntFoldBit)" %
|
||||
reg.upper())
|
||||
|
||||
for reg in range(16):
|
||||
assembler.symbols["cr%d" % reg] = regIdx("MISCREG_CR%d" % reg)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,12 +55,14 @@ def operand_types {{
|
||||
|
||||
let {{
|
||||
def foldInt(idx, foldBit, id):
|
||||
return ('IntReg', 'uqw', 'INTREG_FOLDED(%s, %s)' % (idx, foldBit),
|
||||
'IsInteger', id)
|
||||
return ('IntReg', 'uqw',
|
||||
'X86ISA::INTREG_FOLDED(%s, %s)' % (idx, foldBit), 'IsInteger',
|
||||
id)
|
||||
def intReg(idx, id):
|
||||
return ('IntReg', 'uqw', idx, 'IsInteger', id)
|
||||
def impIntReg(idx, id):
|
||||
return ('IntReg', 'uqw', 'INTREG_IMPLICIT(%s)' % idx, 'IsInteger', id)
|
||||
return ('IntReg', 'uqw', 'X86ISA::INTREG_IMPLICIT(%s)' % idx,
|
||||
'IsInteger', id)
|
||||
def floatReg(idx, id):
|
||||
return ('FloatReg', 'df', idx, 'IsFloating', id)
|
||||
def ccReg(idx, id):
|
||||
@@ -81,7 +83,7 @@ let {{
|
||||
def squashCReg(idx, id, ctype = 'uqw'):
|
||||
return squashCheckReg(idx, id, 'true', ctype)
|
||||
def squashCSReg(idx, id, ctype = 'uqw'):
|
||||
return squashCheckReg(idx, id, 'dest == SEGMENT_REG_CS', ctype)
|
||||
return squashCheckReg(idx, id, 'dest == X86ISA::SEGMENT_REG_CS', ctype)
|
||||
def squashCR0Reg(idx, id, ctype = 'uqw'):
|
||||
return squashCheckReg(idx, id, 'dest == 0', ctype)
|
||||
}};
|
||||
@@ -104,16 +106,16 @@ def operands {{
|
||||
'Remainder': impIntReg(3, 10),
|
||||
'Divisor': impIntReg(4, 11),
|
||||
'DoubleBits': impIntReg(5, 11),
|
||||
'Rax': intReg('(INTREG_RAX)', 12),
|
||||
'Rbx': intReg('(INTREG_RBX)', 13),
|
||||
'Rcx': intReg('(INTREG_RCX)', 14),
|
||||
'Rdx': intReg('(INTREG_RDX)', 15),
|
||||
'Rsp': intReg('(INTREG_RSP)', 16),
|
||||
'Rbp': intReg('(INTREG_RBP)', 17),
|
||||
'Rsi': intReg('(INTREG_RSI)', 18),
|
||||
'Rdi': intReg('(INTREG_RDI)', 19),
|
||||
'R8': intReg('(INTREG_R8)', 20),
|
||||
'R9': intReg('(INTREG_R9)', 21),
|
||||
'Rax': intReg('X86ISA::INTREG_RAX', 12),
|
||||
'Rbx': intReg('X86ISA::INTREG_RBX', 13),
|
||||
'Rcx': intReg('X86ISA::INTREG_RCX', 14),
|
||||
'Rdx': intReg('X86ISA::INTREG_RDX', 15),
|
||||
'Rsp': intReg('X86ISA::INTREG_RSP', 16),
|
||||
'Rbp': intReg('X86ISA::INTREG_RBP', 17),
|
||||
'Rsi': intReg('X86ISA::INTREG_RSI', 18),
|
||||
'Rdi': intReg('X86ISA::INTREG_RDI', 19),
|
||||
'R8': intReg('X86ISA::INTREG_R8', 20),
|
||||
'R9': intReg('X86ISA::INTREG_R9', 21),
|
||||
'FpSrcReg1': floatReg('src1', 22),
|
||||
'FpSrcReg2': floatReg('src2', 23),
|
||||
'FpDestReg': floatReg('dest', 24),
|
||||
@@ -126,11 +128,11 @@ def operands {{
|
||||
(None, None, 'IsControl'), 50),
|
||||
# These registers hold the condition code portion of the flag
|
||||
# register. The nccFlagBits version holds the rest.
|
||||
'ccFlagBits': ccReg('(CCREG_ZAPS)', 60),
|
||||
'cfofBits': ccReg('(CCREG_CFOF)', 61),
|
||||
'dfBit': ccReg('(CCREG_DF)', 62),
|
||||
'ecfBit': ccReg('(CCREG_ECF)', 63),
|
||||
'ezfBit': ccReg('(CCREG_EZF)', 64),
|
||||
'ccFlagBits': ccReg('X86ISA::CCREG_ZAPS', 60),
|
||||
'cfofBits': ccReg('X86ISA::CCREG_CFOF', 61),
|
||||
'dfBit': ccReg('X86ISA::CCREG_DF', 62),
|
||||
'ecfBit': ccReg('X86ISA::CCREG_ECF', 63),
|
||||
'ezfBit': ccReg('X86ISA::CCREG_EZF', 64),
|
||||
|
||||
# These Pred registers are to be used where reading the portions of
|
||||
# condition code registers is possibly optional, depending on how the
|
||||
@@ -147,65 +149,72 @@ def operands {{
|
||||
# would be retained, the write predicate checks if any of the bits
|
||||
# are being written.
|
||||
|
||||
'PredccFlagBits': ('CCReg', 'uqw', '(CCREG_ZAPS)', None,
|
||||
60, None, None, '''(((ext & (PFBit | AFBit | ZFBit | SFBit
|
||||
)) != (PFBit | AFBit | ZFBit | SFBit )) &&
|
||||
((ext & (PFBit | AFBit | ZFBit | SFBit )) != 0))''',
|
||||
'((ext & (PFBit | AFBit | ZFBit | SFBit )) != 0)'),
|
||||
'PredcfofBits': ('CCReg', 'uqw', '(CCREG_CFOF)', None,
|
||||
61, None, None, '''(((ext & CFBit) == 0 ||
|
||||
(ext & OFBit) == 0) && ((ext & (CFBit | OFBit)) != 0))''',
|
||||
'((ext & (CFBit | OFBit)) != 0)'),
|
||||
'PreddfBit': ('CCReg', 'uqw', '(CCREG_DF)', None,
|
||||
62, None, None, '(false)', '((ext & DFBit) != 0)'),
|
||||
'PredecfBit': ('CCReg', 'uqw', '(CCREG_ECF)', None,
|
||||
63, None, None, '(false)', '((ext & ECFBit) != 0)'),
|
||||
'PredezfBit': ('CCReg', 'uqw', '(CCREG_EZF)', None,
|
||||
64, None, None, '(false)', '((ext & EZFBit) != 0)'),
|
||||
'PredccFlagBits': ('CCReg', 'uqw', '(X86ISA::CCREG_ZAPS)', None,
|
||||
60, None, None,
|
||||
'''(((ext & (X86ISA::PFBit | X86ISA::AFBit |
|
||||
X86ISA::ZFBit | X86ISA::SFBit)) !=
|
||||
(X86ISA::PFBit | X86ISA::AFBit |
|
||||
X86ISA::ZFBit | X86ISA::SFBit)) &&
|
||||
((ext & (X86ISA::PFBit | X86ISA::AFBit |
|
||||
X86ISA::ZFBit | X86ISA::SFBit)) != 0))''',
|
||||
'''((ext & (X86ISA::PFBit | X86ISA::AFBit |
|
||||
X86ISA::ZFBit | X86ISA::SFBit)) != 0)'''),
|
||||
'PredcfofBits': ('CCReg', 'uqw', '(X86ISA::CCREG_CFOF)', None,
|
||||
61, None, None, '''(((ext & X86ISA::CFBit) == 0 ||
|
||||
(ext & X86ISA::OFBit) == 0) &&
|
||||
((ext & (X86ISA::CFBit | X86ISA::OFBit)) != 0))''',
|
||||
'((ext & (X86ISA::CFBit | X86ISA::OFBit)) != 0)'),
|
||||
'PreddfBit': ('CCReg', 'uqw', '(X86ISA::CCREG_DF)', None,
|
||||
62, None, None, '(false)', '((ext & X86ISA::DFBit) != 0)'),
|
||||
'PredecfBit': ('CCReg', 'uqw', '(X86ISA::CCREG_ECF)', None,
|
||||
63, None, None, '(false)', '((ext & X86ISA::ECFBit) != 0)'),
|
||||
'PredezfBit': ('CCReg', 'uqw', '(X86ISA::CCREG_EZF)', None,
|
||||
64, None, None, '(false)', '((ext & X86ISA::EZFBit) != 0)'),
|
||||
|
||||
# These register should needs to be more protected so that later
|
||||
# instructions don't map their indexes with an old value.
|
||||
'nccFlagBits': controlReg('MISCREG_RFLAGS', 65),
|
||||
'nccFlagBits': controlReg('X86ISA::MISCREG_RFLAGS', 65),
|
||||
|
||||
# Registers related to the state of x87 floating point unit.
|
||||
'TOP': controlReg('MISCREG_X87_TOP', 66, ctype='ub'),
|
||||
'FSW': controlReg('MISCREG_FSW', 67, ctype='uw'),
|
||||
'FTW': controlReg('MISCREG_FTW', 68, ctype='uw'),
|
||||
'FCW': controlReg('MISCREG_FCW', 69, ctype='uw'),
|
||||
'TOP': controlReg('X86ISA::MISCREG_X87_TOP', 66, ctype='ub'),
|
||||
'FSW': controlReg('X86ISA::MISCREG_FSW', 67, ctype='uw'),
|
||||
'FTW': controlReg('X86ISA::MISCREG_FTW', 68, ctype='uw'),
|
||||
'FCW': controlReg('X86ISA::MISCREG_FCW', 69, ctype='uw'),
|
||||
|
||||
# The segment base as used by memory instructions.
|
||||
'SegBase': controlReg('MISCREG_SEG_EFF_BASE(segment)', 70),
|
||||
'SegBase': controlReg('X86ISA::MISCREG_SEG_EFF_BASE(segment)',
|
||||
70),
|
||||
|
||||
# Operands to get and set registers indexed by the operands of the
|
||||
# original instruction.
|
||||
'ControlDest': squashCR0Reg('MISCREG_CR(dest)', 100),
|
||||
'ControlSrc1': controlReg('MISCREG_CR(src1)', 101),
|
||||
'DebugDest': controlReg('MISCREG_DR(dest)', 102),
|
||||
'DebugSrc1': controlReg('MISCREG_DR(src1)', 103),
|
||||
'SegBaseDest': squashCSReg('MISCREG_SEG_BASE(dest)', 104),
|
||||
'SegBaseSrc1': controlReg('MISCREG_SEG_BASE(src1)', 105),
|
||||
'SegLimitDest': squashCSReg('MISCREG_SEG_LIMIT(dest)', 106),
|
||||
'SegLimitSrc1': controlReg('MISCREG_SEG_LIMIT(src1)', 107),
|
||||
'SegSelDest': controlReg('MISCREG_SEG_SEL(dest)', 108),
|
||||
'SegSelSrc1': controlReg('MISCREG_SEG_SEL(src1)', 109),
|
||||
'SegAttrDest': squashCSReg('MISCREG_SEG_ATTR(dest)', 110),
|
||||
'SegAttrSrc1': controlReg('MISCREG_SEG_ATTR(src1)', 111),
|
||||
'ControlDest': squashCR0Reg('X86ISA::MISCREG_CR(dest)', 100),
|
||||
'ControlSrc1': controlReg('X86ISA::MISCREG_CR(src1)', 101),
|
||||
'DebugDest': controlReg('X86ISA::MISCREG_DR(dest)', 102),
|
||||
'DebugSrc1': controlReg('X86ISA::MISCREG_DR(src1)', 103),
|
||||
'SegBaseDest': squashCSReg('X86ISA::MISCREG_SEG_BASE(dest)', 104),
|
||||
'SegBaseSrc1': controlReg('X86ISA::MISCREG_SEG_BASE(src1)', 105),
|
||||
'SegLimitDest': squashCSReg('X86ISA::MISCREG_SEG_LIMIT(dest)', 106),
|
||||
'SegLimitSrc1': controlReg('X86ISA::MISCREG_SEG_LIMIT(src1)', 107),
|
||||
'SegSelDest': controlReg('X86ISA::MISCREG_SEG_SEL(dest)', 108),
|
||||
'SegSelSrc1': controlReg('X86ISA::MISCREG_SEG_SEL(src1)', 109),
|
||||
'SegAttrDest': squashCSReg('X86ISA::MISCREG_SEG_ATTR(dest)', 110),
|
||||
'SegAttrSrc1': controlReg('X86ISA::MISCREG_SEG_ATTR(src1)', 111),
|
||||
|
||||
# Operands to access specific control registers directly.
|
||||
'EferOp': squashCReg('MISCREG_EFER', 200),
|
||||
'CR4Op': controlReg('MISCREG_CR4', 201),
|
||||
'DR7Op': controlReg('MISCREG_DR7', 202),
|
||||
'LDTRBase': controlReg('MISCREG_TSL_BASE', 203),
|
||||
'LDTRLimit': controlReg('MISCREG_TSL_LIMIT', 204),
|
||||
'LDTRSel': controlReg('MISCREG_TSL', 205),
|
||||
'GDTRBase': controlReg('MISCREG_TSG_BASE', 206),
|
||||
'GDTRLimit': controlReg('MISCREG_TSG_LIMIT', 207),
|
||||
'CSBase': squashCReg('MISCREG_CS_EFF_BASE', 208),
|
||||
'CSAttr': squashCReg('MISCREG_CS_ATTR', 209),
|
||||
'EferOp': squashCReg('X86ISA::MISCREG_EFER', 200),
|
||||
'CR4Op': controlReg('X86ISA::MISCREG_CR4', 201),
|
||||
'DR7Op': controlReg('X86ISA::MISCREG_DR7', 202),
|
||||
'LDTRBase': controlReg('X86ISA::MISCREG_TSL_BASE', 203),
|
||||
'LDTRLimit': controlReg('X86ISA::MISCREG_TSL_LIMIT', 204),
|
||||
'LDTRSel': controlReg('X86ISA::MISCREG_TSL', 205),
|
||||
'GDTRBase': controlReg('X86ISA::MISCREG_TSG_BASE', 206),
|
||||
'GDTRLimit': controlReg('X86ISA::MISCREG_TSG_LIMIT', 207),
|
||||
'CSBase': squashCReg('X86ISA::MISCREG_CS_EFF_BASE', 208),
|
||||
'CSAttr': squashCReg('X86ISA::MISCREG_CS_ATTR', 209),
|
||||
'MiscRegDest': controlReg('dest', 210),
|
||||
'MiscRegSrc1': controlReg('src1', 211),
|
||||
'TscOp': controlReg('MISCREG_TSC', 212),
|
||||
'M5Reg': squashCReg('MISCREG_M5_REG', 213),
|
||||
'TscOp': controlReg('X86ISA::MISCREG_TSC', 212),
|
||||
'M5Reg': squashCReg('X86ISA::MISCREG_M5_REG', 213),
|
||||
'Mem': ('Mem', 'uqw', None, \
|
||||
(None, 'IsLoad', 'IsStore'), 300)
|
||||
}};
|
||||
|
||||
Reference in New Issue
Block a user