brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.0 KiB · 9b05bcc Raw
435 lines · cpp
1//===- CodeGenTarget.cpp - CodeGen Target Class Wrapper -------------------===//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// This class wraps target description classes used by the various code10// generation TableGen backends.  This makes it easier to access the data and11// provides a single place that needs to check it for validity.  All of these12// classes abort on error conditions.13//14//===----------------------------------------------------------------------===//15 16#include "CodeGenTarget.h"17#include "CodeGenInstruction.h"18#include "CodeGenRegisters.h"19#include "CodeGenSchedule.h"20#include "llvm/ADT/STLExtras.h"21#include "llvm/ADT/StringSwitch.h"22#include "llvm/ADT/Twine.h"23#include "llvm/Support/CommandLine.h"24#include "llvm/Support/ErrorHandling.h"25#include "llvm/TableGen/Error.h"26#include "llvm/TableGen/Record.h"27#include <tuple>28using namespace llvm;29 30static cl::OptionCategory AsmParserCat("Options for -gen-asm-parser");31static cl::OptionCategory AsmWriterCat("Options for -gen-asm-writer");32 33static cl::opt<unsigned>34    AsmParserNum("asmparsernum", cl::init(0),35                 cl::desc("Make -gen-asm-parser emit assembly parser #N"),36                 cl::cat(AsmParserCat));37 38static cl::opt<unsigned>39    AsmWriterNum("asmwriternum", cl::init(0),40                 cl::desc("Make -gen-asm-writer emit assembly writer #N"),41                 cl::cat(AsmWriterCat));42 43/// Returns the MVT that the specified TableGen44/// record corresponds to.45MVT llvm::getValueType(const Record *Rec) {46  return StringSwitch<MVT>(Rec->getValueAsString("LLVMName"))47#define GET_VT_ATTR(Ty, Sz, Any, Int, FP, Vec, Sc, Tup, NF, NElem, EltTy)      \48  .Case(#Ty, MVT::Ty)49#include "llvm/CodeGen/GenVT.inc"50#undef GET_VT_ATTR51      .Case("INVALID_SIMPLE_VALUE_TYPE", MVT::INVALID_SIMPLE_VALUE_TYPE);52}53 54StringRef llvm::getEnumName(MVT T) {55  // clang-format off56  switch (T.SimpleTy) {57#define GET_VT_ATTR(Ty, Sz, Any, Int, FP, Vec, Sc, Tup, NF, NElem, EltTy)   \58  case MVT::Ty: return "MVT::" # Ty;59#include "llvm/CodeGen/GenVT.inc"60#undef GET_VT_ATTR61  default: llvm_unreachable("ILLEGAL VALUE TYPE!");62  }63  // clang-format on64}65 66/// getQualifiedName - Return the name of the specified record, with a67/// namespace qualifier if the record contains one.68///69std::string llvm::getQualifiedName(const Record *R) {70  std::string Namespace;71  if (R->getValue("Namespace"))72    Namespace = R->getValueAsString("Namespace").str();73  if (Namespace.empty())74    return R->getName().str();75  return Namespace + "::" + R->getName().str();76}77 78CodeGenTarget::CodeGenTarget(const RecordKeeper &records)79    : Records(records), CGH(records), Intrinsics(records) {80  ArrayRef<const Record *> Targets = Records.getAllDerivedDefinitions("Target");81  if (Targets.size() == 0)82    PrintFatalError("No 'Target' subclasses defined!");83  if (Targets.size() != 1)84    PrintFatalError("Multiple subclasses of Target defined!");85  TargetRec = Targets[0];86  MacroFusions = Records.getAllDerivedDefinitions("Fusion");87}88 89CodeGenTarget::~CodeGenTarget() = default;90 91StringRef CodeGenTarget::getName() const { return TargetRec->getName(); }92 93/// getInstNamespace - Find and return the target machine's instruction94/// namespace. The namespace is cached because it is requested multiple times.95StringRef CodeGenTarget::getInstNamespace() const {96  if (InstNamespace.empty()) {97    for (const CodeGenInstruction *Inst : getInstructions()) {98      // We are not interested in the "TargetOpcode" namespace.99      if (Inst->Namespace != "TargetOpcode") {100        InstNamespace = Inst->Namespace;101        break;102      }103    }104  }105 106  return InstNamespace;107}108 109StringRef CodeGenTarget::getRegNamespace() const {110  auto &RegClasses = RegBank->getRegClasses();111  return RegClasses.size() > 0 ? RegClasses.front().Namespace : "";112}113 114const Record *CodeGenTarget::getInstructionSet() const {115  return TargetRec->getValueAsDef("InstructionSet");116}117 118bool CodeGenTarget::getAllowRegisterRenaming() const {119  return TargetRec->getValueAsInt("AllowRegisterRenaming");120}121 122/// getAsmParser - Return the AssemblyParser definition for this target.123///124const Record *CodeGenTarget::getAsmParser() const {125  std::vector<const Record *> LI =126      TargetRec->getValueAsListOfDefs("AssemblyParsers");127  if (AsmParserNum >= LI.size())128    PrintFatalError("Target does not have an AsmParser #" +129                    Twine(AsmParserNum) + "!");130  return LI[AsmParserNum];131}132 133/// getAsmParserVariant - Return the AssemblyParserVariant definition for134/// this target.135///136const Record *CodeGenTarget::getAsmParserVariant(unsigned Idx) const {137  std::vector<const Record *> LI =138      TargetRec->getValueAsListOfDefs("AssemblyParserVariants");139  if (Idx >= LI.size())140    PrintFatalError("Target does not have an AsmParserVariant #" + Twine(Idx) +141                    "!");142  return LI[Idx];143}144 145/// getAsmParserVariantCount - Return the AssemblyParserVariant definition146/// available for this target.147///148unsigned CodeGenTarget::getAsmParserVariantCount() const {149  return TargetRec->getValueAsListOfDefs("AssemblyParserVariants").size();150}151 152/// getAsmWriter - Return the AssemblyWriter definition for this target.153///154const Record *CodeGenTarget::getAsmWriter() const {155  std::vector<const Record *> LI =156      TargetRec->getValueAsListOfDefs("AssemblyWriters");157  if (AsmWriterNum >= LI.size())158    PrintFatalError("Target does not have an AsmWriter #" +159                    Twine(AsmWriterNum) + "!");160  return LI[AsmWriterNum];161}162 163CodeGenRegBank &CodeGenTarget::getRegBank() const {164  if (!RegBank)165    RegBank = std::make_unique<CodeGenRegBank>(Records, getHwModes());166  return *RegBank;167}168 169/// getRegisterByName - If there is a register with the specific AsmName,170/// return it.171const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const {172  return getRegBank().getRegistersByName().lookup(Name);173}174 175const CodeGenRegisterClass &176CodeGenTarget::getRegisterClass(const Record *R) const {177  return *getRegBank().getRegClass(R);178}179 180std::vector<ValueTypeByHwMode>181CodeGenTarget::getRegisterVTs(const Record *R) const {182  const CodeGenRegister *Reg = getRegBank().getReg(R);183  std::vector<ValueTypeByHwMode> Result;184  for (const auto &RC : getRegBank().getRegClasses()) {185    if (RC.contains(Reg)) {186      ArrayRef<ValueTypeByHwMode> InVTs = RC.getValueTypes();187      llvm::append_range(Result, InVTs);188    }189  }190 191  // Remove duplicates.192  llvm::sort(Result);193  Result.erase(llvm::unique(Result), Result.end());194  return Result;195}196 197void CodeGenTarget::ReadLegalValueTypes() const {198  for (const auto &RC : getRegBank().getRegClasses())199    llvm::append_range(LegalValueTypes, RC.VTs);200 201  // Remove duplicates.202  llvm::sort(LegalValueTypes);203  LegalValueTypes.erase(llvm::unique(LegalValueTypes), LegalValueTypes.end());204}205 206const Record *CodeGenTarget::getInitValueAsRegClass(207    const Init *V, bool AssumeRegClassByHwModeIsDefault) const {208  const Record *RegClassLike = getInitValueAsRegClassLike(V);209  if (!RegClassLike || RegClassLike->isSubClassOf("RegisterClass"))210    return RegClassLike;211 212  // FIXME: We should figure out the hwmode and dispatch. But this interface213  // is broken, we should be returning a register class. The expected uses214  // will use the same RegBanks in all modes.215  if (AssumeRegClassByHwModeIsDefault &&216      RegClassLike->isSubClassOf("RegClassByHwMode")) {217    const HwModeSelect &ModeSelect = getHwModes().getHwModeSelect(RegClassLike);218    if (ModeSelect.Items.empty())219      return nullptr;220    return ModeSelect.Items.front().second;221  }222 223  return nullptr;224}225 226const Record *CodeGenTarget::getInitValueAsRegClassLike(const Init *V) const {227  const DefInit *VDefInit = dyn_cast<DefInit>(V);228  if (!VDefInit)229    return nullptr;230 231  const Record *RegClass = VDefInit->getDef();232  if (RegClass->isSubClassOf("RegisterOperand"))233    return RegClass->getValueAsDef("RegClass");234 235  return RegClass->isSubClassOf("RegisterClassLike") ? RegClass : nullptr;236}237 238CodeGenSchedModels &CodeGenTarget::getSchedModels() const {239  if (!SchedModels)240    SchedModels = std::make_unique<CodeGenSchedModels>(Records, *this);241  return *SchedModels;242}243 244void CodeGenTarget::ReadInstructions() const {245  ArrayRef<const Record *> Insts =246      Records.getAllDerivedDefinitions("Instruction");247  if (Insts.size() <= 2)248    PrintFatalError("No 'Instruction' subclasses defined!");249 250  // Parse the instructions defined in the .td file.251  for (const Record *R : Insts) {252    auto [II, _] =253        InstructionMap.try_emplace(R, std::make_unique<CodeGenInstruction>(R));254    HasVariableLengthEncodings |= II->second->isVariableLengthEncoding();255  }256}257 258static const CodeGenInstruction *GetInstByName(259    StringRef Name,260    const DenseMap<const Record *, std::unique_ptr<CodeGenInstruction>> &Insts,261    const RecordKeeper &Records) {262  const Record *Rec = Records.getDef(Name);263 264  const auto I = Insts.find(Rec);265  if (!Rec || I == Insts.end())266    PrintFatalError("Could not find '" + Name + "' instruction!");267  return I->second.get();268}269 270static const char *FixedInstrs[] = {271#define HANDLE_TARGET_OPCODE(OPC) #OPC,272#include "llvm/Support/TargetOpcodes.def"273};274 275unsigned CodeGenTarget::getNumFixedInstructions() {276  return std::size(FixedInstrs);277}278 279/// Return all of the instructions defined by the target, ordered by280/// their enum value.281void CodeGenTarget::ComputeInstrsByEnum() const {282  const auto &InstMap = getInstructionMap();283  for (const char *Name : FixedInstrs) {284    const CodeGenInstruction *Instr = GetInstByName(Name, InstMap, Records);285    assert(Instr && "Missing target independent instruction");286    assert(Instr->Namespace == "TargetOpcode" && "Bad namespace");287    InstrsByEnum.push_back(Instr);288  }289  unsigned EndOfPredefines = InstrsByEnum.size();290  assert(EndOfPredefines == getNumFixedInstructions() &&291         "Missing generic opcode");292 293  [[maybe_unused]] unsigned SkippedInsts = 0;294 295  for (const auto &[_, CGIUp] : InstMap) {296    const CodeGenInstruction *CGI = CGIUp.get();297    if (CGI->Namespace != "TargetOpcode") {298 299      if (CGI->TheDef->isSubClassOf(300              "TargetSpecializedStandardPseudoInstruction")) {301        ++SkippedInsts;302        continue;303      }304 305      InstrsByEnum.push_back(CGI);306      NumPseudoInstructions += CGI->TheDef->getValueAsBit("isPseudo");307    }308  }309 310  assert(InstrsByEnum.size() + SkippedInsts == InstMap.size() &&311         "Missing predefined instr");312 313  // All of the instructions are now in random order based on the map iteration.314  llvm::sort(315      InstrsByEnum.begin() + EndOfPredefines, InstrsByEnum.end(),316      [](const CodeGenInstruction *Rec1, const CodeGenInstruction *Rec2) {317        const Record &D1 = *Rec1->TheDef;318        const Record &D2 = *Rec2->TheDef;319        // Sort all pseudo instructions before non-pseudo ones, and sort by name320        // within.321        return std::tuple(!Rec1->isPseudo, D1.getName()) <322               std::tuple(!Rec2->isPseudo, D2.getName());323      });324 325  // Assign an enum value to each instruction according to the sorted order.326  for (const auto &[Idx, Inst] : enumerate(InstrsByEnum))327    Inst->EnumVal = Idx;328}329 330/// isLittleEndianEncoding - Return whether this target encodes its instruction331/// in little-endian format, i.e. bits laid out in the order [0..n]332///333bool CodeGenTarget::isLittleEndianEncoding() const {334  return getInstructionSet()->getValueAsBit("isLittleEndianEncoding");335}336 337/// reverseBitsForLittleEndianEncoding - For little-endian instruction bit338/// encodings, reverse the bit order of all instructions.339void CodeGenTarget::reverseBitsForLittleEndianEncoding() {340  if (!isLittleEndianEncoding())341    return;342 343  for (const Record *R :344       Records.getAllDerivedDefinitions("InstructionEncoding")) {345    if (R->getValueAsString("Namespace") == "TargetOpcode" ||346        R->getValueAsBit("isPseudo"))347      continue;348 349    const BitsInit *BI = R->getValueAsBitsInit("Inst");350 351    unsigned numBits = BI->getNumBits();352 353    SmallVector<const Init *, 16> NewBits(numBits);354 355    for (unsigned bit = 0, end = numBits / 2; bit != end; ++bit) {356      unsigned bitSwapIdx = numBits - bit - 1;357      const Init *OrigBit = BI->getBit(bit);358      const Init *BitSwap = BI->getBit(bitSwapIdx);359      NewBits[bit] = BitSwap;360      NewBits[bitSwapIdx] = OrigBit;361    }362    if (numBits % 2) {363      unsigned middle = (numBits + 1) / 2;364      NewBits[middle] = BI->getBit(middle);365    }366 367    RecordKeeper &MutableRC = const_cast<RecordKeeper &>(Records);368    const BitsInit *NewBI = BitsInit::get(MutableRC, NewBits);369 370    // Update the bits in reversed order so that emitters will get the correct371    // endianness.372    // FIXME: Eliminate mutation of TG records by creating a helper function373    // to reverse bits and maintain a cache instead of mutating records.374    Record *MutableR = const_cast<Record *>(R);375    MutableR->getValue("Inst")->setValue(NewBI);376  }377}378 379/// guessInstructionProperties - Return true if it's OK to guess instruction380/// properties instead of raising an error.381///382/// This is configurable as a temporary migration aid. It will eventually be383/// permanently false.384bool CodeGenTarget::guessInstructionProperties() const {385  return getInstructionSet()->getValueAsBit("guessInstructionProperties");386}387 388//===----------------------------------------------------------------------===//389// ComplexPattern implementation390//391ComplexPattern::ComplexPattern(const Record *R) {392  Ty = R->getValueAsDef("Ty");393  NumOperands = R->getValueAsInt("NumOperands");394  SelectFunc = R->getValueAsString("SelectFunc").str();395  RootNodes = R->getValueAsListOfDefs("RootNodes");396 397  // FIXME: This is a hack to statically increase the priority of patterns which398  // maps a sub-dag to a complex pattern. e.g. favors LEA over ADD. To get best399  // possible pattern match we'll need to dynamically calculate the complexity400  // of all patterns a dag can potentially map to.401  int64_t RawComplexity = R->getValueAsInt("Complexity");402  if (RawComplexity == -1)403    Complexity = NumOperands * 3;404  else405    Complexity = RawComplexity;406 407  // FIXME: Why is this different from parseSDPatternOperatorProperties?408  // Parse the properties.409  Properties = 0;410  for (const Record *Prop : R->getValueAsListOfDefs("Properties")) {411    if (Prop->getName() == "SDNPHasChain") {412      Properties |= 1 << SDNPHasChain;413    } else if (Prop->getName() == "SDNPOptInGlue") {414      Properties |= 1 << SDNPOptInGlue;415    } else if (Prop->getName() == "SDNPMayStore") {416      Properties |= 1 << SDNPMayStore;417    } else if (Prop->getName() == "SDNPMayLoad") {418      Properties |= 1 << SDNPMayLoad;419    } else if (Prop->getName() == "SDNPSideEffect") {420      Properties |= 1 << SDNPSideEffect;421    } else if (Prop->getName() == "SDNPMemOperand") {422      Properties |= 1 << SDNPMemOperand;423    } else if (Prop->getName() == "SDNPVariadic") {424      Properties |= 1 << SDNPVariadic;425    } else {426      PrintFatalError(R->getLoc(),427                      "Unsupported SD Node property '" + Prop->getName() +428                          "' on ComplexPattern '" + R->getName() + "'!");429    }430  }431 432  WantsRoot = R->getValueAsBit("WantsRoot");433  WantsParent = R->getValueAsBit("WantsParent");434}435