LLVM: lib/Target/ARM/Thumb2SizeReduction.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
37#include
38#include
39#include
40#include
41#include
42
43using namespace llvm;
44
45#define DEBUG_TYPE "thumb2-reduce-size"
46#define THUMB2_SIZE_REDUCE_NAME "Thumb2 instruction size reduce pass"
47
48STATISTIC(NumNarrows, "Number of 32-bit instrs reduced to 16-bit ones");
49STATISTIC(Num2Addrs, "Number of 32-bit instrs reduced to 2addr 16-bit ones");
50STATISTIC(NumLdSts, "Number of 32-bit load / store reduced to 16-bit ones");
51
58
59namespace {
60
61
62
63 struct ReduceEntry {
64 uint16_t WideOpc;
65 uint16_t NarrowOpc1;
66 uint16_t NarrowOpc2;
67 uint8_t Imm1Limit;
68 uint8_t Imm2Limit;
69 unsigned LowRegs1 : 1;
70 unsigned LowRegs2 : 1;
71 unsigned PredCC1 : 2;
72
73
74 unsigned PredCC2 : 2;
75 unsigned PartFlag : 1;
76 unsigned Special : 1;
77 unsigned AvoidMovs: 1;
78 };
79
80 static const ReduceEntry ReduceTable[] = {
81
82 { ARM::t2ADCrr, 0, ARM::tADC, 0, 0, 0, 1, 0,0, 0,0,0 },
83 { ARM::t2ADDri, ARM::tADDi3, ARM::tADDi8, 3, 8, 1, 1, 0,0, 0,1,0 },
84 { ARM::t2ADDrr, ARM::tADDrr, ARM::tADDhirr, 0, 0, 1, 0, 0,1, 0,0,0 },
85 { ARM::t2ADDSri,ARM::tADDi3, ARM::tADDi8, 3, 8, 1, 1, 2,2, 0,1,0 },
86 { ARM::t2ADDSrr,ARM::tADDrr, 0, 0, 0, 1, 0, 2,0, 0,1,0 },
87 { ARM::t2ANDrr, 0, ARM::tAND, 0, 0, 0, 1, 0,0, 1,0,0 },
88 { ARM::t2ASRri, ARM::tASRri, 0, 5, 0, 1, 0, 0,0, 1,0,1 },
89 { ARM::t2ASRrr, 0, ARM::tASRrr, 0, 0, 0, 1, 0,0, 1,0,1 },
90 { ARM::t2BICrr, 0, ARM::tBIC, 0, 0, 0, 1, 0,0, 1,0,0 },
91
92
93 { ARM::t2CMNzrr, ARM::tCMNz, 0, 0, 0, 1, 0, 2,0, 0,0,0 },
94 { ARM::t2CMPri, ARM::tCMPi8, 0, 8, 0, 1, 0, 2,0, 0,0,0 },
95 { ARM::t2CMPrr, ARM::tCMPhir, 0, 0, 0, 0, 0, 2,0, 0,1,0 },
96 { ARM::t2EORrr, 0, ARM::tEOR, 0, 0, 0, 1, 0,0, 1,0,0 },
97
98
99 { ARM::t2LSLri, ARM::tLSLri, 0, 5, 0, 1, 0, 0,0, 1,0,1 },
100 { ARM::t2LSLrr, 0, ARM::tLSLrr, 0, 0, 0, 1, 0,0, 1,0,1 },
101 { ARM::t2LSRri, ARM::tLSRri, 0, 5, 0, 1, 0, 0,0, 1,0,1 },
102 { ARM::t2LSRrr, 0, ARM::tLSRrr, 0, 0, 0, 1, 0,0, 1,0,1 },
103 { ARM::t2MOVi, ARM::tMOVi8, 0, 8, 0, 1, 0, 0,0, 1,0,0 },
104 { ARM::t2MOVi16,ARM::tMOVi8, 0, 8, 0, 1, 0, 0,0, 1,1,0 },
105
106 { ARM::t2MOVr,ARM::tMOVr, 0, 0, 0, 0, 0, 1,0, 0,0,0 },
107 { ARM::t2MUL, 0, ARM::tMUL, 0, 0, 0, 1, 0,0, 1,0,0 },
108 { ARM::t2MVNr, ARM::tMVN, 0, 0, 0, 1, 0, 0,0, 0,0,0 },
109 { ARM::t2ORRrr, 0, ARM::tORR, 0, 0, 0, 1, 0,0, 1,0,0 },
110 { ARM::t2REV, ARM::tREV, 0, 0, 0, 1, 0, 1,0, 0,0,0 },
111 { ARM::t2REV16, ARM::tREV16, 0, 0, 0, 1, 0, 1,0, 0,0,0 },
112 { ARM::t2REVSH, ARM::tREVSH, 0, 0, 0, 1, 0, 1,0, 0,0,0 },
113 { ARM::t2RORrr, 0, ARM::tROR, 0, 0, 0, 1, 0,0, 1,0,0 },
114 { ARM::t2RSBri, ARM::tRSB, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
115 { ARM::t2RSBSri,ARM::tRSB, 0, 0, 0, 1, 0, 2,0, 0,1,0 },
116 { ARM::t2SBCrr, 0, ARM::tSBC, 0, 0, 0, 1, 0,0, 0,0,0 },
117 { ARM::t2SUBri, ARM::tSUBi3, ARM::tSUBi8, 3, 8, 1, 1, 0,0, 0,0,0 },
118 { ARM::t2SUBrr, ARM::tSUBrr, 0, 0, 0, 1, 0, 0,0, 0,0,0 },
119 { ARM::t2SUBSri,ARM::tSUBi3, ARM::tSUBi8, 3, 8, 1, 1, 2,2, 0,0,0 },
120 { ARM::t2SUBSrr,ARM::tSUBrr, 0, 0, 0, 1, 0, 2,0, 0,0,0 },
121 { ARM::t2SXTB, ARM::tSXTB, 0, 0, 0, 1, 0, 1,0, 0,1,0 },
122 { ARM::t2SXTH, ARM::tSXTH, 0, 0, 0, 1, 0, 1,0, 0,1,0 },
123 { ARM::t2TEQrr, ARM::tEOR, 0, 0, 0, 1, 0, 2,0, 0,1,0 },
124 { ARM::t2TSTrr, ARM::tTST, 0, 0, 0, 1, 0, 2,0, 0,0,0 },
125 { ARM::t2UXTB, ARM::tUXTB, 0, 0, 0, 1, 0, 1,0, 0,1,0 },
126 { ARM::t2UXTH, ARM::tUXTH, 0, 0, 0, 1, 0, 1,0, 0,1,0 },
127
128
129
130 { ARM::t2LDRi12,ARM::tLDRi, ARM::tLDRspi, 5, 8, 1, 0, 0,0, 0,1,0 },
131 { ARM::t2LDRs, ARM::tLDRr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
132 { ARM::t2LDRBi12,ARM::tLDRBi, 0, 5, 0, 1, 0, 0,0, 0,1,0 },
133 { ARM::t2LDRBs, ARM::tLDRBr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
134 { ARM::t2LDRHi12,ARM::tLDRHi, 0, 5, 0, 1, 0, 0,0, 0,1,0 },
135 { ARM::t2LDRHs, ARM::tLDRHr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
136 { ARM::t2LDRSBs,ARM::tLDRSB, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
137 { ARM::t2LDRSHs,ARM::tLDRSH, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
138 { ARM::t2LDR_POST,ARM::tLDMIA_UPD,0, 0, 0, 1, 0, 0,0, 0,1,0 },
139 { ARM::t2STRi12,ARM::tSTRi, ARM::tSTRspi, 5, 8, 1, 0, 0,0, 0,1,0 },
140 { ARM::t2STRs, ARM::tSTRr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
141 { ARM::t2STRBi12,ARM::tSTRBi, 0, 5, 0, 1, 0, 0,0, 0,1,0 },
142 { ARM::t2STRBs, ARM::tSTRBr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
143 { ARM::t2STRHi12,ARM::tSTRHi, 0, 5, 0, 1, 0, 0,0, 0,1,0 },
144 { ARM::t2STRHs, ARM::tSTRHr, 0, 0, 0, 1, 0, 0,0, 0,1,0 },
145 { ARM::t2STR_POST,ARM::tSTMIA_UPD,0, 0, 0, 1, 0, 0,0, 0,1,0 },
146
147 { ARM::t2LDMIA, ARM::tLDMIA, 0, 0, 0, 1, 1, 1,1, 0,1,0 },
148 { ARM::t2LDMIA_RET,0, ARM::tPOP_RET, 0, 0, 1, 1, 1,1, 0,1,0 },
149 { ARM::t2LDMIA_UPD,ARM::tLDMIA_UPD,ARM::tPOP,0, 0, 1, 1, 1,1, 0,1,0 },
150
151
152
153 { ARM::t2STMIA, ARM::tSTMIA_UPD, 0, 0, 0, 1, 1, 1,1, 0,1,0 },
154 { ARM::t2STMIA_UPD,ARM::tSTMIA_UPD, 0, 0, 0, 1, 1, 1,1, 0,1,0 },
155 { ARM::t2STMDB_UPD, 0, ARM::tPUSH, 0, 0, 1, 1, 1,1, 0,1,0 }
156 };
157
159 public:
160 static char ID;
161
162 const Thumb2InstrInfo *TII;
163 const ARMSubtarget *STI;
164
165 Thumb2SizeReduce(std::function<bool(const Function &)> Ftor = nullptr);
166
167 bool runOnMachineFunction(MachineFunction &MF) override;
168
169 MachineFunctionProperties getRequiredProperties() const override {
170 return MachineFunctionProperties().setNoVRegs();
171 }
172
173 StringRef getPassName() const override {
175 }
176
177 private:
178
179 DenseMap<unsigned, unsigned> ReduceOpcodeMap;
180
181 bool canAddPseudoFlagDep(MachineInstr *Use, bool IsSelfLoop);
182
183 bool VerifyPredAndCC(MachineInstr *MI, const ReduceEntry &Entry,
185 bool LiveCPSR, bool &HasCC, bool &CCDead);
186
187 bool ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,
188 const ReduceEntry &Entry);
189
190 bool ReduceSpecial(MachineBasicBlock &MBB, MachineInstr *MI,
191 const ReduceEntry &Entry, bool LiveCPSR, bool IsSelfLoop);
192
193
194
195 bool ReduceTo2Addr(MachineBasicBlock &MBB, MachineInstr *MI,
196 const ReduceEntry &Entry, bool LiveCPSR,
197 bool IsSelfLoop);
198
199
200
201 bool ReduceToNarrow(MachineBasicBlock &MBB, MachineInstr *MI,
202 const ReduceEntry &Entry, bool LiveCPSR,
203 bool IsSelfLoop);
204
205
206 bool ReduceMI(MachineBasicBlock &MBB, MachineInstr *MI, bool LiveCPSR,
207 bool IsSelfLoop, bool SkipPrologueEpilogue);
208
209
210 bool ReduceMBB(MachineBasicBlock &MBB, bool SkipPrologueEpilogue);
211
212 bool OptimizeSize;
213 bool MinimizeSize;
214
215
216 MachineInstr *CPSRDef;
217
218
219 bool HighLatencyCPSR;
220
221 struct MBBInfo {
222
223 bool HighLatencyCPSR = false;
224
225 bool Visited = false;
226
227 MBBInfo() = default;
228 };
229
231
232 std::function<bool(const Function &)> PredicateFtor;
233 };
234
235 char Thumb2SizeReduce::ID = 0;
236
237}
238
240 false)
241
244 OptimizeSize = MinimizeSize = false;
245 for (unsigned i = 0, e = std::size(ReduceTable); i != e; ++i) {
246 unsigned FromOpc = ReduceTable[i].WideOpc;
247 if (!ReduceOpcodeMap.insert(std::make_pair(FromOpc, i)).second)
249 }
250}
251
255
256
258 switch(Def->getOpcode()) {
259 case ARM::FMSTAT:
260 case ARM::tMUL:
261 return true;
262 }
263 return false;
264}
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283bool
284Thumb2SizeReduce::canAddPseudoFlagDep(MachineInstr *Use, bool FirstInSelfLoop) {
285
286 if (MinimizeSize || !STI->avoidCPSRPartialUpdate())
287 return false;
288
289 if (!CPSRDef)
290
291
292 return HighLatencyCPSR || FirstInSelfLoop;
293
294 SmallSet<unsigned, 2> Defs;
295 for (const MachineOperand &MO : CPSRDef->operands()) {
296 if (!MO.isReg() || MO.isUndef() || MO.isUse())
297 continue;
299 if (Reg == 0 || Reg == ARM::CPSR)
300 continue;
302 }
303
304 for (const MachineOperand &MO : Use->operands()) {
305 if (!MO.isReg() || MO.isUndef() || MO.isDef())
306 continue;
309 return false;
310 }
311
312
313 if (HighLatencyCPSR)
314 return true;
315
316
317
318 if (Use->getOpcode() == ARM::t2MOVi ||
319 Use->getOpcode() == ARM::t2MOVi16)
320 return false;
321
322
323 return true;
324}
325
326bool
327Thumb2SizeReduce::VerifyPredAndCC(MachineInstr *MI, const ReduceEntry &Entry,
329 bool LiveCPSR, bool &HasCC, bool &CCDead) {
330 if ((is2Addr && Entry.PredCC2 == 0) ||
331 (!is2Addr && Entry.PredCC1 == 0)) {
333
334 if (!HasCC) {
335
336
337
338 if (!LiveCPSR) {
339 HasCC = true;
340 CCDead = true;
341 return true;
342 }
343 return false;
344 }
345 } else {
346
347 if (HasCC)
348 return false;
349 }
350 } else if ((is2Addr && Entry.PredCC2 == 2) ||
351 (!is2Addr && Entry.PredCC1 == 2)) {
352
353 if (HasCC)
354 return true;
355
356
358 return false;
359 HasCC = true;
360 } else {
361
362 if (HasCC)
363 return false;
364 }
365
366 return true;
367}
368
370 unsigned Opc = MI->getOpcode();
371 bool isPCOk = (Opc == ARM::t2LDMIA_RET || Opc == ARM::t2LDMIA_UPD);
372 bool isLROk = (Opc == ARM::t2STMDB_UPD);
373 bool isSPOk = isPCOk || isLROk;
374 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
377 continue;
379 if (Reg == 0 || Reg == ARM::CPSR)
380 continue;
381 if (isPCOk && Reg == ARM::PC)
382 continue;
383 if (isLROk && Reg == ARM::LR)
384 continue;
385 if (Reg == ARM::SP) {
386 if (isSPOk)
387 continue;
388 if (i == 1 && (Opc == ARM::t2LDRi12 || Opc == ARM::t2STRi12))
389
390 continue;
391 }
393 return false;
394 }
395 return true;
396}
397
398bool
399Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,
400 const ReduceEntry &Entry) {
402 return false;
403
404 unsigned Scale = 1;
405 bool HasImmOffset = false;
406 bool HasShift = false;
407 bool HasOffReg = true;
408 bool isLdStMul = false;
409 unsigned Opc = Entry.NarrowOpc1;
410 unsigned OpNum = 3;
411 uint8_t ImmLimit = Entry.Imm1Limit;
412
413 switch (Entry.WideOpc) {
414 default:
416 case ARM::t2LDRi12:
417 case ARM::t2STRi12:
418 if (MI->getOperand(1).getReg() == ARM::SP) {
420 ImmLimit = Entry.Imm2Limit;
421 }
422
423 Scale = 4;
424 HasImmOffset = true;
425 HasOffReg = false;
426 break;
427 case ARM::t2LDRBi12:
428 case ARM::t2STRBi12:
429 HasImmOffset = true;
430 HasOffReg = false;
431 break;
432 case ARM::t2LDRHi12:
433 case ARM::t2STRHi12:
434 Scale = 2;
435 HasImmOffset = true;
436 HasOffReg = false;
437 break;
438 case ARM::t2LDRs:
439 case ARM::t2LDRBs:
440 case ARM::t2LDRHs:
441 case ARM::t2LDRSBs:
442 case ARM::t2LDRSHs:
443 case ARM::t2STRs:
444 case ARM::t2STRBs:
445 case ARM::t2STRHs:
446 HasShift = true;
447 OpNum = 4;
448 break;
449 case ARM::t2LDR_POST:
450 case ARM::t2STR_POST: {
451 if (!MinimizeSize)
452 return false;
453
454 if (->hasOneMemOperand() ||
455 (*MI->memoperands_begin())->getAlign() < Align(4))
456 return false;
457
458
459
460
461 bool IsStore = Entry.WideOpc == ARM::t2STR_POST;
462 Register Rt = MI->getOperand(IsStore ? 1 : 0).getReg();
463 Register Rn = MI->getOperand(IsStore ? 0 : 1).getReg();
464 unsigned Offset = MI->getOperand(3).getImm();
465 unsigned PredImm = MI->getOperand(4).getImm();
466 Register PredReg = MI->getOperand(5).getReg();
469
471 return false;
472
473
481
482
484
485
487
488
489 MI->eraseFromBundle();
490 ++NumLdSts;
491 return true;
492 }
493 case ARM::t2LDMIA: {
496
497
498
499 bool isOK = false;
500 for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), 3)) {
501 if (MO.getReg() == BaseReg) {
502 isOK = true;
503 break;
504 }
505 }
506
507 if (!isOK)
508 return false;
509
510 OpNum = 0;
511 isLdStMul = true;
512 break;
513 }
514 case ARM::t2STMIA: {
515
516
517
518 if (->getOperand(0).isKill())
519 return false;
520
521
522
523
526 if (MO.getReg() == BaseReg)
527 return false;
528
529 break;
530 }
531 case ARM::t2LDMIA_RET: {
533 if (BaseReg != ARM::SP)
534 return false;
536 OpNum = 2;
537 isLdStMul = true;
538 break;
539 }
540 case ARM::t2LDMIA_UPD:
541 case ARM::t2STMIA_UPD:
542 case ARM::t2STMDB_UPD: {
543 OpNum = 0;
544
546 if (BaseReg == ARM::SP &&
547 (Entry.WideOpc == ARM::t2LDMIA_UPD ||
548 Entry.WideOpc == ARM::t2STMDB_UPD)) {
550 OpNum = 2;
552 (Entry.WideOpc != ARM::t2LDMIA_UPD &&
553 Entry.WideOpc != ARM::t2STMIA_UPD)) {
554 return false;
555 }
556
557 isLdStMul = true;
558 break;
559 }
560 }
561
562 unsigned OffsetReg = 0;
563 bool OffsetKill = false;
564 bool OffsetInternal = false;
565 if (HasShift) {
566 OffsetReg = MI->getOperand(2).getReg();
567 OffsetKill = MI->getOperand(2).isKill();
568 OffsetInternal = MI->getOperand(2).isInternalRead();
569
570 if (MI->getOperand(3).getImm())
571
572 return false;
573 }
574
575 unsigned OffsetImm = 0;
576 if (HasImmOffset) {
577 OffsetImm = MI->getOperand(2).getImm();
578 unsigned MaxOffset = ((1 << ImmLimit) - 1) * Scale;
579
580 if ((OffsetImm & (Scale - 1)) || OffsetImm > MaxOffset)
581
582 return false;
583 }
584
585
588
589
590
591 if (Entry.WideOpc == ARM::t2STMIA)
593
594 if (!isLdStMul) {
595 MIB.add(MI->getOperand(0));
596 MIB.add(MI->getOperand(1));
597
598 if (HasImmOffset)
599 MIB.addImm(OffsetImm / Scale);
600
601 assert((!HasShift || OffsetReg) && "Invalid so_reg load / store address!");
602
603 if (HasOffReg)
606 }
607
608
609 for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), OpNum))
610 MIB.add(MO);
611
612
614
615
617
619 << " to 16-bit: " << *MIB);
620
622 ++NumLdSts;
623 return true;
624}
625
626bool
627Thumb2SizeReduce::ReduceSpecial(MachineBasicBlock &MBB, MachineInstr *MI,
628 const ReduceEntry &Entry,
629 bool LiveCPSR, bool IsSelfLoop) {
630 unsigned Opc = MI->getOpcode();
631 if (Opc == ARM::t2ADDri) {
632
633
634 if (MI->getOperand(1).getReg() != ARM::SP) {
635 if (ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
636 return true;
637 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
638 }
639
640 unsigned Imm = MI->getOperand(2).getImm();
641
642
643
644 if (Imm & 3 || Imm > 1020)
645 return false;
647 return false;
648 if (MI->getOperand(3).getImm() != ARMCC::AL)
649 return false;
650 const MCInstrDesc &MCID = MI->getDesc();
652 MI->getOperand(MCID.getNumOperands()-1).getReg() == ARM::CPSR)
653 return false;
654
655 MachineInstrBuilder MIB =
660 .addImm(Imm / 4)
662
663
665
667 << " to 16-bit: " << *MIB);
668
670 ++NumNarrows;
671 return true;
672 }
673
675 return false;
676
677 if (MI->mayLoadOrStore())
678 return ReduceLoadStore(MBB, MI, Entry);
679
680 switch (Opc) {
681 default: break;
682 case ARM::t2ADDSri:
683 case ARM::t2ADDSrr: {
686 switch (Opc) {
687 default: break;
688 case ARM::t2ADDSri:
689 if (ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
690 return true;
691 [[fallthrough]];
692 case ARM::t2ADDSrr:
693 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
694 }
695 }
696 break;
697 }
698 case ARM::t2RSBri:
699 case ARM::t2RSBSri:
700 case ARM::t2SXTB:
701 case ARM::t2SXTH:
702 case ARM::t2UXTB:
703 case ARM::t2UXTH:
704 if (MI->getOperand(2).getImm() == 0)
705 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
706 break;
707 case ARM::t2MOVi16:
708
709
710 if (MI->getOperand(1).isImm())
711 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
712 break;
713 case ARM::t2CMPrr: {
714
715
716
717
718
719 static const ReduceEntry NarrowEntry =
720 { ARM::t2CMPrr,ARM::tCMPr, 0, 0, 0, 1, 1,2, 0, 0,1,0 };
721 if (ReduceToNarrow(MBB, MI, NarrowEntry, LiveCPSR, IsSelfLoop))
722 return true;
723 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
724 }
725 case ARM::t2TEQrr: {
727
729 break;
730
731
732 if (MI->getOperand(0).isKill())
733 return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
734 }
735 }
736 return false;
737}
738
739bool
740Thumb2SizeReduce::ReduceTo2Addr(MachineBasicBlock &MBB, MachineInstr *MI,
741 const ReduceEntry &Entry,
742 bool LiveCPSR, bool IsSelfLoop) {
744 return false;
745
746 if (!OptimizeSize && Entry.AvoidMovs && STI->avoidMOVsShifterOperand())
747
748
749 return false;
750
751 Register Reg0 = MI->getOperand(0).getReg();
752 Register Reg1 = MI->getOperand(1).getReg();
753
754 if (MI->getOpcode() == ARM::t2MUL) {
755
756 if (!MinimizeSize && STI->avoidMULS())
757 return false;
758 Register Reg2 = MI->getOperand(2).getReg();
759
762 return false;
763 if (Reg0 != Reg2) {
764
765
766 if (Reg1 != Reg0)
767 return false;
768
770 if (!CommutedMI)
771 return false;
772 }
773 } else if (Reg0 != Reg1) {
774
775 unsigned CommOpIdx1 = 1;
778 MI->getOperand(CommOpIdx2).getReg() != Reg0)
779 return false;
780 MachineInstr *CommutedMI =
782 if (!CommutedMI)
783 return false;
784 }
786 return false;
787 if (Entry.Imm2Limit) {
788 unsigned Imm = MI->getOperand(2).getImm();
789 unsigned Limit = (1 << Entry.Imm2Limit) - 1;
790 if (Imm > Limit)
791 return false;
792 } else {
793 Register Reg2 = MI->getOperand(2).getReg();
795 return false;
796 }
797
798
799 const MCInstrDesc &NewMCID = TII->get(Entry.NarrowOpc2);
802 bool SkipPred = false;
805
806 return false;
807 } else {
809 }
810
811 bool HasCC = false;
812 bool CCDead = false;
813 const MCInstrDesc &MCID = MI->getDesc();
816 HasCC = (MI->getOperand(NumOps-1).getReg() == ARM::CPSR);
817 if (HasCC && MI->getOperand(NumOps-1).isDead())
818 CCDead = true;
819 }
820 if (!VerifyPredAndCC(MI, Entry, true, Pred, LiveCPSR, HasCC, CCDead))
821 return false;
822
823
824
826 canAddPseudoFlagDep(MI, IsSelfLoop))
827 return false;
828
829
831 MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID);
832 MIB.add(MI->getOperand(0));
835
836
838 for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {
839 if (i < NumOps && MCID.operands()[i].isOptionalDef())
840 continue;
841 if (SkipPred && MCID.operands()[i].isPredicate())
842 continue;
843 MIB.add(MI->getOperand(i));
844 }
845
846
848
850 << " to 16-bit: " << *MIB);
851
853 ++Num2Addrs;
854 return true;
855}
856
857bool
858Thumb2SizeReduce::ReduceToNarrow(MachineBasicBlock &MBB, MachineInstr *MI,
859 const ReduceEntry &Entry,
860 bool LiveCPSR, bool IsSelfLoop) {
862 return false;
863
864 if (!OptimizeSize && Entry.AvoidMovs && STI->avoidMOVsShifterOperand())
865
866
867 return false;
868
869 unsigned Limit = ~0U;
870 if (Entry.Imm1Limit)
871 Limit = (1 << Entry.Imm1Limit) - 1;
872
873 const MCInstrDesc &MCID = MI->getDesc();
874 for (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i) {
875 if (MCID.operands()[i].isPredicate())
876 continue;
877 const MachineOperand &MO = MI->getOperand(i);
878 if (MO.isReg()) {
880 if ( || Reg == ARM::CPSR)
881 continue;
883 return false;
884 } else if (MO.isImm() && !MCID.operands()[i].isPredicate()) {
885 if (((unsigned)MO.getImm()) > Limit)
886 return false;
887 }
888 }
889
890
891 const MCInstrDesc &NewMCID = TII->get(Entry.NarrowOpc1);
894 bool SkipPred = false;
897
898 return false;
899 } else {
901 }
902
903 bool HasCC = false;
904 bool CCDead = false;
907 HasCC = (MI->getOperand(NumOps-1).getReg() == ARM::CPSR);
908 if (HasCC && MI->getOperand(NumOps-1).isDead())
909 CCDead = true;
910 }
911 if (!VerifyPredAndCC(MI, Entry, false, Pred, LiveCPSR, HasCC, CCDead))
912 return false;
913
914
915
917 canAddPseudoFlagDep(MI, IsSelfLoop))
918 return false;
919
920
922 MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID);
923
924
925
926
927 if (MCID.getOpcode() == ARM::t2TEQrr) {
928 MIB.add(MI->getOperand(0));
932
935 MIB.add(MI->getOperand(0));
936 } else {
937 MIB.add(MI->getOperand(0));
940 }
941
942
944 for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {
945 if (i < NumOps && MCID.operands()[i].isOptionalDef())
946 continue;
947 if ((MCID.getOpcode() == ARM::t2RSBSri ||
948 MCID.getOpcode() == ARM::t2RSBri ||
949 MCID.getOpcode() == ARM::t2SXTB ||
950 MCID.getOpcode() == ARM::t2SXTH ||
951 MCID.getOpcode() == ARM::t2UXTB ||
952 MCID.getOpcode() == ARM::t2UXTH) && i == 2)
953
954 continue;
955 bool isPred = (i < NumOps && MCID.operands()[i].isPredicate());
956 if (SkipPred && isPred)
957 continue;
958 const MachineOperand &MO = MI->getOperand(i);
960
961
962 continue;
963 MIB.add(MO);
964 }
967
968
970
972 << " to 16-bit: " << *MIB);
973
975 ++NumNarrows;
976 return true;
977}
978
980 bool HasDef = false;
983 continue;
984 if (MO.getReg() != ARM::CPSR)
985 continue;
986
987 DefCPSR = true;
989 HasDef = true;
990 }
991
992 return HasDef || LiveCPSR;
993}
994
998 continue;
999 if (MO.getReg() != ARM::CPSR)
1000 continue;
1001 assert(LiveCPSR && "CPSR liveness tracking is wrong!");
1003 LiveCPSR = false;
1004 break;
1005 }
1006 }
1007
1008 return LiveCPSR;
1009}
1010
1011bool Thumb2SizeReduce::ReduceMI(MachineBasicBlock &MBB, MachineInstr *MI,
1012 bool LiveCPSR, bool IsSelfLoop,
1013 bool SkipPrologueEpilogue) {
1014 unsigned Opcode = MI->getOpcode();
1015 DenseMap<unsigned, unsigned>::iterator OPI = ReduceOpcodeMap.find(Opcode);
1016 if (OPI == ReduceOpcodeMap.end())
1017 return false;
1020 return false;
1021 const ReduceEntry &Entry = ReduceTable[OPI->second];
1022
1023
1024 if (Entry.Special)
1025 return ReduceSpecial(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
1026
1027
1028 if (Entry.NarrowOpc2 &&
1029 ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
1030 return true;
1031
1032
1033 if (Entry.NarrowOpc1 &&
1034 ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
1035 return true;
1036
1037 return false;
1038}
1039
1040bool Thumb2SizeReduce::ReduceMBB(MachineBasicBlock &MBB,
1041 bool SkipPrologueEpilogue) {
1043
1044
1045 bool LiveCPSR = MBB.isLiveIn(ARM::CPSR);
1046 MachineInstr *BundleMI = nullptr;
1047
1048 CPSRDef = nullptr;
1049 HighLatencyCPSR = false;
1050
1051
1053 const MBBInfo &PInfo = BlockInfo[Pred->getNumber()];
1054 if (!PInfo.Visited) {
1055
1056 continue;
1057 }
1058 if (PInfo.HighLatencyCPSR) {
1059 HighLatencyCPSR = true;
1060 break;
1061 }
1062 }
1063
1064
1065
1069 for (; MII != E; MII = NextMII) {
1070 NextMII = std::next(MII);
1071
1072 MachineInstr *MI = &*MII;
1073 if (MI->isBundle()) {
1074 BundleMI = MI;
1075 continue;
1076 }
1077 if (MI->isDebugInstr())
1078 continue;
1079
1081
1082
1083 bool NextInSameBundle = NextMII != E && NextMII->isBundledWithPred();
1084
1085 if (ReduceMI(MBB, MI, LiveCPSR, IsSelfLoop, SkipPrologueEpilogue)) {
1089
1090
1091 if (NextInSameBundle && !NextMII->isBundledWithPred())
1092 NextMII->bundleWithPred();
1093 }
1094
1095 if (BundleMI && !NextInSameBundle && MI->isInsideBundle()) {
1096
1097
1098
1099
1100 if (BundleMI->killsRegister(ARM::CPSR, nullptr))
1101 LiveCPSR = false;
1102 MachineOperand *MO =
1104 if (MO && !MO->isDead())
1105 LiveCPSR = true;
1107 if (MO && !MO->isKill())
1108 LiveCPSR = true;
1109 }
1110
1111 bool DefCPSR = false;
1113 if (MI->isCall()) {
1114
1115 CPSRDef = nullptr;
1116 HighLatencyCPSR = false;
1117 IsSelfLoop = false;
1118 } else if (DefCPSR) {
1119
1120 CPSRDef = MI;
1122 IsSelfLoop = false;
1123 }
1124 }
1125
1127 Info.HighLatencyCPSR = HighLatencyCPSR;
1128 Info.Visited = true;
1130}
1131
1132bool Thumb2SizeReduce::runOnMachineFunction(MachineFunction &MF) {
1133 if (PredicateFtor && !PredicateFtor(MF.getFunction()))
1134 return false;
1135
1137 if (STI->isThumb1Only() || STI->prefers32BitThumb())
1138 return false;
1139
1140 TII = static_cast<const Thumb2InstrInfo *>(STI->getInstrInfo());
1141
1142
1145
1146 BlockInfo.clear();
1148
1149
1150
1151 ReversePostOrderTraversal<MachineFunction*> RPOT(&MF);
1155 for (MachineBasicBlock *MBB : RPOT)
1156 Modified |= ReduceMBB(*MBB, NeedsWinCFI);
1158}
1159
1160
1161
1163 std::function<bool(const Function &)> Ftor) {
1164 return new Thumb2SizeReduce(std::move(Ftor));
1165}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const TargetInstrInfo & TII
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Analysis containing CSE Info
This file defines the DenseMap class.
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
Promote Memory to Register
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
dot regions Print regions of function to dot true view regions View regions of function(with no function bodies)"
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static cl::opt< int > ReduceLimit("t2-reduce-limit", cl::init(-1), cl::Hidden)
static cl::opt< int > ReduceLimitLdSt("t2-reduce-limit3", cl::init(-1), cl::Hidden)
static cl::opt< int > ReduceLimit2Addr("t2-reduce-limit2", cl::init(-1), cl::Hidden)
static bool HasImplicitCPSRDef(const MCInstrDesc &MCID)
Definition Thumb2SizeReduction.cpp:252
static bool isHighLatencyCPSR(MachineInstr *Def)
Definition Thumb2SizeReduction.cpp:257
static bool UpdateCPSRUse(MachineInstr &MI, bool LiveCPSR)
Definition Thumb2SizeReduction.cpp:995
static bool VerifyLowRegs(MachineInstr *MI)
Definition Thumb2SizeReduction.cpp:369
#define THUMB2_SIZE_REDUCE_NAME
Definition Thumb2SizeReduction.cpp:46
static bool UpdateCPSRDef(MachineInstr &MI, bool LiveCPSR, bool &DefCPSR)
Definition Thumb2SizeReduction.cpp:979
const ARMBaseInstrInfo * getInstrInfo() const override
bool isThumb1Only() const
iterator find(const_arg_type_t< KeyT > Val)
FunctionPass class - This class is used to implement most global optimizations.
bool hasOptSize() const
Optimize this function for size (-Os) or minimum size (-Oz).
bool needsUnwindTableEntry() const
True if this function needs an unwind table.
bool usesWindowsCFI() const
Describe properties that are true of each instruction in the target description file.
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
ArrayRef< MCOperandInfo > operands() const
bool hasOptionalDef() const
Set if this instruction has an optional definition, e.g.
bool isPredicable() const
Return true if this instruction has a predicate operand that controls execution.
unsigned getOpcode() const
Return the opcode number for this descriptor.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
instr_iterator instr_begin()
instr_iterator erase_instr(MachineInstr *I)
Remove an instruction from the instruction list and delete it.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
Instructions::iterator instr_iterator
instr_iterator instr_end()
LLVM_ABI bool isSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a successor of this block.
iterator_range< pred_iterator > predecessors()
LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
unsigned getNumBlockIDs() const
getNumBlockIDs - Return the number of MBB ID's allocated.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
Representation of each machine instruction.
bool killsRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr kills the specified register.
MachineOperand * findRegisterUseOperand(Register Reg, const TargetRegisterInfo *TRI, bool isKill=false)
Wrapper for findRegisterUseOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
const MachineOperand & getOperand(unsigned i) const
MachineOperand * findRegisterDefOperand(Register Reg, const TargetRegisterInfo *TRI, bool isDead=false, bool Overlap=false)
Wrapper for findRegisterDefOperandIdx, it returns a pointer to the MachineOperand rather than an inde...
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsDead(bool Val=true)
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
LLVM_ABI void setIsDef(bool Val=true)
Change a def to a use, or a use to a def.
Wrapper class representing virtual and physical registers.
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
virtual bool findCommutedOpIndices(const MachineInstr &MI, unsigned &SrcOpIdx1, unsigned &SrcOpIdx2) const
Returns true iff the routine could find two commutable operands in the given machine instruction.
MachineInstr * commuteInstruction(MachineInstr &MI, bool NewMI=false, unsigned OpIdx1=CommuteAnyOperandIndex, unsigned OpIdx2=CommuteAnyOperandIndex) const
This method commutes the operands of the given machine instruction MI.
static const unsigned CommuteAnyOperandIndex
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
A Use represents the edge between a Value definition and its users.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Define
Register definition.
initializer< Ty > init(const Ty &Val)
NodeAddr< UseNode * > Use
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
static bool isARMLowRegister(MCRegister Reg)
isARMLowRegister - Returns true if the register is a low register (r0-r7).
static std::array< MachineOperand, 2 > predOps(ARMCC::CondCodes Pred, unsigned PredReg=0)
Get the operands corresponding to the given Pred value.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
unsigned getInternalReadRegState(bool B)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
unsigned getKillRegState(bool B)
ARMCC::CondCodes getInstrPredicate(const MachineInstr &MI, Register &PredReg)
getInstrPredicate - If instruction is predicated, returns its predicate condition,...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
static MachineOperand t1CondCodeOp(bool isDead=false)
Get the operand corresponding to the conditional code result for Thumb1.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
static MachineOperand condCodeOp(unsigned CCReg=0)
Get the operand corresponding to the conditional code result.
FunctionPass * createThumb2SizeReductionPass(std::function< bool(const Function &)> Ftor=nullptr)
createThumb2SizeReductionPass - Returns an instance of the Thumb2 size reduction pass.
Definition Thumb2SizeReduction.cpp:1162
Implement std::hash so that hash_code can be used in STL containers.