Skip to content

Commit 8ba2ae3

Browse files
authored
[RISCV][GISel] Implement canLowerReturn. (#105465)
This allows us to handle return values that are too large to fit in x10 and x11. They will be converted to a sret by passing a pointer to where to store the return value.
1 parent c4c5fdd commit 8ba2ae3

File tree

4 files changed

+363
-30
lines changed

4 files changed

+363
-30
lines changed

llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "RISCVMachineFunctionInfo.h"
1818
#include "RISCVSubtarget.h"
1919
#include "llvm/CodeGen/Analysis.h"
20+
#include "llvm/CodeGen/FunctionLoweringInfo.h"
2021
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
2122
#include "llvm/CodeGen/MachineFrameInfo.h"
2223

@@ -360,13 +361,7 @@ static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget,
360361
// lowerCall.
361362
static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget,
362363
bool IsLowerRetVal = false) {
363-
// TODO: Integers larger than 2*XLen are passed indirectly which is not
364-
// supported yet.
365-
if (T->isIntegerTy())
366-
return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
367-
if (T->isHalfTy() || T->isFloatTy() || T->isDoubleTy())
368-
return true;
369-
if (T->isPointerTy())
364+
if (T->isIntegerTy() || T->isFloatingPointTy() || T->isPointerTy())
370365
return true;
371366

372367
if (T->isArrayTy())
@@ -394,10 +389,13 @@ bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
394389
assert(!Val == VRegs.empty() && "Return value without a vreg");
395390
MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET);
396391

397-
if (!VRegs.empty()) {
392+
if (!FLI.CanLowerReturn) {
393+
insertSRetStores(MIRBuilder, Val->getType(), VRegs, FLI.DemoteRegister);
394+
} else if (!VRegs.empty()) {
398395
const RISCVSubtarget &Subtarget =
399396
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
400-
if (!isSupportedReturnType(Val->getType(), Subtarget, /*IsLowerRetVal=*/true))
397+
if (!isSupportedReturnType(Val->getType(), Subtarget,
398+
/*IsLowerRetVal=*/true))
401399
return false;
402400

403401
MachineFunction &MF = MIRBuilder.getMF();
@@ -418,14 +416,38 @@ bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
418416
/*IsRet=*/true, Dispatcher);
419417
RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret);
420418
if (!determineAndHandleAssignments(Handler, Assigner, SplitRetInfos,
421-
MIRBuilder, CC, F.isVarArg()))
419+
MIRBuilder, CC, F.isVarArg()))
422420
return false;
423421
}
424422

425423
MIRBuilder.insertInstr(Ret);
426424
return true;
427425
}
428426

427+
bool RISCVCallLowering::canLowerReturn(MachineFunction &MF,
428+
CallingConv::ID CallConv,
429+
SmallVectorImpl<BaseArgInfo> &Outs,
430+
bool IsVarArg) const {
431+
SmallVector<CCValAssign, 16> ArgLocs;
432+
const auto &TLI = *getTLI<RISCVTargetLowering>();
433+
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs,
434+
MF.getFunction().getContext());
435+
436+
RVVArgDispatcher Dispatcher{&MF, &TLI,
437+
ArrayRef(MF.getFunction().getReturnType())};
438+
439+
RISCVABI::ABI ABI = MF.getSubtarget<RISCVSubtarget>().getTargetABI();
440+
441+
for (unsigned I = 0, E = Outs.size(); I < E; ++I) {
442+
MVT VT = MVT::getVT(Outs[I].Ty);
443+
if (RISCV::CC_RISCV(MF.getDataLayout(), ABI, I, VT, VT, CCValAssign::Full,
444+
Outs[I].Flags[0], CCInfo, /*IsFixed=*/true,
445+
/*isRet=*/true, nullptr, TLI, Dispatcher))
446+
return false;
447+
}
448+
return true;
449+
}
450+
429451
/// If there are varargs that were passed in a0-a7, the data in those registers
430452
/// must be copied to the varargs save area on the stack.
431453
void RISCVCallLowering::saveVarArgRegisters(
@@ -498,24 +520,26 @@ bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
498520
const Function &F,
499521
ArrayRef<ArrayRef<Register>> VRegs,
500522
FunctionLoweringInfo &FLI) const {
501-
// Early exit if there are no arguments. varargs are not part of F.args() but
502-
// must be lowered.
503-
if (F.arg_empty() && !F.isVarArg())
504-
return true;
523+
MachineFunction &MF = MIRBuilder.getMF();
505524

506-
const RISCVSubtarget &Subtarget =
507-
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
525+
const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
508526
for (auto &Arg : F.args()) {
509527
if (!isSupportedArgumentType(Arg.getType(), Subtarget,
510528
/*IsLowerArgs=*/true))
511529
return false;
512530
}
513531

514-
MachineFunction &MF = MIRBuilder.getMF();
532+
MachineRegisterInfo &MRI = MF.getRegInfo();
515533
const DataLayout &DL = MF.getDataLayout();
516534
CallingConv::ID CC = F.getCallingConv();
517535

518536
SmallVector<ArgInfo, 32> SplitArgInfos;
537+
538+
// Insert the hidden sret parameter if the return value won't fit in the
539+
// return registers.
540+
if (!FLI.CanLowerReturn)
541+
insertSRetIncomingArgument(F, SplitArgInfos, FLI.DemoteRegister, MRI, DL);
542+
519543
SmallVector<Type *, 4> TypeList;
520544
unsigned Index = 0;
521545
for (auto &Arg : F.args()) {
@@ -625,21 +649,24 @@ bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
625649
*Subtarget.getRegBankInfo(), *Call,
626650
Call->getDesc(), Call->getOperand(0), 0);
627651

628-
if (Info.OrigRet.Ty->isVoidTy())
629-
return true;
652+
if (Info.CanLowerReturn && !Info.OrigRet.Ty->isVoidTy()) {
653+
SmallVector<ArgInfo, 4> SplitRetInfos;
654+
splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
630655

631-
SmallVector<ArgInfo, 4> SplitRetInfos;
632-
splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC);
656+
RVVArgDispatcher RetDispatcher{&MF, getTLI<RISCVTargetLowering>(),
657+
ArrayRef(F.getReturnType())};
658+
RISCVIncomingValueAssigner RetAssigner(
659+
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
660+
/*IsRet=*/true, RetDispatcher);
661+
RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
662+
if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
663+
MIRBuilder, CC, Info.IsVarArg))
664+
return false;
665+
}
633666

