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