summaryrefslogtreecommitdiffstats
path: root/utils/TableGen
diff options
context:
space:
mode:
Diffstat (limited to 'utils/TableGen')
-rw-r--r--utils/TableGen/CMakeLists.txt2
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp15
-rw-r--r--utils/TableGen/CodeEmitterGen.h3
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp5
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp78
-rw-r--r--utils/TableGen/DAGISelEmitter.cpp4
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp99
-rw-r--r--utils/TableGen/LLVMCConfigurationEmitter.cpp469
-rw-r--r--utils/TableGen/Record.cpp4
-rw-r--r--utils/TableGen/X86DisassemblerShared.h38
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp603
-rw-r--r--utils/TableGen/X86DisassemblerTables.h291
-rw-r--r--utils/TableGen/X86ModRMFilters.h197
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp959
-rw-r--r--utils/TableGen/X86RecognizableInstr.h237
15 files changed, 2786 insertions, 218 deletions
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index daf8676..ce9b66f 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -23,6 +23,8 @@ add_executable(tblgen
TGValueTypes.cpp
TableGen.cpp
TableGenBackend.cpp
+ X86DisassemblerTables.cpp
+ X86RecognizableInstr.cpp
)
target_link_libraries(tblgen LLVMSupport LLVMSystem)
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index e9f30be..7e6c769 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -61,11 +61,14 @@ void CodeEmitterGen::reverseBits(std::vector<Record*> &Insts) {
// If the VarBitInit at position 'bit' matches the specified variable then
// return the variable bit position. Otherwise return -1.
-int CodeEmitterGen::getVariableBit(const Init *VarVal,
+int CodeEmitterGen::getVariableBit(const std::string &VarName,
BitsInit *BI, int bit) {
if (VarBitInit *VBI = dynamic_cast<VarBitInit*>(BI->getBit(bit))) {
TypedInit *TI = VBI->getVariable();
- if (TI == VarVal) return VBI->getBitNum();
+
+ if (VarInit *VI = dynamic_cast<VarInit*>(TI)) {
+ if (VI->getName() == VarName) return VBI->getBitNum();
+ }
}
return -1;
@@ -159,11 +162,11 @@ void CodeEmitterGen::run(raw_ostream &o) {
if (!Vals[i].getPrefix() && !Vals[i].getValue()->isComplete()) {
// Is the operand continuous? If so, we can just mask and OR it in
// instead of doing it bit-by-bit, saving a lot in runtime cost.
- const Init *VarVal = Vals[i].getValue();
+ const std::string &VarName = Vals[i].getName();
bool gotOp = false;
for (int bit = BI->getNumBits()-1; bit >= 0; ) {
- int varBit = getVariableBit(VarVal, BI, bit);
+ int varBit = getVariableBit(VarName, BI, bit);
if (varBit == -1) {
--bit;
@@ -173,7 +176,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
int N = 1;
for (--bit; bit >= 0;) {
- varBit = getVariableBit(VarVal, BI, bit);
+ varBit = getVariableBit(VarName, BI, bit);
if (varBit == -1 || varBit != (beginVarBit - N)) break;
++N;
--bit;
@@ -185,7 +188,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
while (CGI.isFlatOperandNotEmitted(op))
++op;
- Case += " // op: " + Vals[i].getName() + "\n"
+ Case += " // op: " + VarName + "\n"
+ " op = getMachineOpValue(MI, MI.getOperand("
+ utostr(op++) + "));\n";
gotOp = true;
diff --git a/utils/TableGen/CodeEmitterGen.h b/utils/TableGen/CodeEmitterGen.h
index 2dc34ba..f0b3229 100644
--- a/utils/TableGen/CodeEmitterGen.h
+++ b/utils/TableGen/CodeEmitterGen.h
@@ -23,7 +23,6 @@ namespace llvm {
class RecordVal;
class BitsInit;
-struct Init;
class CodeEmitterGen : public TableGenBackend {
RecordKeeper &Records;
@@ -36,7 +35,7 @@ private:
void emitMachineOpEmitter(raw_ostream &o, const std::string &Namespace);
void emitGetValueBit(raw_ostream &o, const std::string &Namespace);
void reverseBits(std::vector<Record*> &Insts);
- int getVariableBit(const Init *VarVal, BitsInit *BI, int bit);
+ int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
};
} // End llvm namespace
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index fab41c5..cf79365 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -321,8 +321,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N,NumResults);
// It must be integer.
- bool MadeChange = false;
- MadeChange |= OtherNode->UpdateNodeType(MVT::iAny, TP);
+ bool MadeChange = OtherNode->UpdateNodeType(MVT::iAny, TP);
// This code only handles nodes that have one type set. Assert here so
// that we can change this if we ever need to deal with multiple value
@@ -330,7 +329,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N,
assert(OtherNode->getExtTypes().size() == 1 && "Node has too many types!");
if (OtherNode->hasTypeSet() && OtherNode->getTypeNum(0) <= VT)
OtherNode->UpdateNodeType(MVT::Other, TP); // Throw an error.
- return false;
+ return MadeChange;
}
case SDTCisOpSmallerThanOp: {
TreePatternNode *BigOperand =
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index 8520d9e..c69ce96 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -18,36 +18,56 @@
using namespace llvm;
static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) {
- // FIXME: Only supports TIED_TO for now.
+ // EARLY_CLOBBER: @early $reg
+ std::string::size_type wpos = CStr.find_first_of(" \t");
+ std::string::size_type start = CStr.find_first_not_of(" \t");
+ std::string Tok = CStr.substr(start, wpos - start);
+ if (Tok == "@earlyclobber") {
+ std::string Name = CStr.substr(wpos+1);
+ wpos = Name.find_first_not_of(" \t");
+ if (wpos == std::string::npos)
+ throw "Illegal format for @earlyclobber constraint: '" + CStr + "'";
+ Name = Name.substr(wpos);
+ std::pair<unsigned,unsigned> Op =
+ I->ParseOperandName(Name, false);
+
+ // Build the string for the operand
+ std::string OpConstraint = "(1 << TOI::EARLY_CLOBBER)";
+ if (!I->OperandList[Op.first].Constraints[Op.second].empty())
+ throw "Operand '" + Name + "' cannot have multiple constraints!";
+ I->OperandList[Op.first].Constraints[Op.second] = OpConstraint;
+ return;
+ }
+
+ // Only other constraint is "TIED_TO" for now.
std::string::size_type pos = CStr.find_first_of('=');
assert(pos != std::string::npos && "Unrecognized constraint");
- std::string::size_type start = CStr.find_first_not_of(" \t");
+ start = CStr.find_first_not_of(" \t");
std::string Name = CStr.substr(start, pos - start);
-
+
// TIED_TO: $src1 = $dst
- std::string::size_type wpos = Name.find_first_of(" \t");
+ wpos = Name.find_first_of(" \t");
if (wpos == std::string::npos)
throw "Illegal format for tied-to constraint: '" + CStr + "'";
std::string DestOpName = Name.substr(0, wpos);
std::pair<unsigned,unsigned> DestOp = I->ParseOperandName(DestOpName, false);
-
+
Name = CStr.substr(pos+1);
wpos = Name.find_first_not_of(" \t");
if (wpos == std::string::npos)
throw "Illegal format for tied-to constraint: '" + CStr + "'";
-
+
std::pair<unsigned,unsigned> SrcOp =
I->ParseOperandName(Name.substr(wpos), false);
if (SrcOp > DestOp)
throw "Illegal tied-to operand constraint '" + CStr + "'";
-
-
+
+
unsigned FlatOpNo = I->getFlattenedOperandNumber(SrcOp);
// Build the string for the operand.
std::string OpConstraint =
"((" + utostr(FlatOpNo) + " << 16) | (1 << TOI::TIED_TO))";
-
-
+
if (!I->OperandList[DestOp.first].Constraints[DestOp.second].empty())
throw "Operand '" + DestOpName + "' cannot have multiple constraints!";
I->OperandList[DestOp.first].Constraints[DestOp.second] = OpConstraint;
@@ -56,20 +76,20 @@ static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) {
static void ParseConstraints(const std::string &CStr, CodeGenInstruction *I) {
// Make sure the constraints list for each operand is large enough to hold
// constraint info, even if none is present.
- for (unsigned i = 0, e = I->OperandList.size(); i != e; ++i)
+ for (unsigned i = 0, e = I->OperandList.size(); i != e; ++i)
I->OperandList[i].Constraints.resize(I->OperandList[i].MINumOperands);
-
+
if (CStr.empty()) return;
-
+
const std::string delims(",");
std::string::size_type bidx, eidx;
-
+
bidx = CStr.find_first_not_of(delims);
while (bidx != std::string::npos) {
eidx = CStr.find_first_of(delims, bidx);
if (eidx == std::string::npos)
eidx = CStr.length();
-
+
ParseConstraint(CStr.substr(bidx, eidx - bidx), I);
bidx = CStr.find_first_not_of(delims, eidx);
}
@@ -145,7 +165,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
if (Rec->isSubClassOf("Operand")) {
PrintMethod = Rec->getValueAsString("PrintMethod");
MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
-
+
// Verify that MIOpInfo has an 'ops' root value.
if (!dynamic_cast<DefInit*>(MIOpInfo->getOperator()) ||
dynamic_cast<DefInit*>(MIOpInfo->getOperator())
@@ -165,7 +185,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
} else if (Rec->getName() == "variable_ops") {
isVariadic = true;
continue;
- } else if (!Rec->isSubClassOf("RegisterClass") &&
+ } else if (!Rec->isSubClassOf("RegisterClass") &&
Rec->getName() != "ptr_rc" && Rec->getName() != "unknown")
throw "Unknown operand class '" + Rec->getName() +
"' in '" + R->getName() + "' instruction!";
@@ -177,15 +197,15 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
if (!OperandNames.insert(DI->getArgName(i)).second)
throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
" has the same name as a previous operand!";
-
- OperandList.push_back(OperandInfo(Rec, DI->getArgName(i), PrintMethod,
+
+ OperandList.push_back(OperandInfo(Rec, DI->getArgName(i), PrintMethod,
MIOperandNo, NumOps, MIOpInfo));
MIOperandNo += NumOps;
}
// Parse Constraints.
ParseConstraints(R->getValueAsString("Constraints"), this);
-
+
// For backward compatibility: isTwoAddress means operand 1 is tied to
// operand 0.
if (isTwoAddress) {
@@ -194,13 +214,13 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
"already has constraint set!";
OperandList[1].Constraints[0] = "((0 << 16) | (1 << TOI::TIED_TO))";
}
-
+
// Any operands with unset constraints get 0 as their constraint.
for (unsigned op = 0, e = OperandList.size(); op != e; ++op)
for (unsigned j = 0, e = OperandList[op].MINumOperands; j != e; ++j)
if (OperandList[op].Constraints[j].empty())
OperandList[op].Constraints[j] = "0";
-
+
// Parse the DisableEncoding field.
std::string DisableEncoding = R->getValueAsString("DisableEncoding");
while (1) {
@@ -229,15 +249,15 @@ unsigned CodeGenInstruction::getOperandNamed(const std::string &Name) const {
"' does not have an operand named '$" + Name + "'!";
}
-std::pair<unsigned,unsigned>
+std::pair<unsigned,unsigned>
CodeGenInstruction::ParseOperandName(const std::string &Op,
bool AllowWholeOp) {
if (Op.empty() || Op[0] != '$')
throw TheDef->getName() + ": Illegal operand name: '" + Op + "'";
-
+
std::string OpName = Op.substr(1);
std::string SubOpName;
-
+
// Check to see if this is $foo.bar.
std::string::size_type DotIdx = OpName.find_first_of(".");
if (DotIdx != std::string::npos) {
@@ -246,7 +266,7 @@ CodeGenInstruction::ParseOperandName(const std::string &Op,
throw TheDef->getName() + ": illegal empty suboperand name in '" +Op +"'";
OpName = OpName.substr(0, DotIdx);
}
-
+
unsigned OpIdx = getOperandNamed(OpName);
if (SubOpName.empty()) { // If no suboperand name was specified:
@@ -255,16 +275,16 @@ CodeGenInstruction::ParseOperandName(const std::string &Op,
SubOpName.empty())
throw TheDef->getName() + ": Illegal to refer to"
" whole operand part of complex operand '" + Op + "'";
-
+
// Otherwise, return the operand.
return std::make_pair(OpIdx, 0U);
}
-
+
// Find the suboperand number involved.
DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo;
if (MIOpInfo == 0)
throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'";
-
+
// Find the operand with the right name.
for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i)
if (MIOpInfo->getArgName(i) == SubOpName)
diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp
index 66debe2..a901fd0 100644
--- a/utils/TableGen/DAGISelEmitter.cpp
+++ b/utils/TableGen/DAGISelEmitter.cpp
@@ -1292,8 +1292,8 @@ public:
// possible and it avoids CSE map recalculation for the node's
// users, however it's tricky to use in a non-root context.
//
- // We also don't use if the pattern replacement is being used to
- // jettison a chain result, since morphing the node in place
+ // We also don't use SelectNodeTo if the pattern replacement is being
+ // used to jettison a chain result, since morphing the node in place
// would leave users of the chain dangling.
//
if (!isRoot || (InputHasChain && !NodeHasChain)) {
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index cc13125..61b9b15 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -10,7 +10,86 @@
#include "DisassemblerEmitter.h"
#include "CodeGenTarget.h"
#include "Record.h"
+#include "X86DisassemblerTables.h"
+#include "X86RecognizableInstr.h"
using namespace llvm;
+using namespace llvm::X86Disassembler;
+
+/// DisassemblerEmitter - Contains disassembler table emitters for various
+/// architectures.
+
+/// X86 Disassembler Emitter
+///
+/// *** IF YOU'RE HERE TO RESOLVE A "Primary decode conflict", LOOK DOWN NEAR
+/// THE END OF THIS COMMENT!
+///
+/// The X86 disassembler emitter is part of the X86 Disassembler, which is
+/// documented in lib/Target/X86/X86Disassembler.h.
+///
+/// The emitter produces the tables that the disassembler uses to translate
+/// instructions. The emitter generates the following tables:
+///
+/// - One table (CONTEXTS_SYM) that contains a mapping of attribute masks to
+/// instruction contexts. Although for each attribute there are cases where
+/// that attribute determines decoding, in the majority of cases decoding is
+/// the same whether or not an attribute is present. For example, a 64-bit
+/// instruction with an OPSIZE prefix and an XS prefix decodes the same way in
+/// all cases as a 64-bit instruction with only OPSIZE set. (The XS prefix
+/// may have effects on its execution, but does not change the instruction
+/// returned.) This allows considerable space savings in other tables.
+/// - Four tables (ONEBYTE_SYM, TWOBYTE_SYM, THREEBYTE38_SYM, and
+/// THREEBYTE3A_SYM) contain the hierarchy that the decoder traverses while
+/// decoding an instruction. At the lowest level of this hierarchy are
+/// instruction UIDs, 16-bit integers that can be used to uniquely identify
+/// the instruction and correspond exactly to its position in the list of
+/// CodeGenInstructions for the target.
+/// - One table (INSTRUCTIONS_SYM) contains information about the operands of
+/// each instruction and how to decode them.
+///
+/// During table generation, there may be conflicts between instructions that
+/// occupy the same space in the decode tables. These conflicts are resolved as
+/// follows in setTableFields() (X86DisassemblerTables.cpp)
+///
+/// - If the current context is the native context for one of the instructions
+/// (that is, the attributes specified for it in the LLVM tables specify
+/// precisely the current context), then it has priority.
+/// - If the current context isn't native for either of the instructions, then
+/// the higher-priority context wins (that is, the one that is more specific).
+/// That hierarchy is determined by outranks() (X86DisassemblerTables.cpp)
+/// - If the current context is native for both instructions, then the table
+/// emitter reports a conflict and dies.
+///
+/// *** RESOLUTION FOR "Primary decode conflict"S
+///
+/// If two instructions collide, typically the solution is (in order of
+/// likelihood):
+///
+/// (1) to filter out one of the instructions by editing filter()
+/// (X86RecognizableInstr.cpp). This is the most common resolution, but
+/// check the Intel manuals first to make sure that (2) and (3) are not the
+/// problem.
+/// (2) to fix the tables (X86.td and its subsidiaries) so the opcodes are
+/// accurate. Sometimes they are not.
+/// (3) to fix the tables to reflect the actual context (for example, required
+/// prefixes), and possibly to add a new context by editing
+/// lib/Target/X86/X86DisassemblerDecoderCommon.h. This is unlikely to be
+/// the cause.
+///
+/// DisassemblerEmitter.cpp contains the implementation for the emitter,
+/// which simply pulls out instructions from the CodeGenTarget and pushes them
+/// into X86DisassemblerTables.
+/// X86DisassemblerTables.h contains the interface for the instruction tables,
+/// which manage and emit the structures discussed above.
+/// X86DisassemblerTables.cpp contains the implementation for the instruction
+/// tables.
+/// X86ModRMFilters.h contains filters that can be used to determine which
+/// ModR/M values are valid for a particular instruction. These are used to
+/// populate ModRMDecisions.
+/// X86RecognizableInstr.h contains the interface for a single instruction,
+/// which knows how to translate itself from a CodeGenInstruction and provide
+/// the information necessary for integration into the tables.
+/// X86RecognizableInstr.cpp contains the implementation for a single
+/// instruction.
void DisassemblerEmitter::run(raw_ostream &OS) {
CodeGenTarget Target;
@@ -25,6 +104,26 @@ void DisassemblerEmitter::run(raw_ostream &OS) {
<< " *===---------------------------------------------------------------"
<< "-------===*/\n";
+ // X86 uses a custom disassembler.
+ if (Target.getName() == "X86") {
+ DisassemblerTables Tables;
+
+ std::vector<const CodeGenInstruction*> numberedInstructions;
+ Target.getInstructionsByEnumValue(numberedInstructions);
+
+ for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i)
+ RecognizableInstr::processInstr(Tables, *numberedInstructions[i], i);
+
+ // FIXME: As long as we are using exceptions, might as well drop this to the
+ // actual conflict site.
+ if (Tables.hasConflicts())
+ throw TGError(Target.getTargetRecord()->getLoc(),
+ "Primary decode conflict");
+
+ Tables.emit(OS);
+ return;
+ }
+
throw TGError(Target.getTargetRecord()->getLoc(),
"Unable to generate disassembler for this target");
}
diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp
index 5be9ab7..88fb6c3 100644
--- a/utils/TableGen/LLVMCConfigurationEmitter.cpp
+++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp
@@ -17,6 +17,7 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
+
#include <algorithm>
#include <cassert>
#include <functional>
@@ -26,6 +27,7 @@
using namespace llvm;
+namespace {
//===----------------------------------------------------------------------===//
/// Typedefs
@@ -37,18 +39,16 @@ typedef std::vector<std::string> StrVector;
/// Constants
// Indentation.
-static const unsigned TabWidth = 4;
-static const unsigned Indent1 = TabWidth*1;
-static const unsigned Indent2 = TabWidth*2;
-static const unsigned Indent3 = TabWidth*3;
+const unsigned TabWidth = 4;
+const unsigned Indent1 = TabWidth*1;
+const unsigned Indent2 = TabWidth*2;
+const unsigned Indent3 = TabWidth*3;
// Default help string.
-static const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED";
+const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED";
// Name for the "sink" option.
-static const char * const SinkOptionName = "AutoGeneratedSinkOption";
-
-namespace {
+const char * const SinkOptionName = "AutoGeneratedSinkOption";
//===----------------------------------------------------------------------===//
/// Helper functions
@@ -86,26 +86,30 @@ const DagInit& InitPtrToDag(const Init* ptr) {
return val;
}
-const std::string GetOperatorName(const DagInit* D) {
- return D->getOperator()->getAsString();
+const std::string GetOperatorName(const DagInit& D) {
+ return D.getOperator()->getAsString();
}
-const std::string GetOperatorName(const DagInit& D) {
- return GetOperatorName(&D);
+/// CheckBooleanConstant - Check that the provided value is a boolean constant.
+void CheckBooleanConstant(const Init* I) {
+ const DefInit& val = dynamic_cast<const DefInit&>(*I);
+ const std::string& str = val.getAsString();
+
+ if (str != "true" && str != "false") {
+ throw "Incorrect boolean value: '" + str +
+ "': must be either 'true' or 'false'";
+ }
}
-// checkNumberOfArguments - Ensure that the number of args in d is
+// CheckNumberOfArguments - Ensure that the number of args in d is
// greater than or equal to min_arguments, otherwise throw an exception.
-void checkNumberOfArguments (const DagInit* d, unsigned minArgs) {
- if (!d || d->getNumArgs() < minArgs)
+void CheckNumberOfArguments (const DagInit& d, unsigned minArgs) {
+ if (d.getNumArgs() < minArgs)
throw GetOperatorName(d) + ": too few arguments!";
}
-void checkNumberOfArguments (const DagInit& d, unsigned minArgs) {
- checkNumberOfArguments(&d, minArgs);
-}
-// isDagEmpty - is this DAG marked with an empty marker?
-bool isDagEmpty (const DagInit* d) {
+// IsDagEmpty - is this DAG marked with an empty marker?
+bool IsDagEmpty (const DagInit& d) {
return GetOperatorName(d) == "empty_dag_marker";
}
@@ -132,8 +136,8 @@ std::string EscapeVariableName(const std::string& Var) {
return ret;
}
-/// oneOf - Does the input string contain this character?
-bool oneOf(const char* lst, char c) {
+/// OneOf - Does the input string contain this character?
+bool OneOf(const char* lst, char c) {
while (*lst) {
if (*lst++ == c)
return true;
@@ -142,7 +146,7 @@ bool oneOf(const char* lst, char c) {
}
template <class I, class S>
-void checkedIncrement(I& P, I E, S ErrorString) {
+void CheckedIncrement(I& P, I E, S ErrorString) {
++P;
if (P == E)
throw ErrorString;
@@ -499,17 +503,36 @@ public:
};
+template <class Handler, class FunctionObject>
+Handler GetHandler(FunctionObject* Obj, const DagInit& Dag) {
+ const std::string& HandlerName = GetOperatorName(Dag);
+ return Obj->GetHandler(HandlerName);
+}
+
+template <class FunctionObject>
+void InvokeDagInitHandler(FunctionObject* Obj, Init* I) {
+ typedef void (FunctionObject::*Handler) (const DagInit&);
+
+ const DagInit& Dag = InitPtrToDag(I);
+ Handler h = GetHandler<Handler>(Obj, Dag);
+
+ ((Obj)->*(h))(Dag);
+}
+
template <class FunctionObject>
-void InvokeDagInitHandler(FunctionObject* Obj, Init* i) {
- typedef void (FunctionObject::*Handler) (const DagInit*);
+void InvokeDagInitHandler(const FunctionObject* const Obj,
+ const Init* I, unsigned IndentLevel, raw_ostream& O)
+{
+ typedef void (FunctionObject::*Handler)
+ (const DagInit&, unsigned IndentLevel, raw_ostream& O) const;
- const DagInit& property = InitPtrToDag(i);
- const std::string& property_name = GetOperatorName(property);
- Handler h = Obj->GetHandler(property_name);
+ const DagInit& Dag = InitPtrToDag(I);
+ Handler h = GetHandler<Handler>(Obj, Dag);
- ((Obj)->*(h))(&property);
+ ((Obj)->*(h))(Dag, IndentLevel, O);
}
+
template <typename H>
typename HandlerTable<H>::HandlerMap HandlerTable<H>::Handlers_;
@@ -521,7 +544,7 @@ bool HandlerTable<H>::staticMembersInitialized_ = false;
/// option property list.
class CollectOptionProperties;
typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler)
-(const DagInit*);
+(const DagInit&);
class CollectOptionProperties
: public HandlerTable<CollectOptionPropertiesHandler>
@@ -555,8 +578,8 @@ public:
/// operator() - Just forwards to the corresponding property
/// handler.
- void operator() (Init* i) {
- InvokeDagInitHandler(this, i);
+ void operator() (Init* I) {
+ InvokeDagInitHandler(this, I);
}
private:
@@ -564,44 +587,44 @@ private:
/// Option property handlers --
/// Methods that handle option properties such as (help) or (hidden).
- void onExtern (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onExtern (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
optDesc_.setExtern();
}
- void onHelp (const DagInit* d) {
- checkNumberOfArguments(d, 1);
- optDesc_.Help = InitPtrToString(d->getArg(0));
+ void onHelp (const DagInit& d) {
+ CheckNumberOfArguments(d, 1);
+ optDesc_.Help = InitPtrToString(d.getArg(0));
}
- void onHidden (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onHidden (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
optDesc_.setHidden();
}
- void onReallyHidden (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onReallyHidden (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
optDesc_.setReallyHidden();
}
- void onCommaSeparated (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onCommaSeparated (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
if (!optDesc_.isList())
throw "'comma_separated' is valid only on list options!";
optDesc_.setCommaSeparated();
}
- void onRequired (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onRequired (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
if (optDesc_.isOneOrMore() || optDesc_.isOptional())
throw "Only one of (required), (optional) or "
"(one_or_more) properties is allowed!";
optDesc_.setRequired();
}
- void onInit (const DagInit* d) {
- checkNumberOfArguments(d, 1);
- Init* i = d->getArg(0);
+ void onInit (const DagInit& d) {
+ CheckNumberOfArguments(d, 1);
+ Init* i = d.getArg(0);
const std::string& str = i->getAsString();
bool correct = optDesc_.isParameter() && dynamic_cast<StringInit*>(i);
@@ -613,8 +636,8 @@ private:
optDesc_.InitVal = i;
}
- void onOneOrMore (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onOneOrMore (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
if (optDesc_.isRequired() || optDesc_.isOptional())
throw "Only one of (required), (optional) or "
"(one_or_more) properties is allowed!";
@@ -624,8 +647,8 @@ private:
optDesc_.setOneOrMore();
}
- void onOptional (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onOptional (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
if (optDesc_.isRequired() || optDesc_.isOneOrMore())
throw "Only one of (required), (optional) or "
"(one_or_more) properties is allowed!";
@@ -635,9 +658,9 @@ private:
optDesc_.setOptional();
}
- void onMultiVal (const DagInit* d) {
- checkNumberOfArguments(d, 1);
- int val = InitPtrToInt(d->getArg(0));
+ void onMultiVal (const DagInit& d) {
+ CheckNumberOfArguments(d, 1);
+ int val = InitPtrToInt(d.getArg(0));
if (val < 2)
throw "Error in the 'multi_val' property: "
"the value must be greater than 1!";
@@ -660,7 +683,7 @@ public:
void operator()(const Init* i) {
const DagInit& d = InitPtrToDag(i);
- checkNumberOfArguments(&d, 1);
+ CheckNumberOfArguments(d, 1);
const OptionType::OptionType Type =
stringToOptionType(GetOperatorName(d));
@@ -669,14 +692,14 @@ public:
OptionDescription OD(Type, Name);
if (!OD.isExtern())
- checkNumberOfArguments(&d, 2);
+ CheckNumberOfArguments(d, 2);
if (OD.isAlias()) {
// Aliases store the aliased option name in the 'Help' field.
OD.Help = InitPtrToString(d.getArg(1));
}
else if (!OD.isExtern()) {
- processOptionProperties(&d, OD);
+ processOptionProperties(d, OD);
}
OptDescs_.InsertDescription(OD);
}
@@ -684,12 +707,12 @@ public:
private:
/// processOptionProperties - Go through the list of option
/// properties and call a corresponding handler for each.
- static void processOptionProperties (const DagInit* d, OptionDescription& o) {
- checkNumberOfArguments(d, 2);
- DagInit::const_arg_iterator B = d->arg_begin();
+ static void processOptionProperties (const DagInit& d, OptionDescription& o) {
+ CheckNumberOfArguments(d, 2);
+ DagInit::const_arg_iterator B = d.arg_begin();
// Skip the first argument: it's always the option name.
++B;
- std::for_each(B, d->arg_end(), CollectOptionProperties(o));
+ std::for_each(B, d.arg_end(), CollectOptionProperties(o));
}
};
@@ -750,7 +773,7 @@ typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions;
class CollectToolProperties;
typedef void (CollectToolProperties::* CollectToolPropertiesHandler)
-(const DagInit*);
+(const DagInit&);
class CollectToolProperties : public HandlerTable<CollectToolPropertiesHandler>
{
@@ -779,8 +802,8 @@ public:
}
}
- void operator() (Init* i) {
- InvokeDagInitHandler(this, i);
+ void operator() (Init* I) {
+ InvokeDagInitHandler(this, I);
}
private:
@@ -789,23 +812,23 @@ private:
/// Functions that extract information about tool properties from
/// DAG representation.
- void onActions (const DagInit* d) {
- checkNumberOfArguments(d, 1);
- Init* Case = d->getArg(0);
+ void onActions (const DagInit& d) {
+ CheckNumberOfArguments(d, 1);
+ Init* Case = d.getArg(0);
if (typeid(*Case) != typeid(DagInit) ||
- GetOperatorName(static_cast<DagInit*>(Case)) != "case")
+ GetOperatorName(static_cast<DagInit&>(*Case)) != "case")
throw "The argument to (actions) should be a 'case' construct!";
toolDesc_.Actions = Case;
}
- void onCmdLine (const DagInit* d) {
- checkNumberOfArguments(d, 1);
- toolDesc_.CmdLine = d->getArg(0);
+ void onCmdLine (const DagInit& d) {
+ CheckNumberOfArguments(d, 1);
+ toolDesc_.CmdLine = d.getArg(0);
}
- void onInLanguage (const DagInit* d) {
- checkNumberOfArguments(d, 1);
- Init* arg = d->getArg(0);
+ void onInLanguage (const DagInit& d) {
+ CheckNumberOfArguments(d, 1);
+ Init* arg = d.getArg(0);
// Find out the argument's type.
if (typeid(*arg) == typeid(StringInit)) {
@@ -830,23 +853,23 @@ private:
}
}
- void onJoin (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onJoin (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
toolDesc_.setJoin();
}
- void onOutLanguage (const DagInit* d) {
- checkNumberOfArguments(d, 1);
- toolDesc_.OutLanguage = InitPtrToString(d->getArg(0));
+ void onOutLanguage (const DagInit& d) {
+ CheckNumberOfArguments(d, 1);
+ toolDesc_.OutLanguage = InitPtrToString(d.getArg(0));
}
- void onOutputSuffix (const DagInit* d) {
- checkNumberOfArguments(d, 1);
- toolDesc_.OutputSuffix = InitPtrToString(d->getArg(0));
+ void onOutputSuffix (const DagInit& d) {
+ CheckNumberOfArguments(d, 1);
+ toolDesc_.OutputSuffix = InitPtrToString(d.getArg(0));
}
- void onSink (const DagInit* d) {
- checkNumberOfArguments(d, 0);
+ void onSink (const DagInit& d) {
+ CheckNumberOfArguments(d, 0);
toolDesc_.setSink();
}
@@ -1033,12 +1056,12 @@ void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback,
throw "Case construct handler: no corresponding action "
"found for the test " + Test.getAsString() + '!';
- TestCallback(&Test, IndentLevel, (i == 1));
+ TestCallback(Test, IndentLevel, (i == 1));
}
else
{
if (dynamic_cast<DagInit*>(arg)
- && GetOperatorName(static_cast<DagInit*>(arg)) == "case") {
+ && GetOperatorName(static_cast<DagInit&>(*arg)) == "case") {
// Nested 'case'.
WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1);
}
@@ -1063,14 +1086,28 @@ class ExtractOptionNames {
if (ActionName == "forward" || ActionName == "forward_as" ||
ActionName == "forward_value" ||
ActionName == "forward_transformed_value" ||
- ActionName == "switch_on" || ActionName == "parameter_equals" ||
+ ActionName == "switch_on" || ActionName == "any_switch_on" ||
+ ActionName == "parameter_equals" ||
ActionName == "element_in_list" || ActionName == "not_empty" ||
ActionName == "empty") {
- checkNumberOfArguments(&Stmt, 1);
- const std::string& Name = InitPtrToString(Stmt.getArg(0));
- OptionNames_.insert(Name);
+ CheckNumberOfArguments(Stmt, 1);
+
+ Init* Arg = Stmt.getArg(0);
+ if (typeid(*Arg) == typeid(StringInit)) {
+ const std::string& Name = InitPtrToString(Arg);
+ OptionNames_.insert(Name);
+ }
+ else {
+ // It's a list.
+ const ListInit& List = InitPtrToList(Arg);
+ for (ListInit::const_iterator B = List.begin(), E = List.end();
+ B != E; ++B) {
+ const std::string& Name = InitPtrToString(*B);
+ OptionNames_.insert(Name);
+ }
+ }
}
- else if (ActionName == "and" || ActionName == "or") {
+ else if (ActionName == "and" || ActionName == "or" || ActionName == "not") {
for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
this->processDag(Stmt.getArg(i));
}
@@ -1093,8 +1130,8 @@ public:
}
}
- void operator()(const DagInit* Test, unsigned, bool) {
- this->operator()(Test);
+ void operator()(const DagInit& Test, unsigned, bool) {
+ this->operator()(&Test);
}
void operator()(const Init* Statement, unsigned) {
this->operator()(Statement);
@@ -1125,10 +1162,10 @@ void CheckForSuperfluousOptions (const RecordVector& Edges,
for (RecordVector::const_iterator B = Edges.begin(), E = Edges.end();
B != E; ++B) {
const Record* Edge = *B;
- DagInit* Weight = Edge->getValueAsDag("weight");
+ DagInit& Weight = *Edge->getValueAsDag("weight");
- if (!isDagEmpty(Weight))
- WalkCase(Weight, ExtractOptionNames(nonSuperfluousOptions), Id());
+ if (!IsDagEmpty(Weight))
+ WalkCase(&Weight, ExtractOptionNames(nonSuperfluousOptions), Id());
}
// Check that all options in OptDescs belong to the set of
@@ -1169,7 +1206,7 @@ void EmitListTest(const ListInit& L, const char* LogicOp,
if (isFirst)
isFirst = false;
else
- O << " || ";
+ O << ' ' << LogicOp << ' ';
Callback(InitPtrToString(*B), O);
}
}
@@ -1217,7 +1254,7 @@ bool EmitCaseTest1ArgList(const std::string& TestName,
const DagInit& d,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
- const ListInit& L = *static_cast<ListInit*>(d.getArg(0));
+ const ListInit& L = InitPtrToList(d.getArg(0));
if (TestName == "any_switch_on") {
EmitListTest(L, "||", EmitSwitchOn(OptDescs), O);
@@ -1284,7 +1321,7 @@ bool EmitCaseTest1Arg(const std::string& TestName,
const DagInit& d,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
- checkNumberOfArguments(&d, 1);
+ CheckNumberOfArguments(d, 1);
if (typeid(*d.getArg(0)) == typeid(ListInit))
return EmitCaseTest1ArgList(TestName, d, OptDescs, O);
else
@@ -1297,7 +1334,7 @@ bool EmitCaseTest2Args(const std::string& TestName,
unsigned IndentLevel,
const OptionDescriptions& OptDescs,
raw_ostream& O) {
- checkNumberOfArguments(&d, 2);
+ CheckNumberOfArguments(d, 2);
const std::string& OptName = InitPtrToString(d.getArg(0));
const std::string& OptArg = InitPtrToString(d.getArg(1));
@@ -1348,7 +1385,7 @@ void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
void EmitLogicalNot(const DagInit& d, unsigned IndentLevel,
const OptionDescriptions& OptDescs, raw_ostream& O)
{
- checkNumberOfArguments(&d, 1);
+ CheckNumberOfArguments(d, 1);
const DagInit& InnerTest = InitPtrToDag(d.getArg(0));
O << "! (";
EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
@@ -1374,7 +1411,7 @@ void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
return;
else
- throw TestName + ": unknown edge property!";
+ throw "Unknown test '" + TestName + "' used in the 'case' construct!";
}
@@ -1390,7 +1427,7 @@ public:
: EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O)
{}
- void operator()(const DagInit* Test, unsigned IndentLevel, bool FirstTest)
+ void operator()(const DagInit& Test, unsigned IndentLevel, bool FirstTest)
{
if (GetOperatorName(Test) == "default") {
O_.indent(IndentLevel) << "else {\n";
@@ -1398,7 +1435,7 @@ public:
else {
O_.indent(IndentLevel)
<< ((!FirstTest && EmitElseIf_) ? "else if (" : "if (");
- EmitCaseTest(*Test, IndentLevel, OptDescs_, O_);
+ EmitCaseTest(Test, IndentLevel, OptDescs_, O_);
O_ << ") {\n";
}
}
@@ -1419,7 +1456,7 @@ public:
// Ignore nested 'case' DAG.
if (!(dynamic_cast<const DagInit*>(Statement) &&
- GetOperatorName(static_cast<const DagInit*>(Statement)) == "case")) {
+ GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case")) {
if (typeid(*Statement) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(Statement);
for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
@@ -1452,10 +1489,10 @@ void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel,
EmitCaseStatementCallback<F>(Callback, O), IndentLevel);
}
-/// TokenizeCmdline - converts from
+/// TokenizeCmdLine - converts from
/// "$CALL(HookName, 'Arg1', 'Arg2')/path -arg1 -arg2" to
/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path", "-arg1", "-arg2"].
-void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
+void TokenizeCmdLine(const std::string& CmdLine, StrVector& Out) {
const char* Delimiters = " \t\n\v\f\r";
enum TokenizerState
{ Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
@@ -1477,7 +1514,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
cur_st = SpecialCommand;
break;
}
- if (oneOf(Delimiters, cur_ch)) {
+ if (OneOf(Delimiters, cur_ch)) {
// Skip whitespace
B = CmdLine.find_first_not_of(Delimiters, B);
if (B == std::string::npos) {
@@ -1492,7 +1529,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
case SpecialCommand:
- if (oneOf(Delimiters, cur_ch)) {
+ if (OneOf(Delimiters, cur_ch)) {
cur_st = Normal;
Out.push_back("");
continue;
@@ -1505,7 +1542,7 @@ void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
break;
case InsideSpecialCommand:
- if (oneOf(Delimiters, cur_ch)) {
+ if (OneOf(Delimiters, cur_ch)) {
continue;
}
if (cur_ch == '\'') {
@@ -1544,7 +1581,7 @@ SubstituteCall (StrVector::const_iterator Pos,
bool IsJoin, raw_ostream& O)
{
const char* errorMessage = "Syntax error in $CALL invocation!";
- checkedIncrement(Pos, End, errorMessage);
+ CheckedIncrement(Pos, End, errorMessage);
const std::string& CmdName = *Pos;
if (CmdName == ")")
@@ -1556,7 +1593,7 @@ SubstituteCall (StrVector::const_iterator Pos,
bool firstIteration = true;
while (true) {
- checkedIncrement(Pos, End, errorMessage);
+ CheckedIncrement(Pos, End, errorMessage);
const std::string& Arg = *Pos;
assert(Arg.size() != 0);
@@ -1591,7 +1628,7 @@ SubstituteEnv (StrVector::const_iterator Pos,
StrVector::const_iterator End, raw_ostream& O)
{
const char* errorMessage = "Syntax error in $ENV invocation!";
- checkedIncrement(Pos, End, errorMessage);
+ CheckedIncrement(Pos, End, errorMessage);
const std::string& EnvName = *Pos;
if (EnvName == ")")
@@ -1601,7 +1638,7 @@ SubstituteEnv (StrVector::const_iterator Pos,
O << EnvName;
O << "\"))";
- checkedIncrement(Pos, End, errorMessage);
+ CheckedIncrement(Pos, End, errorMessage);
return Pos;
}
@@ -1642,7 +1679,7 @@ void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
bool IsJoin, unsigned IndentLevel,
raw_ostream& O) {
StrVector StrVec;
- TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
+ TokenizeCmdLine(InitPtrToString(CmdLine), StrVec);
if (StrVec.empty())
throw "Tool '" + ToolName + "' has empty command line!";
@@ -1786,7 +1823,8 @@ void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
/// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and
/// EmitPreprocessOptionsCallback.
-struct ActionHandlingCallbackBase {
+struct ActionHandlingCallbackBase
+{
void onErrorDag(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const
@@ -1801,7 +1839,7 @@ struct ActionHandlingCallbackBase {
void onWarningDag(const DagInit& d,
unsigned IndentLevel, raw_ostream& O) const
{
- checkNumberOfArguments(&d, 1);
+ CheckNumberOfArguments(d, 1);
O.indent(IndentLevel) << "llvm::errs() << \""
<< InitPtrToString(d.getArg(0)) << "\";\n";
}
@@ -1810,17 +1848,20 @@ struct ActionHandlingCallbackBase {
/// EmitActionHandlersCallback - Emit code that handles actions. Used by
/// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler().
+
class EmitActionHandlersCallback;
+
typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler)
(const DagInit&, unsigned, raw_ostream&) const;
-class EmitActionHandlersCallback
-: public ActionHandlingCallbackBase,
+class EmitActionHandlersCallback :
+ public ActionHandlingCallbackBase,
public HandlerTable<EmitActionHandlersCallbackHandler>
{
- const OptionDescriptions& OptDescs;
typedef EmitActionHandlersCallbackHandler Handler;
+ const OptionDescriptions& OptDescs;
+
/// EmitHookInvocation - Common code for hook invocation from actions. Used by
/// onAppendCmd and onOutputSuffix.
void EmitHookInvocation(const std::string& Str,
@@ -1828,7 +1869,7 @@ class EmitActionHandlersCallback
unsigned IndentLevel, raw_ostream& O) const
{
StrVector Out;
- TokenizeCmdline(Str, Out);
+ TokenizeCmdLine(Str, Out);
for (StrVector::const_iterator B = Out.begin(), E = Out.end();
B != E; ++B) {
@@ -1848,7 +1889,7 @@ class EmitActionHandlersCallback
void onAppendCmd (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
- checkNumberOfArguments(&Dag, 1);
+ CheckNumberOfArguments(Dag, 1);
this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
"vec.push_back(", ");\n", IndentLevel, O);
}
@@ -1856,7 +1897,7 @@ class EmitActionHandlersCallback
void onForward (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
- checkNumberOfArguments(&Dag, 1);
+ CheckNumberOfArguments(Dag, 1);
const std::string& Name = InitPtrToString(Dag.getArg(0));
EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
IndentLevel, "", O);
@@ -1865,7 +1906,7 @@ class EmitActionHandlersCallback
void onForwardAs (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
- checkNumberOfArguments(&Dag, 2);
+ CheckNumberOfArguments(Dag, 2);
const std::string& Name = InitPtrToString(Dag.getArg(0));
const std::string& NewName = InitPtrToString(Dag.getArg(1));
EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
@@ -1875,7 +1916,7 @@ class EmitActionHandlersCallback
void onForwardValue (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
- checkNumberOfArguments(&Dag, 1);
+ CheckNumberOfArguments(Dag, 1);
const std::string& Name = InitPtrToString(Dag.getArg(0));
const OptionDescription& D = OptDescs.FindListOrParameter(Name);
@@ -1893,7 +1934,7 @@ class EmitActionHandlersCallback
void onForwardTransformedValue (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
- checkNumberOfArguments(&Dag, 2);
+ CheckNumberOfArguments(Dag, 2);
const std::string& Name = InitPtrToString(Dag.getArg(0));
const std::string& Hook = InitPtrToString(Dag.getArg(1));
const OptionDescription& D = OptDescs.FindListOrParameter(Name);
@@ -1906,7 +1947,7 @@ class EmitActionHandlersCallback
void onOutputSuffix (const DagInit& Dag,
unsigned IndentLevel, raw_ostream& O) const
{
- checkNumberOfArguments(&Dag, 1);
+ CheckNumberOfArguments(Dag, 1);
this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
"output_suffix = ", ";\n", IndentLevel, O);
}
@@ -1949,20 +1990,16 @@ class EmitActionHandlersCallback
}
}
- void operator()(const Init* Statement,
+ void operator()(const Init* I,
unsigned IndentLevel, raw_ostream& O) const
{
- const DagInit& Dag = InitPtrToDag(Statement);
- const std::string& ActionName = GetOperatorName(Dag);
- Handler h = GetHandler(ActionName);
-
- ((this)->*(h))(Dag, IndentLevel, O);
+ InvokeDagInitHandler(this, I, IndentLevel, O);
}
};
bool IsOutFileIndexCheckRequiredStr (const Init* CmdLine) {
StrVector StrVec;
- TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
+ TokenizeCmdLine(InitPtrToString(CmdLine), StrVec);
for (StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
I != E; ++I) {
@@ -2280,11 +2317,46 @@ void EmitOptionDefinitions (const OptionDescriptions& descs,
/// EmitPreprocessOptionsCallback - Helper function passed to
/// EmitCaseConstructHandler() by EmitPreprocessOptions().
-class EmitPreprocessOptionsCallback : ActionHandlingCallbackBase {
+
+class EmitPreprocessOptionsCallback;
+
+typedef void
+(EmitPreprocessOptionsCallback::* EmitPreprocessOptionsCallbackHandler)
+(const DagInit&, unsigned, raw_ostream&) const;
+
+class EmitPreprocessOptionsCallback :
+ public ActionHandlingCallbackBase,
+ public HandlerTable<EmitPreprocessOptionsCallbackHandler>
+{
+ typedef EmitPreprocessOptionsCallbackHandler Handler;
+ typedef void
+ (EmitPreprocessOptionsCallback::* HandlerImpl)
+ (const Init*, unsigned, raw_ostream&) const;
+
const OptionDescriptions& OptDescs_;
- void onUnsetOption(Init* i, unsigned IndentLevel, raw_ostream& O) {
- const std::string& OptName = InitPtrToString(i);
+ void onListOrDag(const DagInit& d, HandlerImpl h,
+ unsigned IndentLevel, raw_ostream& O) const
+ {
+ CheckNumberOfArguments(d, 1);
+ const Init* I = d.getArg(0);
+
+ // If I is a list, apply h to each element.
+ if (typeid(*I) == typeid(ListInit)) {
+ const ListInit& L = *static_cast<const ListInit*>(I);
+ for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B)
+ ((this)->*(h))(*B, IndentLevel, O);
+ }
+ // Otherwise, apply h to I.
+ else {
+ ((this)->*(h))(I, IndentLevel, O);
+ }
+ }
+
+ void onUnsetOptionImpl(const Init* I,
+ unsigned IndentLevel, raw_ostream& O) const
+ {
+ const std::string& OptName = InitPtrToString(I);
const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
if (OptDesc.isSwitch()) {
@@ -2301,45 +2373,93 @@ class EmitPreprocessOptionsCallback : ActionHandlingCallbackBase {
}
}
- void processDag(const Init* I, unsigned IndentLevel, raw_ostream& O)
+ void onUnsetOption(const DagInit& d,
+ unsigned IndentLevel, raw_ostream& O) const
{
- const DagInit& d = InitPtrToDag(I);
- const std::string& OpName = GetOperatorName(d);
+ this->onListOrDag(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
+ IndentLevel, O);
+ }
+
+ void onSetOptionImpl(const DagInit& d,
+ unsigned IndentLevel, raw_ostream& O) const {
+ CheckNumberOfArguments(d, 2);
+ const std::string& OptName = InitPtrToString(d.getArg(0));
+ const Init* Value = d.getArg(1);
+ const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
- if (OpName == "warning") {
- this->onWarningDag(d, IndentLevel, O);
+ if (OptDesc.isList()) {
+ const ListInit& List = InitPtrToList(Value);
+
+ O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
+ for (ListInit::const_iterator B = List.begin(), E = List.end();
+ B != E; ++B) {
+ O.indent(IndentLevel) << OptDesc.GenVariableName() << ".push_back(\""
+ << InitPtrToString(*B) << "\");\n";
+ }
}
- else if (OpName == "error") {
- this->onWarningDag(d, IndentLevel, O);
+ else if (OptDesc.isSwitch()) {
+ CheckBooleanConstant(Value);
+ O.indent(IndentLevel) << OptDesc.GenVariableName()
+ << " = " << Value->getAsString() << ";\n";
}
- else if (OpName == "unset_option") {
- checkNumberOfArguments(&d, 1);
- Init* I = d.getArg(0);
- if (typeid(*I) == typeid(ListInit)) {
- const ListInit& DagList = *static_cast<const ListInit*>(I);
- for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
- B != E; ++B)
- this->onUnsetOption(*B, IndentLevel, O);
- }
- else {
- this->onUnsetOption(I, IndentLevel, O);
- }
+ else if (OptDesc.isParameter()) {
+ const std::string& Str = InitPtrToString(Value);
+ O.indent(IndentLevel) << OptDesc.GenVariableName()
+ << " = \"" << Str << "\";\n";
}
else {
- throw "Unknown operator in the option preprocessor: '" + OpName + "'!"
- "\nOnly 'warning', 'error' and 'unset_option' are allowed.";
+ throw "Can't apply 'set_option' to alias option -" + OptName + " !";
}
}
-public:
+ void onSetSwitch(const Init* I,
+ unsigned IndentLevel, raw_ostream& O) const {
+ const std::string& OptName = InitPtrToString(I);
+ const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
- void operator()(const Init* I, unsigned IndentLevel, raw_ostream& O) {
- this->processDag(I, IndentLevel, O);
+ if (OptDesc.isSwitch())
+ O.indent(IndentLevel) << OptDesc.GenVariableName() << " = true;\n";
+ else
+ throw "set_option: -" + OptName + " is not a switch option!";
+ }
+
+ void onSetOption(const DagInit& d,
+ unsigned IndentLevel, raw_ostream& O) const
+ {
+ CheckNumberOfArguments(d, 1);
+
+ // Two arguments: (set_option "parameter", VALUE), where VALUE can be a
+ // boolean, a string or a string list.
+ if (d.getNumArgs() > 1)
+ this->onSetOptionImpl(d, IndentLevel, O);
+ // One argument: (set_option "switch")
+ // or (set_option ["switch1", "switch2", ...])
+ else
+ this->onListOrDag(d, &EmitPreprocessOptionsCallback::onSetSwitch,
+ IndentLevel, O);
}
+public:
+
EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs)
: OptDescs_(OptDescs)
- {}
+ {
+ if (!staticMembersInitialized_) {
+ AddHandler("error", &EmitPreprocessOptionsCallback::onErrorDag);
+ AddHandler("warning", &EmitPreprocessOptionsCallback::onWarningDag);
+ AddHandler("unset_option", &EmitPreprocessOptionsCallback::onUnsetOption);
+ AddHandler("set_option", &EmitPreprocessOptionsCallback::onSetOption);
+
+ staticMembersInitialized_ = true;
+ }
+ }
+
+ void operator()(const Init* I,
+ unsigned IndentLevel, raw_ostream& O) const
+ {
+ InvokeDagInitHandler(this, I, IndentLevel, O);
+ }
+
};
/// EmitPreprocessOptions - Emit the PreprocessOptionsLocal() function.
@@ -2407,7 +2527,7 @@ void IncDecWeight (const Init* i, unsigned IndentLevel,
O.indent(IndentLevel) << "ret -= ";
}
else if (OpName == "error") {
- checkNumberOfArguments(&d, 1);
+ CheckNumberOfArguments(d, 1);
O.indent(IndentLevel) << "throw std::runtime_error(\""
<< InitPtrToString(d.getArg(0))
<< "\");\n";
@@ -2445,7 +2565,7 @@ void EmitEdgeClass (unsigned N, const std::string& Target,
EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O);
O.indent(Indent2) << "return ret;\n";
- O.indent(Indent1) << "};\n\n};\n\n";
+ O.indent(Indent1) << "}\n\n};\n\n";
}
/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
@@ -2457,10 +2577,10 @@ void EmitEdgeClasses (const RecordVector& EdgeVector,
E = EdgeVector.end(); B != E; ++B) {
const Record* Edge = *B;
const std::string& NodeB = Edge->getValueAsString("b");
- DagInit* Weight = Edge->getValueAsDag("weight");
+ DagInit& Weight = *Edge->getValueAsDag("weight");
- if (!isDagEmpty(Weight))
- EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
+ if (!IsDagEmpty(Weight))
+ EmitEdgeClass(i, NodeB, &Weight, OptDescs, O);
++i;
}
}
@@ -2487,11 +2607,11 @@ void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
const Record* Edge = *B;
const std::string& NodeA = Edge->getValueAsString("a");
const std::string& NodeB = Edge->getValueAsString("b");
- DagInit* Weight = Edge->getValueAsDag("weight");
+ DagInit& Weight = *Edge->getValueAsDag("weight");
O.indent(Indent1) << "G.insertEdge(\"" << NodeA << "\", ";
- if (isDagEmpty(Weight))
+ if (IsDagEmpty(Weight))
O << "new SimpleEdge(\"" << NodeB << "\")";
else
O << "new Edge" << i << "()";
@@ -2540,7 +2660,7 @@ public:
const std::string& Name = GetOperatorName(Dag);
if (Name == "forward_transformed_value") {
- checkNumberOfArguments(Dag, 2);
+ CheckNumberOfArguments(Dag, 2);
const std::string& OptName = InitPtrToString(Dag.getArg(0));
const std::string& HookName = InitPtrToString(Dag.getArg(1));
const OptionDescription& D = OptDescs_.FindOption(OptName);
@@ -2549,14 +2669,14 @@ public:
: HookInfo::ArgHook);
}
else if (Name == "append_cmd" || Name == "output_suffix") {
- checkNumberOfArguments(Dag, 1);
+ CheckNumberOfArguments(Dag, 1);
this->onCmdLine(InitPtrToString(Dag.getArg(0)));
}
}
void onCmdLine(const std::string& Cmd) {
StrVector cmds;
- TokenizeCmdline(Cmd, cmds);
+ TokenizeCmdLine(Cmd, cmds);
for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
B != E; ++B) {
@@ -2564,7 +2684,7 @@ public:
if (cmd == "$CALL") {
unsigned NumArgs = 0;
- checkedIncrement(B, E, "Syntax error in $CALL invocation!");
+ CheckedIncrement(B, E, "Syntax error in $CALL invocation!");
const std::string& HookName = *B;
if (HookName.at(0) == ')')
@@ -2789,7 +2909,6 @@ void CheckPluginData(PluginData& Data) {
// Check that there are no options without side effects (specified
// only in the OptionList).
CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
-
}
void EmitPluginCode(const PluginData& Data, raw_ostream& O) {
diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp
index 53f9014..542735e 100644
--- a/utils/TableGen/Record.cpp
+++ b/utils/TableGen/Record.cpp
@@ -945,11 +945,13 @@ Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
std::string Val = RHSs->getValue();
std::string::size_type found;
+ std::string::size_type idx = 0;
do {
- found = Val.find(LHSs->getValue());
+ found = Val.find(LHSs->getValue(), idx);
if (found != std::string::npos) {
Val.replace(found, LHSs->getValue().size(), MHSs->getValue());
}
+ idx = found + MHSs->getValue().size();
} while (found != std::string::npos);
return new StringInit(Val);
diff --git a/utils/TableGen/X86DisassemblerShared.h b/utils/TableGen/X86DisassemblerShared.h
new file mode 100644
index 0000000..0417e9d
--- /dev/null
+++ b/utils/TableGen/X86DisassemblerShared.h
@@ -0,0 +1,38 @@
+//===- X86DisassemblerShared.h - Emitter shared header ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86DISASSEMBLERSHARED_H
+#define X86DISASSEMBLERSHARED_H
+
+#include <string>
+#include <string.h>
+
+#define INSTRUCTION_SPECIFIER_FIELDS \
+ bool filtered; \
+ InstructionContext insnContext; \
+ std::string name; \
+ \
+ InstructionSpecifier() { \
+ filtered = false; \
+ insnContext = IC; \
+ name = ""; \
+ modifierType = MODIFIER_NONE; \
+ modifierBase = 0; \
+ memset(operands, 0, sizeof(operands)); \
+ }
+
+#define INSTRUCTION_IDS \
+ InstrUID instructionIDs[256];
+
+#include "../../lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h"
+
+#undef INSTRUCTION_SPECIFIER_FIELDS
+#undef INSTRUCTION_IDS
+
+#endif
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
new file mode 100644
index 0000000..be07031
--- /dev/null
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -0,0 +1,603 @@
+//===- X86DisassemblerTables.cpp - Disassembler tables ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the X86 Disassembler Emitter.
+// It contains the implementation of the disassembler tables.
+// Documentation for the disassembler emitter in general can be found in
+// X86DisasemblerEmitter.h.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86DisassemblerShared.h"
+#include "X86DisassemblerTables.h"
+
+#include "TableGenBackend.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace X86Disassembler;
+
+/// inheritsFrom - Indicates whether all instructions in one class also belong
+/// to another class.
+///
+/// @param child - The class that may be the subset
+/// @param parent - The class that may be the superset
+/// @return - True if child is a subset of parent, false otherwise.
+static inline bool inheritsFrom(InstructionContext child,
+ InstructionContext parent) {
+ if (child == parent)
+ return true;
+
+ switch (parent) {
+ case IC:
+ return true;
+ case IC_64BIT:
+ return(inheritsFrom(child, IC_64BIT_REXW) ||
+ inheritsFrom(child, IC_64BIT_OPSIZE) ||
+ inheritsFrom(child, IC_64BIT_XD) ||
+ inheritsFrom(child, IC_64BIT_XS));
+ case IC_OPSIZE:
+ return(inheritsFrom(child, IC_64BIT_OPSIZE));
+ case IC_XD:
+ return(inheritsFrom(child, IC_64BIT_XD));
+ case IC_XS:
+ return(inheritsFrom(child, IC_64BIT_XS));
+ case IC_64BIT_REXW:
+ return(inheritsFrom(child, IC_64BIT_REXW_XS) ||
+ inheritsFrom(child, IC_64BIT_REXW_XD) ||
+ inheritsFrom(child, IC_64BIT_REXW_OPSIZE));
+ case IC_64BIT_OPSIZE:
+ return(inheritsFrom(child, IC_64BIT_REXW_OPSIZE));
+ case IC_64BIT_XD:
+ return(inheritsFrom(child, IC_64BIT_REXW_XD));
+ case IC_64BIT_XS:
+ return(inheritsFrom(child, IC_64BIT_REXW_XS));
+ case IC_64BIT_REXW_XD:
+ return false;
+ case IC_64BIT_REXW_XS:
+ return false;
+ case IC_64BIT_REXW_OPSIZE:
+ return false;
+ default:
+ return false;
+ }
+}
+
+/// outranks - Indicates whether, if an instruction has two different applicable
+/// classes, which class should be preferred when performing decode. This
+/// imposes a total ordering (ties are resolved toward "lower")
+///
+/// @param upper - The class that may be preferable
+/// @param lower - The class that may be less preferable
+/// @return - True if upper is to be preferred, false otherwise.
+static inline bool outranks(InstructionContext upper,
+ InstructionContext lower) {
+ assert(upper < IC_max);
+ assert(lower < IC_max);
+
+#define ENUM_ENTRY(n, r, d) r,
+ static int ranks[IC_max] = {
+ INSTRUCTION_CONTEXTS
+ };
+#undef ENUM_ENTRY
+
+ return (ranks[upper] > ranks[lower]);
+}
+
+/// stringForContext - Returns a string containing the name of a particular
+/// InstructionContext, usually for diagnostic purposes.
+///
+/// @param insnContext - The instruction class to transform to a string.
+/// @return - A statically-allocated string constant that contains the
+/// name of the instruction class.
+static inline const char* stringForContext(InstructionContext insnContext) {
+ switch (insnContext) {
+ default:
+ llvm_unreachable("Unhandled instruction class");
+#define ENUM_ENTRY(n, r, d) case n: return #n; break;
+ INSTRUCTION_CONTEXTS
+#undef ENUM_ENTRY
+ }
+
+ return 0;
+}
+
+/// stringForOperandType - Like stringForContext, but for OperandTypes.
+static inline const char* stringForOperandType(OperandType type) {
+ switch (type) {
+ default:
+ llvm_unreachable("Unhandled type");
+#define ENUM_ENTRY(i, d) case i: return #i;
+ TYPES
+#undef ENUM_ENTRY
+ }
+}
+
+/// stringForOperandEncoding - like stringForContext, but for
+/// OperandEncodings.
+static inline const char* stringForOperandEncoding(OperandEncoding encoding) {
+ switch (encoding) {
+ default:
+ llvm_unreachable("Unhandled encoding");
+#define ENUM_ENTRY(i, d) case i: return #i;
+ ENCODINGS
+#undef ENUM_ENTRY
+ }
+}
+
+void DisassemblerTables::emitOneID(raw_ostream &o,
+ uint32_t &i,
+ InstrUID id,
+ bool addComma) const {
+ if (id)
+ o.indent(i * 2) << format("0x%hx", id);
+ else
+ o.indent(i * 2) << 0;
+
+ if (addComma)
+ o << ", ";
+ else
+ o << " ";
+
+ o << "/* ";
+ o << InstructionSpecifiers[id].name;
+ o << "*/";
+
+ o << "\n";
+}
+
+/// emitEmptyTable - Emits the modRMEmptyTable, which is used as a ID table by
+/// all ModR/M decisions for instructions that are invalid for all possible
+/// ModR/M byte values.
+///
+/// @param o - The output stream on which to emit the table.
+/// @param i - The indentation level for that output stream.
+static void emitEmptyTable(raw_ostream &o, uint32_t &i)
+{
+ o.indent(i * 2) << "InstrUID modRMEmptyTable[1] = { 0 };" << "\n";
+ o << "\n";
+}
+
+/// getDecisionType - Determines whether a ModRM decision with 255 entries can
+/// be compacted by eliminating redundant information.
+///
+/// @param decision - The decision to be compacted.
+/// @return - The compactest available representation for the decision.
+static ModRMDecisionType getDecisionType(ModRMDecision &decision)
+{
+ bool satisfiesOneEntry = true;
+ bool satisfiesSplitRM = true;
+
+ uint16_t index;
+
+ for (index = 0; index < 256; ++index) {
+ if (decision.instructionIDs[index] != decision.instructionIDs[0])
+ satisfiesOneEntry = false;
+
+ if (((index & 0xc0) == 0xc0) &&
+ (decision.instructionIDs[index] != decision.instructionIDs[0xc0]))
+ satisfiesSplitRM = false;
+
+ if (((index & 0xc0) != 0xc0) &&
+ (decision.instructionIDs[index] != decision.instructionIDs[0x00]))
+ satisfiesSplitRM = false;
+ }
+
+ if (satisfiesOneEntry)
+ return MODRM_ONEENTRY;
+
+ if (satisfiesSplitRM)
+ return MODRM_SPLITRM;
+
+ return MODRM_FULL;
+}
+
+/// stringForDecisionType - Returns a statically-allocated string corresponding
+/// to a particular decision type.
+///
+/// @param dt - The decision type.
+/// @return - A pointer to the statically-allocated string (e.g.,
+/// "MODRM_ONEENTRY" for MODRM_ONEENTRY).
+static const char* stringForDecisionType(ModRMDecisionType dt)
+{
+#define ENUM_ENTRY(n) case n: return #n;
+ switch (dt) {
+ default:
+ llvm_unreachable("Unknown decision type");
+ MODRMTYPES
+ };
+#undef ENUM_ENTRY
+}
+
+/// stringForModifierType - Returns a statically-allocated string corresponding
+/// to an opcode modifier type.
+///
+/// @param mt - The modifier type.
+/// @return - A pointer to the statically-allocated string (e.g.,
+/// "MODIFIER_NONE" for MODIFIER_NONE).
+static const char* stringForModifierType(ModifierType mt)
+{
+#define ENUM_ENTRY(n) case n: return #n;
+ switch(mt) {
+ default:
+ llvm_unreachable("Unknown modifier type");
+ MODIFIER_TYPES
+ };
+#undef ENUM_ENTRY
+}
+
+DisassemblerTables::DisassemblerTables() {
+ unsigned i;
+
+ for (i = 0; i < 4; i++) {
+ Tables[i] = new ContextDecision;
+ memset(Tables[i], 0, sizeof(ContextDecision));
+ }
+
+ HasConflicts = false;
+}
+
+DisassemblerTables::~DisassemblerTables() {
+ unsigned i;
+
+ for (i = 0; i < 4; i++)
+ delete Tables[i];
+}
+
+void DisassemblerTables::emitModRMDecision(raw_ostream &o1,
+ raw_ostream &o2,
+ uint32_t &i1,
+ uint32_t &i2,
+ ModRMDecision &decision)
+ const {
+ static uint64_t sTableNumber = 0;
+ uint64_t thisTableNumber = sTableNumber;
+ ModRMDecisionType dt = getDecisionType(decision);
+ uint16_t index;
+
+ if (dt == MODRM_ONEENTRY && decision.instructionIDs[0] == 0)
+ {
+ o2.indent(i2) << "{ /* ModRMDecision */" << "\n";
+ i2++;
+
+ o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
+ o2.indent(i2) << "modRMEmptyTable";
+
+ i2--;
+ o2.indent(i2) << "}";
+ return;
+ }
+
+ o1.indent(i1) << "InstrUID modRMTable" << thisTableNumber;
+
+ switch (dt) {
+ default:
+ llvm_unreachable("Unknown decision type");
+ case MODRM_ONEENTRY:
+ o1 << "[1]";
+ break;
+ case MODRM_SPLITRM:
+ o1 << "[2]";
+ break;
+ case MODRM_FULL:
+ o1 << "[256]";
+ break;
+ }
+
+ o1 << " = {" << "\n";
+ i1++;
+
+ switch (dt) {
+ default:
+ llvm_unreachable("Unknown decision type");
+ case MODRM_ONEENTRY:
+ emitOneID(o1, i1, decision.instructionIDs[0], false);
+ break;
+ case MODRM_SPLITRM:
+ emitOneID(o1, i1, decision.instructionIDs[0x00], true); // mod = 0b00
+ emitOneID(o1, i1, decision.instructionIDs[0xc0], false); // mod = 0b11
+ break;
+ case MODRM_FULL:
+ for (index = 0; index < 256; ++index)
+ emitOneID(o1, i1, decision.instructionIDs[index], index < 255);
+ break;
+ }
+
+ i1--;
+ o1.indent(i1) << "};" << "\n";
+ o1 << "\n";
+
+ o2.indent(i2) << "{ /* struct ModRMDecision */" << "\n";
+ i2++;
+
+ o2.indent(i2) << stringForDecisionType(dt) << "," << "\n";
+ o2.indent(i2) << "modRMTable" << sTableNumber << "\n";
+
+ i2--;
+ o2.indent(i2) << "}";
+
+ ++sTableNumber;
+}
+
+void DisassemblerTables::emitOpcodeDecision(
+ raw_ostream &o1,
+ raw_ostream &o2,
+ uint32_t &i1,
+ uint32_t &i2,
+ OpcodeDecision &decision) const {
+ uint16_t index;
+
+ o2.indent(i2) << "{ /* struct OpcodeDecision */" << "\n";
+ i2++;
+ o2.indent(i2) << "{" << "\n";
+ i2++;
+
+ for (index = 0; index < 256; ++index) {
+ o2.indent(i2);
+
+ o2 << "/* 0x" << format("%02hhx", index) << " */" << "\n";
+
+ emitModRMDecision(o1, o2, i1, i2, decision.modRMDecisions[index]);
+
+ if (index < 255)
+ o2 << ",";
+
+ o2 << "\n";
+ }
+
+ i2--;
+ o2.indent(i2) << "}" << "\n";
+ i2--;
+ o2.indent(i2) << "}" << "\n";
+}
+
+void DisassemblerTables::emitContextDecision(
+ raw_ostream &o1,
+ raw_ostream &o2,
+ uint32_t &i1,
+ uint32_t &i2,
+ ContextDecision &decision,
+ const char* name) const {
+ o2.indent(i2) << "struct ContextDecision " << name << " = {" << "\n";
+ i2++;
+ o2.indent(i2) << "{ /* opcodeDecisions */" << "\n";
+ i2++;
+
+ unsigned index;
+
+ for (index = 0; index < IC_max; ++index) {
+ o2.indent(i2) << "/* ";
+ o2 << stringForContext((InstructionContext)index);
+ o2 << " */";
+ o2 << "\n";
+
+ emitOpcodeDecision(o1, o2, i1, i2, decision.opcodeDecisions[index]);
+
+ if (index + 1 < IC_max)
+ o2 << ", ";
+ }
+
+ i2--;
+ o2.indent(i2) << "}" << "\n";
+ i2--;
+ o2.indent(i2) << "};" << "\n";
+}
+
+void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i)
+ const {
+ o.indent(i * 2) << "struct InstructionSpecifier ";
+ o << INSTRUCTIONS_STR << "[";
+ o << InstructionSpecifiers.size();
+ o << "] = {" << "\n";
+
+ i++;
+
+ uint16_t numInstructions = InstructionSpecifiers.size();
+ uint16_t index, operandIndex;
+
+ for (index = 0; index < numInstructions; ++index) {
+ o.indent(i * 2) << "{ /* " << index << " */" << "\n";
+ i++;
+
+ o.indent(i * 2) <<
+ stringForModifierType(InstructionSpecifiers[index].modifierType);
+ o << "," << "\n";
+
+ o.indent(i * 2) << "0x";
+ o << format("%02hhx", (uint16_t)InstructionSpecifiers[index].modifierBase);
+ o << "," << "\n";
+
+ o.indent(i * 2) << "{" << "\n";
+ i++;
+
+ for (operandIndex = 0; operandIndex < X86_MAX_OPERANDS; ++operandIndex) {
+ o.indent(i * 2) << "{ ";
+ o << stringForOperandEncoding(InstructionSpecifiers[index]
+ .operands[operandIndex]
+ .encoding);
+ o << ", ";
+ o << stringForOperandType(InstructionSpecifiers[index]
+ .operands[operandIndex]
+ .type);
+ o << " }";
+
+ if (operandIndex < X86_MAX_OPERANDS - 1)
+ o << ",";
+
+ o << "\n";
+ }
+
+ i--;
+ o.indent(i * 2) << "}," << "\n";
+
+ o.indent(i * 2) << "\"" << InstructionSpecifiers[index].name << "\"";
+ o << "\n";
+
+ i--;
+ o.indent(i * 2) << "}";
+
+ if (index + 1 < numInstructions)
+ o << ",";
+
+ o << "\n";
+ }
+
+ i--;
+ o.indent(i * 2) << "};" << "\n";
+}
+
+void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const {
+ uint16_t index;
+
+ o.indent(i * 2) << "InstructionContext ";
+ o << CONTEXTS_STR << "[256] = {" << "\n";
+ i++;
+
+ for (index = 0; index < 256; ++index) {
+ o.indent(i * 2);
+
+ if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
+ o << "IC_64BIT_REXW_XS";
+ else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
+ o << "IC_64BIT_REXW_XD";
+ else if ((index & ATTR_64BIT) && (index & ATTR_REXW) &&
+ (index & ATTR_OPSIZE))
+ o << "IC_64BIT_REXW_OPSIZE";
+ else if ((index & ATTR_64BIT) && (index & ATTR_XS))
+ o << "IC_64BIT_XS";
+ else if ((index & ATTR_64BIT) && (index & ATTR_XD))
+ o << "IC_64BIT_XD";
+ else if ((index & ATTR_64BIT) && (index & ATTR_OPSIZE))
+ o << "IC_64BIT_OPSIZE";
+ else if ((index & ATTR_64BIT) && (index & ATTR_REXW))
+ o << "IC_64BIT_REXW";
+ else if ((index & ATTR_64BIT))
+ o << "IC_64BIT";
+ else if (index & ATTR_XS)
+ o << "IC_XS";
+ else if (index & ATTR_XD)
+ o << "IC_XD";
+ else if (index & ATTR_OPSIZE)
+ o << "IC_OPSIZE";
+ else
+ o << "IC";
+
+ if (index < 255)
+ o << ",";
+ else
+ o << " ";
+
+ o << " /* " << index << " */";
+
+ o << "\n";
+ }
+
+ i--;
+ o.indent(i * 2) << "};" << "\n";
+}
+
+void DisassemblerTables::emitContextDecisions(raw_ostream &o1,
+ raw_ostream &o2,
+ uint32_t &i1,
+ uint32_t &i2)
+ const {
+ emitContextDecision(o1, o2, i1, i2, *Tables[0], ONEBYTE_STR);
+ emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR);
+ emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR);
+ emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR);
+}
+
+void DisassemblerTables::emit(raw_ostream &o) const {
+ uint32_t i1 = 0;
+ uint32_t i2 = 0;
+
+ std::string s1;
+ std::string s2;
+
+ raw_string_ostream o1(s1);
+ raw_string_ostream o2(s2);
+
+ emitInstructionInfo(o, i2);
+ o << "\n";
+
+ emitContextTable(o, i2);
+ o << "\n";
+
+ emitEmptyTable(o1, i1);
+ emitContextDecisions(o1, o2, i1, i2);
+
+ o << o1.str();
+ o << "\n";
+ o << o2.str();
+ o << "\n";
+ o << "\n";
+}
+
+void DisassemblerTables::setTableFields(ModRMDecision &decision,
+ const ModRMFilter &filter,
+ InstrUID uid,
+ uint8_t opcode) {
+ unsigned index;
+
+ for (index = 0; index < 256; ++index) {
+ if (filter.accepts(index)) {
+ if (decision.instructionIDs[index] == uid)
+ continue;
+
+ if (decision.instructionIDs[index] != 0) {
+ InstructionSpecifier &newInfo =
+ InstructionSpecifiers[uid];
+ InstructionSpecifier &previousInfo =
+ InstructionSpecifiers[decision.instructionIDs[index]];
+
+ if(newInfo.filtered)
+ continue; // filtered instructions get lowest priority
+
+ if(previousInfo.name == "NOOP")
+ continue; // special case for XCHG32ar and NOOP
+
+ if (outranks(previousInfo.insnContext, newInfo.insnContext))
+ continue;
+
+ if (previousInfo.insnContext == newInfo.insnContext &&
+ !previousInfo.filtered) {
+ errs() << "Error: Primary decode conflict: ";
+ errs() << newInfo.name << " would overwrite " << previousInfo.name;
+ errs() << "\n";
+ errs() << "ModRM " << index << "\n";
+ errs() << "Opcode " << (uint16_t)opcode << "\n";
+ errs() << "Context " << stringForContext(newInfo.insnContext) << "\n";
+ HasConflicts = true;
+ }
+ }
+
+ decision.instructionIDs[index] = uid;
+ }
+ }
+}
+
+void DisassemblerTables::setTableFields(OpcodeType type,
+ InstructionContext insnContext,
+ uint8_t opcode,
+ const ModRMFilter &filter,
+ InstrUID uid) {
+ unsigned index;
+
+ ContextDecision &decision = *Tables[type];
+
+ for (index = 0; index < IC_max; ++index) {
+ if (inheritsFrom((InstructionContext)index,
+ InstructionSpecifiers[uid].insnContext))
+ setTableFields(decision.opcodeDecisions[index].modRMDecisions[opcode],
+ filter,
+ uid,
+ opcode);
+ }
+}
diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h
new file mode 100644
index 0000000..08eba01
--- /dev/null
+++ b/utils/TableGen/X86DisassemblerTables.h
@@ -0,0 +1,291 @@
+//===- X86DisassemblerTables.h - Disassembler tables ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the X86 Disassembler Emitter.
+// It contains the interface of the disassembler tables.
+// Documentation for the disassembler emitter in general can be found in
+// X86DisasemblerEmitter.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86DISASSEMBLERTABLES_H
+#define X86DISASSEMBLERTABLES_H
+
+#include "X86DisassemblerShared.h"
+#include "X86ModRMFilters.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+#include <vector>
+
+namespace llvm {
+
+namespace X86Disassembler {
+
+/// DisassemblerTables - Encapsulates all the decode tables being generated by
+/// the table emitter. Contains functions to populate the tables as well as
+/// to emit them as hierarchical C structures suitable for consumption by the
+/// runtime.
+class DisassemblerTables {
+private:
+ /// The decoder tables. There is one for each opcode type:
+ /// [0] one-byte opcodes
+ /// [1] two-byte opcodes of the form 0f __
+ /// [2] three-byte opcodes of the form 0f 38 __
+ /// [3] three-byte opcodes of the form 0f 3a __
+ ContextDecision* Tables[4];
+
+ /// The instruction information table
+ std::vector<InstructionSpecifier> InstructionSpecifiers;
+
+ /// True if there are primary decode conflicts in the instruction set
+ bool HasConflicts;
+
+ /// emitOneID - Emits a table entry for a single instruction entry, at the
+ /// innermost level of the structure hierarchy. The entry is printed out
+ /// in the format "nnnn, /* MNEMONIC */" where nnnn is the ID in decimal,
+ /// the comma is printed if addComma is true, and the menonic is the name
+ /// of the instruction as listed in the LLVM tables.
+ ///
+ /// @param o - The output stream to print the entry on.
+ /// @param i - The indentation level for o.
+ /// @param id - The unique ID of the instruction to print.
+ /// @param addComma - Whether or not to print a comma after the ID. True if
+ /// additional items will follow.
+ void emitOneID(raw_ostream &o,
+ uint32_t &i,
+ InstrUID id,
+ bool addComma) const;
+
+ /// emitModRMDecision - Emits a table of entries corresponding to a single
+ /// ModR/M decision. Compacts the ModR/M decision if possible. ModR/M
+ /// decisions are printed as:
+ ///
+ /// { /* struct ModRMDecision */
+ /// TYPE,
+ /// modRMTablennnn
+ /// }
+ ///
+ /// where nnnn is a unique ID for the corresponding table of IDs.
+ /// TYPE indicates whether the table has one entry that is the same
+ /// regardless of ModR/M byte, two entries - one for bytes 0x00-0xbf and one
+ /// for bytes 0xc0-0xff -, or 256 entries, one for each possible byte.
+ /// nnnn is the number of a table for looking up these values. The tables
+ /// are writen separately so that tables consisting entirely of zeros will
+ /// not be duplicated. (These all have the name modRMEmptyTable.) A table
+ /// is printed as:
+ ///
+ /// InstrUID modRMTablennnn[k] = {
+ /// nnnn, /* MNEMONIC */
+ /// ...
+ /// nnnn /* MNEMONIC */
+ /// };
+ ///
+ /// @param o1 - The output stream to print the ID table to.
+ /// @param o2 - The output stream to print the decision structure to.
+ /// @param i1 - The indentation level to use with stream o1.
+ /// @param i2 - The indentation level to use with stream o2.
+ /// @param decision - The ModR/M decision to emit. This decision has 256
+ /// entries - emitModRMDecision decides how to compact it.
+ void emitModRMDecision(raw_ostream &o1,
+ raw_ostream &o2,
+ uint32_t &i1,
+ uint32_t &i2,
+ ModRMDecision &decision) const;
+
+ /// emitOpcodeDecision - Emits an OpcodeDecision and all its subsidiary ModR/M
+ /// decisions. An OpcodeDecision is printed as:
+ ///
+ /// { /* struct OpcodeDecision */
+ /// /* 0x00 */
+ /// { /* struct ModRMDecision */
+ /// ...
+ /// }
+ /// ...
+ /// }
+ ///
+ /// where the ModRMDecision structure is printed as described in the
+ /// documentation for emitModRMDecision(). emitOpcodeDecision() passes on a
+ /// stream and indent level for the UID tables generated by
+ /// emitModRMDecision(), but does not use them itself.
+ ///
+ /// @param o1 - The output stream to print the ID tables generated by
+ /// emitModRMDecision() to.
+ /// @param o2 - The output stream for the decision structure itself.
+ /// @param i1 - The indent level to use with stream o1.
+ /// @param i2 - The indent level to use with stream o2.
+ /// @param decision - The OpcodeDecision to emit along with its subsidiary
+ /// structures.
+ void emitOpcodeDecision(raw_ostream &o1,
+ raw_ostream &o2,
+ uint32_t &i1,
+ uint32_t &i2,
+ OpcodeDecision &decision) const;
+
+ /// emitContextDecision - Emits a ContextDecision and all its subsidiary
+ /// Opcode and ModRMDecisions. A ContextDecision is printed as:
+ ///
+ /// struct ContextDecision NAME = {
+ /// { /* OpcodeDecisions */
+ /// /* IC */
+ /// { /* struct OpcodeDecision */
+ /// ...
+ /// },
+ /// ...
+ /// }
+ /// }
+ ///
+ /// NAME is the name of the ContextDecision (typically one of the four names
+ /// ONEBYTE_SYM, TWOBYTE_SYM, THREEBYTE38_SYM, and THREEBYTE3A_SYM from
+ /// X86DisassemblerDecoderCommon.h).
+ /// IC is one of the contexts in InstructionContext. There is an opcode
+ /// decision for each possible context.
+ /// The OpcodeDecision structures are printed as described in the
+ /// documentation for emitOpcodeDecision.
+ ///
+ /// @param o1 - The output stream to print the ID tables generated by
+ /// emitModRMDecision() to.
+ /// @param o2 - The output stream to print the decision structure to.
+ /// @param i1 - The indent level to use with stream o1.
+ /// @param i2 - The indent level to use with stream o2.
+ /// @param decision - The ContextDecision to emit along with its subsidiary
+ /// structures.
+ /// @param name - The name for the ContextDecision.
+ void emitContextDecision(raw_ostream &o1,
+ raw_ostream &o2,
+ uint32_t &i1,
+ uint32_t &i2,
+ ContextDecision &decision,
+ const char* name) const;
+
+ /// emitInstructionInfo - Prints the instruction specifier table, which has
+ /// one entry for each instruction, and contains name and operand
+ /// information. This table is printed as:
+ ///
+ /// struct InstructionSpecifier CONTEXTS_SYM[k] = {
+ /// {
+ /// /* nnnn */
+ /// "MNEMONIC",
+ /// 0xnn,
+ /// {
+ /// {
+ /// ENCODING,
+ /// TYPE
+ /// },
+ /// ...
+ /// }
+ /// },
+ /// };
+ ///
+ /// k is the total number of instructions.
+ /// nnnn is the ID of the current instruction (0-based). This table
+ /// includes entries for non-instructions like PHINODE.
+ /// 0xnn is the lowest possible opcode for the current instruction, used for
+ /// AddRegFrm instructions to compute the operand's value.
+ /// ENCODING and TYPE describe the encoding and type for a single operand.
+ ///
+ /// @param o - The output stream to which the instruction table should be
+ /// written.
+ /// @param i - The indent level for use with the stream.
+ void emitInstructionInfo(raw_ostream &o, uint32_t &i) const;
+
+ /// emitContextTable - Prints the table that is used to translate from an
+ /// instruction attribute mask to an instruction context. This table is
+ /// printed as:
+ ///
+ /// InstructionContext CONTEXTS_STR[256] = {
+ /// IC, /* 0x00 */
+ /// ...
+ /// };
+ ///
+ /// IC is the context corresponding to the mask 0x00, and there are 256
+ /// possible masks.
+ ///
+ /// @param o - The output stream to which the context table should be written.
+ /// @param i - The indent level for use with the stream.
+ void emitContextTable(raw_ostream &o, uint32_t &i) const;
+
+ /// emitContextDecisions - Prints all four ContextDecision structures using
+ /// emitContextDecision().
+ ///
+ /// @param o1 - The output stream to print the ID tables generated by
+ /// emitModRMDecision() to.
+ /// @param o2 - The output stream to print the decision structures to.
+ /// @param i1 - The indent level to use with stream o1.
+ /// @param i2 - The indent level to use with stream o2.
+ void emitContextDecisions(raw_ostream &o1,
+ raw_ostream &o2,
+ uint32_t &i1,
+ uint32_t &i2) const;
+
+ /// setTableFields - Uses a ModRMFilter to set the appropriate entries in a
+ /// ModRMDecision to refer to a particular instruction ID.
+ ///
+ /// @param decision - The ModRMDecision to populate.
+ /// @param filter - The filter to use in deciding which entries to populate.
+ /// @param uid - The unique ID to set matching entries to.
+ /// @param opcode - The opcode of the instruction, for error reporting.
+ void setTableFields(ModRMDecision &decision,
+ const ModRMFilter &filter,
+ InstrUID uid,
+ uint8_t opcode);
+public:
+ /// Constructor - Allocates space for the class decisions and clears them.
+ DisassemblerTables();
+
+ ~DisassemblerTables();
+
+ /// emit - Emits the instruction table, context table, and class decisions.
+ ///
+ /// @param o - The output stream to print the tables to.
+ void emit(raw_ostream &o) const;
+
+ /// setTableFields - Uses the opcode type, instruction context, opcode, and a
+ /// ModRMFilter as criteria to set a particular set of entries in the
+ /// decode tables to point to a specific uid.
+ ///
+ /// @param type - The opcode type (ONEBYTE, TWOBYTE, etc.)
+ /// @param insnContext - The context to use (IC, IC_64BIT, etc.)
+ /// @param opcode - The last byte of the opcode (not counting any escape
+ /// or extended opcodes).
+ /// @param filter - The ModRMFilter that decides which ModR/M byte values
+ /// correspond to the desired instruction.
+ /// @param uid - The unique ID of the instruction.
+ void setTableFields(OpcodeType type,
+ InstructionContext insnContext,
+ uint8_t opcode,
+ const ModRMFilter &filter,
+ InstrUID uid);
+
+ /// specForUID - Returns the instruction specifier for a given unique
+ /// instruction ID. Used when resolving collisions.
+ ///
+ /// @param uid - The unique ID of the instruction.
+ /// @return - A reference to the instruction specifier.
+ InstructionSpecifier& specForUID(InstrUID uid) {
+ if (uid >= InstructionSpecifiers.size())
+ InstructionSpecifiers.resize(uid + 1);
+
+ return InstructionSpecifiers[uid];
+ }
+
+ // hasConflicts - Reports whether there were primary decode conflicts
+ // from any instructions added to the tables.
+ // @return - true if there were; false otherwise.
+
+ bool hasConflicts() {
+ return HasConflicts;
+ }
+};
+
+} // namespace X86Disassembler
+
+} // namespace llvm
+
+#endif
diff --git a/utils/TableGen/X86ModRMFilters.h b/utils/TableGen/X86ModRMFilters.h
new file mode 100644
index 0000000..45cb07a
--- /dev/null
+++ b/utils/TableGen/X86ModRMFilters.h
@@ -0,0 +1,197 @@
+//===- X86ModRMFilters.h - Disassembler ModR/M filterss ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the X86 Disassembler Emitter.
+// It contains ModR/M filters that determine which values of the ModR/M byte
+// are valid for a partiuclar instruction.
+// Documentation for the disassembler emitter in general can be found in
+// X86DisasemblerEmitter.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86MODRMFILTERS_H
+#define X86MODRMFILTERS_H
+
+#include "llvm/System/DataTypes.h"
+
+namespace llvm {
+
+namespace X86Disassembler {
+
+/// ModRMFilter - Abstract base class for clases that recognize patterns in
+/// ModR/M bytes.
+class ModRMFilter {
+public:
+ /// Destructor - Override as necessary.
+ virtual ~ModRMFilter() { }
+
+ /// isDumb - Indicates whether this filter returns the same value for
+ /// any value of the ModR/M byte.
+ ///
+ /// @result - True if the filter returns the same value for any ModR/M
+ /// byte; false if not.
+ virtual bool isDumb() const { return false; }
+
+ /// accepts - Indicates whether the filter accepts a particular ModR/M
+ /// byte value.
+ ///
+ /// @result - True if the filter accepts the ModR/M byte; false if not.
+ virtual bool accepts(uint8_t modRM) const = 0;
+};
+
+/// DumbFilter - Accepts any ModR/M byte. Used for instructions that do not
+/// require a ModR/M byte or instructions where the entire ModR/M byte is used
+/// for operands.
+class DumbFilter : public ModRMFilter {
+public:
+ bool isDumb() const {
+ return true;
+ }
+
+ bool accepts(uint8_t modRM) const {
+ return true;
+ }
+};
+
+/// ModFilter - Filters based on the mod bits [bits 7-6] of the ModR/M byte.
+/// Some instructions are classified based on whether they are 11 or anything
+/// else. This filter performs that classification.
+class ModFilter : public ModRMFilter {
+private:
+ bool R;
+public:
+ /// Constructor
+ ///
+ /// @r - True if the mod bits of the ModR/M byte must be 11; false
+ /// otherwise. The name r derives from the fact that the mod
+ /// bits indicate whether the R/M bits [bits 2-0] signify a
+ /// register or a memory operand.
+ ModFilter(bool r) :
+ ModRMFilter(),
+ R(r) {
+ }
+
+ bool accepts(uint8_t modRM) const {
+ if (R == ((modRM & 0xc0) == 0xc0))
+ return true;
+ else
+ return false;
+ }
+};
+
+/// EscapeFilter - Filters escape opcodes, which are classified in two ways. If
+/// the ModR/M byte is between 0xc0 and 0xff, then there is one slot for each
+/// possible value. Otherwise, there is one instruction for each value of the
+/// nnn field [bits 5-3], known elsewhere as the reg field.
+class EscapeFilter : public ModRMFilter {
+private:
+ bool C0_FF;
+ uint8_t NNN_or_ModRM;
+public:
+ /// Constructor
+ ///
+ /// @c0_ff - True if the ModR/M byte must fall between 0xc0 and 0xff;
+ /// false otherwise.
+ /// @nnn_or_modRM - If c0_ff is true, the required value of the entire ModR/M
+ /// byte. If c0_ff is false, the required value of the nnn
+ /// field.
+ EscapeFilter(bool c0_ff, uint8_t nnn_or_modRM) :
+ ModRMFilter(),
+ C0_FF(c0_ff),
+ NNN_or_ModRM(nnn_or_modRM) {
+ }
+
+ bool accepts(uint8_t modRM) const {
+ if ((C0_FF && modRM >= 0xc0 && (modRM == NNN_or_ModRM)) ||
+ (!C0_FF && modRM < 0xc0 && ((modRM & 0x38) >> 3) == NNN_or_ModRM))
+ return true;
+ else
+ return false;
+ }
+};
+
+/// AddRegEscapeFilter - Some escape opcodes have one of the register operands
+/// added to the ModR/M byte, meaning that a range of eight ModR/M values
+/// maps to a single instruction. Such instructions require the ModR/M byte
+/// to fall between 0xc0 and 0xff.
+class AddRegEscapeFilter : public ModRMFilter {
+private:
+ uint8_t ModRM;
+public:
+ /// Constructor
+ ///
+ /// @modRM - The value of the ModR/M byte when the register operand
+ /// refers to the first register in the register set.
+ AddRegEscapeFilter(uint8_t modRM) : ModRM(modRM) {
+ }
+
+ bool accepts(uint8_t modRM) const {
+ if (modRM >= ModRM && modRM < ModRM + 8)
+ return true;
+ else
+ return false;
+ }
+};
+
+/// ExtendedFilter - Extended opcodes are classified based on the value of the
+/// mod field [bits 7-6] and the value of the nnn field [bits 5-3].
+class ExtendedFilter : public ModRMFilter {
+private:
+ bool R;
+ uint8_t NNN;
+public:
+ /// Constructor
+ ///
+ /// @r - True if the mod field must be set to 11; false otherwise.
+ /// The name is explained at ModFilter.
+ /// @nnn - The required value of the nnn field.
+ ExtendedFilter(bool r, uint8_t nnn) :
+ ModRMFilter(),
+ R(r),
+ NNN(nnn) {
+ }
+
+ bool accepts(uint8_t modRM) const {
+ if (((R && ((modRM & 0xc0) == 0xc0)) ||
+ (!R && ((modRM & 0xc0) != 0xc0))) &&
+ (((modRM & 0x38) >> 3) == NNN))
+ return true;
+ else
+ return false;
+ }
+};
+
+/// ExactFilter - The occasional extended opcode (such as VMCALL or MONITOR)
+/// requires the ModR/M byte to have a specific value.
+class ExactFilter : public ModRMFilter
+{
+private:
+ uint8_t ModRM;
+public:
+ /// Constructor
+ ///
+ /// @modRM - The required value of the full ModR/M byte.
+ ExactFilter(uint8_t modRM) :
+ ModRMFilter(),
+ ModRM(modRM) {
+ }
+
+ bool accepts(uint8_t modRM) const {
+ if (ModRM == modRM)
+ return true;
+ else
+ return false;
+ }
+};
+
+} // namespace X86Disassembler
+
+} // namespace llvm
+
+#endif
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
new file mode 100644
index 0000000..2b6e30d
--- /dev/null
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -0,0 +1,959 @@
+//===- X86RecognizableInstr.cpp - Disassembler instruction spec --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the X86 Disassembler Emitter.
+// It contains the implementation of a single recognizable instruction.
+// Documentation for the disassembler emitter in general can be found in
+// X86DisasemblerEmitter.h.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86DisassemblerShared.h"
+#include "X86RecognizableInstr.h"
+#include "X86ModRMFilters.h"
+
+#include "llvm/Support/ErrorHandling.h"
+
+#include <string>
+
+using namespace llvm;
+
+// A clone of X86 since we can't depend on something that is generated.
+namespace X86Local {
+ enum {
+ Pseudo = 0,
+ RawFrm = 1,
+ AddRegFrm = 2,
+ MRMDestReg = 3,
+ MRMDestMem = 4,
+ MRMSrcReg = 5,
+ MRMSrcMem = 6,
+ MRM0r = 16, MRM1r = 17, MRM2r = 18, MRM3r = 19,
+ MRM4r = 20, MRM5r = 21, MRM6r = 22, MRM7r = 23,
+ MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27,
+ MRM4m = 28, MRM5m = 29, MRM6m = 30, MRM7m = 31,
+ MRMInitReg = 32
+ };
+
+ enum {
+ TB = 1,
+ REP = 2,
+ D8 = 3, D9 = 4, DA = 5, DB = 6,
+ DC = 7, DD = 8, DE = 9, DF = 10,
+ XD = 11, XS = 12,
+ T8 = 13, TA = 14
+ };
+}
+
+#define ONE_BYTE_EXTENSION_TABLES \
+ EXTENSION_TABLE(80) \
+ EXTENSION_TABLE(81) \
+ EXTENSION_TABLE(82) \
+ EXTENSION_TABLE(83) \
+ EXTENSION_TABLE(8f) \
+ EXTENSION_TABLE(c0) \
+ EXTENSION_TABLE(c1) \
+ EXTENSION_TABLE(c6) \
+ EXTENSION_TABLE(c7) \
+ EXTENSION_TABLE(d0) \
+ EXTENSION_TABLE(d1) \
+ EXTENSION_TABLE(d2) \
+ EXTENSION_TABLE(d3) \
+ EXTENSION_TABLE(f6) \
+ EXTENSION_TABLE(f7) \
+ EXTENSION_TABLE(fe) \
+ EXTENSION_TABLE(ff)
+
+#define TWO_BYTE_EXTENSION_TABLES \
+ EXTENSION_TABLE(00) \
+ EXTENSION_TABLE(01) \
+ EXTENSION_TABLE(18) \
+ EXTENSION_TABLE(71) \
+ EXTENSION_TABLE(72) \
+ EXTENSION_TABLE(73) \
+ EXTENSION_TABLE(ae) \
+ EXTENSION_TABLE(b9) \
+ EXTENSION_TABLE(ba) \
+ EXTENSION_TABLE(c7)
+
+#define TWO_BYTE_FULL_EXTENSION_TABLES \
+ EXTENSION_TABLE(01)
+
+
+using namespace X86Disassembler;
+
+/// needsModRMForDecode - Indicates whether a particular instruction requires a
+/// ModR/M byte for the instruction to be properly decoded. For example, a
+/// MRMDestReg instruction needs the Mod field in the ModR/M byte to be set to
+/// 0b11.
+///
+/// @param form - The form of the instruction.
+/// @return - true if the form implies that a ModR/M byte is required, false
+/// otherwise.
+static bool needsModRMForDecode(uint8_t form) {
+ if (form == X86Local::MRMDestReg ||
+ form == X86Local::MRMDestMem ||
+ form == X86Local::MRMSrcReg ||
+ form == X86Local::MRMSrcMem ||
+ (form >= X86Local::MRM0r && form <= X86Local::MRM7r) ||
+ (form >= X86Local::MRM0m && form <= X86Local::MRM7m))
+ return true;
+ else
+ return false;
+}
+
+/// isRegFormat - Indicates whether a particular form requires the Mod field of
+/// the ModR/M byte to be 0b11.
+///
+/// @param form - The form of the instruction.
+/// @return - true if the form implies that Mod must be 0b11, false
+/// otherwise.
+static bool isRegFormat(uint8_t form) {
+ if (form == X86Local::MRMDestReg ||
+ form == X86Local::MRMSrcReg ||
+ (form >= X86Local::MRM0r && form <= X86Local::MRM7r))
+ return true;
+ else
+ return false;
+}
+
+/// byteFromBitsInit - Extracts a value at most 8 bits in width from a BitsInit.
+/// Useful for switch statements and the like.
+///
+/// @param init - A reference to the BitsInit to be decoded.
+/// @return - The field, with the first bit in the BitsInit as the lowest
+/// order bit.
+static uint8_t byteFromBitsInit(BitsInit &init) {
+ int width = init.getNumBits();
+
+ assert(width <= 8 && "Field is too large for uint8_t!");
+
+ int index;
+ uint8_t mask = 0x01;
+
+ uint8_t ret = 0;
+
+ for (index = 0; index < width; index++) {
+ if (static_cast<BitInit*>(init.getBit(index))->getValue())
+ ret |= mask;
+
+ mask <<= 1;
+ }
+
+ return ret;
+}
+
+/// byteFromRec - Extract a value at most 8 bits in with from a Record given the
+/// name of the field.
+///
+/// @param rec - The record from which to extract the value.
+/// @param name - The name of the field in the record.
+/// @return - The field, as translated by byteFromBitsInit().
+static uint8_t byteFromRec(const Record* rec, const std::string &name) {
+ BitsInit* bits = rec->getValueAsBitsInit(name);
+ return byteFromBitsInit(*bits);
+}
+
+RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
+ const CodeGenInstruction &insn,
+ InstrUID uid) {
+ UID = uid;
+
+ Rec = insn.TheDef;
+ Name = Rec->getName();
+ Spec = &tables.specForUID(UID);
+
+ if (!Rec->isSubClassOf("X86Inst")) {
+ ShouldBeEmitted = false;
+ return;
+ }
+
+ Prefix = byteFromRec(Rec, "Prefix");
+ Opcode = byteFromRec(Rec, "Opcode");
+ Form = byteFromRec(Rec, "FormBits");
+ SegOvr = byteFromRec(Rec, "SegOvrBits");
+
+ HasOpSizePrefix = Rec->getValueAsBit("hasOpSizePrefix");
+ HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix");
+ HasLockPrefix = Rec->getValueAsBit("hasLockPrefix");
+ IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly");
+
+ Name = Rec->getName();
+ AsmString = Rec->getValueAsString("AsmString");
+
+ Operands = &insn.OperandList;
+
+ IsSSE = HasOpSizePrefix && (Name.find("16") == Name.npos);
+ HasFROperands = false;
+
+ ShouldBeEmitted = true;
+}
+
+void RecognizableInstr::processInstr(DisassemblerTables &tables,
+ const CodeGenInstruction &insn,
+ InstrUID uid)
+{
+ RecognizableInstr recogInstr(tables, insn, uid);
+
+ recogInstr.emitInstructionSpecifier(tables);
+
+ if (recogInstr.shouldBeEmitted())
+ recogInstr.emitDecodePath(tables);
+}
+
+InstructionContext RecognizableInstr::insnContext() const {
+ InstructionContext insnContext;
+
+ if (Name.find("64") != Name.npos || HasREX_WPrefix) {
+ if (HasREX_WPrefix && HasOpSizePrefix)
+ insnContext = IC_64BIT_REXW_OPSIZE;
+ else if (HasOpSizePrefix)
+ insnContext = IC_64BIT_OPSIZE;
+ else if (HasREX_WPrefix && Prefix == X86Local::XS)
+ insnContext = IC_64BIT_REXW_XS;
+ else if (HasREX_WPrefix && Prefix == X86Local::XD)
+ insnContext = IC_64BIT_REXW_XD;
+ else if (Prefix == X86Local::XD)
+ insnContext = IC_64BIT_XD;
+ else if (Prefix == X86Local::XS)
+ insnContext = IC_64BIT_XS;
+ else if (HasREX_WPrefix)
+ insnContext = IC_64BIT_REXW;
+ else
+ insnContext = IC_64BIT;
+ } else {
+ if (HasOpSizePrefix)
+ insnContext = IC_OPSIZE;
+ else if (Prefix == X86Local::XD)
+ insnContext = IC_XD;
+ else if (Prefix == X86Local::XS)
+ insnContext = IC_XS;
+ else
+ insnContext = IC;
+ }
+
+ return insnContext;
+}
+
+RecognizableInstr::filter_ret RecognizableInstr::filter() const {
+ // Filter out intrinsics
+
+ if (!Rec->isSubClassOf("X86Inst"))
+ return FILTER_STRONG;
+
+ if (Form == X86Local::Pseudo ||
+ IsCodeGenOnly)
+ return FILTER_STRONG;
+
+ // Filter out instructions with a LOCK prefix;
+ // prefer forms that do not have the prefix
+ if (HasLockPrefix)
+ return FILTER_WEAK;
+
+ // Filter out artificial instructions
+
+ if (Name.find("TAILJMP") != Name.npos ||
+ Name.find("_Int") != Name.npos ||
+ Name.find("_int") != Name.npos ||
+ Name.find("Int_") != Name.npos ||
+ Name.find("_NOREX") != Name.npos ||
+ Name.find("EH_RETURN") != Name.npos ||
+ Name.find("V_SET") != Name.npos ||
+ Name.find("LOCK_") != Name.npos ||
+ Name.find("WIN") != Name.npos)
+ return FILTER_STRONG;
+
+ // Special cases.
+
+ if (Name.find("PCMPISTRI") != Name.npos && Name != "PCMPISTRI")
+ return FILTER_WEAK;
+ if (Name.find("PCMPESTRI") != Name.npos && Name != "PCMPESTRI")
+ return FILTER_WEAK;
+
+ if (Name.find("MOV") != Name.npos && Name.find("r0") != Name.npos)
+ return FILTER_WEAK;
+ if (Name.find("MOVZ") != Name.npos && Name.find("MOVZX") == Name.npos)
+ return FILTER_WEAK;
+ if (Name.find("Fs") != Name.npos)
+ return FILTER_WEAK;
+ if (Name == "MOVLPDrr" ||
+ Name == "MOVLPSrr" ||
+ Name == "PUSHFQ" ||
+ Name == "BSF16rr" ||
+ Name == "BSF16rm" ||
+ Name == "BSR16rr" ||
+ Name == "BSR16rm" ||
+ Name == "MOVSX16rm8" ||
+ Name == "MOVSX16rr8" ||
+ Name == "MOVZX16rm8" ||
+ Name == "MOVZX16rr8" ||
+ Name == "PUSH32i16" ||
+ Name == "PUSH64i16" ||
+ Name == "MOVPQI2QImr" ||
+ Name == "MOVSDmr" ||
+ Name == "MOVSDrm" ||
+ Name == "MOVSSmr" ||
+ Name == "MOVSSrm" ||
+ Name == "MMX_MOVD64rrv164" ||
+ Name == "CRC32m16" ||
+ Name == "MOV64ri64i32" ||
+ Name == "CRC32r16")
+ return FILTER_WEAK;
+
+ // Filter out instructions with segment override prefixes.
+ // They're too messy to handle now and we'll special case them if needed.
+
+ if (SegOvr)
+ return FILTER_STRONG;
+
+ // Filter out instructions that can't be printed.
+
+ if (AsmString.size() == 0)
+ return FILTER_STRONG;
+
+ // Filter out instructions with subreg operands.
+
+ if (AsmString.find("subreg") != AsmString.npos)
+ return FILTER_STRONG;
+
+ assert(Form != X86Local::MRMInitReg &&
+ "FORMAT_MRMINITREG instruction not skipped");
+
+ if (HasFROperands && Name.find("MOV") != Name.npos &&
+ ((Name.find("2") != Name.npos && Name.find("32") == Name.npos) ||
+ (Name.find("to") != Name.npos)))
+ return FILTER_WEAK;
+
+ return FILTER_NORMAL;
+}
+
+void RecognizableInstr::handleOperand(
+ bool optional,
+ unsigned &operandIndex,
+ unsigned &physicalOperandIndex,
+ unsigned &numPhysicalOperands,
+ unsigned *operandMapping,
+ OperandEncoding (*encodingFromString)(const std::string&, bool hasOpSizePrefix)) {
+ if (optional) {
+ if (physicalOperandIndex >= numPhysicalOperands)
+ return;
+ } else {
+ assert(physicalOperandIndex < numPhysicalOperands);
+ }
+
+ while (operandMapping[operandIndex] != operandIndex) {
+ Spec->operands[operandIndex].encoding = ENCODING_DUP;
+ Spec->operands[operandIndex].type =
+ (OperandType)(TYPE_DUP0 + operandMapping[operandIndex]);
+ ++operandIndex;
+ }
+
+ const std::string &typeName = (*Operands)[operandIndex].Rec->getName();
+
+ Spec->operands[operandIndex].encoding = encodingFromString(typeName,
+ HasOpSizePrefix);
+ Spec->operands[operandIndex].type = typeFromString(typeName,
+ IsSSE,
+ HasREX_WPrefix,
+ HasOpSizePrefix);
+
+ ++operandIndex;
+ ++physicalOperandIndex;
+}
+
+void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
+ Spec->name = Name;
+
+ if (!Rec->isSubClassOf("X86Inst"))
+ return;
+
+ switch (filter()) {
+ case FILTER_WEAK:
+ Spec->filtered = true;
+ break;
+ case FILTER_STRONG:
+ ShouldBeEmitted = false;
+ return;
+ case FILTER_NORMAL:
+ break;
+ }
+
+ Spec->insnContext = insnContext();
+
+ const std::vector<CodeGenInstruction::OperandInfo> &OperandList = *Operands;
+
+ unsigned operandIndex;
+ unsigned numOperands = OperandList.size();
+ unsigned numPhysicalOperands = 0;
+
+ // operandMapping maps from operands in OperandList to their originals.
+ // If operandMapping[i] != i, then the entry is a duplicate.
+ unsigned operandMapping[X86_MAX_OPERANDS];
+
+ bool hasFROperands = false;
+
+ assert(numOperands < X86_MAX_OPERANDS && "X86_MAX_OPERANDS is not large enough");
+
+ for (operandIndex = 0; operandIndex < numOperands; ++operandIndex) {
+ if (OperandList[operandIndex].Constraints.size()) {
+ const std::string &constraint = OperandList[operandIndex].Constraints[0];
+ std::string::size_type tiedToPos;
+
+ if ((tiedToPos = constraint.find(" << 16) | (1 << TOI::TIED_TO))")) !=
+ constraint.npos) {
+ tiedToPos--;
+ operandMapping[operandIndex] = constraint[tiedToPos] - '0';
+ } else {
+ ++numPhysicalOperands;
+ operandMapping[operandIndex] = operandIndex;
+ }
+ } else {
+ ++numPhysicalOperands;
+ operandMapping[operandIndex] = operandIndex;
+ }
+
+ const std::string &recName = OperandList[operandIndex].Rec->getName();
+
+ if (recName.find("FR") != recName.npos)
+ hasFROperands = true;
+ }
+
+ if (hasFROperands && Name.find("MOV") != Name.npos &&
+ ((Name.find("2") != Name.npos && Name.find("32") == Name.npos) ||
+ (Name.find("to") != Name.npos)))
+ ShouldBeEmitted = false;
+
+ if (!ShouldBeEmitted)
+ return;
+
+#define HANDLE_OPERAND(class) \
+ handleOperand(false, \
+ operandIndex, \
+ physicalOperandIndex, \
+ numPhysicalOperands, \
+ operandMapping, \
+ class##EncodingFromString);
+
+#define HANDLE_OPTIONAL(class) \
+ handleOperand(true, \
+ operandIndex, \
+ physicalOperandIndex, \
+ numPhysicalOperands, \
+ operandMapping, \
+ class##EncodingFromString);
+
+ // operandIndex should always be < numOperands
+ operandIndex = 0;
+ // physicalOperandIndex should always be < numPhysicalOperands
+ unsigned physicalOperandIndex = 0;
+
+ switch (Form) {
+ case X86Local::RawFrm:
+ // Operand 1 (optional) is an address or immediate.
+ // Operand 2 (optional) is an immediate.
+ assert(numPhysicalOperands <= 2 &&
+ "Unexpected number of operands for RawFrm");
+ HANDLE_OPTIONAL(relocation)
+ HANDLE_OPTIONAL(immediate)
+ break;
+ case X86Local::AddRegFrm:
+ // Operand 1 is added to the opcode.
+ // Operand 2 (optional) is an address.
+ assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 &&
+ "Unexpected number of operands for AddRegFrm");
+ HANDLE_OPERAND(opcodeModifier)
+ HANDLE_OPTIONAL(relocation)
+ break;
+ case X86Local::MRMDestReg:
+ // Operand 1 is a register operand in the R/M field.
+ // Operand 2 is a register operand in the Reg/Opcode field.
+ // Operand 3 (optional) is an immediate.
+ assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
+ "Unexpected number of operands for MRMDestRegFrm");
+ HANDLE_OPERAND(rmRegister)
+ HANDLE_OPERAND(roRegister)
+ HANDLE_OPTIONAL(immediate)
+ break;
+ case X86Local::MRMDestMem:
+ // Operand 1 is a memory operand (possibly SIB-extended)
+ // Operand 2 is a register operand in the Reg/Opcode field.
+ // Operand 3 (optional) is an immediate.
+ assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
+ "Unexpected number of operands for MRMDestMemFrm");
+ HANDLE_OPERAND(memory)
+ HANDLE_OPERAND(roRegister)
+ HANDLE_OPTIONAL(immediate)
+ break;
+ case X86Local::MRMSrcReg:
+ // Operand 1 is a register operand in the Reg/Opcode field.
+ // Operand 2 is a register operand in the R/M field.
+ // Operand 3 (optional) is an immediate.
+ assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
+ "Unexpected number of operands for MRMSrcRegFrm");
+ HANDLE_OPERAND(roRegister)
+ HANDLE_OPERAND(rmRegister)
+ HANDLE_OPTIONAL(immediate)
+ break;
+ case X86Local::MRMSrcMem:
+ // Operand 1 is a register operand in the Reg/Opcode field.
+ // Operand 2 is a memory operand (possibly SIB-extended)
+ // Operand 3 (optional) is an immediate.
+ assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 &&
+ "Unexpected number of operands for MRMSrcMemFrm");
+ HANDLE_OPERAND(roRegister)
+ HANDLE_OPERAND(memory)
+ HANDLE_OPTIONAL(immediate)
+ break;
+ case X86Local::MRM0r:
+ case X86Local::MRM1r:
+ case X86Local::MRM2r:
+ case X86Local::MRM3r:
+ case X86Local::MRM4r:
+ case X86Local::MRM5r:
+ case X86Local::MRM6r:
+ case X86Local::MRM7r:
+ // Operand 1 is a register operand in the R/M field.
+ // Operand 2 (optional) is an immediate or relocation.
+ assert(numPhysicalOperands <= 2 &&
+ "Unexpected number of operands for MRMnRFrm");
+ HANDLE_OPTIONAL(rmRegister)
+ HANDLE_OPTIONAL(relocation)
+ break;
+ case X86Local::MRM0m:
+ case X86Local::MRM1m:
+ case X86Local::MRM2m:
+ case X86Local::MRM3m:
+ case X86Local::MRM4m:
+ case X86Local::MRM5m:
+ case X86Local::MRM6m:
+ case X86Local::MRM7m:
+ // Operand 1 is a memory operand (possibly SIB-extended)
+ // Operand 2 (optional) is an immediate or relocation.
+ assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 &&
+ "Unexpected number of operands for MRMnMFrm");
+ HANDLE_OPERAND(memory)
+ HANDLE_OPTIONAL(relocation)
+ break;
+ case X86Local::MRMInitReg:
+ // Ignored.
+ break;
+ }
+
+ #undef HANDLE_OPERAND
+ #undef HANDLE_OPTIONAL
+}
+
+void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const {
+ // Special cases where the LLVM tables are not complete
+
+#define EXACTCASE(class, name, lastbyte) \
+ if (Name == name) { \
+ tables.setTableFields(class, \
+ insnContext(), \
+ Opcode, \
+ ExactFilter(lastbyte), \
+ UID); \
+ Spec->modifierBase = Opcode; \
+ return; \
+ }
+
+ EXACTCASE(TWOBYTE, "MONITOR", 0xc8)
+ EXACTCASE(TWOBYTE, "MWAIT", 0xc9)
+ EXACTCASE(TWOBYTE, "SWPGS", 0xf8)
+ EXACTCASE(TWOBYTE, "INVEPT", 0x80)
+ EXACTCASE(TWOBYTE, "INVVPID", 0x81)
+ EXACTCASE(TWOBYTE, "VMCALL", 0xc1)
+ EXACTCASE(TWOBYTE, "VMLAUNCH", 0xc2)
+ EXACTCASE(TWOBYTE, "VMRESUME", 0xc3)
+ EXACTCASE(TWOBYTE, "VMXOFF", 0xc4)
+
+ if (Name == "INVLPG") {
+ tables.setTableFields(TWOBYTE,
+ insnContext(),
+ Opcode,
+ ExtendedFilter(false, 7),
+ UID);
+ Spec->modifierBase = Opcode;
+ return;
+ }
+
+ OpcodeType opcodeType = (OpcodeType)-1;
+
+ ModRMFilter* filter = NULL;
+ uint8_t opcodeToSet = 0;
+
+ switch (Prefix) {
+ // Extended two-byte opcodes can start with f2 0f, f3 0f, or 0f
+ case X86Local::XD:
+ case X86Local::XS:
+ case X86Local::TB:
+ opcodeType = TWOBYTE;
+
+ switch (Opcode) {
+#define EXTENSION_TABLE(n) case 0x##n:
+ TWO_BYTE_EXTENSION_TABLES
+#undef EXTENSION_TABLE
+ switch (Form) {
+ default:
+ llvm_unreachable("Unhandled two-byte extended opcode");
+ case X86Local::MRM0r:
+ case X86Local::MRM1r:
+ case X86Local::MRM2r:
+ case X86Local::MRM3r:
+ case X86Local::MRM4r:
+ case X86Local::MRM5r:
+ case X86Local::MRM6r:
+ case X86Local::MRM7r:
+ filter = new ExtendedFilter(true, Form - X86Local::MRM0r);
+ break;
+ case X86Local::MRM0m:
+ case X86Local::MRM1m:
+ case X86Local::MRM2m:
+ case X86Local::MRM3m:
+ case X86Local::MRM4m:
+ case X86Local::MRM5m:
+ case X86Local::MRM6m:
+ case X86Local::MRM7m:
+ filter = new ExtendedFilter(false, Form - X86Local::MRM0m);
+ break;
+ } // switch (Form)
+ break;
+ default:
+ if (needsModRMForDecode(Form))
+ filter = new ModFilter(isRegFormat(Form));
+ else
+ filter = new DumbFilter();
+
+ break;
+ } // switch (opcode)
+ opcodeToSet = Opcode;
+ break;
+ case X86Local::T8:
+ opcodeType = THREEBYTE_38;
+ if (needsModRMForDecode(Form))
+ filter = new ModFilter(isRegFormat(Form));
+ else
+ filter = new DumbFilter();
+ opcodeToSet = Opcode;
+ break;
+ case X86Local::TA:
+ opcodeType = THREEBYTE_3A;
+ if (needsModRMForDecode(Form))
+ filter = new ModFilter(isRegFormat(Form));
+ else
+ filter = new DumbFilter();
+ opcodeToSet = Opcode;
+ break;
+ case X86Local::D8:
+ case X86Local::D9:
+ case X86Local::DA:
+ case X86Local::DB:
+ case X86Local::DC:
+ case X86Local::DD:
+ case X86Local::DE:
+ case X86Local::DF:
+ assert(Opcode >= 0xc0 && "Unexpected opcode for an escape opcode");
+ opcodeType = ONEBYTE;
+ if (Form == X86Local::AddRegFrm) {
+ Spec->modifierType = MODIFIER_MODRM;
+ Spec->modifierBase = Opcode;
+ filter = new AddRegEscapeFilter(Opcode);
+ } else {
+ filter = new EscapeFilter(true, Opcode);
+ }
+ opcodeToSet = 0xd8 + (Prefix - X86Local::D8);
+ break;
+ default:
+ opcodeType = ONEBYTE;
+ switch (Opcode) {
+#define EXTENSION_TABLE(n) case 0x##n:
+ ONE_BYTE_EXTENSION_TABLES
+#undef EXTENSION_TABLE
+ switch (Form) {
+ default:
+ llvm_unreachable("Fell through the cracks of a single-byte "
+ "extended opcode");
+ case X86Local::MRM0r:
+ case X86Local::MRM1r:
+ case X86Local::MRM2r:
+ case X86Local::MRM3r:
+ case X86Local::MRM4r:
+ case X86Local::MRM5r:
+ case X86Local::MRM6r:
+ case X86Local::MRM7r:
+ filter = new ExtendedFilter(true, Form - X86Local::MRM0r);
+ break;
+ case X86Local::MRM0m:
+ case X86Local::MRM1m:
+ case X86Local::MRM2m:
+ case X86Local::MRM3m:
+ case X86Local::MRM4m:
+ case X86Local::MRM5m:
+ case X86Local::MRM6m:
+ case X86Local::MRM7m:
+ filter = new ExtendedFilter(false, Form - X86Local::MRM0m);
+ break;
+ } // switch (Form)
+ break;
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ filter = new EscapeFilter(false, Form - X86Local::MRM0m);
+ break;
+ default:
+ if (needsModRMForDecode(Form))
+ filter = new ModFilter(isRegFormat(Form));
+ else
+ filter = new DumbFilter();
+ break;
+ } // switch (Opcode)
+ opcodeToSet = Opcode;
+ } // switch (Prefix)
+
+ assert(opcodeType != (OpcodeType)-1 &&
+ "Opcode type not set");
+ assert(filter && "Filter not set");
+
+ if (Form == X86Local::AddRegFrm) {
+ if(Spec->modifierType != MODIFIER_MODRM) {
+ assert(opcodeToSet < 0xf9 &&
+ "Not enough room for all ADDREG_FRM operands");
+
+ uint8_t currentOpcode;
+
+ for (currentOpcode = opcodeToSet;
+ currentOpcode < opcodeToSet + 8;
+ ++currentOpcode)
+ tables.setTableFields(opcodeType,
+ insnContext(),
+ currentOpcode,
+ *filter,
+ UID);
+
+ Spec->modifierType = MODIFIER_OPCODE;
+ Spec->modifierBase = opcodeToSet;
+ } else {
+ // modifierBase was set where MODIFIER_MODRM was set
+ tables.setTableFields(opcodeType,
+ insnContext(),
+ opcodeToSet,
+ *filter,
+ UID);
+ }
+ } else {
+ tables.setTableFields(opcodeType,
+ insnContext(),
+ opcodeToSet,
+ *filter,
+ UID);
+
+ Spec->modifierType = MODIFIER_NONE;
+ Spec->modifierBase = opcodeToSet;
+ }
+
+ delete filter;
+}
+
+#define TYPE(str, type) if (s == str) return type;
+OperandType RecognizableInstr::typeFromString(const std::string &s,
+ bool isSSE,
+ bool hasREX_WPrefix,
+ bool hasOpSizePrefix) {
+ if (isSSE) {
+ // For SSE instructions, we ignore the OpSize prefix and force operand
+ // sizes.
+ TYPE("GR16", TYPE_R16)
+ TYPE("GR32", TYPE_R32)
+ TYPE("GR64", TYPE_R64)
+ }
+ if(hasREX_WPrefix) {
+ // For instructions with a REX_W prefix, a declared 32-bit register encoding
+ // is special.
+ TYPE("GR32", TYPE_R32)
+ }
+ if(!hasOpSizePrefix) {
+ // For instructions without an OpSize prefix, a declared 16-bit register or
+ // immediate encoding is special.
+ TYPE("GR16", TYPE_R16)
+ TYPE("i16imm", TYPE_IMM16)
+ }
+ TYPE("i16mem", TYPE_Mv)
+ TYPE("i16imm", TYPE_IMMv)
+ TYPE("i16i8imm", TYPE_IMMv)
+ TYPE("GR16", TYPE_Rv)
+ TYPE("i32mem", TYPE_Mv)
+ TYPE("i32imm", TYPE_IMMv)
+ TYPE("i32i8imm", TYPE_IMM32)
+ TYPE("GR32", TYPE_Rv)
+ TYPE("i64mem", TYPE_Mv)
+ TYPE("i64i32imm", TYPE_IMM64)
+ TYPE("i64i8imm", TYPE_IMM64)
+ TYPE("GR64", TYPE_R64)
+ TYPE("i8mem", TYPE_M8)
+ TYPE("i8imm", TYPE_IMM8)
+ TYPE("GR8", TYPE_R8)
+ TYPE("VR128", TYPE_XMM128)
+ TYPE("f128mem", TYPE_M128)
+ TYPE("FR64", TYPE_XMM64)
+ TYPE("f64mem", TYPE_M64FP)
+ TYPE("FR32", TYPE_XMM32)
+ TYPE("f32mem", TYPE_M32FP)
+ TYPE("RST", TYPE_ST)
+ TYPE("i128mem", TYPE_M128)
+ TYPE("i64i32imm_pcrel", TYPE_REL64)
+ TYPE("i32imm_pcrel", TYPE_REL32)
+ TYPE("SSECC", TYPE_IMM8)
+ TYPE("brtarget", TYPE_RELv)
+ TYPE("brtarget8", TYPE_REL8)
+ TYPE("f80mem", TYPE_M80FP)
+ TYPE("lea32mem", TYPE_LEA)
+ TYPE("lea64_32mem", TYPE_LEA)
+ TYPE("lea64mem", TYPE_LEA)
+ TYPE("VR64", TYPE_MM64)
+ TYPE("i64imm", TYPE_IMMv)
+ TYPE("opaque32mem", TYPE_M1616)
+ TYPE("opaque48mem", TYPE_M1632)
+ TYPE("opaque80mem", TYPE_M1664)
+ TYPE("opaque512mem", TYPE_M512)
+ TYPE("SEGMENT_REG", TYPE_SEGMENTREG)
+ TYPE("DEBUG_REG", TYPE_DEBUGREG)
+ TYPE("CONTROL_REG_32", TYPE_CR32)
+ TYPE("CONTROL_REG_64", TYPE_CR64)
+ TYPE("offset8", TYPE_MOFFS8)
+ TYPE("offset16", TYPE_MOFFS16)
+ TYPE("offset32", TYPE_MOFFS32)
+ TYPE("offset64", TYPE_MOFFS64)
+ errs() << "Unhandled type string " << s << "\n";
+ llvm_unreachable("Unhandled type string");
+}
+#undef TYPE
+
+#define ENCODING(str, encoding) if (s == str) return encoding;
+OperandEncoding RecognizableInstr::immediateEncodingFromString
+ (const std::string &s,
+ bool hasOpSizePrefix) {
+ if(!hasOpSizePrefix) {
+ // For instructions without an OpSize prefix, a declared 16-bit register or
+ // immediate encoding is special.
+ ENCODING("i16imm", ENCODING_IW)
+ }
+ ENCODING("i32i8imm", ENCODING_IB)
+ ENCODING("SSECC", ENCODING_IB)
+ ENCODING("i16imm", ENCODING_Iv)
+ ENCODING("i16i8imm", ENCODING_IB)
+ ENCODING("i32imm", ENCODING_Iv)
+ ENCODING("i64i32imm", ENCODING_ID)
+ ENCODING("i64i8imm", ENCODING_IB)
+ ENCODING("i8imm", ENCODING_IB)
+ errs() << "Unhandled immediate encoding " << s << "\n";
+ llvm_unreachable("Unhandled immediate encoding");
+}
+
+OperandEncoding RecognizableInstr::rmRegisterEncodingFromString
+ (const std::string &s,
+ bool hasOpSizePrefix) {
+ ENCODING("GR16", ENCODING_RM)
+ ENCODING("GR32", ENCODING_RM)
+ ENCODING("GR64", ENCODING_RM)
+ ENCODING("GR8", ENCODING_RM)
+ ENCODING("VR128", ENCODING_RM)
+ ENCODING("FR64", ENCODING_RM)
+ ENCODING("FR32", ENCODING_RM)
+ ENCODING("VR64", ENCODING_RM)
+ errs() << "Unhandled R/M register encoding " << s << "\n";
+ llvm_unreachable("Unhandled R/M register encoding");
+}
+
+OperandEncoding RecognizableInstr::roRegisterEncodingFromString
+ (const std::string &s,
+ bool hasOpSizePrefix) {
+ ENCODING("GR16", ENCODING_REG)
+ ENCODING("GR32", ENCODING_REG)
+ ENCODING("GR64", ENCODING_REG)
+ ENCODING("GR8", ENCODING_REG)
+ ENCODING("VR128", ENCODING_REG)
+ ENCODING("FR64", ENCODING_REG)
+ ENCODING("FR32", ENCODING_REG)
+ ENCODING("VR64", ENCODING_REG)
+ ENCODING("SEGMENT_REG", ENCODING_REG)
+ ENCODING("DEBUG_REG", ENCODING_REG)
+ ENCODING("CONTROL_REG_32", ENCODING_REG)
+ ENCODING("CONTROL_REG_64", ENCODING_REG)
+ errs() << "Unhandled reg/opcode register encoding " << s << "\n";
+ llvm_unreachable("Unhandled reg/opcode register encoding");
+}
+
+OperandEncoding RecognizableInstr::memoryEncodingFromString
+ (const std::string &s,
+ bool hasOpSizePrefix) {
+ ENCODING("i16mem", ENCODING_RM)
+ ENCODING("i32mem", ENCODING_RM)
+ ENCODING("i64mem", ENCODING_RM)
+ ENCODING("i8mem", ENCODING_RM)
+ ENCODING("f128mem", ENCODING_RM)
+ ENCODING("f64mem", ENCODING_RM)
+ ENCODING("f32mem", ENCODING_RM)
+ ENCODING("i128mem", ENCODING_RM)
+ ENCODING("f80mem", ENCODING_RM)
+ ENCODING("lea32mem", ENCODING_RM)
+ ENCODING("lea64_32mem", ENCODING_RM)
+ ENCODING("lea64mem", ENCODING_RM)
+ ENCODING("opaque32mem", ENCODING_RM)
+ ENCODING("opaque48mem", ENCODING_RM)
+ ENCODING("opaque80mem", ENCODING_RM)
+ ENCODING("opaque512mem", ENCODING_RM)
+ errs() << "Unhandled memory encoding " << s << "\n";
+ llvm_unreachable("Unhandled memory encoding");
+}
+
+OperandEncoding RecognizableInstr::relocationEncodingFromString
+ (const std::string &s,
+ bool hasOpSizePrefix) {
+ if(!hasOpSizePrefix) {
+ // For instructions without an OpSize prefix, a declared 16-bit register or
+ // immediate encoding is special.
+ ENCODING("i16imm", ENCODING_IW)
+ }
+ ENCODING("i16imm", ENCODING_Iv)
+ ENCODING("i16i8imm", ENCODING_IB)
+ ENCODING("i32imm", ENCODING_Iv)
+ ENCODING("i32i8imm", ENCODING_IB)
+ ENCODING("i64i32imm", ENCODING_ID)
+ ENCODING("i64i8imm", ENCODING_IB)
+ ENCODING("i8imm", ENCODING_IB)
+ ENCODING("i64i32imm_pcrel", ENCODING_ID)
+ ENCODING("i32imm_pcrel", ENCODING_ID)
+ ENCODING("brtarget", ENCODING_Iv)
+ ENCODING("brtarget8", ENCODING_IB)
+ ENCODING("i64imm", ENCODING_IO)
+ ENCODING("offset8", ENCODING_Ia)
+ ENCODING("offset16", ENCODING_Ia)
+ ENCODING("offset32", ENCODING_Ia)
+ ENCODING("offset64", ENCODING_Ia)
+ errs() << "Unhandled relocation encoding " << s << "\n";
+ llvm_unreachable("Unhandled relocation encoding");
+}
+
+OperandEncoding RecognizableInstr::opcodeModifierEncodingFromString
+ (const std::string &s,
+ bool hasOpSizePrefix) {
+ ENCODING("RST", ENCODING_I)
+ ENCODING("GR32", ENCODING_Rv)
+ ENCODING("GR64", ENCODING_RO)
+ ENCODING("GR16", ENCODING_Rv)
+ ENCODING("GR8", ENCODING_RB)
+ errs() << "Unhandled opcode modifier encoding " << s << "\n";
+ llvm_unreachable("Unhandled opcode modifier encoding");
+}
+#undef ENCODING
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
new file mode 100644
index 0000000..84374b0
--- /dev/null
+++ b/utils/TableGen/X86RecognizableInstr.h
@@ -0,0 +1,237 @@
+//===- X86RecognizableInstr.h - Disassembler instruction spec ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the X86 Disassembler Emitter.
+// It contains the interface of a single recognizable instruction.
+// Documentation for the disassembler emitter in general can be found in
+// X86DisasemblerEmitter.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86RECOGNIZABLEINSTR_H
+#define X86RECOGNIZABLEINSTR_H
+
+#include "X86DisassemblerTables.h"
+
+#include "CodeGenTarget.h"
+#include "Record.h"
+
+#include "llvm/System/DataTypes.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace llvm {
+
+namespace X86Disassembler {
+
+/// RecognizableInstr - Encapsulates all information required to decode a single
+/// instruction, as extracted from the LLVM instruction tables. Has methods
+/// to interpret the information available in the LLVM tables, and to emit the
+/// instruction into DisassemblerTables.
+class RecognizableInstr {
+private:
+ /// The opcode of the instruction, as used in an MCInst
+ InstrUID UID;
+ /// The record from the .td files corresponding to this instruction
+ const Record* Rec;
+ /// The prefix field from the record
+ uint8_t Prefix;
+ /// The opcode field from the record; this is the opcode used in the Intel
+ /// encoding and therefore distinct from the UID
+ uint8_t Opcode;
+ /// The form field from the record
+ uint8_t Form;
+ /// The segment override field from the record
+ uint8_t SegOvr;
+ /// The hasOpSizePrefix field from the record
+ bool HasOpSizePrefix;
+ /// The hasREX_WPrefix field from the record
+ bool HasREX_WPrefix;
+ /// The hasLockPrefix field from the record
+ bool HasLockPrefix;
+ /// The isCodeGenOnly filed from the record
+ bool IsCodeGenOnly;
+
+ /// The instruction name as listed in the tables
+ std::string Name;
+ /// The AT&T AsmString for the instruction
+ std::string AsmString;
+
+ /// Indicates whether the instruction is SSE
+ bool IsSSE;
+ /// Indicates whether the instruction has FR operands - MOVs with FR operands
+ /// are typically ignored
+ bool HasFROperands;
+ /// Indicates whether the instruction should be emitted into the decode
+ /// tables; regardless, it will be emitted into the instruction info table
+ bool ShouldBeEmitted;
+
+ /// The operands of the instruction, as listed in the CodeGenInstruction.
+ /// They are not one-to-one with operands listed in the MCInst; for example,
+ /// memory operands expand to 5 operands in the MCInst
+ const std::vector<CodeGenInstruction::OperandInfo>* Operands;
+ /// The description of the instruction that is emitted into the instruction
+ /// info table
+ InstructionSpecifier* Spec;
+
+ /// insnContext - Returns the primary context in which the instruction is
+ /// valid.
+ ///
+ /// @return - The context in which the instruction is valid.
+ InstructionContext insnContext() const;
+
+ enum filter_ret {
+ FILTER_STRONG, // instruction has no place in the instruction tables
+ FILTER_WEAK, // instruction may conflict, and should be eliminated if
+ // it does
+ FILTER_NORMAL // instruction should have high priority and generate an
+ // error if it conflcits with any other FILTER_NORMAL
+ // instruction
+ };
+
+ /// filter - Determines whether the instruction should be decodable. Some
+ /// instructions are pure intrinsics and use unencodable operands; many
+ /// synthetic instructions are duplicates of other instructions; other
+ /// instructions only differ in the logical way in which they are used, and
+ /// have the same decoding. Because these would cause decode conflicts,
+ /// they must be filtered out.
+ ///
+ /// @return - The degree of filtering to be applied (see filter_ret).
+ filter_ret filter() const;
+
+ /// typeFromString - Translates an operand type from the string provided in
+ /// the LLVM tables to an OperandType for use in the operand specifier.
+ ///
+ /// @param s - The string, as extracted by calling Rec->getName()
+ /// on a CodeGenInstruction::OperandInfo.
+ /// @param isSSE - Indicates whether the instruction is an SSE
+ /// instruction. For SSE instructions, immediates are
+ /// fixed-size rather than being affected by the
+ /// mandatory OpSize prefix.
+ /// @param hasREX_WPrefix - Indicates whether the instruction has a REX.W
+ /// prefix. If it does, 32-bit register operands stay
+ /// 32-bit regardless of the operand size.
+ /// @param hasOpSizePrefix- Indicates whether the instruction has an OpSize
+ /// prefix. If it does not, then 16-bit register
+ /// operands stay 16-bit.
+ /// @return - The operand's type.
+ static OperandType typeFromString(const std::string& s,
+ bool isSSE,
+ bool hasREX_WPrefix,
+ bool hasOpSizePrefix);
+
+ /// immediateEncodingFromString - Translates an immediate encoding from the
+ /// string provided in the LLVM tables to an OperandEncoding for use in
+ /// the operand specifier.
+ ///
+ /// @param s - See typeFromString().
+ /// @param hasOpSizePrefix - Indicates whether the instruction has an OpSize
+ /// prefix. If it does not, then 16-bit immediate
+ /// operands stay 16-bit.
+ /// @return - The operand's encoding.
+ static OperandEncoding immediateEncodingFromString(const std::string &s,
+ bool hasOpSizePrefix);
+
+ /// rmRegisterEncodingFromString - Like immediateEncodingFromString, but
+ /// handles operands that are in the REG field of the ModR/M byte.
+ static OperandEncoding rmRegisterEncodingFromString(const std::string &s,
+ bool hasOpSizePrefix);
+
+ /// rmRegisterEncodingFromString - Like immediateEncodingFromString, but
+ /// handles operands that are in the REG field of the ModR/M byte.
+ static OperandEncoding roRegisterEncodingFromString(const std::string &s,
+ bool hasOpSizePrefix);
+ static OperandEncoding memoryEncodingFromString(const std::string &s,
+ bool hasOpSizePrefix);
+ static OperandEncoding relocationEncodingFromString(const std::string &s,
+ bool hasOpSizePrefix);
+ static OperandEncoding opcodeModifierEncodingFromString(const std::string &s,
+ bool hasOpSizePrefix);
+
+ /// handleOperand - Converts a single operand from the LLVM table format to
+ /// the emitted table format, handling any duplicate operands it encounters
+ /// and then one non-duplicate.
+ ///
+ /// @param optional - Determines whether to assert that the
+ /// operand exists.
+ /// @param operandIndex - The index into the generated operand table.
+ /// Incremented by this function one or more
+ /// times to reflect possible duplicate
+ /// operands).
+ /// @param physicalOperandIndex - The index of the current operand into the
+ /// set of non-duplicate ('physical') operands.
+ /// Incremented by this function once.
+ /// @param numPhysicalOperands - The number of non-duplicate operands in the
+ /// instructions.
+ /// @param operandMapping - The operand mapping, which has an entry for
+ /// each operand that indicates whether it is a
+ /// duplicate, and of what.
+ void handleOperand(bool optional,
+ unsigned &operandIndex,
+ unsigned &physicalOperandIndex,
+ unsigned &numPhysicalOperands,
+ unsigned *operandMapping,
+ OperandEncoding (*encodingFromString)
+ (const std::string&,
+ bool hasOpSizePrefix));
+
+ /// shouldBeEmitted - Returns the shouldBeEmitted field. Although filter()
+ /// filters out many instructions, at various points in decoding we
+ /// determine that the instruction should not actually be decodable. In
+ /// particular, MMX MOV instructions aren't emitted, but they're only
+ /// identified during operand parsing.
+ ///
+ /// @return - true if at this point we believe the instruction should be
+ /// emitted; false if not. This will return false if filter() returns false
+ /// once emitInstructionSpecifier() has been called.
+ bool shouldBeEmitted() const {
+ return ShouldBeEmitted;
+ }
+
+ /// emitInstructionSpecifier - Loads the instruction specifier for the current
+ /// instruction into a DisassemblerTables.
+ ///
+ /// @arg tables - The DisassemblerTables to populate with the specifier for
+ /// the current instruction.
+ void emitInstructionSpecifier(DisassemblerTables &tables);
+
+ /// emitDecodePath - Populates the proper fields in the decode tables
+ /// corresponding to the decode paths for this instruction.
+ ///
+ /// @arg tables - The DisassemblerTables to populate with the decode
+ /// decode information for the current instruction.
+ void emitDecodePath(DisassemblerTables &tables) const;
+
+ /// Constructor - Initializes a RecognizableInstr with the appropriate fields
+ /// from a CodeGenInstruction.
+ ///
+ /// @arg tables - The DisassemblerTables that the specifier will be added to.
+ /// @arg insn - The CodeGenInstruction to extract information from.
+ /// @arg uid - The unique ID of the current instruction.
+ RecognizableInstr(DisassemblerTables &tables,
+ const CodeGenInstruction &insn,
+ InstrUID uid);
+public:
+ /// processInstr - Accepts a CodeGenInstruction and loads decode information
+ /// for it into a DisassemblerTables if appropriate.
+ ///
+ /// @arg tables - The DiassemblerTables to be populated with decode
+ /// information.
+ /// @arg insn - The CodeGenInstruction to be used as a source for this
+ /// information.
+ /// @uid - The unique ID of the instruction.
+ static void processInstr(DisassemblerTables &tables,
+ const CodeGenInstruction &insn,
+ InstrUID uid);
+};
+
+} // namespace X86Disassembler
+
+} // namespace llvm
+
+#endif
OpenPOWER on IntegriCloud