From 8d165718522e6ffd07a4e718c1287a2e5fcc0e0a Mon Sep 17 00:00:00 2001 From: Quentin Colombet Date: Sun, 20 Oct 2024 20:47:50 +0200 Subject: [PATCH] [H2BLB][SDISel] Call lowering with stack arguments This commit implements the lowering of calls when these have stack arguments. The change consists in mainly three things: 1. Populate the CALLSEQ_START/END instructions with the amount of stack space required to hold the outgoing arguments. 2. Issue the stores that populate the stack space with the arguments 3. Assert that the frame lowering used the reserved call mode. This mode allocate the stack space required for all the calls within the current function in the prologue. Without this mode, we would need to adjust the stack pointer before and after each call. --- llvm/lib/Target/H2BLB/H2BLBFrameLowering.cpp | 7 +- llvm/lib/Target/H2BLB/H2BLBISelLowering.cpp | 41 ++- llvm/test/CodeGen/H2BLB/SDISel/e2e-abi.ll | 267 +++++++++++++++++- .../CodeGen/H2BLB/SDISel/isel-only-abi.ll | 95 +++++++ 4 files changed, 388 insertions(+), 22 deletions(-) diff --git a/llvm/lib/Target/H2BLB/H2BLBFrameLowering.cpp b/llvm/lib/Target/H2BLB/H2BLBFrameLowering.cpp index a3dd041d85da..6e3c16c85acf 100644 --- a/llvm/lib/Target/H2BLB/H2BLBFrameLowering.cpp +++ b/llvm/lib/Target/H2BLB/H2BLBFrameLowering.cpp @@ -60,13 +60,14 @@ MachineBasicBlock::iterator H2BLBFrameLowering::eliminateCallFramePseudoInstr( const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); unsigned Opc = MI->getOpcode(); + // The call frame should always be included in the stack frame in the + // prologue. + assert(hasReservedCallFrame(MF) && "H2BLB doesn't have a FP register"); + if (Opc != TII->getCallFrameSetupOpcode() && Opc != TII->getCallFrameDestroyOpcode()) report_fatal_error("Unexpected frame pseudo instruction"); - if (MI->getOperand(0).getImm() != 0) - report_fatal_error("Proper frame lowering not yet implemented"); - if (MI->getOperand(1).getImm() != 0) report_fatal_error("Callee pop count not supported"); diff --git a/llvm/lib/Target/H2BLB/H2BLBISelLowering.cpp b/llvm/lib/Target/H2BLB/H2BLBISelLowering.cpp index 996a27286680..98417b84cb1a 100644 --- a/llvm/lib/Target/H2BLB/H2BLBISelLowering.cpp +++ b/llvm/lib/Target/H2BLB/H2BLBISelLowering.cpp @@ -170,6 +170,7 @@ SDValue H2BLBTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SDValue Callee = CLI.Callee; CallingConv::ID CallConv = CLI.CallConv; MachineFunction &MF = DAG.getMachineFunction(); + SDLoc &DL = CLI.DL; // H2BLB target does not support tail call optimization. CLI.IsTailCall = false; @@ -205,8 +206,15 @@ SDValue H2BLBTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, } SDValue InGlue; + // Now that we collected all the registers, start the call sequence. + auto PtrVT = getPointerTy(MF.getDataLayout()); + Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, DL); + + SDValue StackPtr = DAG.getCopyFromReg(Chain, DL, H2BLB::SP, + getPointerTy(DAG.getDataLayout())); SmallVector> RegsToPass; + SmallVector MemOpChains; // Walk arg assignments for (size_t i = 0, e = ArgLocs.size(); i != e; ++i) { @@ -223,20 +231,30 @@ SDValue H2BLBTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, continue; } assert(VA.isMemLoc() && "Expected stack argument"); - report_fatal_error("stack arguments not yet implemented"); + SDValue DstAddr; + MachinePointerInfo DstInfo; + + unsigned OpSize = VA.getValVT().getSizeInBits(); + OpSize = (OpSize + 7) / 8; + unsigned LocMemOffset = VA.getLocMemOffset(); + SDValue PtrOff = DAG.getIntPtrConstant(LocMemOffset, DL); + DstAddr = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, PtrOff); + DstInfo = MachinePointerInfo::getStack(MF, LocMemOffset); + + SDValue Store = DAG.getStore(Chain, DL, Arg, DstAddr, DstInfo); + MemOpChains.push_back(Store); } - // Now that we collected all the registers, start the call sequence. - auto PtrVT = getPointerTy(MF.getDataLayout()); - Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); // Build a sequence of copy-to-reg nodes chained together with token chain // and flag operands which copy the outgoing args into the appropriate regs. // We do this and not in the previous loop to chain the registers as close // as possible to the actual call. for (auto &RegToPass : RegsToPass) { - Chain = DAG.getCopyToReg(Chain, CLI.DL, RegToPass.first, RegToPass.second, - InGlue); + Chain = + DAG.getCopyToReg(Chain, DL, RegToPass.first, RegToPass.second, InGlue); InGlue = Chain.getValue(1); } @@ -244,7 +262,7 @@ SDValue H2BLBTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // turn it into a TargetGlobalAddress node so that all the generic code cannot // mess with it. if (GlobalAddressSDNode *G = dyn_cast(Callee)) - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), CLI.DL, PtrVT, + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVT, G->getOffset(), 0); else report_fatal_error("non-direct calls not implemented"); @@ -269,14 +287,14 @@ SDValue H2BLBTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // The call will return a chain & a flag for retval copies to use. SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); - Chain = DAG.getNode(H2BLBISD::CALL, CLI.DL, NodeTys, Ops); + Chain = DAG.getNode(H2BLBISD::CALL, DL, NodeTys, Ops); InGlue = Chain.getValue(1); // Propagate any NoMerge attribute that we may have. DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); // Finish the call sequence. - Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, InGlue, CLI.DL); + Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, InGlue, DL); InGlue = Chain.getValue(1); // Assign locations to each value returned by this call. @@ -292,9 +310,8 @@ SDValue H2BLBTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, assert(VA.getLocInfo() == CCValAssign::Full && "extension/truncation of any sort, not yet implemented"); - Chain = - DAG.getCopyFromReg(Chain, CLI.DL, VA.getLocReg(), VA.getValVT(), InGlue) - .getValue(1); + Chain = DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getValVT(), InGlue) + .getValue(1); // Guarantee that all emitted copies are stuck together, // avoiding something bad. diff --git a/llvm/test/CodeGen/H2BLB/SDISel/e2e-abi.ll b/llvm/test/CodeGen/H2BLB/SDISel/e2e-abi.ll index c1c38b605abb..77443fe0ea96 100644 --- a/llvm/test/CodeGen/H2BLB/SDISel/e2e-abi.ll +++ b/llvm/test/CodeGen/H2BLB/SDISel/e2e-abi.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 -; RUN: llc -O0 -o - %s -fast-isel=0 | FileCheck %s +; RUN: llc -o - %s -fast-isel=0 -verify-machineinstrs | FileCheck %s target triple="h2blb--" define void @empty() { @@ -60,9 +60,11 @@ define i16 @callAFctWithOneArg(i16 %arg) { ; CHECK-LABEL: callAFctWithOneArg: ; CHECK: # %bb.0: ; CHECK-NEXT: subsp sp, sp, 8 -; CHECK-NEXT: strsp16 r0, sp, 6 # 2-byte Folded Spill +; CHECK-NEXT: strsp32 d2, sp, 4 # 4-byte Folded Spill +; CHECK-NEXT: mov16 r4, r0 ; CHECK-NEXT: call oneArgi16 -; CHECK-NEXT: ldrsp16 r0, sp, 6 # 2-byte Folded Reload +; CHECK-NEXT: mov16 r0, r4 +; CHECK-NEXT: ldrsp32 d2, sp, 4 # 4-byte Folded Reload ; CHECK-NEXT: addsp sp, sp, 8 ; CHECK-NEXT: ret %res = call i16 @oneArgi16(i16 %arg) @@ -76,9 +78,11 @@ define i16 @callAFctWithArg16_32(i16 %arg, i32 %arg1) { ; CHECK-LABEL: callAFctWithArg16_32: ; CHECK: # %bb.0: ; CHECK-NEXT: subsp sp, sp, 8 -; CHECK-NEXT: strsp16 r0, sp, 6 # 2-byte Folded Spill +; CHECK-NEXT: strsp32 d2, sp, 4 # 4-byte Folded Spill +; CHECK-NEXT: mov16 r4, r0 ; CHECK-NEXT: call arg16_32 -; CHECK-NEXT: ldrsp16 r0, sp, 6 # 2-byte Folded Reload +; CHECK-NEXT: mov16 r0, r4 +; CHECK-NEXT: ldrsp32 d2, sp, 4 # 4-byte Folded Reload ; CHECK-NEXT: addsp sp, sp, 8 ; CHECK-NEXT: ret %res = call i16 @arg16_32(i16 %arg, i32 %arg1) @@ -91,11 +95,260 @@ define i16 @callAFctWithTwoI16Arg(i16 %arg, i16 %arg1) { ; CHECK-LABEL: callAFctWithTwoI16Arg: ; CHECK: # %bb.0: ; CHECK-NEXT: subsp sp, sp, 8 -; CHECK-NEXT: strsp16 r0, sp, 6 # 2-byte Folded Spill +; CHECK-NEXT: strsp32 d2, sp, 4 # 4-byte Folded Spill +; CHECK-NEXT: mov16 r4, r0 ; CHECK-NEXT: call arg16_16 -; CHECK-NEXT: ldrsp16 r0, sp, 6 # 2-byte Folded Reload +; CHECK-NEXT: mov16 r0, r4 +; CHECK-NEXT: ldrsp32 d2, sp, 4 # 4-byte Folded Reload ; CHECK-NEXT: addsp sp, sp, 8 ; CHECK-NEXT: ret %res = call i16 @arg16_16(i16 %arg, i16 %arg1) ret i16 %res } + +declare i16 @lotsOfArgs2(i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16) + +; Check that we duplicate %arg on as many stack slots as +; required to call lotsOfArgs1. +define i16 @foo1(i16 %arg) { +; CHECK-LABEL: foo1: +; CHECK: # %bb.0: +; CHECK-NEXT: subsp sp, sp, 24 +; CHECK-NEXT: strsp32 d2, sp, 20 # 4-byte Folded Spill +; CHECK-NEXT: mov16 r4, r0 +; CHECK-NEXT: strsp16 r1, sp, 14 +; CHECK-NEXT: strsp16 r1, sp, 12 +; CHECK-NEXT: strsp16 r1, sp, 10 +; CHECK-NEXT: strsp16 r1, sp, 8 +; CHECK-NEXT: strsp16 r1, sp, 6 +; CHECK-NEXT: strsp16 r1, sp, 4 +; CHECK-NEXT: strsp16 r1, sp, 2 +; CHECK-NEXT: strsp16 r1, sp, 0 +; CHECK-NEXT: mov16 r2, r1 +; CHECK-NEXT: mov16 r3, r1 +; CHECK-NEXT: call lotsOfArgs1 +; CHECK-NEXT: mov16 r0, r4 +; CHECK-NEXT: ldrsp32 d2, sp, 20 # 4-byte Folded Reload +; CHECK-NEXT: addsp sp, sp, 24 +; CHECK-NEXT: ret + %res = call i16 @lotsOfArgs1(i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg) + ret i16 %res +} + +; Stress test for the stack lowering. +; +; At the entry of the function the stack looks like: +; high addr %a11 incoming stack arguments +; ... +; low addr %a4 <-- sp at the entry of bar1 +; +; After the prologue, the space for the spill slots and the space for the +; arguments of lotsOfArgs2 is allocated: +; +; high addr +; | incoming stack arguments +; | ---- sp at the entry of lotsOfArgs1 +; | spill slot 1 | +; | ... |> spill slots +; | spill slot N | +; | ----------------- +; | space for the outgoing arguments space +; | This space will be used to store the arguments to lotsOfArgs2. +; | Since there are two calls to lotsOfArgs2, the content of this +; | space is different between each of them. +; v ---- sp after the prologue +; low addr +; +; We have 11 spill slots: 9 for 2-byte values and 2 for 4-byte values +; (the callee saved registers (CSRs)) +; Why 9: a1-a11 needs to live through the first call of bar2 +; r0 is used for the link register +; r1 r2 and r3 are used for the arguments +; Therefore we can use r4-r7 to keep values alive +; => this creates the 2 CSR spills +; At this point we have 11 - 4 (i.e., a1-a11 minus what can be kept +; in r4-r7); so still 7 values to spill. +; Then since r0 is used as a link register for lotsOfArgs1 (current fct) +; but also lotsOfArgs2, it needs to be saved and since there is no +; register left this creates one more spill. So +1 here. +; Then, %tmp needs to be alive through the second call to lotsOfArgs2. +; Similarly to r0, there's no register left so one more spill. +1 +; Therefore 2 CSR spills, then 7+2 spills. +; +; Finally, we allocate 48 bytes on the stacks. +; That's: +; 9 * 2 bytes for the spill slots. +; + 2 * 4 bytes for the CSRs. +; + 8 * 2 bytes for the outgoing arguments. +; = 42 +; Since we want our stack to be aligned on 8 bytes, we have to push it to the +; next multiple of 8 => 48. Hence, we will insert 6 bytes of padding. +; +; The padding is added between the spill space and the outgoing arguments space. +; +; Here is a picture of the contain of the stack using the LLVM IR value names +; (or the register names for the CSRs.) +; --- incoming arg +; sp+62: a11 +; sp+60: a10 +; sp+58: a9 +; sp+56: a8 +; sp+54: a7 +; sp+52: a6 +; sp+50: a5 +; sp+48: a4 +; --- sp at the entry of the function +; sp+46: d2-high +; sp+44: d2-low +; sp+42: d1-high +; sp+40: d1-low +; sp+38: LR (r0) +; sp+36: a11 +; sp+34: a10 +; sp+32: a9 +; sp+30: a8 +; sp+28: a7 +; sp+26: tmp +; sp+24: a1 (note the order for the spill slot doesn't matter) +; sp+22: a2 +; sp+20: padding +; sp+18: padding +; sp+16: padding +; -- lotsOfArgs2 first call | second call +; sp+14: a11 | a1 +; sp+12: a10 | a2 +; sp+10: a9 | a3 +; sp+8: a8 | a4 +; sp+6: a7 | a5 +; sp+4: a6 | a6 +; sp+2: a5 | a7 +; sp+0: a4 | a8 <-- sp address after prologue +; ------------------------------------ +; r3: a3 | a9 +; r2: a2 | a10 +; r1: a1 | a11 +; ---- +; Tagged ASM for checking that everything is correct. +; LHS is what is hold in the related location. +; subsp sp, sp, 48 +; CSR strsp16 d2, sp, 44 # 4-byte Folded Spill +; CSR strsp16 d3, sp, 40 # 4-byte Folded Spill +; LR strsp16 r0, sp, 38 # 2-byte Folded Spill +; a3 mov16 r4, r3 +; a2 strsp16 r2, sp, 22 # 2-byte Folded Spill +; a1 strsp16 r1, sp, 24 # 2-byte Folded Spill +; a11 ldrsp16 r0, sp, 62 +; a11 strsp16 r0, sp, 36 # 2-byte Folded Spill +; a11 strsp16 r0, sp, 14 +; a10 ldrsp16 r0, sp, 60 +; a10 strsp16 r0, sp, 34 # 2-byte Folded Spill +; a10 strsp16 r0, sp, 12 +; a9 ldrsp16 r0, sp, 58 +; a9 strsp16 r0, sp, 32 # 2-byte Folded Spill +; a9 strsp16 r0, sp, 10 +; a8 ldrsp16 r0, sp, 56 +; a8 strsp16 r0, sp, 30 # 2-byte Folded Spill +; a8 strsp16 r0, sp, 8 +; a7 ldrsp16 r0, sp, 54 +; a7 strsp16 r0, sp, 28 # 2-byte Folded Spill +; a7 strsp16 r0, sp, 6 +; a6 ldrsp16 r7, sp, 52 +; a6 strsp16 r7, sp, 4 +; a5 ldrsp16 r5, sp, 50 +; a5 strsp16 r5, sp, 2 +; a4 ldrsp16 r6, sp, 48 +; a4 strsp16 r6, sp, 0 +; call lotsOfArgs2 +; tmp strsp16 r1, sp, 26 # 2-byte Folded Spill +; a2 ldrsp16 r0, sp, 22 # 2-byte Folded Reload +; a2 strsp16 r0, sp, 12 +; a3 strsp16 r4, sp, 10 +; a4 strsp16 r6, sp, 8 +; a5 strsp16 r5, sp, 6 +; a6 strsp16 r7, sp, 4 +; a7 ldrsp16 r0, sp, 28 # 2-byte Folded Reload +; a7 strsp16 r0, sp, 2 +; a8 ldrsp16 r0, sp, 30 # 2-byte Folded Reload +; a8 strsp16 r0, sp, 0 +; a1 ldrsp16 r5, sp, 24 # 2-byte Folded Reload +; a1 strsp16 r5, sp, 14 +; a11 ldrsp16 r1, sp, 36 # 2-byte Folded Reload +; a10 ldrsp16 r4, sp, 34 # 2-byte Folded Reload +; a10 mov16 r2, r4 +; a9 ldrsp16 r3, sp, 32 # 2-byte Folded Reload +; call lotsOfArgs2 +; tmp ldrsp16 r0, sp, 26 # 2-byte Folded Reload +; a1+ addi16 r0, r5, r0 +; a10+ addi16 r0, r4, r0 +;tmp0+ addi16 r1, r0, r1 +; LR ldrsp16 r0, sp, 38 # 2-byte Folded Reload +; CSR ldrsp16 d3, sp, 40 # 4-byte Folded Reload +; CSR ldrsp16 d2, sp, 44 # 4-byte Folded Reload +; addsp sp, sp, 48 +; ret +define i16 @lotsOfArgs1(i16 %a1, i16 %a2, i16 %a3, i16 %a4, i16 %a5, i16 %a6, i16 %a7, i16 %a8, i16 %a9, i16 %a10, i16 %a11) { +; CHECK-LABEL: lotsOfArgs1: +; CHECK: # %bb.0: +; CHECK-NEXT: subsp sp, sp, 48 +; CHECK-NEXT: strsp32 d2, sp, 44 # 4-byte Folded Spill +; CHECK-NEXT: strsp32 d3, sp, 40 # 4-byte Folded Spill +; CHECK-NEXT: strsp16 r0, sp, 38 # 2-byte Folded Spill +; CHECK-NEXT: mov16 r4, r3 +; CHECK-NEXT: strsp16 r2, sp, 22 # 2-byte Folded Spill +; CHECK-NEXT: strsp16 r1, sp, 24 # 2-byte Folded Spill +; CHECK-NEXT: ldrsp16 r0, sp, 62 +; CHECK-NEXT: strsp16 r0, sp, 36 # 2-byte Folded Spill +; CHECK-NEXT: strsp16 r0, sp, 14 +; CHECK-NEXT: ldrsp16 r0, sp, 60 +; CHECK-NEXT: strsp16 r0, sp, 34 # 2-byte Folded Spill +; CHECK-NEXT: strsp16 r0, sp, 12 +; CHECK-NEXT: ldrsp16 r0, sp, 58 +; CHECK-NEXT: strsp16 r0, sp, 32 # 2-byte Folded Spill +; CHECK-NEXT: strsp16 r0, sp, 10 +; CHECK-NEXT: ldrsp16 r0, sp, 56 +; CHECK-NEXT: strsp16 r0, sp, 30 # 2-byte Folded Spill +; CHECK-NEXT: strsp16 r0, sp, 8 +; CHECK-NEXT: ldrsp16 r0, sp, 54 +; CHECK-NEXT: strsp16 r0, sp, 28 # 2-byte Folded Spill +; CHECK-NEXT: strsp16 r0, sp, 6 +; CHECK-NEXT: ldrsp16 r7, sp, 52 +; CHECK-NEXT: strsp16 r7, sp, 4 +; CHECK-NEXT: ldrsp16 r5, sp, 50 +; CHECK-NEXT: strsp16 r5, sp, 2 +; CHECK-NEXT: ldrsp16 r6, sp, 48 +; CHECK-NEXT: strsp16 r6, sp, 0 +; CHECK-NEXT: call lotsOfArgs2 +; CHECK-NEXT: strsp16 r1, sp, 26 # 2-byte Folded Spill +; CHECK-NEXT: ldrsp16 r0, sp, 22 # 2-byte Folded Reload +; CHECK-NEXT: strsp16 r0, sp, 12 +; CHECK-NEXT: strsp16 r4, sp, 10 +; CHECK-NEXT: strsp16 r6, sp, 8 +; CHECK-NEXT: strsp16 r5, sp, 6 +; CHECK-NEXT: strsp16 r7, sp, 4 +; CHECK-NEXT: ldrsp16 r0, sp, 28 # 2-byte Folded Reload +; CHECK-NEXT: strsp16 r0, sp, 2 +; CHECK-NEXT: ldrsp16 r0, sp, 30 # 2-byte Folded Reload +; CHECK-NEXT: strsp16 r0, sp, 0 +; CHECK-NEXT: ldrsp16 r5, sp, 24 # 2-byte Folded Reload +; CHECK-NEXT: strsp16 r5, sp, 14 +; CHECK-NEXT: ldrsp16 r1, sp, 36 # 2-byte Folded Reload +; CHECK-NEXT: ldrsp16 r4, sp, 34 # 2-byte Folded Reload +; CHECK-NEXT: mov16 r2, r4 +; CHECK-NEXT: ldrsp16 r3, sp, 32 # 2-byte Folded Reload +; CHECK-NEXT: call lotsOfArgs2 +; CHECK-NEXT: ldrsp16 r0, sp, 26 # 2-byte Folded Reload +; CHECK-NEXT: addi16 r0, r5, r0 +; CHECK-NEXT: addi16 r0, r4, r0 +; CHECK-NEXT: addi16 r1, r0, r1 +; CHECK-NEXT: ldrsp16 r0, sp, 38 # 2-byte Folded Reload +; CHECK-NEXT: ldrsp32 d3, sp, 40 # 4-byte Folded Reload +; CHECK-NEXT: ldrsp32 d2, sp, 44 # 4-byte Folded Reload +; CHECK-NEXT: addsp sp, sp, 48 +; CHECK-NEXT: ret + %tmp = call i16 @lotsOfArgs2(i16 %a1, i16 %a2, i16 %a3, i16 %a4, i16 %a5, i16 %a6, i16 %a7, i16 %a8, i16 %a9, i16 %a10, i16 %a11) + %tmp0 = call i16 @lotsOfArgs2(i16 %a11, i16 %a10, i16 %a9, i16 %a8, i16 %a7, i16 %a6, i16 %a5, i16 %a4, i16 %a3, i16 %a2, i16 %a1) + %tmp1 = add i16 %a1, %tmp + %tmp2 = add i16 %a10, %tmp1 + %res = add i16 %tmp2, %tmp0 + ret i16 %res +} diff --git a/llvm/test/CodeGen/H2BLB/SDISel/isel-only-abi.ll b/llvm/test/CodeGen/H2BLB/SDISel/isel-only-abi.ll index 2782d74fdf29..539d00cb62db 100644 --- a/llvm/test/CodeGen/H2BLB/SDISel/isel-only-abi.ll +++ b/llvm/test/CodeGen/H2BLB/SDISel/isel-only-abi.ll @@ -197,3 +197,98 @@ define i16 @callAFctWithTwoI16Arg(i16 %arg, i16 %arg1) { %res = call i16 @arg16_16(i16 %arg1, i16 %arg) ret i16 %res } + +declare i16 @lotsOfArgs2(i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16) + +; Check that we duplicate %arg on as many stack slots as +; required to call lotsOfArgs1. +define i16 @foo1(i16 %arg) { + ; CHECK-LABEL: name: foo1 + ; CHECK: bb.0 (%ir-block.0): + ; CHECK-NEXT: liveins: $r1, $r0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr16 = COPY $r0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr16 = COPY $r1 + ; CHECK-NEXT: ADJCALLSTACKDOWN 16, 0, implicit-def dead $sp, implicit $sp + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 14 :: (store (s16) into stack + 14) + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 12 :: (store (s16) into stack + 12) + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 10 :: (store (s16) into stack + 10) + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 8 :: (store (s16) into stack + 8) + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 6 :: (store (s16) into stack + 6) + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 4 :: (store (s16) into stack + 4) + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 2 :: (store (s16) into stack + 2) + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 0 :: (store (s16) into stack) + ; CHECK-NEXT: $r1 = COPY [[COPY1]] + ; CHECK-NEXT: $r2 = COPY [[COPY1]] + ; CHECK-NEXT: $r3 = COPY [[COPY1]] + ; CHECK-NEXT: CALL @lotsOfArgs1, csr, implicit-def dead $r0, implicit $sp, implicit $r1, implicit $r2, implicit $r3, implicit-def $sp, implicit-def $r1 + ; CHECK-NEXT: ADJCALLSTACKUP 16, 0, implicit-def dead $sp, implicit $sp + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr16 = COPY $r1 + ; CHECK-NEXT: $r1 = COPY [[COPY2]] + ; CHECK-NEXT: $r0 = COPY [[COPY]] + ; CHECK-NEXT: RETURN implicit $r0, implicit $r1 + %res = call i16 @lotsOfArgs1(i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg, i16 %arg) + ret i16 %res +} + +; Stress test for the stack lowering. +define i16 @lotsOfArgs1(i16 %a1, i16 %a2, i16 %a3, i16 %a4, i16 %a5, i16 %a6, i16 %a7, i16 %a8, i16 %a9, i16 %a10, i16 %a11) { + ; CHECK-LABEL: name: lotsOfArgs1 + ; CHECK: bb.0 (%ir-block.0): + ; CHECK-NEXT: liveins: $r1, $r2, $r3, $r0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr16 = COPY $r0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr16 = COPY $r3 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr16 = COPY $r2 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr16 = COPY $r1 + ; CHECK-NEXT: ADJCALLSTACKDOWN 16, 0, implicit-def dead $sp, implicit $sp + ; CHECK-NEXT: [[LDRSP16_:%[0-9]+]]:gpr16 = LDRSP16 %fixed-stack.0, 0 :: (load (s16) from %fixed-stack.0) + ; CHECK-NEXT: STRSP16 [[LDRSP16_]], $sp, 14 :: (store (s16) into stack + 14) + ; CHECK-NEXT: [[LDRSP16_1:%[0-9]+]]:gpr16 = LDRSP16 %fixed-stack.1, 0 :: (load (s16) from %fixed-stack.1, align 4) + ; CHECK-NEXT: STRSP16 [[LDRSP16_1]], $sp, 12 :: (store (s16) into stack + 12) + ; CHECK-NEXT: [[LDRSP16_2:%[0-9]+]]:gpr16 = LDRSP16 %fixed-stack.2, 0 :: (load (s16) from %fixed-stack.2) + ; CHECK-NEXT: STRSP16 [[LDRSP16_2]], $sp, 10 :: (store (s16) into stack + 10) + ; CHECK-NEXT: [[LDRSP16_3:%[0-9]+]]:gpr16 = LDRSP16 %fixed-stack.3, 0 :: (load (s16) from %fixed-stack.3, align 8) + ; CHECK-NEXT: STRSP16 [[LDRSP16_3]], $sp, 8 :: (store (s16) into stack + 8) + ; CHECK-NEXT: [[LDRSP16_4:%[0-9]+]]:gpr16 = LDRSP16 %fixed-stack.4, 0 :: (load (s16) from %fixed-stack.4) + ; CHECK-NEXT: STRSP16 [[LDRSP16_4]], $sp, 6 :: (store (s16) into stack + 6) + ; CHECK-NEXT: [[LDRSP16_5:%[0-9]+]]:gpr16 = LDRSP16 %fixed-stack.5, 0 :: (load (s16) from %fixed-stack.5, align 4) + ; CHECK-NEXT: STRSP16 [[LDRSP16_5]], $sp, 4 :: (store (s16) into stack + 4) + ; CHECK-NEXT: [[LDRSP16_6:%[0-9]+]]:gpr16 = LDRSP16 %fixed-stack.6, 0 :: (load (s16) from %fixed-stack.6) + ; CHECK-NEXT: STRSP16 [[LDRSP16_6]], $sp, 2 :: (store (s16) into stack + 2) + ; CHECK-NEXT: [[LDRSP16_7:%[0-9]+]]:gpr16 = LDRSP16 %fixed-stack.7, 0 :: (load (s16) from %fixed-stack.7, align 8) + ; CHECK-NEXT: STRSP16 [[LDRSP16_7]], $sp, 0 :: (store (s16) into stack) + ; CHECK-NEXT: $r1 = COPY [[COPY3]] + ; CHECK-NEXT: $r2 = COPY [[COPY2]] + ; CHECK-NEXT: $r3 = COPY [[COPY1]] + ; CHECK-NEXT: CALL @lotsOfArgs2, csr, implicit-def dead $r0, implicit $sp, implicit $r1, implicit $r2, implicit $r3, implicit-def $sp, implicit-def $r1 + ; CHECK-NEXT: ADJCALLSTACKUP 16, 0, implicit-def dead $sp, implicit $sp + ; CHECK-NEXT: [[COPY4:%[0-9]+]]:gpr16 = COPY $r1 + ; CHECK-NEXT: ADJCALLSTACKDOWN 16, 0, implicit-def dead $sp, implicit $sp + ; CHECK-NEXT: STRSP16 [[COPY2]], $sp, 12 :: (store (s16) into stack + 12) + ; CHECK-NEXT: STRSP16 [[COPY1]], $sp, 10 :: (store (s16) into stack + 10) + ; CHECK-NEXT: STRSP16 [[LDRSP16_7]], $sp, 8 :: (store (s16) into stack + 8) + ; CHECK-NEXT: STRSP16 [[LDRSP16_6]], $sp, 6 :: (store (s16) into stack + 6) + ; CHECK-NEXT: STRSP16 [[LDRSP16_5]], $sp, 4 :: (store (s16) into stack + 4) + ; CHECK-NEXT: STRSP16 [[LDRSP16_4]], $sp, 2 :: (store (s16) into stack + 2) + ; CHECK-NEXT: STRSP16 [[LDRSP16_3]], $sp, 0 :: (store (s16) into stack) + ; CHECK-NEXT: STRSP16 [[COPY3]], $sp, 14 :: (store (s16) into stack + 14) + ; CHECK-NEXT: $r1 = COPY [[LDRSP16_]] + ; CHECK-NEXT: $r2 = COPY [[LDRSP16_1]] + ; CHECK-NEXT: $r3 = COPY [[LDRSP16_2]] + ; CHECK-NEXT: CALL @lotsOfArgs2, csr, implicit-def dead $r0, implicit $sp, implicit $r1, implicit $r2, implicit $r3, implicit-def $sp, implicit-def $r1 + ; CHECK-NEXT: ADJCALLSTACKUP 16, 0, implicit-def dead $sp, implicit $sp + ; CHECK-NEXT: [[COPY5:%[0-9]+]]:gpr16 = COPY $r1 + ; CHECK-NEXT: [[ADDi16rr:%[0-9]+]]:gpr16 = ADDi16rr [[COPY3]], [[COPY4]] + ; CHECK-NEXT: [[ADDi16rr1:%[0-9]+]]:gpr16 = ADDi16rr [[LDRSP16_1]], killed [[ADDi16rr]] + ; CHECK-NEXT: [[ADDi16rr2:%[0-9]+]]:gpr16 = ADDi16rr killed [[ADDi16rr1]], [[COPY5]] + ; CHECK-NEXT: $r1 = COPY [[ADDi16rr2]] + ; CHECK-NEXT: $r0 = COPY [[COPY]] + ; CHECK-NEXT: RETURN implicit $r0, implicit $r1 + %tmp = call i16 @lotsOfArgs2(i16 %a1, i16 %a2, i16 %a3, i16 %a4, i16 %a5, i16 %a6, i16 %a7, i16 %a8, i16 %a9, i16 %a10, i16 %a11) + %tmp0 = call i16 @lotsOfArgs2(i16 %a11, i16 %a10, i16 %a9, i16 %a8, i16 %a7, i16 %a6, i16 %a5, i16 %a4, i16 %a3, i16 %a2, i16 %a1) + %tmp1 = add i16 %a1, %tmp + %tmp2 = add i16 %a10, %tmp1 + %res = add i16 %tmp2, %tmp0 + ret i16 %res +}