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