634-
RVVArgDispatcher RetDispatcher{&MF, getTLI<RISCVTargetLowering>(),
635-
ArrayRef(F.getReturnType())};
636-
RISCVIncomingValueAssigner RetAssigner(
637-
CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV,
638-
/*IsRet=*/true, RetDispatcher);
639-
RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call);
640-
if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos,
641-
MIRBuilder, CC, Info.IsVarArg))
642-
return false;
667+
if (!Info.CanLowerReturn)
668+
insertSRetLoads(MIRBuilder, Info.OrigRet.Ty, Info.OrigRet.Regs,
669+
Info.DemoteRegister, Info.DemoteStackIndex);
643670

644671
return true;
645672
}

llvm/lib/Target/RISCV/GISel/RISCVCallLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ class RISCVCallLowering : public CallLowering {
3232
ArrayRef<Register> VRegs,
3333
FunctionLoweringInfo &FLI) const override;
3434

35+
bool canLowerReturn(MachineFunction &MF, CallingConv::ID CallConv,
36+
SmallVectorImpl<BaseArgInfo> &Outs,
37+
bool IsVarArg) const override;
38+
3539
bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
3640
ArrayRef<ArrayRef<Register>> VRegs,
3741
FunctionLoweringInfo &FLI) const override;

llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-ilp32d-common.ll

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,54 @@ define i32 @caller_small_struct_ret() nounwind {
945945
ret i32 %5
946946
}
947947

