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