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