948+
; Check return of >2x xlen scalars
949+
950+
define fp128 @callee_large_scalar_ret() nounwind {
951+
; RV32I-LABEL: name: callee_large_scalar_ret
952+
; RV32I: bb.1 (%ir-block.0):
953+
; RV32I-NEXT: liveins: $x10
954+
; RV32I-NEXT: {{ $}}
955+
; RV32I-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x10
956+
; RV32I-NEXT: [[C:%[0-9]+]]:_(s128) = G_FCONSTANT fp128 0xL00000000000000007FFF000000000000
957+
; RV32I-NEXT: G_STORE [[C]](s128), [[COPY]](p0) :: (store (s128))
958+
; RV32I-NEXT: PseudoRET
959+
ret fp128 0xL00000000000000007FFF000000000000
960+
}
961+
962+
define void @caller_large_scalar_ret() nounwind {
963+
; ILP32-LABEL: name: caller_large_scalar_ret
964+
; ILP32: bb.1 (%ir-block.0):
965+
; ILP32-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
966+
; ILP32-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2
967+
; ILP32-NEXT: $x10 = COPY [[FRAME_INDEX]](p0)
968+
; ILP32-NEXT: PseudoCALL target-flags(riscv-call) @callee_large_scalar_ret, csr_ilp32_lp64, implicit-def $x1, implicit $x10
969+
; ILP32-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
970+
; ILP32-NEXT: [[LOAD:%[0-9]+]]:_(s128) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s128) from %stack.0)
971+
; ILP32-NEXT: PseudoRET
972+
;
973+
; ILP32F-LABEL: name: caller_large_scalar_ret
974+
; ILP32F: bb.1 (%ir-block.0):
975+
; ILP32F-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
976+
; ILP32F-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2
977+
; ILP32F-NEXT: $x10 = COPY [[FRAME_INDEX]](p0)
978+
; ILP32F-NEXT: PseudoCALL target-flags(riscv-call) @callee_large_scalar_ret, csr_ilp32f_lp64f, implicit-def $x1, implicit $x10
979+
; ILP32F-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
980+
; ILP32F-NEXT: [[LOAD:%[0-9]+]]:_(s128) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s128) from %stack.0)
981+
; ILP32F-NEXT: PseudoRET
982+
;
983+
; ILP32D-LABEL: name: caller_large_scalar_ret
984+
; ILP32D: bb.1 (%ir-block.0):
985+
; ILP32D-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
986+
; ILP32D-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2
987+
; ILP32D-NEXT: $x10 = COPY [[FRAME_INDEX]](p0)
988+
; ILP32D-NEXT: PseudoCALL target-flags(riscv-call) @callee_large_scalar_ret, csr_ilp32d_lp64d, implicit-def $x1, implicit $x10
989+
; ILP32D-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
990+
; ILP32D-NEXT: [[LOAD:%[0-9]+]]:_(s128) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s128) from %stack.0)
991+
; ILP32D-NEXT: PseudoRET
992+
%1 = call fp128 @callee_large_scalar_ret()
993+
ret void
994+
}
995+
948996
; Check return of >2x xlen structs
949997

