///
/// \p CI is the call/invoke instruction.
///
- /// \p ResReg is a register where the call's return value should be stored (or
- /// 0 if there is no return value).
+ /// \p ResRegs are the registers where the call's return value should be
+ /// stored (or 0 if there is no return value). There will be one register for
+ /// each non-aggregate type, as returned by \c computeValueLLTs.
///
/// \p ArgRegs is a list of virtual registers containing each argument that
/// needs to be passed.
///
/// \return true if the lowering succeeded, false otherwise.
bool lowerCall(MachineIRBuilder &MIRBuilder, ImmutableCallSite CS,
- Register ResReg, ArrayRef<Register> ArgRegs,
+ ArrayRef<Register> ResRegs, ArrayRef<Register> ArgRegs,
Register SwiftErrorVReg,
std::function<unsigned()> GetCalleeReg) const;
-
};
} // end namespace llvm
void CallLowering::anchor() {}
bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, ImmutableCallSite CS,
- Register ResReg, ArrayRef<Register> ArgRegs,
+ ArrayRef<Register> ResRegs,
+ ArrayRef<Register> ArgRegs,
Register SwiftErrorVReg,
std::function<unsigned()> GetCalleeReg) const {
auto &DL = CS.getParent()->getParent()->getParent()->getDataLayout();
else
Callee = MachineOperand::CreateReg(GetCalleeReg(), false);
- ArgInfo OrigRet{ResReg, CS.getType(), ISD::ArgFlagsTy{}};
+ ArgInfo OrigRet{ResRegs, CS.getType(), ISD::ArgFlagsTy{}};
if (!OrigRet.Ty->isVoidTy())
setArgFlags(OrigRet, AttributeList::ReturnIndex, DL, CS);
}
if (!F || !F->isIntrinsic() || ID == Intrinsic::not_intrinsic) {
- bool IsSplitType = valueIsSplit(CI);
- Register Res = IsSplitType ? MRI->createGenericVirtualRegister(
- getLLTForType(*CI.getType(), *DL))
- : getOrCreateVReg(CI);
+ ArrayRef<Register> Res = getOrCreateVRegs(CI);
SmallVector<Register, 8> Args;
Register SwiftErrorVReg;
CLI->lowerCall(MIRBuilder, &CI, Res, Args, SwiftErrorVReg,
[&]() { return getOrCreateVReg(*CI.getCalledValue()); });
- if (IsSplitType)
- unpackRegs(CI, Res, MIRBuilder);
-
return Success;
}
MCSymbol *BeginSymbol = Context.createTempSymbol();
MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(BeginSymbol);
- Register Res;
+ ArrayRef<Register> Res;
if (!I.getType()->isVoidTy())
- Res = MRI->createGenericVirtualRegister(getLLTForType(*I.getType(), *DL));
+ Res = getOrCreateVRegs(I);
SmallVector<Register, 8> Args;
- Register SwiftErrorVReg;
+ Register SwiftErrorVReg = 0;
for (auto &Arg : I.arg_operands()) {
if (CLI->supportSwiftError() && isSwiftError(Arg)) {
LLT Ty = getLLTForType(*Arg->getType(), *DL);
[&]() { return getOrCreateVReg(*I.getCalledValue()); }))
return false;
- unpackRegs(I, Res, MIRBuilder);
-
MCSymbol *EndSymbol = Context.createTempSymbol();
MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(EndSymbol);
// symmetry with the arugments, the physical register must be an
// implicit-define of the call instruction.
CCAssignFn *RetAssignFn = TLI.CCAssignFnForReturn(F.getCallingConv());
- assert(OrigRet.Regs.size() == 1 && "Can't handle multple regs yet");
- if (OrigRet.Regs[0]) {
+ if (!OrigRet.Ty->isVoidTy()) {
SplitArgs.clear();
- SmallVector<uint64_t, 8> RegOffsets;
- SmallVector<Register, 8> SplitRegs;
splitToValueTypes(OrigRet, SplitArgs, DL, MRI, F.getCallingConv(),
[&](unsigned Reg, uint64_t Offset) {
- RegOffsets.push_back(Offset);
- SplitRegs.push_back(Reg);
+ llvm_unreachable(
+ "Call results should already be split");
});
CallReturnHandler Handler(MIRBuilder, MRI, MIB, RetAssignFn);
if (!handleAssignments(MIRBuilder, SplitArgs, Handler))
return false;
-
- if (!RegOffsets.empty())
- MIRBuilder.buildSequence(OrigRet.Regs[0], SplitRegs, RegOffsets);
}
if (SwiftErrorVReg) {
return false;
ArgInfos.clear();
- SmallVector<Register, 8> SplitRegs;
- splitToValueTypes(OrigRet, ArgInfos, MF,
- [&](Register Reg) { SplitRegs.push_back(Reg); });
+ splitToValueTypes(OrigRet, ArgInfos, MF, [&](Register Reg) {
+ llvm_unreachable("Call results should already be split");
+ });
auto RetAssignFn = TLI.CCAssignFnForReturn(CallConv, IsVarArg);
CallReturnHandler RetHandler(MIRBuilder, MRI, MIB, RetAssignFn);
if (!handleAssignments(MIRBuilder, ArgInfos, RetHandler))
return false;
-
- if (!SplitRegs.empty()) {
- // We have split the value and allocated each individual piece, now build
- // it up again.
- assert(OrigRet.Regs.size() == 1 && "Can't handle multple regs yet");
- MIRBuilder.buildMerge(OrigRet.Regs[0], SplitRegs);
- }
}
// We now know the size of the stack - update the ADJCALLSTACKDOWN
return false;
case G_SREM:
case G_UREM: {
- unsigned OriginalResult = MI.getOperand(0).getReg();
+ Register OriginalResult = MI.getOperand(0).getReg();
auto Size = MRI.getType(OriginalResult).getSizeInBits();
if (Size != 32)
return false;
MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
// Our divmod libcalls return a struct containing the quotient and the
- // remainder. We need to create a virtual register for it.
+ // remainder. Create a new, unused register for the quotient and use the
+ // destination of the original instruction for the remainder.
Type *ArgTy = Type::getInt32Ty(Ctx);
StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true);
- auto RetVal = MRI.createGenericVirtualRegister(
- getLLTForType(*RetTy, MIRBuilder.getMF().getDataLayout()));
-
- auto Status = createLibcall(MIRBuilder, Libcall, {RetVal, RetTy},
+ Register RetRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
+ OriginalResult};
+ auto Status = createLibcall(MIRBuilder, Libcall, {RetRegs, RetTy},
{{MI.getOperand(1).getReg(), ArgTy},
{MI.getOperand(2).getReg(), ArgTy}});
if (Status != LegalizerHelper::Legalized)
return false;
-
- // The remainder is the second result of divmod. Split the return value into
- // a new, unused register for the quotient and the destination of the
- // original instruction for the remainder.
- MIRBuilder.buildUnmerge(
- {MRI.createGenericVirtualRegister(LLT::scalar(32)), OriginalResult},
- RetVal);
break;
}
case G_FCMP: {
return false;
}
- assert(OrigRet.Regs.size() == 1 && "Can't handle multple regs yet");
if (OrigRet.Regs[0] && !isSupportedType(OrigRet.Ty))
return false;
// implicit-define of the call instruction.
if (!OrigRet.Ty->isVoidTy()) {
- assert(OrigRet.Regs.size() == 1 && "Can't handle multple regs yet");
+ if (OrigRet.Regs.size() > 1)
+ return false;
SplitArgs.clear();
SmallVector<Register, 8> NewRegs;
; CHECK: [[E1:%[0-9]+]]:_(s64) = COPY $x1
; CHECK: [[E2:%[0-9]+]]:_(s64) = COPY $x2
; CHECK: [[E3:%[0-9]+]]:_(s64) = COPY $x3
-; CHECK: [[RES:%[0-9]+]]:_(s256) = G_MERGE_VALUES [[E0]](s64), [[E1]](s64), [[E2]](s64), [[E3]](s64)
-; CHECK: G_EXTRACT [[RES]](s256), 64
+; CHECK: $x0 = COPY [[E1]]
declare [4 x i64] @arr_callee([4 x i64])
define i64 @test_arr_call([4 x i64]* %addr) {
%arg = load [4 x i64], [4 x i64]* %addr
; CHECK: [[R0:%[0-9]+]]:_(s32) = COPY $r0
; CHECK: [[R1:%[0-9]+]]:_(s32) = COPY $r1
; CHECK: [[R2:%[0-9]+]]:_(s32) = COPY $r2
-; CHECK: [[RES_ARR:%[0-9]+]]:_(s96) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32), [[R2]](s32)
; CHECK: ADJCALLSTACKUP 0, 0, 14, $noreg, implicit-def $sp, implicit $sp
-; CHECK: [[EXT3:%[0-9]+]]:_(s32) = G_EXTRACT [[RES_ARR]](s96), 0
-; CHECK: [[EXT4:%[0-9]+]]:_(s32) = G_EXTRACT [[RES_ARR]](s96), 32
-; CHECK: [[EXT5:%[0-9]+]]:_(s32) = G_EXTRACT [[RES_ARR]](s96), 64
; FIXME: This doesn't seem correct with regard to the AAPCS docs (which say
; that composite types larger than 4 bytes should be passed through memory),
; but it's what DAGISel does. We should fix it in the common code for both.
-; CHECK: $r0 = COPY [[EXT3]]
-; CHECK: $r1 = COPY [[EXT4]]
-; CHECK: $r2 = COPY [[EXT5]]
+; CHECK: $r0 = COPY [[R0]]
+; CHECK: $r1 = COPY [[R1]]
+; CHECK: $r2 = COPY [[R2]]
; ARM: BX_RET 14, $noreg, implicit $r0, implicit $r1, implicit $r2
; THUMB: tBX_RET 14, $noreg, implicit $r0, implicit $r1, implicit $r2
entry:
; THUMB: tBL 14, $noreg, @fp_arrays_aapcs_target, csr_aapcs, implicit-def $lr, implicit $sp, implicit $r0, implicit $r1, implicit $r2, implicit $r3, implicit-def $r0, implicit-def $r1
; CHECK: [[R0:%[0-9]+]]:_(s32) = COPY $r0
; CHECK: [[R1:%[0-9]+]]:_(s32) = COPY $r1
-; CHECK: [[R_MERGED:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32)
; CHECK: ADJCALLSTACKUP 8, 0, 14, $noreg, implicit-def $sp, implicit $sp
-; CHECK: [[EXT4:%[0-9]+]]:_(s32) = G_EXTRACT [[R_MERGED]](s64), 0
-; CHECK: [[EXT5:%[0-9]+]]:_(s32) = G_EXTRACT [[R_MERGED]](s64), 32
-; CHECK: $r0 = COPY [[EXT4]]
-; CHECK: $r1 = COPY [[EXT5]]
+; CHECK: $r0 = COPY [[R0]]
+; CHECK: $r1 = COPY [[R1]]
; ARM: BX_RET 14, $noreg, implicit $r0, implicit $r1
; THUMB: tBX_RET 14, $noreg, implicit $r0, implicit $r1
entry:
; CHECK: [[R1:%[0-9]+]]:_(s32) = COPY $s1
; CHECK: [[R2:%[0-9]+]]:_(s32) = COPY $s2
; CHECK: [[R3:%[0-9]+]]:_(s32) = COPY $s3
-; CHECK: [[R_MERGED:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32), [[R2]](s32), [[R3]](s32)
; CHECK: ADJCALLSTACKUP 32, 0, 14, $noreg, implicit-def $sp, implicit $sp
-; CHECK: [[EXT11:%[0-9]+]]:_(s32) = G_EXTRACT [[R_MERGED]](s128), 0
-; CHECK: [[EXT12:%[0-9]+]]:_(s32) = G_EXTRACT [[R_MERGED]](s128), 32
-; CHECK: [[EXT13:%[0-9]+]]:_(s32) = G_EXTRACT [[R_MERGED]](s128), 64
-; CHECK: [[EXT14:%[0-9]+]]:_(s32) = G_EXTRACT [[R_MERGED]](s128), 96
-; CHECK: $s0 = COPY [[EXT11]]
-; CHECK: $s1 = COPY [[EXT12]]
-; CHECK: $s2 = COPY [[EXT13]]
-; CHECK: $s3 = COPY [[EXT14]]
+; CHECK: $s0 = COPY [[R0]]
+; CHECK: $s1 = COPY [[R1]]
+; CHECK: $s2 = COPY [[R2]]
+; CHECK: $s3 = COPY [[R3]]
; ARM: BX_RET 14, $noreg, implicit $s0, implicit $s1, implicit $s2, implicit $s3
; THUMB: tBX_RET 14, $noreg, implicit $s0, implicit $s1, implicit $s2, implicit $s3
entry:
; CHECK: G_STORE [[LAST_STACK_ELEMENT]](s32), [[LAST_STACK_ARG_ADDR]]{{.*}}store 4
; ARM: BL @tough_arrays_target, csr_aapcs, implicit-def $lr, implicit $sp, implicit $r0, implicit $r1, implicit $r2, implicit $r3, implicit-def $r0, implicit-def $r1
; THUMB: tBL 14, $noreg, @tough_arrays_target, csr_aapcs, implicit-def $lr, implicit $sp, implicit $r0, implicit $r1, implicit $r2, implicit $r3, implicit-def $r0, implicit-def $r1
-; CHECK: [[R0:%[0-9]+]]:_(s32) = COPY $r0
-; CHECK: [[R1:%[0-9]+]]:_(s32) = COPY $r1
-; CHECK: [[RES_ARR:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32)
+; CHECK: [[R0:%[0-9]+]]:_(p0) = COPY $r0
+; CHECK: [[R1:%[0-9]+]]:_(p0) = COPY $r1
; CHECK: ADJCALLSTACKUP 80, 0, 14, $noreg, implicit-def $sp, implicit $sp
-; CHECK: [[EXT1:%[0-9]+]]:_(p0) = G_EXTRACT [[RES_ARR]](s64), 0
-; CHECK: [[EXT2:%[0-9]+]]:_(p0) = G_EXTRACT [[RES_ARR]](s64), 32
-; CHECK: $r0 = COPY [[EXT1]]
-; CHECK: $r1 = COPY [[EXT2]]
+; CHECK: $r0 = COPY [[R0]]
+; CHECK: $r1 = COPY [[R1]]
; ARM: BX_RET 14, $noreg, implicit $r0, implicit $r1
; THUMB: tBX_RET 14, $noreg, implicit $r0, implicit $r1
entry:
; THUMB: tBL 14, $noreg, @structs_target, csr_aapcs, implicit-def $lr, implicit $sp, implicit $r0, implicit $r1, implicit-def $r0, implicit-def $r1
; CHECK: [[R0:%[0-9]+]]:_(s32) = COPY $r0
; CHECK: [[R1:%[0-9]+]]:_(s32) = COPY $r1
-; CHECK: [[R:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[R0]](s32), [[R1]](s32)
; CHECK: ADJCALLSTACKUP 0, 0, 14, $noreg, implicit-def $sp, implicit $sp
-; CHECK: [[EXT3:%[0-9]+]]:_(s32) = G_EXTRACT [[R]](s64), 0
-; CHECK: [[EXT4:%[0-9]+]]:_(s32) = G_EXTRACT [[R]](s64), 32
-; CHECK: $r0 = COPY [[EXT3]](s32)
-; CHECK: $r1 = COPY [[EXT4]](s32)
+; CHECK: $r0 = COPY [[R0]](s32)
+; CHECK: $r1 = COPY [[R1]](s32)
; ARM: BX_RET 14, $noreg, implicit $r0, implicit $r1
; THUMB: tBX_RET 14, $noreg, implicit $r0, implicit $r1
%r = notail call arm_aapcscc {i32, i32} @structs_target({i32, i32} %x)