961 lines · cpp
1//===-------- CompressInstEmitter.cpp - Generator for Compression ---------===//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// CompressInstEmitter implements a tablegen-driven CompressPat based8// Instruction Compression mechanism.9//10//===----------------------------------------------------------------------===//11//12// CompressInstEmitter implements a tablegen-driven CompressPat Instruction13// Compression mechanism for generating compressed instructions from the14// expanded instruction form.15 16// This tablegen backend processes CompressPat declarations in a17// td file and generates all the required checks to validate the pattern18// declarations; validate the input and output operands to generate the correct19// compressed instructions. The checks include validating different types of20// operands; register operands, immediate operands, fixed register and fixed21// immediate inputs.22//23// Example:24// /// Defines a Pat match between compressed and uncompressed instruction.25// /// The relationship and helper function generation are handled by26// /// CompressInstEmitter backend.27// class CompressPat<dag input, dag output, list<Predicate> predicates = []> {28// /// Uncompressed instruction description.29// dag Input = input;30// /// Compressed instruction description.31// dag Output = output;32// /// Predicates that must be true for this to match.33// list<Predicate> Predicates = predicates;34// /// Duplicate match when tied operand is just different.35// bit isCompressOnly = false;36// }37//38// let Predicates = [HasStdExtC] in {39// def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2),40// (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>;41// }42//43// The <TargetName>GenCompressInstEmitter.inc is an auto-generated header44// file which exports two functions for compressing/uncompressing MCInst45// instructions, plus some helper functions:46//47// bool compressInst(MCInst &OutInst, const MCInst &MI,48// const MCSubtargetInfo &STI);49//50// bool uncompressInst(MCInst &OutInst, const MCInst &MI,51// const MCSubtargetInfo &STI);52//53// In addition, it exports a function for checking whether54// an instruction is compressable:55//56// bool isCompressibleInst(const MachineInstr& MI,57// const <TargetName>Subtarget &STI);58//59// The clients that include this auto-generated header file and60// invoke these functions can compress an instruction before emitting61// it in the target-specific ASM or ELF streamer or can uncompress62// an instruction before printing it when the expanded instruction63// format aliases is favored.64 65//===----------------------------------------------------------------------===//66 67#include "Common/CodeGenInstruction.h"68#include "Common/CodeGenRegisters.h"69#include "Common/CodeGenTarget.h"70#include "llvm/ADT/IndexedMap.h"71#include "llvm/ADT/SmallVector.h"72#include "llvm/ADT/StringMap.h"73#include "llvm/Support/Debug.h"74#include "llvm/Support/ErrorHandling.h"75#include "llvm/TableGen/Error.h"76#include "llvm/TableGen/Record.h"77#include "llvm/TableGen/TableGenBackend.h"78#include <limits>79#include <set>80#include <vector>81using namespace llvm;82 83#define DEBUG_TYPE "compress-inst-emitter"84 85namespace {86class CompressInstEmitter {87 struct OpData {88 enum MapKind { Operand, Imm, Reg } Kind;89 // Info for an operand.90 struct OpndInfo {91 // Record from the Dag.92 const Record *DagRec;93 // Operand number mapped to.94 unsigned Idx;95 // Tied operand index within the instruction.96 int TiedOpIdx;97 };98 union {99 OpndInfo OpInfo;100 // Integer immediate value.101 int64_t ImmVal;102 // Physical register.103 const Record *RegRec;104 };105 };106 struct ArgData {107 unsigned DAGOpNo;108 unsigned MIOpNo;109 };110 struct CompressPat {111 // The source instruction definition.112 CodeGenInstruction Source;113 // The destination instruction to transform to.114 CodeGenInstruction Dest;115 // Required target features to enable pattern.116 std::vector<const Record *> PatReqFeatures;117 // Maps operands in the Source Instruction to118 // the corresponding Dest instruction operand.119 IndexedMap<OpData> SourceOperandMap;120 // Maps operands in the Dest Instruction121 // to the corresponding Source instruction operand.122 IndexedMap<OpData> DestOperandMap;123 124 bool IsCompressOnly;125 CompressPat(const CodeGenInstruction &S, const CodeGenInstruction &D,126 std::vector<const Record *> RF,127 const IndexedMap<OpData> &SourceMap,128 const IndexedMap<OpData> &DestMap, bool IsCompressOnly)129 : Source(S), Dest(D), PatReqFeatures(std::move(RF)),130 SourceOperandMap(SourceMap), DestOperandMap(DestMap),131 IsCompressOnly(IsCompressOnly) {}132 };133 enum EmitterType { Compress, Uncompress, CheckCompress };134 const RecordKeeper &Records;135 const CodeGenTarget Target;136 std::vector<CompressPat> CompressPatterns;137 void addDagOperandMapping(const Record *Rec, const DagInit *Dag,138 const CodeGenInstruction &Inst,139 IndexedMap<OpData> &OperandMap,140 StringMap<ArgData> &Operands, bool IsSourceInst);141 void evaluateCompressPat(const Record *Compress);142 void emitCompressInstEmitter(raw_ostream &OS, EmitterType EType);143 bool validateTypes(const Record *DagOpType, const Record *InstOpType,144 bool IsSourceInst);145 bool validateRegister(const Record *Reg, const Record *RegClass);146 void checkDagOperandMapping(const Record *Rec,147 const StringMap<ArgData> &DestOperands,148 const DagInit *SourceDag, const DagInit *DestDag);149 150 void createInstOperandMapping(const Record *Rec, const DagInit *SourceDag,151 const DagInit *DestDag,152 IndexedMap<OpData> &SourceOperandMap,153 IndexedMap<OpData> &DestOperandMap,154 StringMap<ArgData> &SourceOperands,155 const CodeGenInstruction &DestInst);156 157public:158 CompressInstEmitter(const RecordKeeper &R) : Records(R), Target(R) {}159 160 void run(raw_ostream &OS);161};162} // End anonymous namespace.163 164bool CompressInstEmitter::validateRegister(const Record *Reg,165 const Record *RegClass) {166 assert(Reg->isSubClassOf("Register") && "Reg record should be a Register");167 assert(RegClass->isSubClassOf("RegisterClass") &&168 "RegClass record should be a RegisterClass");169 const CodeGenRegisterClass &RC = Target.getRegisterClass(RegClass);170 const CodeGenRegister *R = Target.getRegBank().getReg(Reg);171 assert(R != nullptr && "Register not defined!!");172 return RC.contains(R);173}174 175bool CompressInstEmitter::validateTypes(const Record *DagOpType,176 const Record *InstOpType,177 bool IsSourceInst) {178 if (DagOpType == InstOpType)179 return true;180 181 if (DagOpType->isSubClassOf("RegisterClass") &&182 InstOpType->isSubClassOf("RegisterClass")) {183 const CodeGenRegisterClass &RC = Target.getRegisterClass(InstOpType);184 const CodeGenRegisterClass &SubRC = Target.getRegisterClass(DagOpType);185 return RC.hasSubClass(&SubRC);186 }187 188 // At this point either or both types are not registers, reject the pattern.189 if (DagOpType->isSubClassOf("RegisterClass") ||190 InstOpType->isSubClassOf("RegisterClass"))191 return false;192 193 // Let further validation happen when compress()/uncompress() functions are194 // invoked.195 LLVM_DEBUG(dbgs() << (IsSourceInst ? "Input" : "Output")196 << " Dag Operand Type: '" << DagOpType->getName()197 << "' and "198 << "Instruction Operand Type: '" << InstOpType->getName()199 << "' can't be checked at pattern validation time!\n");200 return true;201}202 203static bool validateArgsTypes(const Init *Arg1, const Init *Arg2) {204 return cast<DefInit>(Arg1)->getDef() == cast<DefInit>(Arg2)->getDef();205}206 207/// The patterns in the Dag contain different types of operands:208/// Register operands, e.g.: GPRC:$rs1; Fixed registers, e.g: X1; Immediate209/// operands, e.g.: simm6:$imm; Fixed immediate operands, e.g.: 0. This function210/// maps Dag operands to its corresponding instruction operands. For register211/// operands and fixed registers it expects the Dag operand type to be contained212/// in the instantiated instruction operand type. For immediate operands and213/// immediates no validation checks are enforced at pattern validation time.214void CompressInstEmitter::addDagOperandMapping(const Record *Rec,215 const DagInit *Dag,216 const CodeGenInstruction &Inst,217 IndexedMap<OpData> &OperandMap,218 StringMap<ArgData> &Operands,219 bool IsSourceInst) {220 unsigned NumMIOperands = 0;221 if (!Inst.Operands.empty())222 NumMIOperands =223 Inst.Operands.back().MIOperandNo + Inst.Operands.back().MINumOperands;224 OperandMap.grow(NumMIOperands);225 226 // Tied operands are not represented in the DAG so we count them separately.227 unsigned DAGOpNo = 0;228 unsigned OpNo = 0;229 for (const auto &Opnd : Inst.Operands) {230 int TiedOpIdx = Opnd.getTiedRegister();231 if (-1 != TiedOpIdx) {232 assert((unsigned)TiedOpIdx < OpNo);233 // Set the entry in OperandMap for the tied operand we're skipping.234 OperandMap[OpNo] = OperandMap[TiedOpIdx];235 ++OpNo;236 237 // Source instructions can have at most 1 tied operand.238 if (IsSourceInst && (OpNo - DAGOpNo > 1))239 PrintFatalError(Rec->getLoc(),240 "Input operands for Inst '" + Inst.getName() +241 "' and input Dag operand count mismatch");242 243 continue;244 }245 for (unsigned SubOp = 0; SubOp != Opnd.MINumOperands;246 ++SubOp, ++OpNo, ++DAGOpNo) {247 const Record *OpndRec = Opnd.Rec;248 if (Opnd.MINumOperands > 1)249 OpndRec = cast<DefInit>(Opnd.MIOperandInfo->getArg(SubOp))->getDef();250 251 if (DAGOpNo >= Dag->getNumArgs())252 PrintFatalError(Rec->getLoc(), "Inst '" + Inst.getName() +253 "' and Dag operand count mismatch");254 255 if (const auto *DI = dyn_cast<DefInit>(Dag->getArg(DAGOpNo))) {256 if (DI->getDef()->isSubClassOf("Register")) {257 // Check if the fixed register belongs to the Register class.258 if (!validateRegister(DI->getDef(), OpndRec))259 PrintFatalError(Rec->getLoc(),260 "Error in Dag '" + Dag->getAsString() +261 "'Register: '" + DI->getDef()->getName() +262 "' is not in register class '" +263 OpndRec->getName() + "'");264 OperandMap[OpNo].Kind = OpData::Reg;265 OperandMap[OpNo].RegRec = DI->getDef();266 continue;267 }268 // Validate that Dag operand type matches the type defined in the269 // corresponding instruction. Operands in the input and output Dag270 // patterns are allowed to be a subclass of the type specified in the271 // corresponding instruction operand instead of being an exact match.272 if (!validateTypes(DI->getDef(), OpndRec, IsSourceInst))273 PrintFatalError(Rec->getLoc(),274 "Error in Dag '" + Dag->getAsString() +275 "'. Operand '" + Dag->getArgNameStr(DAGOpNo) +276 "' has type '" + DI->getDef()->getName() +277 "' which does not match the type '" +278 OpndRec->getName() +279 "' in the corresponding instruction operand!");280 281 OperandMap[OpNo].Kind = OpData::Operand;282 OperandMap[OpNo].OpInfo.DagRec = DI->getDef();283 OperandMap[OpNo].OpInfo.TiedOpIdx = -1;284 285 // Create a mapping between the operand name in the Dag (e.g. $rs1) and286 // its index in the list of Dag operands and check that operands with287 // the same name have the same type. For example in 'C_ADD $rs1, $rs2'288 // we generate the mapping $rs1 --> 0, $rs2 ---> 1. If the operand289 // appears twice in the same Dag (tied in the compressed instruction),290 // we note the previous index in the TiedOpIdx field.291 StringRef ArgName = Dag->getArgNameStr(DAGOpNo);292 if (ArgName.empty())293 continue;294 295 if (IsSourceInst) {296 auto It = Operands.find(ArgName);297 if (It != Operands.end()) {298 OperandMap[OpNo].OpInfo.TiedOpIdx = It->getValue().MIOpNo;299 if (OperandMap[It->getValue().MIOpNo].OpInfo.DagRec != DI->getDef())300 PrintFatalError(Rec->getLoc(),301 "Input Operand '" + ArgName +302 "' has a mismatched tied operand!");303 }304 }305 306 Operands[ArgName] = {DAGOpNo, OpNo};307 } else if (const auto *II = dyn_cast<IntInit>(Dag->getArg(DAGOpNo))) {308 // Validate that corresponding instruction operand expects an immediate.309 if (!OpndRec->isSubClassOf("Operand"))310 PrintFatalError(Rec->getLoc(), "Error in Dag '" + Dag->getAsString() +311 "' Found immediate: '" +312 II->getAsString() +313 "' but corresponding instruction "314 "operand expected a register!");315 // No pattern validation check possible for values of fixed immediate.316 OperandMap[OpNo].Kind = OpData::Imm;317 OperandMap[OpNo].ImmVal = II->getValue();318 LLVM_DEBUG(319 dbgs() << " Found immediate '" << II->getValue() << "' at "320 << (IsSourceInst ? "input " : "output ")321 << "Dag. No validation time check possible for values of "322 "fixed immediate.\n");323 } else {324 llvm_unreachable("Unhandled CompressPat argument type!");325 }326 }327 }328 329 // We shouldn't have extra Dag operands.330 if (DAGOpNo != Dag->getNumArgs())331 PrintFatalError(Rec->getLoc(), "Inst '" + Inst.getName() +332 "' and Dag operand count mismatch");333}334 335// Check that all names in the source DAG appear in the destionation DAG.336void CompressInstEmitter::checkDagOperandMapping(337 const Record *Rec, const StringMap<ArgData> &DestOperands,338 const DagInit *SourceDag, const DagInit *DestDag) {339 340 for (unsigned I = 0; I < SourceDag->getNumArgs(); ++I) {341 // Skip fixed immediates and registers, they were handled in342 // addDagOperandMapping.343 StringRef ArgName = SourceDag->getArgNameStr(I);344 if (ArgName.empty())345 continue;346 347 auto It = DestOperands.find(ArgName);348 if (It == DestOperands.end())349 PrintFatalError(Rec->getLoc(), "Operand " + ArgName +350 " defined in Input Dag but not used in"351 " Output Dag!");352 // Input Dag operand types must match output Dag operand type.353 if (!validateArgsTypes(DestDag->getArg(It->getValue().DAGOpNo),354 SourceDag->getArg(I)))355 PrintFatalError(Rec->getLoc(), "Type mismatch between Input and "356 "Output Dag operand '" +357 ArgName + "'!");358 }359}360 361/// Map operand names in the Dag to their index in both corresponding input and362/// output instructions. Validate that operands defined in the input are363/// used in the output pattern while populating the maps.364void CompressInstEmitter::createInstOperandMapping(365 const Record *Rec, const DagInit *SourceDag, const DagInit *DestDag,366 IndexedMap<OpData> &SourceOperandMap, IndexedMap<OpData> &DestOperandMap,367 StringMap<ArgData> &SourceOperands, const CodeGenInstruction &DestInst) {368 // TiedCount keeps track of the number of operands skipped in Inst369 // operands list to get to the corresponding Dag operand.370 unsigned TiedCount = 0;371 LLVM_DEBUG(dbgs() << " Operand mapping:\n Source Dest\n");372 unsigned OpNo = 0;373 for (const auto &Operand : DestInst.Operands) {374 int TiedInstOpIdx = Operand.getTiedRegister();375 if (TiedInstOpIdx != -1) {376 ++TiedCount;377 assert((unsigned)TiedInstOpIdx < OpNo);378 DestOperandMap[OpNo] = DestOperandMap[TiedInstOpIdx];379 if (DestOperandMap[OpNo].Kind == OpData::Operand)380 // No need to fill the SourceOperandMap here since it was mapped to381 // destination operand 'TiedInstOpIdx' in a previous iteration.382 LLVM_DEBUG(dbgs() << " " << DestOperandMap[OpNo].OpInfo.Idx383 << " ====> " << OpNo384 << " Dest operand tied with operand '"385 << TiedInstOpIdx << "'\n");386 ++OpNo;387 continue;388 }389 390 for (unsigned SubOp = 0; SubOp != Operand.MINumOperands; ++SubOp, ++OpNo) {391 // Skip fixed immediates and registers, they were handled in392 // addDagOperandMapping.393 if (DestOperandMap[OpNo].Kind != OpData::Operand)394 continue;395 396 unsigned DagArgIdx = OpNo - TiedCount;397 StringRef ArgName = DestDag->getArgNameStr(DagArgIdx);398 auto SourceOp = SourceOperands.find(ArgName);399 if (SourceOp == SourceOperands.end())400 PrintFatalError(Rec->getLoc(),401 "Output Dag operand '" + ArgName +402 "' has no matching input Dag operand.");403 404 assert(ArgName ==405 SourceDag->getArgNameStr(SourceOp->getValue().DAGOpNo) &&406 "Incorrect operand mapping detected!\n");407 408 unsigned SourceOpNo = SourceOp->getValue().MIOpNo;409 DestOperandMap[OpNo].OpInfo.Idx = SourceOpNo;410 SourceOperandMap[SourceOpNo].OpInfo.Idx = OpNo;411 LLVM_DEBUG(dbgs() << " " << SourceOpNo << " ====> " << OpNo << "\n");412 }413 }414}415 416/// Validates the CompressPattern and create operand mapping.417/// These are the checks to validate a CompressPat pattern declarations.418/// Error out with message under these conditions:419/// - Dag Input opcode is an expanded instruction and Dag Output opcode is a420/// compressed instruction.421/// - Operands in Dag Input must be all used in Dag Output.422/// Register Operand type in Dag Input Type must be contained in the423/// corresponding Source Instruction type.424/// - Register Operand type in Dag Input must be the same as in Dag Ouput.425/// - Register Operand type in Dag Output must be the same as the426/// corresponding Destination Inst type.427/// - Immediate Operand type in Dag Input must be the same as in Dag Ouput.428/// - Immediate Operand type in Dag Ouput must be the same as the corresponding429/// Destination Instruction type.430/// - Fixed register must be contained in the corresponding Source Instruction431/// type.432/// - Fixed register must be contained in the corresponding Destination433/// Instruction type.434/// Warning message printed under these conditions:435/// - Fixed immediate in Dag Input or Dag Ouput cannot be checked at this time436/// and generate warning.437/// - Immediate operand type in Dag Input differs from the corresponding Source438/// Instruction type and generate a warning.439void CompressInstEmitter::evaluateCompressPat(const Record *Rec) {440 // Validate input Dag operands.441 const DagInit *SourceDag = Rec->getValueAsDag("Input");442 assert(SourceDag && "Missing 'Input' in compress pattern!");443 LLVM_DEBUG(dbgs() << "Input: " << *SourceDag << "\n");444 445 // Checking we are transforming from compressed to uncompressed instructions.446 const Record *SourceOperator = SourceDag->getOperatorAsDef(Rec->getLoc());447 CodeGenInstruction SourceInst(SourceOperator);448 449 // Validate output Dag operands.450 const DagInit *DestDag = Rec->getValueAsDag("Output");451 assert(DestDag && "Missing 'Output' in compress pattern!");452 LLVM_DEBUG(dbgs() << "Output: " << *DestDag << "\n");453 454 const Record *DestOperator = DestDag->getOperatorAsDef(Rec->getLoc());455 CodeGenInstruction DestInst(DestOperator);456 457 if (SourceOperator->getValueAsInt("Size") <=458 DestOperator->getValueAsInt("Size"))459 PrintFatalError(460 Rec->getLoc(),461 "Compressed instruction '" + DestOperator->getName() +462 "'is not strictly smaller than the uncompressed instruction '" +463 SourceOperator->getName() + "' !");464 465 // Fill the mapping from the source to destination instructions.466 467 IndexedMap<OpData> SourceOperandMap;468 // Map from arg name to DAG operand number and MI operand number.469 StringMap<ArgData> SourceOperands;470 // Create a mapping between source Dag operands and source Inst operands.471 addDagOperandMapping(Rec, SourceDag, SourceInst, SourceOperandMap,472 SourceOperands, /*IsSourceInst*/ true);473 474 IndexedMap<OpData> DestOperandMap;475 // Map from arg name to DAG operand number and MI operand number.476 StringMap<ArgData> DestOperands;477 // Create a mapping between destination Dag operands and destination Inst478 // operands.479 addDagOperandMapping(Rec, DestDag, DestInst, DestOperandMap, DestOperands,480 /*IsSourceInst*/ false);481 482 checkDagOperandMapping(Rec, DestOperands, SourceDag, DestDag);483 // Create operand mapping between the source and destination instructions.484 createInstOperandMapping(Rec, SourceDag, DestDag, SourceOperandMap,485 DestOperandMap, SourceOperands, DestInst);486 487 // Get the target features for the CompressPat.488 std::vector<const Record *> PatReqFeatures;489 std::vector<const Record *> RF = Rec->getValueAsListOfDefs("Predicates");490 copy_if(RF, std::back_inserter(PatReqFeatures), [](const Record *R) {491 return R->getValueAsBit("AssemblerMatcherPredicate");492 });493 494 CompressPatterns.emplace_back(SourceInst, DestInst, std::move(PatReqFeatures),495 SourceOperandMap, DestOperandMap,496 Rec->getValueAsBit("isCompressOnly"));497}498 499static void500getReqFeatures(std::set<std::pair<bool, StringRef>> &FeaturesSet,501 std::set<std::set<std::pair<bool, StringRef>>> &AnyOfFeatureSets,502 ArrayRef<const Record *> ReqFeatures) {503 for (const Record *R : ReqFeatures) {504 const DagInit *D = R->getValueAsDag("AssemblerCondDag");505 std::string CombineType = D->getOperator()->getAsString();506 if (CombineType != "any_of" && CombineType != "all_of")507 PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");508 if (D->getNumArgs() == 0)509 PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");510 bool IsOr = CombineType == "any_of";511 std::set<std::pair<bool, StringRef>> AnyOfSet;512 513 for (auto *Arg : D->getArgs()) {514 bool IsNot = false;515 if (auto *NotArg = dyn_cast<DagInit>(Arg)) {516 if (NotArg->getOperator()->getAsString() != "not" ||517 NotArg->getNumArgs() != 1)518 PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");519 Arg = NotArg->getArg(0);520 IsNot = true;521 }522 if (!isa<DefInit>(Arg) ||523 !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature"))524 PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");525 if (IsOr)526 AnyOfSet.emplace(IsNot, cast<DefInit>(Arg)->getDef()->getName());527 else528 FeaturesSet.emplace(IsNot, cast<DefInit>(Arg)->getDef()->getName());529 }530 531 if (IsOr)532 AnyOfFeatureSets.insert(std::move(AnyOfSet));533 }534}535 536static unsigned getPredicates(DenseMap<const Record *, unsigned> &PredicateMap,537 std::vector<const Record *> &Predicates,538 const Record *Rec, StringRef Name) {539 unsigned &Entry = PredicateMap[Rec];540 if (Entry)541 return Entry;542 543 if (!Rec->isValueUnset(Name)) {544 Predicates.push_back(Rec);545 Entry = Predicates.size();546 return Entry;547 }548 549 PrintFatalError(Rec->getLoc(), "No " + Name +550 " predicate on this operand at all: '" +551 Rec->getName() + "'");552 return 0;553}554 555static void printPredicates(ArrayRef<const Record *> Predicates, StringRef Name,556 raw_ostream &OS) {557 for (unsigned I = 0; I < Predicates.size(); ++I) {558 StringRef Pred = Predicates[I]->getValueAsString(Name);559 Pred = Pred.trim();560 OS.indent(2) << "case " << I + 1 << ": {\n";561 OS.indent(4) << "// " << Predicates[I]->getName() << "\n";562 OS.indent(4) << Pred << "\n";563 OS.indent(2) << "}\n";564 }565}566 567static void mergeCondAndCode(raw_ostream &CombinedStream, StringRef CondStr,568 StringRef CodeStr) {569 CombinedStream.indent(4) << "if (" << CondStr << ") {\n";570 CombinedStream << CodeStr;571 CombinedStream.indent(4) << " return true;\n";572 CombinedStream.indent(4) << "} // if\n";573}574 575void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &OS,576 EmitterType EType) {577 const Record *AsmWriter = Target.getAsmWriter();578 if (!AsmWriter->getValueAsInt("PassSubtarget"))579 PrintFatalError(AsmWriter->getLoc(),580 "'PassSubtarget' is false. SubTargetInfo object is needed "581 "for target features.");582 583 StringRef TargetName = Target.getName();584 585 // Sort entries in CompressPatterns to handle instructions that can have more586 // than one candidate for compression\uncompression, e.g ADD can be587 // transformed to a C_ADD or a C_MV. When emitting 'uncompress()' function the588 // source and destination are flipped and the sort key needs to change589 // accordingly.590 llvm::stable_sort(CompressPatterns, [EType](const CompressPat &LHS,591 const CompressPat &RHS) {592 if (EType == EmitterType::Compress || EType == EmitterType::CheckCompress)593 return LHS.Source.getName() < RHS.Source.getName();594 return LHS.Dest.getName() < RHS.Dest.getName();595 });596 597 // A list of MCOperandPredicates for all operands in use, and the reverse map.598 std::vector<const Record *> MCOpPredicates;599 DenseMap<const Record *, unsigned> MCOpPredicateMap;600 // A list of ImmLeaf Predicates for all operands in use, and the reverse map.601 std::vector<const Record *> ImmLeafPredicates;602 DenseMap<const Record *, unsigned> ImmLeafPredicateMap;603 604 std::string F;605 std::string FH;606 raw_string_ostream Func(F);607 raw_string_ostream FuncH(FH);608 609 if (EType == EmitterType::Compress)610 OS << "\n#ifdef GEN_COMPRESS_INSTR\n"611 << "#undef GEN_COMPRESS_INSTR\n\n";612 else if (EType == EmitterType::Uncompress)613 OS << "\n#ifdef GEN_UNCOMPRESS_INSTR\n"614 << "#undef GEN_UNCOMPRESS_INSTR\n\n";615 else if (EType == EmitterType::CheckCompress)616 OS << "\n#ifdef GEN_CHECK_COMPRESS_INSTR\n"617 << "#undef GEN_CHECK_COMPRESS_INSTR\n\n";618 619 if (EType == EmitterType::Compress) {620 FuncH << "static bool compressInst(MCInst &OutInst,\n";621 FuncH.indent(25) << "const MCInst &MI,\n";622 FuncH.indent(25) << "const MCSubtargetInfo &STI) {\n";623 } else if (EType == EmitterType::Uncompress) {624 FuncH << "static bool uncompressInst(MCInst &OutInst,\n";625 FuncH.indent(27) << "const MCInst &MI,\n";626 FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n";627 } else if (EType == EmitterType::CheckCompress) {628 FuncH << "static bool isCompressibleInst(const MachineInstr &MI,\n";629 FuncH.indent(31) << "const " << TargetName << "Subtarget &STI) {\n";630 }631 632 if (CompressPatterns.empty()) {633 OS << FH;634 OS.indent(2) << "return false;\n}\n";635 if (EType == EmitterType::Compress)636 OS << "\n#endif //GEN_COMPRESS_INSTR\n";637 else if (EType == EmitterType::Uncompress)638 OS << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n";639 else if (EType == EmitterType::CheckCompress)640 OS << "\n#endif //GEN_CHECK_COMPRESS_INSTR\n\n";641 return;642 }643 644 std::string CaseString;645 raw_string_ostream CaseStream(CaseString);646 StringRef PrevOp;647 StringRef CurOp;648 CaseStream << " switch (MI.getOpcode()) {\n";649 CaseStream << " default: return false;\n";650 651 bool CompressOrCheck =652 EType == EmitterType::Compress || EType == EmitterType::CheckCompress;653 bool CompressOrUncompress =654 EType == EmitterType::Compress || EType == EmitterType::Uncompress;655 std::string ValidatorName =656 CompressOrUncompress657 ? (TargetName + "ValidateMCOperandFor" +658 (EType == EmitterType::Compress ? "Compress" : "Uncompress"))659 .str()660 : "";661 662 for (const auto &CompressPat : CompressPatterns) {663 if (EType == EmitterType::Uncompress && CompressPat.IsCompressOnly)664 continue;665 666 std::string CondString;667 std::string CodeString;668 raw_string_ostream CondStream(CondString);669 raw_string_ostream CodeStream(CodeString);670 const CodeGenInstruction &Source =671 CompressOrCheck ? CompressPat.Source : CompressPat.Dest;672 const CodeGenInstruction &Dest =673 CompressOrCheck ? CompressPat.Dest : CompressPat.Source;674 const IndexedMap<OpData> &SourceOperandMap =675 CompressOrCheck ? CompressPat.SourceOperandMap676 : CompressPat.DestOperandMap;677 const IndexedMap<OpData> &DestOperandMap =678 CompressOrCheck ? CompressPat.DestOperandMap679 : CompressPat.SourceOperandMap;680 681 CurOp = Source.getName();682 // Check current and previous opcode to decide to continue or end a case.683 if (CurOp != PrevOp) {684 if (!PrevOp.empty()) {685 CaseStream.indent(4) << "break;\n";686 CaseStream.indent(2) << "} // case " + PrevOp + "\n";687 }688 CaseStream.indent(2) << "case " + TargetName + "::" + CurOp + ": {\n";689 }690 691 std::set<std::pair<bool, StringRef>> FeaturesSet;692 std::set<std::set<std::pair<bool, StringRef>>> AnyOfFeatureSets;693 // Add CompressPat required features.694 getReqFeatures(FeaturesSet, AnyOfFeatureSets, CompressPat.PatReqFeatures);695 696 // Add Dest instruction required features.697 std::vector<const Record *> ReqFeatures;698 std::vector<const Record *> RF =699 Dest.TheDef->getValueAsListOfDefs("Predicates");700 copy_if(RF, std::back_inserter(ReqFeatures), [](const Record *R) {701 return R->getValueAsBit("AssemblerMatcherPredicate");702 });703 getReqFeatures(FeaturesSet, AnyOfFeatureSets, ReqFeatures);704 705 ListSeparator CondSep(" &&\n ");706 707 // Emit checks for all required features.708 for (auto &Op : FeaturesSet) {709 StringRef Not = Op.first ? "!" : "";710 CondStream << CondSep << Not << "STI.getFeatureBits()[" << TargetName711 << "::" << Op.second << "]";712 }713 714 // Emit checks for all required feature groups.715 for (auto &Set : AnyOfFeatureSets) {716 CondStream << CondSep << "(";717 for (auto &Op : Set) {718 bool IsLast = &Op == &*Set.rbegin();719 StringRef Not = Op.first ? "!" : "";720 CondStream << Not << "STI.getFeatureBits()[" << TargetName721 << "::" << Op.second << "]";722 if (!IsLast)723 CondStream << " || ";724 }725 CondStream << ")";726 }727 728 // Start Source Inst operands validation.729 unsigned OpNo = 0;730 for (const auto &SourceOperand : Source.Operands) {731 for (unsigned SubOp = 0; SubOp != SourceOperand.MINumOperands; ++SubOp) {732 // Check for fixed immediates\registers in the source instruction.733 switch (SourceOperandMap[OpNo].Kind) {734 case OpData::Operand:735 if (SourceOperandMap[OpNo].OpInfo.TiedOpIdx != -1) {736 if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass"))737 CondStream << CondSep << "MI.getOperand(" << OpNo738 << ").isReg() && MI.getOperand("739 << SourceOperandMap[OpNo].OpInfo.TiedOpIdx740 << ").isReg()" << CondSep << "(MI.getOperand(" << OpNo741 << ").getReg() == MI.getOperand("742 << SourceOperandMap[OpNo].OpInfo.TiedOpIdx743 << ").getReg())";744 else745 PrintFatalError("Unexpected tied operand types!");746 }747 748 // We don't need to do anything for source instruction operand checks.749 break;750 case OpData::Imm:751 CondStream << CondSep << "MI.getOperand(" << OpNo << ").isImm()"752 << CondSep << "(MI.getOperand(" << OpNo753 << ").getImm() == " << SourceOperandMap[OpNo].ImmVal754 << ")";755 break;756 case OpData::Reg: {757 const Record *Reg = SourceOperandMap[OpNo].RegRec;758 CondStream << CondSep << "MI.getOperand(" << OpNo << ").isReg()"759 << CondSep << "(MI.getOperand(" << OpNo760 << ").getReg() == " << TargetName << "::" << Reg->getName()761 << ")";762 break;763 }764 }765 ++OpNo;766 }767 }768 CodeStream.indent(6) << "// " << Dest.AsmString << "\n";769 if (CompressOrUncompress)770 CodeStream.indent(6) << "OutInst.setOpcode(" << TargetName771 << "::" << Dest.getName() << ");\n";772 OpNo = 0;773 for (const auto &DestOperand : Dest.Operands) {774 CodeStream.indent(6) << "// Operand: " << DestOperand.Name << "\n";775 776 for (unsigned SubOp = 0; SubOp != DestOperand.MINumOperands; ++SubOp) {777 const Record *DestRec = DestOperand.Rec;778 779 if (DestOperand.MINumOperands > 1)780 DestRec =781 cast<DefInit>(DestOperand.MIOperandInfo->getArg(SubOp))->getDef();782 783 switch (DestOperandMap[OpNo].Kind) {784 case OpData::Operand: {785 unsigned OpIdx = DestOperandMap[OpNo].OpInfo.Idx;786 const Record *DagRec = DestOperandMap[OpNo].OpInfo.DagRec;787 // Check that the operand in the Source instruction fits788 // the type for the Dest instruction.789 if (DagRec->isSubClassOf("RegisterClass") ||790 DagRec->isSubClassOf("RegisterOperand")) {791 auto *ClassRec = DagRec->isSubClassOf("RegisterClass")792 ? DagRec793 : DagRec->getValueAsDef("RegClass");794 // This is a register operand. Check the register class.795 // Don't check register class if this is a tied operand, it was done796 // for the operand it's tied to.797 if (DestOperand.getTiedRegister() == -1) {798 CondStream << CondSep << "MI.getOperand(" << OpIdx << ").isReg()";799 if (EType == EmitterType::CheckCompress)800 CondStream << " && MI.getOperand(" << OpIdx801 << ").getReg().isPhysical()";802 CondStream << CondSep << TargetName << "MCRegisterClasses["803 << TargetName << "::" << ClassRec->getName()804 << "RegClassID].contains(MI.getOperand(" << OpIdx805 << ").getReg())";806 }807 808 if (CompressOrUncompress)809 CodeStream.indent(6)810 << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n";811 } else {812 // Handling immediate operands.813 if (CompressOrUncompress) {814 unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates,815 DagRec, "MCOperandPredicate");816 CondStream << CondSep << ValidatorName << "("817 << "MI.getOperand(" << OpIdx << "), STI, " << Entry818 << " /* " << DagRec->getName() << " */)";819 // Also check DestRec if different than DagRec.820 if (DagRec != DestRec) {821 Entry = getPredicates(MCOpPredicateMap, MCOpPredicates, DestRec,822 "MCOperandPredicate");823 CondStream << CondSep << ValidatorName << "("824 << "MI.getOperand(" << OpIdx << "), STI, " << Entry825 << " /* " << DestRec->getName() << " */)";826 }827 } else {828 unsigned Entry =829 getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, DagRec,830 "ImmediateCode");831 CondStream << CondSep << "MI.getOperand(" << OpIdx << ").isImm()";832 CondStream << CondSep << TargetName << "ValidateMachineOperand("833 << "MI.getOperand(" << OpIdx << "), &STI, " << Entry834 << " /* " << DagRec->getName() << " */)";835 if (DagRec != DestRec) {836 Entry = getPredicates(ImmLeafPredicateMap, ImmLeafPredicates,837 DestRec, "ImmediateCode");838 CondStream << CondSep << "MI.getOperand(" << OpIdx839 << ").isImm()";840 CondStream << CondSep << TargetName << "ValidateMachineOperand("841 << "MI.getOperand(" << OpIdx << "), &STI, " << Entry842 << " /* " << DestRec->getName() << " */)";843 }844 }845 if (CompressOrUncompress)846 CodeStream.indent(6)847 << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n";848 }849 break;850 }851 case OpData::Imm: {852 if (CompressOrUncompress) {853 unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates,854 DestRec, "MCOperandPredicate");855 CondStream << CondSep << ValidatorName << "("856 << "MCOperand::createImm(" << DestOperandMap[OpNo].ImmVal857 << "), STI, " << Entry << " /* " << DestRec->getName()858 << " */)";859 } else {860 unsigned Entry =861 getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, DestRec,862 "ImmediateCode");863 CondStream << CondSep << TargetName864 << "ValidateMachineOperand(MachineOperand::CreateImm("865 << DestOperandMap[OpNo].ImmVal << "), &STI, " << Entry866 << " /* " << DestRec->getName() << " */)";867 }868 if (CompressOrUncompress)869 CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createImm("870 << DestOperandMap[OpNo].ImmVal << "));\n";871 } break;872 case OpData::Reg: {873 if (CompressOrUncompress) {874 // Fixed register has been validated at pattern validation time.875 const Record *Reg = DestOperandMap[OpNo].RegRec;876 CodeStream.indent(6)877 << "OutInst.addOperand(MCOperand::createReg(" << TargetName878 << "::" << Reg->getName() << "));\n";879 }880 } break;881 }882 ++OpNo;883 }884 }885 if (CompressOrUncompress)886 CodeStream.indent(6) << "OutInst.setLoc(MI.getLoc());\n";887 mergeCondAndCode(CaseStream, CondString, CodeString);888 PrevOp = CurOp;889 }890 Func << CaseString;891 Func.indent(4) << "break;\n";892 // Close brace for the last case.893 Func.indent(2) << "} // case " << CurOp << "\n";894 Func.indent(2) << "} // switch\n";895 Func.indent(2) << "return false;\n}\n";896 897 if (!MCOpPredicates.empty()) {898 auto IndentLength = ValidatorName.size() + 13;899 OS << "static bool " << ValidatorName << "(const MCOperand &MCOp,\n";900 OS.indent(IndentLength) << "const MCSubtargetInfo &STI,\n";901 OS.indent(IndentLength) << "unsigned PredicateIndex) {\n";902 OS << " switch (PredicateIndex) {\n"903 << " default:\n"904 << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"905 << " break;\n";906 907 printPredicates(MCOpPredicates, "MCOperandPredicate", OS);908 909 OS << " }\n"910 << "}\n\n";911 }912 913 if (!ImmLeafPredicates.empty()) {914 auto IndentLength = TargetName.size() + 35;915 OS << "static bool " << TargetName916 << "ValidateMachineOperand(const MachineOperand &MO,\n";917 OS.indent(IndentLength)918 << "const " << TargetName << "Subtarget *Subtarget,\n";919 OS.indent(IndentLength)920 << "unsigned PredicateIndex) {\n"921 << " int64_t Imm = MO.getImm();\n"922 << " switch (PredicateIndex) {\n"923 << " default:\n"924 << " llvm_unreachable(\"Unknown ImmLeaf Predicate kind\");\n"925 << " break;\n";926 927 printPredicates(ImmLeafPredicates, "ImmediateCode", OS);928 929 OS << " }\n"930 << "}\n\n";931 }932 933 OS << FH;934 OS << F;935 936 if (EType == EmitterType::Compress)937 OS << "\n#endif //GEN_COMPRESS_INSTR\n";938 else if (EType == EmitterType::Uncompress)939 OS << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n";940 else if (EType == EmitterType::CheckCompress)941 OS << "\n#endif //GEN_CHECK_COMPRESS_INSTR\n\n";942}943 944void CompressInstEmitter::run(raw_ostream &OS) {945 // Process the CompressPat definitions, validating them as we do so.946 for (const Record *Pat : Records.getAllDerivedDefinitions("CompressPat"))947 evaluateCompressPat(Pat);948 949 // Emit file header.950 emitSourceFileHeader("Compress instruction Source Fragment", OS, Records);951 // Generate compressInst() function.952 emitCompressInstEmitter(OS, EmitterType::Compress);953 // Generate uncompressInst() function.954 emitCompressInstEmitter(OS, EmitterType::Uncompress);955 // Generate isCompressibleInst() function.956 emitCompressInstEmitter(OS, EmitterType::CheckCompress);957}958 959static TableGen::Emitter::OptClass<CompressInstEmitter>960 X("gen-compress-inst-emitter", "Generate compressed instructions.");961