950998
%struct.large = type { i32, i32, i32, i32 }
@@ -1033,3 +1081,106 @@ define i32 @caller_large_struct_ret() nounwind {
10331081
%5 = add i32 %2, %4
10341082
ret i32 %5
10351083
}
1084+
1085+
%struct.large2 = type { i32, float, i16, i32 }
1086+
1087+
define %struct.large2 @callee_large_struct_ret2() nounwind {
1088+
; RV32I-LABEL: name: callee_large_struct_ret2
1089+
; RV32I: bb.1 (%ir-block.0):
1090+
; RV32I-NEXT: liveins: $x10
1091+
; RV32I-NEXT: {{ $}}
1092+
; RV32I-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x10
1093+
; RV32I-NEXT: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
1094+
; RV32I-NEXT: [[DEF1:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
1095+
; RV32I-NEXT: [[DEF2:%[0-9]+]]:_(s16) = G_IMPLICIT_DEF
1096+
; RV32I-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
1097+
; RV32I-NEXT: [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
1098+
; RV32I-NEXT: [[C2:%[0-9]+]]:_(s16) = G_CONSTANT i16 3
1099+
; RV32I-NEXT: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
1100+
; RV32I-NEXT: G_STORE [[C]](s32), [[COPY]](p0) :: (store (s32), align 8)
1101+
; RV32I-NEXT: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
1102+
; RV32I-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C4]](s32)
1103+
; RV32I-NEXT: G_STORE [[C1]](s32), [[PTR_ADD]](p0) :: (store (s32))
1104+
; RV32I-NEXT: [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
1105+
; RV32I-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C5]](s32)
1106+
; RV32I-NEXT: G_STORE [[C2]](s16), [[PTR_ADD1]](p0) :: (store (s16), align 8)
1107+
; RV32I-NEXT: [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
1108+
; RV32I-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C6]](s32)
1109+
; RV32I-NEXT: G_STORE [[C3]](s32), [[PTR_ADD2]](p0) :: (store (s32))
1110+
; RV32I-NEXT: PseudoRET
1111+
%a = insertvalue %struct.large2 poison, i32 1, 0
1112+
%b = insertvalue %struct.large2 %a, float 2.0, 1
1113+
%c = insertvalue %struct.large2 %b, i16 3, 2
1114+
%d = insertvalue %struct.large2 %c, i32 4, 3
1115+
ret %struct.large2 %d
1116+
}
1117+
1118+
define i32 @caller_large_struct_ret2() nounwind {
1119+
; ILP32-LABEL: name: caller_large_struct_ret2
1120+
; ILP32: bb.1 (%ir-block.0):
1121+
; ILP32-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
1122+
; ILP32-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2
1123+
; ILP32-NEXT: $x10 = COPY [[FRAME_INDEX]](p0)
1124+
; ILP32-NEXT: PseudoCALL target-flags(riscv-call) @callee_large_struct_ret, csr_ilp32_lp64, implicit-def $x1, implicit $x10
1125+
; ILP32-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
1126+
; ILP32-NEXT: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %stack.0, align 8)
1127+
; ILP32-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
1128+
; ILP32-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C]](s32)
1129+
; ILP32-NEXT: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD]](p0) :: (load (s32) from %stack.0)
1130+
; ILP32-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
1131+
; ILP32-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C1]](s32)
1132+
; ILP32-NEXT: [[LOAD2:%[0-9]+]]:_(s16) = G_LOAD [[PTR_ADD1]](p0) :: (load (s16) from %stack.0, align 8)
1133+
; ILP32-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
1134+
; ILP32-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C2]](s32)
1135+
; ILP32-NEXT: [[LOAD3:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD2]](p0) :: (load (s32) from %stack.0)
1136+
; ILP32-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[LOAD]], [[LOAD3]]
1137+
; ILP32-NEXT: $x10 = COPY [[ADD]](s32)
1138+
; ILP32-NEXT: PseudoRET implicit $x10
1139+
;
1140+
; ILP32F-LABEL: name: caller_large_struct_ret2
1141+
; ILP32F: bb.1 (%ir-block.0):
1142+
; ILP32F-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
1143+
; ILP32F-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2
1144+
; ILP32F-NEXT: $x10 = COPY [[FRAME_INDEX]](p0)
1145+
; ILP32F-NEXT: PseudoCALL target-flags(riscv-call) @callee_large_struct_ret, csr_ilp32f_lp64f, implicit-def $x1, implicit $x10
1146+
; ILP32F-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
1147+
; ILP32F-NEXT: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %stack.0, align 8)
1148+
; ILP32F-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
1149+
; ILP32F-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C]](s32)
1150+
; ILP32F-NEXT: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD]](p0) :: (load (s32) from %stack.0)
1151+
; ILP32F-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
1152+
; ILP32F-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C1]](s32)
1153+
; ILP32F-NEXT: [[LOAD2:%[0-9]+]]:_(s16) = G_LOAD [[PTR_ADD1]](p0) :: (load (s16) from %stack.0, align 8)
1154+
; ILP32F-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
1155+
; ILP32F-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C2]](s32)
1156+
; ILP32F-NEXT: [[LOAD3:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD2]](p0) :: (load (s32) from %stack.0)
1157+
; ILP32F-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[LOAD]], [[LOAD3]]
1158+
; ILP32F-NEXT: $x10 = COPY [[ADD]](s32)
1159+
; ILP32F-NEXT: PseudoRET implicit $x10
1160+
;
1161+
; ILP32D-LABEL: name: caller_large_struct_ret2
1162+
; ILP32D: bb.1 (%ir-block.0):
1163+
; ILP32D-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
1164+
; ILP32D-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $x2, implicit $x2
1165+
; ILP32D-NEXT: $x10 = COPY [[FRAME_INDEX]](p0)
1166+
; ILP32D-NEXT: PseudoCALL target-flags(riscv-call) @callee_large_struct_ret, csr_ilp32d_lp64d, implicit-def $x1, implicit $x10
1167+
; ILP32D-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $x2, implicit $x2
1168+
; ILP32D-NEXT: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %stack.0, align 8)
1169+
; ILP32D-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
1170+
; ILP32D-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C]](s32)
1171+
; ILP32D-NEXT: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD]](p0) :: (load (s32) from %stack.0)
1172+
; ILP32D-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
1173+
; ILP32D-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C1]](s32)
1174+
; ILP32D-NEXT: [[LOAD2:%[0-9]+]]:_(s16) = G_LOAD [[PTR_ADD1]](p0) :: (load (s16) from %stack.0, align 8)
1175+
; ILP32D-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
1176+
; ILP32D-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C2]](s32)
1177+
; ILP32D-NEXT: [[LOAD3:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD2]](p0) :: (load (s32) from %stack.0)
1178+
; ILP32D-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[LOAD]], [[LOAD3]]
1179+
; ILP32D-NEXT: $x10 = COPY [[ADD]](s32)
1180+
; ILP32D-NEXT: PseudoRET implicit $x10
1181+
%1 = call %struct.large2 @callee_large_struct_ret()
1182+
%2 = extractvalue %struct.large2 %1, 0
1183+
%3 = extractvalue %struct.large2 %1, 3
1184+
%4 = add i32 %2, %3
1185+
ret i32 %4
1186+
}

0 commit comments

Comments
 (0)