[GlobalISel] Accept multiple vregs for lowerCall's result
authorDiana Picus <diana.picus@linaro.org>
Thu, 27 Jun 2019 09:15:53 +0000 (09:15 +0000)
committerDiana Picus <diana.picus@linaro.org>
Thu, 27 Jun 2019 09:15:53 +0000 (09:15 +0000)
Change the interface of CallLowering::lowerCall to accept several
virtual registers for the call result, instead of just one.  This is a
follow-up to D46018.

CallLowering::lowerReturn was similarly refactored in D49660 and
lowerFormalArguments in D63549.

With this change, we no longer pack the virtual registers generated for
aggregates into one big lump before delegating to the target. Therefore,
the target can decide itself whether it wants to handle them as separate
pieces or use one big register.

ARM and AArch64 have been updated to use the passed in virtual registers
directly, which means we no longer need to generate so many
merge/extract instructions.

NFCI for AMDGPU, Mips and X86.

Differential Revision: https://reviews.llvm.org/D63550

llvm-svn: 364511

llvm/include/llvm/CodeGen/GlobalISel/CallLowering.h
llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
llvm/lib/Target/AArch64/AArch64CallLowering.cpp
llvm/lib/Target/ARM/ARMCallLowering.cpp
llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
llvm/lib/Target/Mips/MipsCallLowering.cpp
llvm/lib/Target/X86/X86CallLowering.cpp
llvm/test/CodeGen/AArch64/GlobalISel/call-translator.ll
llvm/test/CodeGen/ARM/GlobalISel/arm-param-lowering.ll

index b0a7444af5e4e137e3eb73bda6fc79513d11cf26..99c6b4c4fc1d0eaf3ce395bd4aff8a1427381c08 100644 (file)
@@ -258,8 +258,9 @@ public:
   ///
   /// \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.
@@ -275,10 +276,9 @@ public:
   ///
   /// \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
index b2838d863a65f354cd0a8af951a1f793f94eeba7..0772021bc08c22df32c6343b0c8f47267981b638 100644 (file)
@@ -28,7 +28,8 @@ using 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();
@@ -56,7 +57,7 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, ImmutableCallSite CS,
   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);
 
index 5e5e1bedad06c6168e1f8529a9df533406dbc9f2..2f076595065d6c7f95f1e82ddd36225adc188a0c 100644 (file)
@@ -1585,10 +1585,7 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
   }
 
   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;
@@ -1611,9 +1608,6 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
         CLI->lowerCall(MIRBuilder, &CI, Res, Args, SwiftErrorVReg,
                        [&]() { return getOrCreateVReg(*CI.getCalledValue()); });
 
-    if (IsSplitType)
-      unpackRegs(CI, Res, MIRBuilder);
-
     return Success;
   }
 
@@ -1687,11 +1681,11 @@ bool IRTranslator::translateInvoke(const User &U,
   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);
@@ -1711,8 +1705,6 @@ bool IRTranslator::translateInvoke(const User &U,
                       [&]() { return getOrCreateVReg(*I.getCalledValue()); }))
     return false;
 
-  unpackRegs(I, Res, MIRBuilder);
-
   MCSymbol *EndSymbol = Context.createTempSymbol();
   MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(EndSymbol);
 
index effca68b09b41e28e12014ea53d3da54dba7fdbc..1fa12b0290b86c0d65bd151057b74053c0b74792 100644 (file)
@@ -498,24 +498,18 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
   // 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) {
index ea5bfb595a900ce42817386e08cfc7fc19b24e1c..71b92517620d8d557c858ca538cf29c8a67eb3d8 100644 (file)
@@ -619,21 +619,14 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
       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
index 796eaeedee7da601a8a37872a3b69d43ce580969..73a57b297ad6dac9c39eeae8bec58202c844764d 100644 (file)
@@ -369,7 +369,7 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI,
     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;
@@ -378,24 +378,17 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI,
         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: {
index 8911ae39988873728c1ef8188540692c3d865334..8d14ecc32f3e8ba9b3a3ad344567e9525c980e7e 100644 (file)
@@ -514,7 +514,6 @@ bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
       return false;
   }
 
-  assert(OrigRet.Regs.size() == 1 && "Can't handle multple regs yet");
   if (OrigRet.Regs[0] && !isSupportedType(OrigRet.Ty))
     return false;
 
index e41bcfac577927fab2962e8f8d671dec649aaba1..3a980f40ab8d4ffa804610c147603b12c6dcef96 100644 (file)
@@ -453,7 +453,8 @@ bool X86CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
   // 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;
index 6ab4fea4649fe0a6c0495af72c95c142c788cd32..cda1dc36677c629897ef22544363cc1a98a854a6 100644 (file)
@@ -131,8 +131,7 @@ define {double, i64, i32} @test_struct_return({double, i64, i32}* %addr) {
 ; 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
index f5c2cb40f11a7d680bf5d2d15938359fac4c56e2..422785ac8601dcb9e7879820c528243ebd16fb64 100644 (file)
@@ -214,17 +214,13 @@ define arm_aapcscc [3 x i32] @test_tiny_int_arrays([2 x i32] %arr) {
 ; 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:
@@ -352,12 +348,9 @@ define arm_aapcscc [2 x float] @test_fp_arrays_aapcs([3 x double] %arr) {
 ; 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:
@@ -434,16 +427,11 @@ define arm_aapcs_vfpcc [4 x float] @test_fp_arrays_aapcs_vfp([3 x double] %x, [3
 ; 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:
@@ -488,14 +476,11 @@ define arm_aapcscc [2 x i32*] @test_tough_arrays([6 x [4 x i32]] %arr) {
 ; 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:
@@ -521,12 +506,9 @@ define arm_aapcscc {i32, i32} @test_structs({i32, i32} %x) {
 ; 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)