llvm.org GIT mirror llvm / 0d31d1e
ARM: Correctly align arguments after a byval struct is passed on the stack git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202985 91177308-0d34-0410-b5e6-96231b3b80d8 Oliver Stannard 6 years ago
8 changed file(s) with 245 addition(s) and 67 deletion(s). Raw diff Collapse all Expand all
403403 ByValRegs.clear();
404404 }
405405
406 // Rewind byval registers tracking info.
407 void rewindByValRegsInfo() {
408 InRegsParamsProceed = 0;
409 }
410
406411 ParmContext getCallOrPrologue() const { return CallOrPrologue; }
407412
408413 private:
174174 if (MF.getFunction()->getCallingConv() == CallingConv::GHC)
175175 return;
176176
177 // Allocate the vararg register save area. This is not counted in NumBytes.
177 // Allocate the vararg register save area.
178178 if (ArgRegsSaveSize) {
179179 emitSPUpdate(isARM, MBB, MBBI, dl, TII, -ArgRegsSaveSize,
180180 MachineInstr::FrameSetup);
187187 }
188188
189189 if (!AFI->hasStackFrame()) {
190 if (NumBytes != 0) {
191 emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes,
190 if (NumBytes - ArgRegsSaveSize != 0) {
191 emitSPUpdate(isARM, MBB, MBBI, dl, TII, -(NumBytes - ArgRegsSaveSize),
192192 MachineInstr::FrameSetup);
193193 MCSymbol *SPLabel = Context.CreateTempSymbol();
194194 BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
195195 .addSym(SPLabel);
196 CFAOffset -= NumBytes;
196 CFAOffset -= NumBytes - ArgRegsSaveSize;
197197 MMI.addFrameInst(MCCFIInstruction::createDefCfaOffset(SPLabel,
198198 CFAOffset));
199199 }
245245
246246 // Determine starting offsets of spill areas.
247247 bool HasFP = hasFP(MF);
248 unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize);
248 unsigned DPRCSOffset = NumBytes - (ArgRegsSaveSize + GPRCS1Size
249 + GPRCS2Size + DPRCSSize);
249250 unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize;
250251 unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size;
251252 int FramePtrOffsetInPush = 0;
252253 if (HasFP) {
253 FramePtrOffsetInPush = MFI->getObjectOffset(FramePtrSpillFI) + GPRCS1Size;
254 FramePtrOffsetInPush = MFI->getObjectOffset(FramePtrSpillFI)
255 + GPRCS1Size + ArgRegsSaveSize;
254256 AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) +
255257 NumBytes);
256258 }
338340 case ARM::LR:
339341 MMI.addFrameInst(MCCFIInstruction::createOffset(SPLabel,
340342 MRI->getDwarfRegNum(Reg, true),
341 MFI->getObjectOffset(FI) - ArgRegsSaveSize));
343 MFI->getObjectOffset(FI)));
342344 break;
343345 }
344346 }
389391 case ARM::R12:
390392 if (STI.isTargetMachO()) {
391393 unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
392 unsigned Offset = MFI->getObjectOffset(FI) - ArgRegsSaveSize;
394 unsigned Offset = MFI->getObjectOffset(FI);
393395 MMI.addFrameInst(
394396 MCCFIInstruction::createOffset(SPLabel, DwarfReg, Offset));
395397 }
535537 return;
536538
537539 if (!AFI->hasStackFrame()) {
538 if (NumBytes != 0)
539 emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes);
540 if (NumBytes - ArgRegsSaveSize != 0)
541 emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes - ArgRegsSaveSize);
540542 } else {
541543 // Unwind MBBI to point to first LDR / VLDRD.
542544 const uint16_t *CSRegs = RegInfo->getCalleeSavedRegs(&MF);
549551 }
550552
551553 // Move SP to start of FP callee save spill area.
552 NumBytes -= (AFI->getGPRCalleeSavedArea1Size() +
554 NumBytes -= (ArgRegsSaveSize +
555 AFI->getGPRCalleeSavedArea1Size() +
553556 AFI->getGPRCalleeSavedArea2Size() +
554557 AFI->getDPRCalleeSavedAreaSize());
555558
18251825 State->getCallOrPrologue() == Call) &&
18261826 "unhandled ParmContext");
18271827
1828 // For in-prologue parameters handling, we also introduce stack offset
1829 // for byval registers: see CallingConvLower.cpp, CCState::HandleByVal.
1830 // This behaviour outsides AAPCS rules (5.5 Parameters Passing) of how
1831 // NSAA should be evaluted (NSAA means "next stacked argument address").
1832 // So: NextStackOffset = NSAAOffset + SizeOfByValParamsStoredInRegs.
1833 // Then: NSAAOffset = NextStackOffset - SizeOfByValParamsStoredInRegs.
1834 unsigned NSAAOffset = State->getNextStackOffset();
1835 if (State->getCallOrPrologue() != Call) {
1836 for (unsigned i = 0, e = State->getInRegsParamsCount(); i != e; ++i) {
1837 unsigned RB, RE;
1838 State->getInRegsParamInfo(i, RB, RE);
1839 assert(NSAAOffset >= (RE-RB)*4 &&
1840 "Stack offset for byval regs doesn't introduced anymore?");
1841 NSAAOffset -= (RE-RB)*4;
1842 }
1843 }
18441828 if ((ARM::R0 <= reg) && (reg <= ARM::R3)) {
18451829 if (Subtarget->isAAPCS_ABI() && Align > 4) {
18461830 unsigned AlignInRegs = Align / 4;
18551839 // all remained GPR regs. In that case we can't split parameter, we must
18561840 // send it to stack. We also must set NCRN to R4, so waste all
18571841 // remained registers.
1842 const unsigned NSAAOffset = State->getNextStackOffset();
18581843 if (Subtarget->isAAPCS_ABI() && NSAAOffset != 0 && size > excess) {
18591844 while (State->AllocateReg(GPRArgRegs, 4))
18601845 ;
18741859 // allocate remained amount of registers we need.
18751860 for (unsigned i = reg+1; i != ByValRegEnd; ++i)
18761861 State->AllocateReg(GPRArgRegs, 4);
1877 // At a call site, a byval parameter that is split between
1878 // registers and memory needs its size truncated here. In a
1879 // function prologue, such byval parameters are reassembled in
1880 // memory, and are not truncated.
1881 if (State->getCallOrPrologue() == Call) {
1882 // Make remained size equal to 0 in case, when
1883 // the whole structure may be stored into registers.
1884 if (size < excess)
1885 size = 0;
1886 else
1887 size -= excess;
1888 }
1862 // A byval parameter that is split between registers and memory needs its
1863 // size truncated here.
1864 // In the case where the entire structure fits in registers, we set the
1865 // size in memory to zero.
1866 if (size < excess)
1867 size = 0;
1868 else
1869 size -= excess;
18891870 }
18901871 }
18911872 }
27932774 unsigned OffsetFromOrigArg,
27942775 unsigned ArgOffset,
27952776 unsigned ArgSize,
2796 bool ForceMutable) const {
2777 bool ForceMutable,
2778 unsigned ByValStoreOffset,
2779 unsigned TotalArgRegsSaveSize) const {
27972780
27982781 // Currently, two use-cases possible:
27992782 // Case #1. Non-var-args function, and we meet first byval parameter.
28302813 // Note: once stack area for byval/varargs registers
28312814 // was initialized, it can't be initialized again.
28322815 if (ArgRegsSaveSize) {
2833
28342816 unsigned Padding = ArgRegsSaveSize - ArgRegsSize;
28352817
28362818 if (Padding) {
28392821 AFI->setStoredByValParamsPadding(Padding);
28402822 }
28412823
2842 int FrameIndex = MFI->CreateFixedObject(
2843 ArgRegsSaveSize,
2844 Padding + ArgOffset,
2845 false);
2824 int FrameIndex = MFI->CreateFixedObject(ArgRegsSaveSize,
2825 Padding +
2826 ByValStoreOffset -
2827 (int64_t)TotalArgRegsSaveSize,
2828 false);
28462829 SDValue FIN = DAG.getFrameIndex(FrameIndex, getPointerTy());
2830 if (Padding) {
2831 MFI->CreateFixedObject(Padding,
2832 ArgOffset + ByValStoreOffset -
2833 (int64_t)ArgRegsSaveSize,
2834 false);
2835 }
28472836
28482837 SmallVector MemOps;
28492838 for (unsigned i = 0; firstRegToSaveIndex < lastRegToSaveIndex;
28712860 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
28722861 &MemOps[0], MemOps.size());
28732862 return FrameIndex;
2874 } else
2863 } else {
2864 if (ArgSize == 0) {
2865 // We cannot allocate a zero-byte object for the first variadic argument,
2866 // so just make up a size.
2867 ArgSize = 4;
2868 }
28752869 // This will point to the next argument passed via stack.
28762870 return MFI->CreateFixedObject(
2877 4, AFI->getStoredByValParamsPadding() + ArgOffset, !ForceMutable);
2871 ArgSize, ArgOffset, !ForceMutable);
2872 }
28782873 }
28792874
28802875 // Setup stack frame, the va_list pointer will start from.
28822877 ARMTargetLowering::VarArgStyleRegisters(CCState &CCInfo, SelectionDAG &DAG,
28832878 SDLoc dl, SDValue &Chain,
28842879 unsigned ArgOffset,
2880 unsigned TotalArgRegsSaveSize,
28852881 bool ForceMutable) const {
28862882 MachineFunction &MF = DAG.getMachineFunction();
28872883 ARMFunctionInfo *AFI = MF.getInfo();
28932889 // argument passed via stack.
28942890 int FrameIndex =
28952891 StoreByValRegs(CCInfo, DAG, dl, Chain, 0, CCInfo.getInRegsParamsCount(),
2896 0, ArgOffset, 0, ForceMutable);
2892 0, ArgOffset, 0, ForceMutable, 0, TotalArgRegsSaveSize);
28972893
28982894 AFI->setVarArgsFrameIndex(FrameIndex);
28992895 }
29292925 // Then we increase this value each time we meet byval parameter.
29302926 // We also increase this value in case of varargs function.
29312927 AFI->setArgRegsSaveSize(0);
2928
2929 unsigned ByValStoreOffset = 0;
2930 unsigned TotalArgRegsSaveSize = 0;
2931 unsigned ArgRegsSaveSizeMaxAlign = 4;
2932
2933 // Calculate the amount of stack space that we need to allocate to store
2934 // byval and variadic arguments that are passed in registers.
2935 // We need to know this before we allocate the first byval or variadic
2936 // argument, as they will be allocated a stack slot below the CFA (Canonical
2937 // Frame Address, the stack pointer at entry to the function).
2938 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
2939 CCValAssign &VA = ArgLocs[i];
2940 if (VA.isMemLoc()) {
2941 int index = VA.getValNo();
2942 if (index != lastInsIndex) {
2943 ISD::ArgFlagsTy Flags = Ins[index].Flags;
2944 if (Flags.isByVal()) {
2945 unsigned ExtraArgRegsSize;
2946 unsigned ExtraArgRegsSaveSize;
2947 computeRegArea(CCInfo, MF, CCInfo.getInRegsParamsProceed(),
2948 Flags.getByValSize(),
2949 ExtraArgRegsSize, ExtraArgRegsSaveSize);
2950
2951 TotalArgRegsSaveSize += ExtraArgRegsSaveSize;
2952 if (Flags.getByValAlign() > ArgRegsSaveSizeMaxAlign)
2953 ArgRegsSaveSizeMaxAlign = Flags.getByValAlign();
2954 CCInfo.nextInRegsParam();
2955 }
2956 lastInsIndex = index;
2957 }
2958 }
2959 }
2960 CCInfo.rewindByValRegsInfo();
2961 lastInsIndex = -1;
2962 if (isVarArg) {
2963 unsigned ExtraArgRegsSize;
2964 unsigned ExtraArgRegsSaveSize;
2965 computeRegArea(CCInfo, MF, CCInfo.getInRegsParamsCount(), 0,
2966 ExtraArgRegsSize, ExtraArgRegsSaveSize);
2967 TotalArgRegsSaveSize += ExtraArgRegsSaveSize;
2968 }
2969 // If the arg regs save area contains N-byte aligned values, the
2970 // bottom of it must be at least N-byte aligned.
2971 TotalArgRegsSaveSize = RoundUpToAlignment(TotalArgRegsSaveSize, ArgRegsSaveSizeMaxAlign);
2972 TotalArgRegsSaveSize = std::min(TotalArgRegsSaveSize, 16U);
29322973
29332974 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
29342975 CCValAssign &VA = ArgLocs[i];
30283069 // a tail call.
30293070 if (Flags.isByVal()) {
30303071 unsigned CurByValIndex = CCInfo.getInRegsParamsProceed();
3072
3073 ByValStoreOffset = RoundUpToAlignment(ByValStoreOffset, Flags.getByValAlign());
30313074 int FrameIndex = StoreByValRegs(
30323075 CCInfo, DAG, dl, Chain, CurOrigArg,
30333076 CurByValIndex,
30343077 Ins[VA.getValNo()].PartOffset,
30353078 VA.getLocMemOffset(),
30363079 Flags.getByValSize(),
3037 true /*force mutable frames*/);
3080 true /*force mutable frames*/,
3081 ByValStoreOffset,
3082 TotalArgRegsSaveSize);
3083 ByValStoreOffset += Flags.getByValSize();
3084 ByValStoreOffset = std::min(ByValStoreOffset, 16U);
30383085 InVals.push_back(DAG.getFrameIndex(FrameIndex, getPointerTy()));
30393086 CCInfo.nextInRegsParam();
30403087 } else {
3041 unsigned FIOffset = VA.getLocMemOffset() +
3042 AFI->getStoredByValParamsPadding();
3088 unsigned FIOffset = VA.getLocMemOffset();
30433089 int FI = MFI->CreateFixedObject(VA.getLocVT().getSizeInBits()/8,
30443090 FIOffset, true);
30453091
30573103 // varargs
30583104 if (isVarArg)
30593105 VarArgStyleRegisters(CCInfo, DAG, dl, Chain,
3060 CCInfo.getNextStackOffset());
3106 CCInfo.getNextStackOffset(),
3107 TotalArgRegsSaveSize);
30613108
30623109 return Chain;
30633110 }
491491 unsigned OffsetFromOrigArg,
492492 unsigned ArgOffset,
493493 unsigned ArgSize,
494 bool ForceMutable) const;
494 bool ForceMutable,
495 unsigned ByValStoreOffset,
496 unsigned TotalArgRegsSaveSize) const;
495497
496498 void VarArgStyleRegisters(CCState &CCInfo, SelectionDAG &DAG,
497499 SDLoc dl, SDValue &Chain,
498500 unsigned ArgOffset,
501 unsigned TotalArgRegsSaveSize,
499502 bool ForceMutable = false) const;
500503
501504 void computeRegArea(CCState &CCInfo, MachineFunction &MF,
9393 unsigned Align = MF.getTarget().getFrameLowering()->getStackAlignment();
9494 unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize(Align);
9595 unsigned NumBytes = MFI->getStackSize();
96 assert(NumBytes >= ArgRegsSaveSize &&
97 "ArgRegsSaveSize is included in NumBytes");
9698 const std::vector &CSI = MFI->getCalleeSavedInfo();
9799 DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
98100 unsigned FramePtr = RegInfo->getFrameRegister(MF);
120122 }
121123
122124 if (!AFI->hasStackFrame()) {
123 if (NumBytes != 0) {
124 emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -NumBytes,
125 if (NumBytes - ArgRegsSaveSize != 0) {
126 emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -(NumBytes - ArgRegsSaveSize),
125127 MachineInstr::FrameSetup);
126128 MCSymbol *SPLabel = MMI.getContext().CreateTempSymbol();
127129 BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
128130 .addSym(SPLabel);
129 CFAOffset -= NumBytes;
131 CFAOffset -= NumBytes - ArgRegsSaveSize;
130132 MMI.addFrameInst(
131133 MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
132134 }
167169 }
168170
169171 // Determine starting offsets of spill areas.
170 unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize);
172 unsigned DPRCSOffset = NumBytes - ArgRegsSaveSize - (GPRCS1Size + GPRCS2Size + DPRCSSize);
171173 unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize;
172174 unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size;
173175 bool HasFP = hasFP(MF);
218220 case ARM::LR:
219221 MMI.addFrameInst(MCCFIInstruction::createOffset(SPLabel,
220222 MRI->getDwarfRegNum(Reg, true),
221 MFI->getObjectOffset(FI) - ArgRegsSaveSize));
223 MFI->getObjectOffset(FI)));
222224 break;
223225 }
224226 }
226228
227229 // Adjust FP so it point to the stack slot that contains the previous FP.
228230 if (HasFP) {
229 FramePtrOffsetInBlock += MFI->getObjectOffset(FramePtrSpillFI) + GPRCS1Size;
231 FramePtrOffsetInBlock += MFI->getObjectOffset(FramePtrSpillFI)
232 + GPRCS1Size + ArgRegsSaveSize;
230233 AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tADDrSPi), FramePtr)
231234 .addReg(ARM::SP).addImm(FramePtrOffsetInBlock / 4)
232235 .setMIFlags(MachineInstr::FrameSetup));
323326 unsigned Align = MF.getTarget().getFrameLowering()->getStackAlignment();
324327 unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize(Align);
325328 int NumBytes = (int)MFI->getStackSize();
329 assert(NumBytes >= ArgRegsSaveSize &&
330 "ArgRegsSaveSize is included in NumBytes");
326331 const uint16_t *CSRegs = RegInfo->getCalleeSavedRegs();
327332 unsigned FramePtr = RegInfo->getFrameRegister(MF);
328333
329334 if (!AFI->hasStackFrame()) {
330 if (NumBytes != 0)
331 emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, NumBytes);
335 if (NumBytes - ArgRegsSaveSize != 0)
336 emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, NumBytes - ArgRegsSaveSize);
332337 } else {
333338 // Unwind MBBI to point to first LDR / VLDRD.
334339 if (MBBI != MBB.begin()) {
342347 // Move SP to start of FP callee save spill area.
343348 NumBytes -= (AFI->getGPRCalleeSavedArea1Size() +
344349 AFI->getGPRCalleeSavedArea2Size() +
345 AFI->getDPRCalleeSavedAreaSize());
350 AFI->getDPRCalleeSavedAreaSize() +
351 ArgRegsSaveSize);
346352
347353 if (AFI->shouldRestoreSPFromFP()) {
348354 NumBytes = AFI->getFramePtrSpillOffset() - NumBytes;
33 ;CHECK-LABEL: foo:
44 ;CHECK: sub sp, sp, #8
55 ;CHECK: push {r11, lr}
6 ;CHECK: str r0, [sp, #8]
7 ;CHECK: add r0, sp, #8
6 ;CHECK: str r0, [sp, #12]
7 ;CHECK: add r0, sp, #12
88 ;CHECK: bl fooUseParam
99 ;CHECK: pop {r11, lr}
1010 ;CHECK: add sp, sp, #8
2222 entry:
2323 ;CHECK: sub sp, #8
2424 ;CHECK: push.w {r11, lr}
25 ;CHECK: add r0, sp, #16
26 ;CHECK: str r2, [sp, #20]
27 ;CHECK: str r1, [sp, #16]
25 ;CHECK: add r0, sp, #8
26 ;CHECK: str r2, [sp, #12]
27 ;CHECK: str r1, [sp, #8]
2828 ;CHECK: bl fooUseStruct
2929 call void @fooUseStruct(%st_t* %p1)
3030 ret void
0 ; RUN: llc -mtriple=arm-linux-gnueabihf < %s | FileCheck %s
1
2 %struct4bytes = type { i32 }
3 %struct8bytes8align = type { i64 }
4 %struct12bytes = type { i32, i32, i32 }
5
6 declare void @useIntPtr(%struct4bytes*)
7 declare void @useLong(i64)
8 declare void @usePtr(%struct8bytes8align*)
9
10 ; a -> r0
11 ; b -> r1..r3
12 ; c -> sp+0..sp+7
13 define void @foo1(i32 %a, %struct12bytes* byval %b, i64 %c) {
14 ; CHECK-LABEL: foo1
15 ; CHECK: sub sp, sp, #16
16 ; CHECK: push {r11, lr}
17 ; CHECK: add [[SCRATCH:r[0-9]+]], sp, #12
18 ; CHECK: stm [[SCRATCH]], {r1, r2, r3}
19 ; CHECK: ldr r0, [sp, #24]
20 ; CHECK: ldr r1, [sp, #28]
21 ; CHECK: bl useLong
22 ; CHECK: pop {r11, lr}
23 ; CHECK: add sp, sp, #16
24
25 tail call void @useLong(i64 %c)
26 ret void
27 }
28
29 ; a -> r0
30 ; b -> r2..r3
31 define void @foo2(i32 %a, %struct8bytes8align* byval %b) {
32 ; CHECK-LABEL: foo2
33 ; CHECK: sub sp, sp, #8
34 ; CHECK: push {r11, lr}
35 ; CHECK: add r0, sp, #8
36 ; CHECK: str r3, [sp, #12]
37 ; CHECK: str r2, [sp, #8]
38 ; CHECK: bl usePtr
39 ; CHECK: pop {r11, lr}
40 ; CHECK: add sp, sp, #8
41
42 tail call void @usePtr(%struct8bytes8align* %b)
43 ret void
44 }
45
46 ; a -> r0..r1
47 ; b -> r2
48 define void @foo3(%struct8bytes8align* byval %a, %struct4bytes* byval %b) {
49 ; CHECK-LABEL: foo3
50 ; CHECK: sub sp, sp, #16
51 ; CHECK: push {r11, lr}
52 ; CHECK: add [[SCRATCH:r[0-9]+]], sp, #8
53 ; CHECK: stm [[SCRATCH]], {r0, r1, r2}
54 ; CHECK: add r0, sp, #8
55 ; CHECK: bl usePtr
56 ; CHECK: pop {r11, lr}
57 ; CHECK: add sp, sp, #16
58
59 tail call void @usePtr(%struct8bytes8align* %a)
60 ret void
61 }
62
63 ; a -> r0
64 ; b -> r2..r3
65 define void @foo4(%struct4bytes* byval %a, %struct8bytes8align* byval %b) {
66 ; CHECK-LABEL: foo4
67 ; CHECK: sub sp, sp, #16
68 ; CHECK: push {r11, lr}
69 ; CHECK: str r0, [sp, #8]
70 ; CHECK: add r0, sp, #16
71 ; CHECK: str r3, [sp, #20]
72 ; CHECK: str r2, [sp, #16]
73 ; CHECK: bl usePtr
74 ; CHECK: pop {r11, lr}
75 ; CHECK: add sp, sp, #16
76 ; CHECK: mov pc, lr
77
78 tail call void @usePtr(%struct8bytes8align* %b)
79 ret void
80 }
81
82 ; a -> r0..r1
83 ; b -> r2
84 ; c -> r3
85 define void @foo5(%struct8bytes8align* byval %a, %struct4bytes* byval %b, %struct4bytes* byval %c) {
86 ; CHECK-LABEL: foo5
87 ; CHECK: sub sp, sp, #16
88 ; CHECK: push {r11, lr}
89 ; CHECK: add [[SCRATCH:r[0-9]+]], sp, #8
90 ; CHECK: stm [[SCRATCH]], {r0, r1, r2, r3}
91 ; CHECK: add r0, sp, #8
92 ; CHECK: bl usePtr
93 ; CHECK: pop {r11, lr}
94 ; CHECK: add sp, sp, #16
95 ; CHECK: mov pc, lr
96
97 tail call void @usePtr(%struct8bytes8align* %a)
98 ret void
99 }
100
101 ; a..c -> r0..r2
102 ; d -> sp+0..sp+7
103 define void @foo6(i32 %a, i32 %b, i32 %c, %struct8bytes8align* byval %d) {
104 ; CHECK-LABEL: foo6
105 ; CHECK: push {r11, lr}
106 ; CHECK: add r0, sp, #8
107 ; CHECK: bl usePtr
108 ; CHECK: pop {r11, lr}
109 ; CHECK: mov pc, lr
110
111 tail call void @usePtr(%struct8bytes8align* %d)
112 ret void
113 }