brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.6 KiB · 0f2f117 Raw
402 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Basic/SequenceToOffsetTable.h"10#include "Common/CodeGenDAGPatterns.h" // For SDNodeInfo.11#include "llvm/Support/CommandLine.h"12#include "llvm/Support/FormatVariadic.h"13#include "llvm/TableGen/CodeGenHelpers.h"14#include "llvm/TableGen/Error.h"15#include "llvm/TableGen/StringToOffsetTable.h"16#include "llvm/TableGen/TableGenBackend.h"17 18using namespace llvm;19 20static cl::OptionCategory SDNodeInfoEmitterCat("Options for -gen-sdnode-info");21 22static cl::opt<std::string> TargetSDNodeNamespace(23    "sdnode-namespace", cl::cat(SDNodeInfoEmitterCat),24    cl::desc("Specify target SDNode namespace (default=<Target>ISD)"));25 26static cl::opt<bool> WarnOnSkippedNodes(27    "warn-on-skipped-nodes", cl::cat(SDNodeInfoEmitterCat),28    cl::desc("Explain why a node was skipped (default=true)"), cl::init(true));29 30namespace {31 32class SDNodeInfoEmitter {33  const RecordKeeper &RK;34  const CodeGenTarget Target;35  std::map<StringRef, SmallVector<SDNodeInfo, 2>> NodesByName;36 37public:38  explicit SDNodeInfoEmitter(const RecordKeeper &RK);39 40  void run(raw_ostream &OS) const;41 42private:43  void emitEnum(raw_ostream &OS) const;44 45  std::vector<unsigned> emitNodeNames(raw_ostream &OS) const;46 47  std::vector<std::pair<unsigned, unsigned>>48  emitTypeConstraints(raw_ostream &OS) const;49 50  void emitDescs(raw_ostream &OS) const;51};52 53} // namespace54 55static bool haveCompatibleDescriptions(const SDNodeInfo &N1,56                                       const SDNodeInfo &N2) {57  // Number of results/operands must match.58  if (N1.getNumResults() != N2.getNumResults() ||59      N1.getNumOperands() != N2.getNumOperands())60    return false;61 62  // Flags must match.63  if (N1.isStrictFP() != N2.isStrictFP() || N1.getTSFlags() != N2.getTSFlags())64    return false;65 66  // We're only interested in a subset of node properties. Properties like67  // SDNPAssociative and SDNPCommutative do not impose constraints on nodes,68  // and sometimes differ between nodes sharing the same enum name.69  constexpr unsigned PropMask = (1 << SDNPHasChain) | (1 << SDNPOutGlue) |70                                (1 << SDNPInGlue) | (1 << SDNPOptInGlue) |71                                (1 << SDNPMemOperand) | (1 << SDNPVariadic);72 73  return (N1.getProperties() & PropMask) == (N2.getProperties() & PropMask);74}75 76static bool haveCompatibleDescriptions(ArrayRef<SDNodeInfo> Nodes) {77  const SDNodeInfo &N = Nodes.front();78  return all_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) {79    return haveCompatibleDescriptions(Other, N);80  });81}82 83static void warnOnSkippedNode(const SDNodeInfo &N, const Twine &Reason) {84  PrintWarning(N.getRecord()->getLoc(), "skipped node: " + Reason);85}86 87SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK)88    : RK(RK), Target(RK) {89  const CodeGenHwModes &HwModes = Target.getHwModes();90 91  // Figure out target SDNode namespace.92  if (!TargetSDNodeNamespace.getNumOccurrences())93    TargetSDNodeNamespace = Target.getName().str() + "ISD";94 95  // Filter nodes by the target SDNode namespace and create a mapping96  // from an enum name to a list of nodes that have that name.97  // The mapping is usually 1:1, but in rare cases it can be 1:N.98  for (const Record *R : RK.getAllDerivedDefinitions("SDNode")) {99    SDNodeInfo Node(R, HwModes);100    auto [NS, EnumName] = Node.getEnumName().split("::");101 102    if (NS.empty() || EnumName.empty()) {103      if (WarnOnSkippedNodes)104        warnOnSkippedNode(Node, "invalid enum name");105      continue;106    }107 108    if (NS != TargetSDNodeNamespace)109      continue;110 111    NodesByName[EnumName].push_back(std::move(Node));112  }113 114  // Filter out nodes that have different "prototypes" and/or flags.115  // Don't look at type constraints though, we will simply skip emitting116  // the constraints if they differ.117  decltype(NodesByName)::iterator Next;118  for (auto I = NodesByName.begin(), E = NodesByName.end(); I != E; I = Next) {119    Next = std::next(I);120 121    if (haveCompatibleDescriptions(I->second))122      continue;123 124    if (WarnOnSkippedNodes)125      for (const SDNodeInfo &N : I->second)126        warnOnSkippedNode(N, "incompatible description");127 128    NodesByName.erase(I);129  }130}131 132void SDNodeInfoEmitter::emitEnum(raw_ostream &OS) const {133  IfDefEmitter IfDef(OS, "GET_SDNODE_ENUM");134  NamespaceEmitter NS(OS, "llvm::" + TargetSDNodeNamespace);135 136  if (!NodesByName.empty()) {137    StringRef FirstName = NodesByName.begin()->first;138    StringRef LastName = NodesByName.rbegin()->first;139 140    OS << "enum GenNodeType : unsigned {\n";141    OS << "  " << FirstName << " = ISD::BUILTIN_OP_END,\n";142 143    for (StringRef EnumName : make_first_range(drop_begin(NodesByName)))144      OS << "  " << EnumName << ",\n";145 146    OS << "};\n\n";147    OS << "static constexpr unsigned GENERATED_OPCODE_END = " << LastName148       << " + 1;\n";149  } else {150    OS << "static constexpr unsigned GENERATED_OPCODE_END = "151          "ISD::BUILTIN_OP_END;\n";152  }153}154 155std::vector<unsigned> SDNodeInfoEmitter::emitNodeNames(raw_ostream &OS) const {156  StringToOffsetTable NameTable;157 158  std::vector<unsigned> NameOffsets;159  NameOffsets.reserve(NodesByName.size());160 161  for (StringRef EnumName : make_first_range(NodesByName)) {162    SmallString<64> DebugName;163    raw_svector_ostream SS(DebugName);164    SS << TargetSDNodeNamespace << "::" << EnumName;165    NameOffsets.push_back(NameTable.GetOrAddStringOffset(DebugName));166  }167 168  NameTable.EmitStringTableDef(OS, Target.getName() + "SDNodeNames");169  OS << '\n';170 171  return NameOffsets;172}173 174static StringRef getTypeConstraintKindName(SDTypeConstraint::KindTy Kind) {175#define CASE(NAME)                                                             \176  case SDTypeConstraint::NAME:                                                 \177    return #NAME178 179  switch (Kind) {180    CASE(SDTCisVT);181    CASE(SDTCisPtrTy);182    CASE(SDTCisInt);183    CASE(SDTCisFP);184    CASE(SDTCisVec);185    CASE(SDTCisSameAs);186    CASE(SDTCisVTSmallerThanOp);187    CASE(SDTCisOpSmallerThanOp);188    CASE(SDTCisEltOfVec);189    CASE(SDTCisSubVecOfVec);190    CASE(SDTCVecEltisVT);191    CASE(SDTCisSameNumEltsAs);192    CASE(SDTCisSameSizeAs);193  }194  llvm_unreachable("Unknown constraint kind"); // Make MSVC happy.195#undef CASE196}197 198static void emitTypeConstraint(199    raw_ostream &OS, SDTypeConstraint C,200    const std::map<ValueTypeByHwMode, unsigned> &VTByHwModeTable) {201  unsigned OtherOpNo = 0;202  unsigned NumHwModes = 0;203  unsigned VTByHwModeOffset = 0;204  MVT VT = MVT::INVALID_SIMPLE_VALUE_TYPE;205 206  switch (C.ConstraintType) {207  case SDTypeConstraint::SDTCisVT:208    // SequenceToOffsetTable::emit() prints a "dummy" (default-constructed)209    // element if the table would otherwise be empty. VVT is empty in this case.210    if (C.VVT.empty())211      break;212    [[fallthrough]];213  case SDTypeConstraint::SDTCVecEltisVT:214    if (C.VVT.isSimple()) {215      VT = C.VVT.getSimple();216    } else {217      NumHwModes = C.VVT.size();218      assert(NumHwModes && "Empty type set?");219      VTByHwModeOffset = VTByHwModeTable.at(C.VVT);220    }221    break;222  case SDTypeConstraint::SDTCisPtrTy:223  case SDTypeConstraint::SDTCisInt:224  case SDTypeConstraint::SDTCisFP:225  case SDTypeConstraint::SDTCisVec:226    break;227  case SDTypeConstraint::SDTCisSameAs:228  case SDTypeConstraint::SDTCisVTSmallerThanOp:229  case SDTypeConstraint::SDTCisOpSmallerThanOp:230  case SDTypeConstraint::SDTCisEltOfVec:231  case SDTypeConstraint::SDTCisSubVecOfVec:232  case SDTypeConstraint::SDTCisSameNumEltsAs:233  case SDTypeConstraint::SDTCisSameSizeAs:234    OtherOpNo = C.OtherOperandNo;235    break;236  }237 238  OS << '{' << getTypeConstraintKindName(C.ConstraintType) << ", "239     << C.OperandNo << ", " << OtherOpNo << ", " << NumHwModes << ", ";240  if (NumHwModes) {241    OS << VTByHwModeOffset;242  } else {243    OS << (VT == MVT::INVALID_SIMPLE_VALUE_TYPE244               ? "MVT::INVALID_SIMPLE_VALUE_TYPE"245               : getEnumName(VT));246  }247  OS << '}';248}249 250std::vector<std::pair<unsigned, unsigned>>251SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const {252  std::map<ValueTypeByHwMode, unsigned> VTByHwModeTable;253 254  using ConstraintsVecTy = SmallVector<SDTypeConstraint, 0>;255  SequenceToOffsetTable<ConstraintsVecTy> ConstraintTable(256      /*Terminator=*/std::nullopt);257 258  std::vector<std::pair<unsigned, unsigned>> ConstraintOffsetsAndCounts;259  ConstraintOffsetsAndCounts.reserve(NodesByName.size());260 261  SmallVector<StringRef> SkippedNodes;262  for (const auto &[EnumName, Nodes] : NodesByName) {263    ArrayRef<SDTypeConstraint> Constraints = Nodes.front().getTypeConstraints();264 265    bool IsAmbiguous = any_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) {266      return ArrayRef(Other.getTypeConstraints()) != Constraints;267    });268 269    // If nodes with the same enum name have different constraints,270    // treat them as if they had no constraints at all.271    if (IsAmbiguous) {272      SkippedNodes.push_back(EnumName);273      continue;274    }275 276    // Don't add empty sequences to the table. This slightly simplifies277    // the implementation and makes the output less confusing if the table278    // ends up empty.279    if (Constraints.empty())280      continue;281 282    for (const SDTypeConstraint &C : Constraints) {283      if (C.ConstraintType == SDTypeConstraint::SDTCisVT ||284          C.ConstraintType == SDTypeConstraint::SDTCVecEltisVT) {285        if (!C.VVT.isSimple()) {286          assert(!C.VVT.empty() && "Unexpected empty type set");287          VTByHwModeTable.try_emplace(C.VVT);288        }289      }290    }291 292    // SequenceToOffsetTable reuses the storage if a sequence matches another293    // sequence's *suffix*. It is more likely that we have a matching *prefix*,294    // so reverse the order to increase the likelihood of a match.295    ConstraintTable.add(ConstraintsVecTy(reverse(Constraints)));296  }297 298  ConstraintTable.layout();299 300  OS << "static const VTByHwModePair " << Target.getName()301     << "VTByHwModeTable[] = {\n";302  unsigned VTByHwModeOffset = 0;303  for (auto &[VTByHwMode, Offset] : VTByHwModeTable) {304    OS << "  /* " << VTByHwModeOffset << " */ ";305    for (auto [Mode, VT] : VTByHwMode)306      OS << '{' << Mode << ", " << getEnumName(VT.SimpleTy) << "}, ";307    OS << '\n';308    Offset = VTByHwModeOffset;309    VTByHwModeOffset += VTByHwMode.size();310  }311  // Avoid "zero size arrays are an extension" warning.312  if (VTByHwModeTable.empty())313    OS << "  /* dummy */ {0, MVT::INVALID_SIMPLE_VALUE_TYPE}\n";314  OS << "};\n\n";315 316  OS << "static const SDTypeConstraint " << Target.getName()317     << "SDTypeConstraints[] = {\n";318  ConstraintTable.emit(OS, std::bind(emitTypeConstraint, std::placeholders::_1,319                                     std::placeholders::_2, VTByHwModeTable));320  OS << "};\n\n";321 322  for (const auto &[EnumName, Nodes] : NodesByName) {323    ArrayRef<SDTypeConstraint> Constraints = Nodes.front().getTypeConstraints();324 325    if (Constraints.empty() || is_contained(SkippedNodes, EnumName)) {326      ConstraintOffsetsAndCounts.emplace_back(/*Offset=*/0, /*Size=*/0);327      continue;328    }329 330    unsigned ConstraintsOffset =331        ConstraintTable.get(ConstraintsVecTy(reverse(Constraints)));332    ConstraintOffsetsAndCounts.emplace_back(ConstraintsOffset,333                                            Constraints.size());334  }335 336  return ConstraintOffsetsAndCounts;337}338 339static void emitDesc(raw_ostream &OS, StringRef EnumName,340                     ArrayRef<SDNodeInfo> Nodes, unsigned NameOffset,341                     unsigned ConstraintsOffset, unsigned ConstraintCount) {342  assert(haveCompatibleDescriptions(Nodes));343  const SDNodeInfo &N = Nodes.front();344  OS << "    {" << N.getNumResults() << ", " << N.getNumOperands() << ", 0";345 346  // Emitted properties must be kept in sync with haveCompatibleDescriptions.347  unsigned Properties = N.getProperties();348  if (Properties & (1 << SDNPHasChain))349    OS << "|1<<SDNPHasChain";350  if (Properties & (1 << SDNPOutGlue))351    OS << "|1<<SDNPOutGlue";352  if (Properties & (1 << SDNPInGlue))353    OS << "|1<<SDNPInGlue";354  if (Properties & (1 << SDNPOptInGlue))355    OS << "|1<<SDNPOptInGlue";356  if (Properties & (1 << SDNPVariadic))357    OS << "|1<<SDNPVariadic";358  if (Properties & (1 << SDNPMemOperand))359    OS << "|1<<SDNPMemOperand";360 361  OS << ", 0";362  if (N.isStrictFP())363    OS << "|1<<SDNFIsStrictFP";364 365  OS << formatv(", {}, {}, {}, {}}, // {}\n", N.getTSFlags(), NameOffset,366                ConstraintsOffset, ConstraintCount, EnumName);367}368 369void SDNodeInfoEmitter::emitDescs(raw_ostream &OS) const {370  StringRef TargetName = Target.getName();371 372  IfDefEmitter IfDef(OS, "GET_SDNODE_DESC");373  NamespaceEmitter NS(OS, "llvm");374 375  std::vector<unsigned> NameOffsets = emitNodeNames(OS);376  std::vector<std::pair<unsigned, unsigned>> ConstraintOffsetsAndCounts =377      emitTypeConstraints(OS);378 379  OS << "static const SDNodeDesc " << TargetName << "SDNodeDescs[] = {\n";380 381  for (const auto &[NameAndNodes, NameOffset, ConstraintOffsetAndCount] :382       zip_equal(NodesByName, NameOffsets, ConstraintOffsetsAndCounts))383    emitDesc(OS, NameAndNodes.first, NameAndNodes.second, NameOffset,384             ConstraintOffsetAndCount.first, ConstraintOffsetAndCount.second);385 386  OS << "};\n\n";387 388  OS << formatv("static const SDNodeInfo {0}GenSDNodeInfo(\n"389                "    /*NumOpcodes=*/{1}, {0}SDNodeDescs, {0}SDNodeNames,\n"390                "    {0}VTByHwModeTable, {0}SDTypeConstraints);\n",391                TargetName, NodesByName.size());392}393 394void SDNodeInfoEmitter::run(raw_ostream &OS) const {395  emitSourceFileHeader("Target SDNode descriptions", OS, RK);396  emitEnum(OS);397  emitDescs(OS);398}399 400static TableGen::Emitter::OptClass<SDNodeInfoEmitter>401    X("gen-sd-node-info", "Generate target SDNode descriptions");402