[PATCH 1/2] TableGen: Generate a function for getting operand indices based on their defined names
Tom Stellard
tom at stellard.net
Mon Jun 24 12:22:52 PDT 2013
Ping.
On Thu, Jun 20, 2013 at 10:58:03AM -0700, Tom Stellard wrote:
> Hi Sean,
>
> Attached is an updated patch which addresses your comments.
>
> On Wed, Jun 19, 2013 at 12:52:03PM -0700, Sean Silva wrote:
> > +.. code-block:: llvm
> >
> > This should be a `c++` code block, since this is c++ code (this determines
> > how it is syntax-highlighted).
> >
> > + int DIndex = SP::getNamedOperandIdx(SP::XNORrr, SP::OpName::d); //
> > => -1
> >
> > Does it even make sense to return -1 for "not found"?
> >
>
> Do you think we should be returning some other value for "not found"?
>
> -Tom
>
> > +/// for looking up the operand index for an instruction, given a vlue
> > from
> >
> > Spelling: vlue
> >
> > + std::map<unsigned, unsigned> OpList = i->first;
> >
> > Do you really need to make a copy here?
> >
> > + std::map<unsigned, unsigned> OpList = i->first;
> > + std::vector<std::string> OpcodeList = i->second;
> >
> > Same.
> >
> > + for (std::map<std::string, unsigned>::iterator i = Operands.begin(),
> > + e = Operands.end();
> > + i != e; ++i) {
> > + OS << " " << i->first << " = " << i->second << ",\n";
> > + }
> >
> > The formatting of this looks really awkward. Regardless, you can make this
> > more readable with a typedef:
> >
> > typedef std::map<std::string, unsigned>::iterator Iter;
> > for (Iter i = Operands.begin(), e = Operands.end(); i != e; ++i)
> > OS << " " << i->first << " = " << i->second << ",\n";
> >
> > + std::map<unsigned, unsigned> OpList;
> > + for (unsigned j = 0, je = Inst->Operands.size(); j != je; ++j) {
> > + CGIOperandList::OperandInfo Info = Inst->Operands[j];
> > + std::string Name = Info.Name;
> > + if (Operands.count(Name) == 0) {
> > + Operands[Name] = NumOperands++;
> > + }
> > + unsigned OperandId = Operands[Name];
> > + OpList[OperandId] = Info.MIOperandNo;
> > + }
> >
> > Do you really need to make a copy of Name? Also, Info is really not cheap
> > to copy (at least 4 std::string and a vector<bool>). Unnecessary copies
> > seems to be a recurring problem in this patch; please go through the entire
> > patch and ensure that you are not unnecessarily making copies.
> >
> > Also, You're doing 2-3 separate map lookups for the same element in the
> > inner loop here (are we smart enough to optimize that away? I would be
> > surprised if we were).
> >
> > + for (unsigned i = 0, e = NumberedInstructions.size(), NumOperands = 0;
> > + i != e;
> > ++i) {
> > + const CodeGenInstruction *Inst = NumberedInstructions[i];
> > + if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable")) {
> > + continue;
> > + }
> > + std::map<unsigned, unsigned> OpList;
> > + for (unsigned j = 0, je = Inst->Operands.size(); j != je; ++j) {
> > + CGIOperandList::OperandInfo Info = Inst->Operands[j];
> > + std::string Name = Info.Name;
> > + if (Operands.count(Name) == 0) {
> > + Operands[Name] = NumOperands++;
> > + }
> > + unsigned OperandId = Operands[Name];
> > + OpList[OperandId] = Info.MIOperandNo;
> > + }
> > + OperandMap[OpList].push_back(Namespace + "::" +
> > Inst->TheDef->getName());
> > + }
> >
> > Can you move this into a helper function?
> >
> > + unsigned TableIndex = 0;
> > + for (OpNameMapTy::iterator i = OperandMap.begin(), e = OperandMap.end();
> > + i != e; ++i,
> > ++TableIndex) {
> > + std::map<unsigned, unsigned> OpList = i->first;
> > + std::vector<std::string> OpcodeList = i->second;
> > +
> > + for (unsigned ii = 0, ie = OpcodeList.size(); ii != ie; ++ii)
> > + OS << " case " << OpcodeList[ii] << ":\n";
> > +
> > + OS << " return OperandMap[" << TableIndex << "][NamedIdx];\n";
> > + }
> >
> > The ++TableIndex is kind of hidden in the loop header, can you just do
> > TableIndex++ as you output it?
> >
> > -- Sean Silva
> From 7e7ee5ee45aee0793c6f27cab7910645063454b9 Mon Sep 17 00:00:00 2001
> From: Tom Stellard <thomas.stellard at amd.com>
> Date: Thu, 30 May 2013 10:10:50 -0700
> Subject: [PATCH] TableGen: Generate a function for getting operand indices
> based on their defined names v5
>
> This patch modifies TableGen to generate a function in
> ${TARGET}GenInstrInfo.inc called getNamedOperandIdx(), which can be used
> to look up indices for operands based on their names.
>
> In order to activate this feature for an instruction, you must set the
> UseNamedOperandTable bit.
>
> For example, if you have an instruction like:
>
> def ADD : TargetInstr <(outs GPR:$dst), (ins GPR:$src0, GPR:$src1)>;
>
> You can look up the operand indices using the new function, like this:
>
> Target::getNamedOperandIdx(Target::ADD, Target::OpName::dst) => 0
> Target::getNamedOperandIdx(Target::ADD, Target::OpName::src0) => 1
> Target::getNamedOperandIdx(Target::ADD, Target::OpName::src1) => 2
>
> The operand names are case sensitive, so $dst and $DST are considered
> different operands.
>
> This change is useful for R600 which has instructions with a large number
> of operands, many of which model single bit instruction configuration
> values. These configuration bits are common across most instructions,
> but may have a different operand index depending on the instruction type.
> It is useful to have a convenient way to look up the operand indices,
> so these bits can be generically set on any instruction.
>
> v2:
> - Don't uppercase enum values
> - Use table compresion to reduce function size
>
> v3:
> - Only generate table for instructions with the UseNamedOperandTable
> bit set.
>
> v4:
> - Clean up code and add documentation
>
> v5:
> - More code cleanups
> ---
> docs/WritingAnLLVMBackend.rst | 41 ++++++++++++
> include/llvm/Target/Target.td | 5 ++
> utils/TableGen/InstrInfoEmitter.cpp | 130 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 176 insertions(+)
>
> diff --git a/docs/WritingAnLLVMBackend.rst b/docs/WritingAnLLVMBackend.rst
> index a03a5e4..9e3cb9e 100644
> --- a/docs/WritingAnLLVMBackend.rst
> +++ b/docs/WritingAnLLVMBackend.rst
> @@ -911,6 +911,47 @@ format instructions will bind the operands to the ``rd``, ``rs1``, and ``rs2``
> fields. This results in the ``XNORrr`` instruction binding ``$dst``, ``$b``,
> and ``$c`` operands to the ``rd``, ``rs1``, and ``rs2`` fields respectively.
>
> +TableGen will also generate a function called getNamedOperandIdx() which
> +can be used to look up an operand's index in a MachineInstr based on its
> +TableGen name. Setting the UseNamedOperandTable bit in an instruction's
> +TableGen definition will add all of its operands to an enumeration in the
> +llvm::XXX:OpName namespace and also add an entry for it into the OperandMap
> +table, which can be queried using getNamedOperandIdx()
> +
> +.. code-block:: llvm
> +
> + int DstIndex = SP::getNamedOperandIdx(SP::XNORrr, SP::OpName::dst); // => 0
> + int BIndex = SP::getNamedOperandIdx(SP::XNORrr, SP::OpName::b); // => 1
> + int CIndex = SP::getNamedOperandIdx(SP::XNORrr, SP::OpName::c); // => 2
> + int DIndex = SP::getNamedOperandIdx(SP::XNORrr, SP::OpName::d); // => -1
> +
> + ...
> +
> +The entries in the OpName enum are taken verbatim from the TableGen definitions,
> +so operands with lowercase names will have lower case entries in the enum.
> +
> +To include the getNamedOperandIdx() function in your backend, you will need
> +to define a few preprocessor macros in XXXInstrInfo.cpp and XXXInstrInfo.h.
> +For example:
> +
> +XXXInstrInfo.cpp:
> +
> +.. code-block:: c++
> +
> + #define GET_INSTRINFO_NAMED_OPS // For getNamedOperandIdx() function
> + #include "XXXGenInstrInfo.inc"
> +
> +XXXInstrInfo.h:
> +
> +.. code-block:: c++
> +
> + #define GET_INSTRINFO_OPERAND_ENUM // For OpName enum
> + #include "XXXGenInstrInfo.inc"
> +
> + namespace XXX {
> + int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIndex);
> + } // End namespace XXX
> +
> Instruction Relation Mapping
> ----------------------------
>
> diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td
> index a9644d4..97df64c 100644
> --- a/include/llvm/Target/Target.td
> +++ b/include/llvm/Target/Target.td
> @@ -445,6 +445,11 @@ class Instruction {
> string TwoOperandAliasConstraint = "";
>
> ///@}
> +
> + /// UseNamedOperandTable - If set, the operand indices of this instruction
> + /// can be queried via the getNamedOperandIdx() function which is generated
> + /// by TableGen.
> + bit UseNamedOperandTable = 0;
> }
>
> /// PseudoInstExpansion - Expansion information for a pseudo-instruction.
> diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
> index d6020a8..532e206 100644
> --- a/utils/TableGen/InstrInfoEmitter.cpp
> +++ b/utils/TableGen/InstrInfoEmitter.cpp
> @@ -45,11 +45,25 @@ private:
> void emitEnums(raw_ostream &OS);
>
> typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
> +
> + /// The keys of this map are maps which have OpName enum values as their keys
> + /// and instruction operand indices as their values. The values of this map
> + /// are lists of instruction names.
> + typedef std::map<std::map<unsigned, unsigned>,
> + std::vector<std::string> > OpNameMapTy;
> + typedef std::map<std::string, unsigned>::iterator StrUintMapIter;
> void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
> Record *InstrInfo,
> std::map<std::vector<Record*>, unsigned> &EL,
> const OperandInfoMapTy &OpInfo,
> raw_ostream &OS);
> + void initOperandMapData(
> + const std::vector<const CodeGenInstruction *> NumberedInstructions,
> + std::string Namespace,
> + std::map<std::string, unsigned> &Operands,
> + OpNameMapTy &OperandMap);
> + void emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target,
> + const std::vector<const CodeGenInstruction*> &NumberedInstructions);
>
> // Operand information.
> void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs);
> @@ -176,6 +190,120 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
> }
> }
>
> +
> +/// Initialize data structures for generating operand name mappings.
> +///
> +/// \p Operands [out] A map used to generate the OpName enum with operand
> +/// names as its keys and operand enum values as its values.
> +/// \p OperandMap [out] A map for representing the operand name mappings for
> +/// each instructions. This is used to generate the OperandMap table as
> +/// well as the getNamedOperandIdx() function.
> +void InstrInfoEmitter::initOperandMapData(
> + const std::vector<const CodeGenInstruction *> NumberedInstructions,
> + std::string Namespace,
> + std::map<std::string, unsigned> &Operands,
> + OpNameMapTy &OperandMap) {
> +
> + for (unsigned i = 0, e = NumberedInstructions.size(), NumOperands = 0;
> + i != e; ++i) {
> + const CodeGenInstruction *Inst = NumberedInstructions[i];
> + if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable")) {
> + continue;
> + }
> + std::map<unsigned, unsigned> OpList;
> + for (unsigned j = 0, je = Inst->Operands.size(); j != je; ++j) {
> + const CGIOperandList::OperandInfo &Info = Inst->Operands[j];
> + StrUintMapIter I = Operands.find(Info.Name);
> +
> + if (I == Operands.end()) {
> + I = Operands.insert(Operands.begin(),
> + std::pair<std::string, unsigned>(Info.Name, NumOperands++));
> + }
> + OpList[I->second] = Info.MIOperandNo;
> + }
> + OperandMap[OpList].push_back(Namespace + "::" + Inst->TheDef->getName());
> + }
> +}
> +
> +/// Generate a table and function for looking up the indices of operands by
> +/// name.
> +///
> +/// This code generates:
> +/// - An enum in the llvm::TargetNamespace::OpName namespace, with one entry
> +/// for each operand name.
> +/// - A 2-dimensional table called OperandMap for mapping OpName enum values to
> +/// operand indices.
> +/// - A function called getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx)
> +/// for looking up the operand index for an instruction, given a value from
> +/// OpName enum
> +void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
> + const CodeGenTarget &Target,
> + const std::vector<const CodeGenInstruction*> &NumberedInstructions) {
> +
> + std::string Namespace = Target.getInstNamespace();
> + std::string OpNameNS = "OpName";
> + // Map of operand names to their enumeration value. This will be used to
> + // generate the OpName enum.
> + std::map<std::string, unsigned> Operands;
> + OpNameMapTy OperandMap;
> +
> + initOperandMapData(NumberedInstructions, Namespace, Operands, OperandMap);
> +
> + OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n";
> + OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n";
> + OS << "namespace llvm {";
> + OS << "namespace " << Namespace << " {\n";
> + OS << "namespace " << OpNameNS << " { \n";
> + OS << "enum {\n";
> + for (StrUintMapIter i = Operands.begin(), e = Operands.end(); i != e; ++i)
> + OS << " " << i->first << " = " << i->second << ",\n";
> +
> + OS << "OPERAND_LAST";
> + OS << "\n};\n";
> + OS << "} // End namespace OpName\n";
> + OS << "} // End namespace " << Namespace << "\n";
> + OS << "} // End namespace llvm\n";
> + OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n";
> +
> + OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n";
> + OS << "#undef GET_INSTRINFO_NAMED_OPS\n";
> + OS << "namespace llvm {";
> + OS << "namespace " << Namespace << " {\n";
> + OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n";
> + OS << " static const int16_t OperandMap []["<< Operands.size() << "] = {\n";
> + for (OpNameMapTy::iterator i = OperandMap.begin(), e = OperandMap.end();
> + i != e; ++i) {
> + const std::map<unsigned, unsigned> &OpList = i->first;
> + OS << "{";
> +
> + // Emit a row of the OperandMap table
> + for (unsigned i = 0, e = Operands.size(); i != e; ++i)
> + OS << (OpList.count(i) == 0 ? -1 : (int)OpList.find(i)->second) << ", ";
> +
> + OS << "},\n";
> + }
> + OS << "};\n";
> +
> + OS << " switch(Opcode) {\n";
> + unsigned TableIndex = 0;
> + for (OpNameMapTy::iterator i = OperandMap.begin(), e = OperandMap.end();
> + i != e; ++i) {
> + std::vector<std::string> &OpcodeList = i->second;
> +
> + for (unsigned ii = 0, ie = OpcodeList.size(); ii != ie; ++ii)
> + OS << " case " << OpcodeList[ii] << ":\n";
> +
> + OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n";
> + }
> + OS << " default: return -1;\n";
> + OS << " }\n";
> + OS << "}\n";
> + OS << "} // End namespace " << Namespace << "\n";
> + OS << "} // End namespace llvm\n";
> + OS << "#endif //GET_INSTRINFO_NAMED_OPS\n";
> +
> +}
> +
> //===----------------------------------------------------------------------===//
> // Main Output.
> //===----------------------------------------------------------------------===//
> @@ -293,6 +421,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
> OS << "} // End llvm namespace \n";
>
> OS << "#endif // GET_INSTRINFO_CTOR\n\n";
> +
> + emitOperandNameMappings(OS, Target, NumberedInstructions);
> }
>
> void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
> --
> 1.7.11.4
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list