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