llvm.org GIT mirror llvm / 40ae57c
Fix the Load/Store optimization pass to work with Thumb1. Patch by Moritz Roth! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208992 91177308-0d34-0410-b5e6-96231b3b80d8 James Molloy 6 years ago
5 changed file(s) with 286 addition(s) and 41 deletion(s). Raw diff Collapse all Expand all
1414 #include "ARM.h"
1515 #include "ARMBaseInstrInfo.h"
1616 #include "ARMBaseRegisterInfo.h"
17 #include "ARMISelLowering.h"
1718 #include "ARMMachineFunctionInfo.h"
1819 #include "ARMSubtarget.h"
1920 #include "MCTargetDesc/ARMAddressingModes.h"
21 #include "Thumb1RegisterInfo.h"
2022 #include "llvm/ADT/DenseMap.h"
2123 #include "llvm/ADT/STLExtras.h"
2224 #include "llvm/ADT/SmallPtrSet.h"
6567 const TargetInstrInfo *TII;
6668 const TargetRegisterInfo *TRI;
6769 const ARMSubtarget *STI;
70 const TargetLowering *TL;
6871 ARMFunctionInfo *AFI;
6972 RegScavenger *RS;
7073 bool isThumb1, isThumb2;
9396 void findUsesOfImpDef(SmallVectorImpl &UsesOfImpDefs,
9497 const MemOpQueue &MemOps, unsigned DefReg,
9598 unsigned RangeBegin, unsigned RangeEnd);
96
99 void UpdateBaseRegUses(MachineBasicBlock &MBB,
100 MachineBasicBlock::iterator MBBI,
101 DebugLoc dl, unsigned Base, unsigned WordOffset,
102 ARMCC::CondCodes Pred, unsigned PredReg);
97103 bool MergeOps(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
98104 int Offset, unsigned Base, bool BaseKill, int Opcode,
99105 ARMCC::CondCodes Pred, unsigned PredReg, unsigned Scratch,
119125 ARMCC::CondCodes Pred, unsigned PredReg,
120126 unsigned Scratch, MemOpQueue &MemOps,
121127 SmallVectorImpl &Merges);
122
123128 void AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps);
124129 bool FixInvalidRegPairOp(MachineBasicBlock &MBB,
125130 MachineBasicBlock::iterator &MBBI);
159164 case ARM_AM::db: return ARM::STMDB;
160165 case ARM_AM::ib: return ARM::STMIB;
161166 }
167 case ARM::tLDRi:
168 // tLDMIA is writeback-only - unless the base register is in the input
169 // reglist.
170 ++NumLDMGened;
171 switch (Mode) {
172 default: llvm_unreachable("Unhandled submode!");
173 case ARM_AM::ia: return ARM::tLDMIA;
174 }
175 case ARM::tSTRi:
176 // There is no non-writeback tSTMIA either.
177 ++NumSTMGened;
178 switch (Mode) {
179 default: llvm_unreachable("Unhandled submode!");
180 case ARM_AM::ia: return ARM::tSTMIA_UPD;
181 }
162182 case ARM::t2LDRi8:
163183 case ARM::t2LDRi12:
164184 ++NumLDMGened;
217237 case ARM::LDMIA_UPD:
218238 case ARM::STMIA:
219239 case ARM::STMIA_UPD:
240 case ARM::tLDMIA:
241 case ARM::tLDMIA_UPD:
242 case ARM::tSTMIA_UPD:
220243 case ARM::t2LDMIA_RET:
221244 case ARM::t2LDMIA:
222245 case ARM::t2LDMIA_UPD:
263286 } // end namespace ARM_AM
264287 } // end namespace llvm
265288
289 static bool isT1i32Load(unsigned Opc) {
290 return Opc == ARM::tLDRi;
291 }
292
266293 static bool isT2i32Load(unsigned Opc) {
267294 return Opc == ARM::t2LDRi12 || Opc == ARM::t2LDRi8;
268295 }
269296
270297 static bool isi32Load(unsigned Opc) {
271 return Opc == ARM::LDRi12 || isT2i32Load(Opc);
298 return Opc == ARM::LDRi12 || isT1i32Load(Opc) || isT2i32Load(Opc) ;
299 }
300
301 static bool isT1i32Store(unsigned Opc) {
302 return Opc == ARM::tSTRi;
272303 }
273304
274305 static bool isT2i32Store(unsigned Opc) {
276307 }
277308
278309 static bool isi32Store(unsigned Opc) {
279 return Opc == ARM::STRi12 || isT2i32Store(Opc);
310 return Opc == ARM::STRi12 || isT1i32Store(Opc) || isT2i32Store(Opc);
311 }
312
313 static unsigned getImmScale(unsigned Opc) {
314 switch (Opc) {
315 default: llvm_unreachable("Unhandled opcode!");
316 case ARM::tLDRi:
317 case ARM::tSTRi:
318 return 1;
319 case ARM::tLDRHi:
320 case ARM::tSTRHi:
321 return 2;
322 case ARM::tLDRBi:
323 case ARM::tSTRBi:
324 return 4;
325 }
326 }
327
328 /// Update future uses of the base register with the offset introduced
329 /// due to writeback. This function only works on Thumb1.
330 void
331 ARMLoadStoreOpt::UpdateBaseRegUses(MachineBasicBlock &MBB,
332 MachineBasicBlock::iterator MBBI,
333 DebugLoc dl, unsigned Base,
334 unsigned WordOffset,
335 ARMCC::CondCodes Pred, unsigned PredReg) {
336 assert(isThumb1 && "Can only update base register uses for Thumb1!");
337
338 // Start updating any instructions with immediate offsets. Insert a sub before
339 // the first non-updateable instruction (if any).
340 for (; MBBI != MBB.end(); ++MBBI) {
341 if (MBBI->readsRegister(Base)) {
342 unsigned Opc = MBBI->getOpcode();
343 int Offset;
344 bool InsertSub = false;
345
346 if (Opc == ARM::tLDRi || Opc == ARM::tSTRi ||
347 Opc == ARM::tLDRHi || Opc == ARM::tSTRHi ||
348 Opc == ARM::tLDRBi || Opc == ARM::tSTRBi) {
349 // Loads and stores with immediate offsets can be updated, but only if
350 // the new offset isn't negative.
351 // The MachineOperand containing the offset immediate is the last one
352 // before predicates.
353 MachineOperand &MO =
354 MBBI->getOperand(MBBI->getDesc().getNumOperands() - 3);
355 // The offsets are scaled by 1, 2 or 4 depending on the Opcode
356 Offset = MO.getImm() - WordOffset * getImmScale(Opc);
357 if (Offset >= 0)
358 MO.setImm(Offset);
359 else
360 InsertSub = true;
361
362 } else if (Opc == ARM::tSUBi8 || Opc == ARM::tADDi8) {
363 // SUB/ADD using this register. Merge it with the update.
364 // If the merged offset is too large, insert a new sub instead.
365 MachineOperand &MO =
366 MBBI->getOperand(MBBI->getDesc().getNumOperands() - 3);
367 Offset = (Opc == ARM::tSUBi8) ?
368 MO.getImm() + WordOffset * 4 :
369 MO.getImm() - WordOffset * 4 ;
370 if (TL->isLegalAddImmediate(Offset)) {
371 MO.setImm(Offset);
372 // The base register has now been reset, so exit early.
373 return;
374 } else {
375 InsertSub = true;
376 }
377
378 } else {
379 // Can't update the instruction.
380 InsertSub = true;
381 }
382
383 if (InsertSub) {
384 // An instruction above couldn't be updated, so insert a sub.
385 AddDefaultT1CC(BuildMI(MBB, MBBI, dl, TII->get(ARM::tSUBi8), Base))
386 .addReg(Base, getKillRegState(true)).addImm(WordOffset * 4)
387 .addImm(Pred).addReg(PredReg);
388 return;
389 }
390 }
391
392 if (MBBI->killsRegister(Base))
393 // Register got killed. Stop updating.
394 return;
395 }
396
397 // The end of the block was reached. This means register liveness escapes the
398 // block, and it's necessary to insert a sub before the last instruction.
399 if (MBB.succ_size() > 0)
400 // But only insert the SUB if there is actually a successor block.
401 // FIXME: Check more carefully if register is live at this point, e.g. by
402 // also examining the successor block's register liveness information.
403 AddDefaultT1CC(BuildMI(MBB, --MBBI, dl, TII->get(ARM::tSUBi8), Base))
404 .addReg(Base, getKillRegState(true)).addImm(WordOffset * 4)
405 .addImm(Pred).addReg(PredReg);
280406 }
281407
282408 /// MergeOps - Create and insert a LDM or STM with Base as base register and
296422 return false;
297423
298424 ARM_AM::AMSubMode Mode = ARM_AM::ia;
299 // VFP and Thumb2 do not support IB or DA modes.
425 // VFP and Thumb2 do not support IB or DA modes. Thumb1 only supports IA.
300426 bool isNotVFP = isi32Load(Opcode) || isi32Store(Opcode);
301 bool haveIBAndDA = isNotVFP && !isThumb2;
427 bool haveIBAndDA = isNotVFP && !isThumb2 && !isThumb1;
428
302429 if (Offset == 4 && haveIBAndDA) {
303430 Mode = ARM_AM::ib;
304431 } else if (Offset == -4 * (int)NumRegs + 4 && haveIBAndDA) {
305432 Mode = ARM_AM::da;
306 } else if (Offset == -4 * (int)NumRegs && isNotVFP) {
433 } else if (Offset == -4 * (int)NumRegs && isNotVFP && !isThumb1) {
307434 // VLDM/VSTM do not support DB mode without also updating the base reg.
308435 Mode = ARM_AM::db;
309436 } else if (Offset != 0) {
328455 if (NewBase == 0)
329456 return false;
330457 }
331 int BaseOpc = !isThumb2 ? ARM::ADDri : ARM::t2ADDri;
458
459 int BaseOpc =
460 isThumb2 ? ARM::t2ADDri :
461 isThumb1 ? ARM::tADDi8 : ARM::ADDri;
462
332463 if (Offset < 0) {
333 BaseOpc = !isThumb2 ? ARM::SUBri : ARM::t2SUBri;
464 BaseOpc =
465 isThumb2 ? ARM::t2SUBri :
466 isThumb1 ? ARM::tSUBi8 : ARM::SUBri;
334467 Offset = - Offset;
335468 }
336 int ImmedOffset = isThumb2
337 ? ARM_AM::getT2SOImmVal(Offset) : ARM_AM::getSOImmVal(Offset);
338 if (ImmedOffset == -1)
339 // FIXME: Try t2ADDri12 or t2SUBri12?
340 return false; // Probably not worth it then.
341
342 BuildMI(MBB, MBBI, dl, TII->get(BaseOpc), NewBase)
343 .addReg(Base, getKillRegState(BaseKill)).addImm(Offset)
344 .addImm(Pred).addReg(PredReg).addReg(0);
469
470 if (!TL->isLegalAddImmediate(Offset))
471 // FIXME: Try add with register operand?
472 return false; // Probably not worth it then.
473
474 if (isThumb1) {
475 if (Base != NewBase) {
476 // Need to insert a MOV to the new base first.
477 // FIXME: If the immediate fits in 3 bits, use ADD instead.
478 BuildMI(MBB, MBBI, dl, TII->get(ARM::tMOVr), NewBase)
479 .addReg(Base, getKillRegState(BaseKill))
480 .addImm(Pred).addReg(PredReg);
481 }
482 AddDefaultT1CC(BuildMI(MBB, MBBI, dl, TII->get(BaseOpc), NewBase))
483 .addReg(NewBase, getKillRegState(true)).addImm(Offset)
484 .addImm(Pred).addReg(PredReg);
485 } else {
486 BuildMI(MBB, MBBI, dl, TII->get(BaseOpc), NewBase)
487 .addReg(Base, getKillRegState(BaseKill)).addImm(Offset)
488 .addImm(Pred).addReg(PredReg).addReg(0);
489 }
490
345491 Base = NewBase;
346492 BaseKill = true; // New base is always killed straight away.
347493 }
348494
349495 bool isDef = (isi32Load(Opcode) || Opcode == ARM::VLDRS ||
350496 Opcode == ARM::VLDRD);
497
498 // Get LS multiple opcode. Note that for Thumb1 this might be an opcode with
499 // base register writeback.
351500 Opcode = getLoadStoreMultipleOpcode(Opcode, Mode);
352501 if (!Opcode) return false;
353 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(Opcode))
354 .addReg(Base, getKillRegState(BaseKill))
355 .addImm(Pred).addReg(PredReg);
502
503 bool Writeback = isThumb1; // Thumb1 LDM/STM have base reg writeback.
504
505 // Exception: If the base register is in the input reglist, Thumb1 LDM is
506 // non-writeback. Check for this.
507 if (Opcode == ARM::tLDRi && isThumb1)
508 for (unsigned I = 0; I < NumRegs; ++I)
509 if (Base == Regs[I].first) {
510 Writeback = false;
511 break;
512 }
513
514 MachineInstrBuilder MIB;
515
516 if (Writeback) {
517 if (Opcode == ARM::tLDMIA)
518 // Update tLDMIA with writeback if necessary.
519 Opcode = ARM::tLDMIA_UPD;
520
521 // The base isn't dead after a merged instruction with writeback. Update
522 // future uses of the base with the added offset (if possible), or reset
523 // the base register as necessary.
524 if (!BaseKill)
525 UpdateBaseRegUses(MBB, MBBI, dl, Base, NumRegs, Pred, PredReg);
526
527 MIB = BuildMI(MBB, MBBI, dl, TII->get(Opcode));
528
529 // Thumb1: we might need to set base writeback when building the MI.
530 MIB.addReg(Base, getDefRegState(true))
531 .addReg(Base, getKillRegState(BaseKill));
532 } else {
533 // No writeback, simply build the MachineInstr.
534 MIB = BuildMI(MBB, MBBI, dl, TII->get(Opcode));
535 MIB.addReg(Base, getKillRegState(BaseKill));
536 }
537
538 MIB.addImm(Pred).addReg(PredReg);
539
356540 for (unsigned i = 0; i != NumRegs; ++i)
357541 MIB = MIB.addReg(Regs[i].first, getDefRegState(isDef)
358542 | getKillRegState(Regs[i].second));
615799 bool CheckCPSRDef = false;
616800 switch (MI->getOpcode()) {
617801 default: return false;
802 case ARM::tSUBi8:
618803 case ARM::t2SUBri:
619804 case ARM::SUBri:
620805 CheckCPSRDef = true;
627812 if (Bytes == 0 || (Limit && Bytes >= Limit))
628813 return false;
629814
630 unsigned Scale = (MI->getOpcode() == ARM::tSUBspi) ? 4 : 1; // FIXME
815 unsigned Scale = (MI->getOpcode() == ARM::tSUBspi ||
816 MI->getOpcode() == ARM::tSUBi8) ? 4 : 1; // FIXME
631817 if (!(MI->getOperand(0).getReg() == Base &&
632818 MI->getOperand(1).getReg() == Base &&
633 (MI->getOperand(2).getImm()*Scale) == Bytes &&
819 (MI->getOperand(2).getImm() * Scale) == Bytes &&
634820 getInstrPredicate(MI, MyPredReg) == Pred &&
635821 MyPredReg == PredReg))
636822 return false;
648834 bool CheckCPSRDef = false;
649835 switch (MI->getOpcode()) {
650836 default: return false;
837 case ARM::tADDi8:
651838 case ARM::t2ADDri:
652839 case ARM::ADDri:
653840 CheckCPSRDef = true;
660847 // Make sure the offset fits in 8 bits.
661848 return false;
662849
663 unsigned Scale = (MI->getOpcode() == ARM::tADDspi) ? 4 : 1; // FIXME
850 unsigned Scale = (MI->getOpcode() == ARM::tADDspi ||
851 MI->getOpcode() == ARM::tADDi8) ? 4 : 1; // FIXME
664852 if (!(MI->getOperand(0).getReg() == Base &&
665853 MI->getOperand(1).getReg() == Base &&
666 (MI->getOperand(2).getImm()*Scale) == Bytes &&
854 (MI->getOperand(2).getImm() * Scale) == Bytes &&
667855 getInstrPredicate(MI, MyPredReg) == Pred &&
668856 MyPredReg == PredReg))
669857 return false;
676864 default: return 0;
677865 case ARM::LDRi12:
678866 case ARM::STRi12:
867 case ARM::tLDRi:
868 case ARM::tSTRi:
679869 case ARM::t2LDRi8:
680870 case ARM::t2LDRi12:
681871 case ARM::t2STRi8:
694884 case ARM::STMDA:
695885 case ARM::STMDB:
696886 case ARM::STMIB:
887 case ARM::tLDMIA:
888 case ARM::tLDMIA_UPD:
889 case ARM::tSTMIA_UPD:
697890 case ARM::t2LDMIA:
698891 case ARM::t2LDMDB:
699892 case ARM::t2STMIA:
790983 MachineBasicBlock::iterator MBBI,
791984 bool &Advance,
792985 MachineBasicBlock::iterator &I) {
986 // Thumb1 is already using updating loads/stores.
987 if (isThumb1) return false;
988
793989 MachineInstr *MI = MBBI;
794990 unsigned Base = MI->getOperand(0).getReg();
795991 bool BaseKill = MI->getOperand(0).isKill();
9261122 const TargetInstrInfo *TII,
9271123 bool &Advance,
9281124 MachineBasicBlock::iterator &I) {
1125 // Thumb1 doesn't have updating LDR/STR.
1126 // FIXME: Use LDM/STM with single register instead.
1127 if (isThumb1) return false;
1128
9291129 MachineInstr *MI = MBBI;
9301130 unsigned Base = MI->getOperand(1).getReg();
9311131 bool BaseKill = MI->getOperand(1).isKill();
10991299 return MI->getOperand(1).isReg();
11001300 case ARM::LDRi12:
11011301 case ARM::STRi12:
1302 case ARM::tLDRi:
1303 case ARM::tSTRi:
11021304 case ARM::t2LDRi8:
11031305 case ARM::t2LDRi12:
11041306 case ARM::t2STRi8:
11351337 Opcode == ARM::t2LDRDi8 || Opcode == ARM::t2STRDi8 ||
11361338 Opcode == ARM::LDRi12 || Opcode == ARM::STRi12)
11371339 return OffField;
1340
1341 // Thumb1 immediate offsets are scaled by 4
1342 if (Opcode == ARM::tLDRi || Opcode == ARM::tSTRi)
1343 return OffField * 4;
11381344
11391345 int Offset = isAM3 ? ARM_AM::getAM3Offset(OffField)
11401346 : ARM_AM::getAM5Offset(OffField) * 4;
14161622 // Try to find a free register to use as a new base in case it's needed.
14171623 // First advance to the instruction just before the start of the chain.
14181624 AdvanceRS(MBB, MemOps);
1625
14191626 // Find a scratch register.
1420 unsigned Scratch = RS->FindUnusedReg(&ARM::GPRRegClass);
1627 unsigned Scratch =
1628 RS->FindUnusedReg(isThumb1 ? &ARM::tGPRRegClass : &ARM::GPRRegClass);
1629
14211630 // Process the load / store instructions.
14221631 RS->forward(std::prev(MBBI));
14231632
14831692 /// =>
14841693 /// ldmfd sp!, {..., pc}
14851694 bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
1695 // Thumb1 LDM doesn't allow high registers.
1696 if (isThumb1) return false;
14861697 if (MBB.empty()) return false;
14871698
14881699 MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
15131724
15141725 bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
15151726 const TargetMachine &TM = Fn.getTarget();
1727 TL = TM.getTargetLowering();
15161728 AFI = Fn.getInfo();
15171729 TII = TM.getInstrInfo();
15181730 TRI = TM.getRegisterInfo();
15201732 RS = new RegScavenger();
15211733 isThumb2 = AFI->isThumb2Function();
15221734 isThumb1 = AFI->isThumbFunction() && !isThumb2;
1523
1524 // Don't do anything in this pass with Thumb1 for now.
1525 if (isThumb1) return false;
15261735
15271736 bool Modified = false;
15281737 for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
15831792 STI = &Fn.getTarget().getSubtarget();
15841793 MRI = &Fn.getRegInfo();
15851794 MF = &Fn;
1586
1587 ARMFunctionInfo *AFI = Fn.getInfo();
1588 bool isThumb1 = AFI->isThumbFunction() && !AFI->isThumb2Function();
1589 // Don't do anything in this pass with Thumb1 for now.
1590 if (isThumb1) return false;
15911795
15921796 bool Modified = false;
15931797 for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
214214
215215 //===---------------------------------------------------------------------===//
216216
217 Add ldmia, stmia support.
218
219 //===---------------------------------------------------------------------===//
220
221217 Thumb load / store address mode offsets are scaled. The values kept in the
222218 instruction operands are pre-scale values. This probably ought to be changed
223219 to avoid extra work when we convert Thumb2 instructions to Thumb1 instructions.
None ; RUN: llc < %s -mtriple=thumb-apple-darwin -disable-cgp-branch-opts -disable-post-ra | FileCheck %s
1 ; RUN: llc < %s -mtriple=thumb-apple-darwin -disable-cgp-branch-opts -disable-post-ra -regalloc=basic | FileCheck %s
0 ; RUN: llc < %s -mtriple=thumb-apple-darwin -disable-cgp-branch-opts -disable-post-ra | FileCheck %s -check-prefix=CHECK -check-prefix=RA_GREEDY
1 ; RUN: llc < %s -mtriple=thumb-apple-darwin -disable-cgp-branch-opts -disable-post-ra -regalloc=basic | FileCheck %s -check-prefix=CHECK -check-prefix=RA_BASIC
22
33 %struct.state = type { i32, %struct.info*, float**, i32, i32, i32, i32, i32, i32, i32, i32, i32, i64, i64, i64, i64, i64, i64, i8* }
44 %struct.info = type { i32, i32, i32, i32, i32, i32, i32, i8* }
4444 ; CHECK: sub sp, #
4545 ; CHECK: mov r[[R0:[0-9]+]], sp
4646 ; CHECK: str r{{[0-9+]}}, [r[[R0]]
47 ; CHECK: str r{{[0-9+]}}, [r[[R0]]
47 ; RA_GREEDY: str r{{[0-9+]}}, [r[[R0]]
48 ; RA_BASIC: stm r[[R0]]!
4849 ; CHECK-NOT: ldr r0, [sp
4950 ; CHECK: mov r[[R1:[0-9]+]], sp
5051 ; CHECK: subs r[[R2:[0-9]+]], r[[R1]], r{{[0-9]+}}
0 ; RUN: llc < %s -mtriple=thumbv6m-eabi -o - | FileCheck %s
1
2 @X = external global [0 x i32] ; <[0 x i32]*> [#uses=5]
3
4 define i32 @t1() {
5 ; CHECK-LABEL: t1:
6 ; CHECK: push {r7, lr}
7 ; CHECK: ldm
8 ; CHECK: pop {r7, pc}
9 %tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 0) ; [#uses=1]
10 %tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 1) ; [#uses=1]
11 %tmp4 = call i32 @f1( i32 %tmp, i32 %tmp3 ) ; [#uses=1]
12 ret i32 %tmp4
13 }
14
15 define i32 @t2() {
16 ; CHECK-LABEL: t2:
17 ; CHECK: push {r7, lr}
18 ; CHECK: ldm
19 ; CHECK: pop {r7, pc}
20 %tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 2) ; [#uses=1]
21 %tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 3) ; [#uses=1]
22 %tmp5 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 4) ; [#uses=1]
23 %tmp6 = call i32 @f2( i32 %tmp, i32 %tmp3, i32 %tmp5 ) ; [#uses=1]
24 ret i32 %tmp6
25 }
26
27 define i32 @t3() {
28 ; CHECK-LABEL: t3:
29 ; CHECK: push {r7, lr}
30 ; CHECK: ldm
31 ; CHECK: pop {r7, pc}
32 %tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 1) ; [#uses=1]
33 %tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 2) ; [#uses=1]
34 %tmp5 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 3) ; [#uses=1]
35 %tmp6 = call i32 @f2( i32 %tmp, i32 %tmp3, i32 %tmp5 ) ; [#uses=1]
36 ret i32 %tmp6
37 }
38
39 declare i32 @f1(i32, i32)
40
41 declare i32 @f2(i32, i32, i32)
44 define i32 @t1() {
55 ; CHECK-LABEL: t1:
66 ; CHECK: push {r7, lr}
7 ; CHECK: ldrd
78 ; CHECK: pop {r7, pc}
89 %tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 0) ; [#uses=1]
910 %tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 1) ; [#uses=1]
2627 define i32 @t3() {
2728 ; CHECK-LABEL: t3:
2829 ; CHECK: push {r7, lr}
30 ; CHECK: ldm
2931 ; CHECK: pop {r7, pc}
3032 %tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 1) ; [#uses=1]
3133 %tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 2) ; [#uses=1]