[llvm] r281977 - GlobalISel: split aggregates for PCS lowering

Tim Northover via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 20 08:20:36 PDT 2016


Author: tnorthover
Date: Tue Sep 20 10:20:36 2016
New Revision: 281977

URL: http://llvm.org/viewvc/llvm-project?rev=281977&view=rev
Log:
GlobalISel: split aggregates for PCS lowering

This should match the existing behaviour for passing complicated struct and
array types, in particular HFAs come through like that from Clang.

For C & C++ we still need to somehow support all the weird ABI flags, or at
least those that are present in the IR (signext, byval, ...), and stack-based
parameter passing.

Modified:
    llvm/trunk/include/llvm/CodeGen/GlobalISel/CallLowering.h
    llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
    llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp
    llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp
    llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
    llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp
    llvm/trunk/lib/Target/AArch64/AArch64CallLowering.cpp
    llvm/trunk/lib/Target/AArch64/AArch64CallLowering.h
    llvm/trunk/test/CodeGen/AArch64/GlobalISel/call-translator.ll

Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/CallLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/CallLowering.h?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/CallLowering.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/CallLowering.h Tue Sep 20 10:20:36 2016
@@ -75,11 +75,10 @@ class CallLowering {
   /// \p Callee is the destination of the call. It should be either a register,
   /// globaladdress, or externalsymbol.
   ///
-  /// \p ResTys is a list of the individual result types this function call will
-  /// produce. The types are used to assign physical registers to each slot.
+  /// \p ResTy is the type returned by the function
   ///
-  /// \p ResRegs is a list of the virtual registers that we expect to be defined
-  /// by this call, one per entry in \p ResTys.
+  /// \p ResReg is the generic virtual register that the returned
+  /// value should be lowered into.
   ///
   /// \p ArgTys is a list of the types each member of \p ArgRegs has; used by
   /// the target to decide which register/stack slot should be allocated.
@@ -89,8 +88,8 @@ class CallLowering {
   ///
   /// \return true if the lowering succeeded, false otherwise.
   virtual bool lowerCall(MachineIRBuilder &MIRBuilder,
-                         const MachineOperand &Callee, ArrayRef<Type *> ResTys,
-                         ArrayRef<unsigned> ResRegs, ArrayRef<Type *> ArgTys,
+                         const MachineOperand &Callee, Type * ResTy,
+                         unsigned ResReg, ArrayRef<Type *> ArgTys,
                          ArrayRef<unsigned> ArgRegs) const {
     return false;
   }

Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h Tue Sep 20 10:20:36 2016
@@ -363,7 +363,7 @@ public:
   /// \return a MachineInstrBuilder for the newly created instruction.
   MachineInstrBuilder buildSequence(unsigned Res,
                                     ArrayRef<unsigned> Ops,
-                                    ArrayRef<unsigned> Indices);
+                                    ArrayRef<uint64_t> Indices);
 
   void addUsesWithIndices(MachineInstrBuilder MIB) {}
 

Modified: llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/CallLowering.cpp Tue Sep 20 10:20:36 2016
@@ -35,6 +35,5 @@ bool CallLowering::lowerCall(
   else
     Callee = MachineOperand::CreateReg(GetCalleeReg(), false);
 
-  return lowerCall(MIRBuilder, Callee, CI.getType(),
-                   ResReg ? ResReg : ArrayRef<unsigned>(), ArgTys, ArgRegs);
+  return lowerCall(MIRBuilder, Callee, CI.getType(), ResReg, ArgTys, ArgRegs);
 }

Modified: llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp Tue Sep 20 10:20:36 2016
@@ -399,7 +399,6 @@ bool IRTranslator::translateCall(const U
   const Function *F = CI.getCalledFunction();
 
   if (!F || !F->isIntrinsic()) {
-    // FIXME: handle multiple return values.
     unsigned Res = CI.getType()->isVoidTy() ? 0 : getOrCreateVReg(CI);
     SmallVector<unsigned, 8> Args;
     for (auto &Arg: CI.arg_operands())

Modified: llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp Tue Sep 20 10:20:36 2016
@@ -33,6 +33,7 @@ void MachineIRBuilder::setMF(MachineFunc
 
 void MachineIRBuilder::setMBB(MachineBasicBlock &MBB, bool Beginning) {
   this->MBB = &MBB;
+  this->MI = nullptr;
   Before = Beginning;
   assert(&getMF() == MBB.getParent() &&
          "Basic block is in a different function");
@@ -274,7 +275,7 @@ MachineInstrBuilder MachineIRBuilder::bu
 MachineInstrBuilder
 MachineIRBuilder::buildSequence(unsigned Res,
                                 ArrayRef<unsigned> Ops,
-                                ArrayRef<unsigned> Indices) {
+                                ArrayRef<uint64_t> Indices) {
 #ifndef NDEBUG
   assert(Ops.size() == Indices.size() && "incompatible args");
   assert(!Ops.empty() && "invalid trivial sequence");

Modified: llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp Tue Sep 20 10:20:36 2016
@@ -135,7 +135,8 @@ MachineLegalizeHelper::narrowScalar(Mach
 
     MIRBuilder.setInstr(MI);
 
-    SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs, Indexes;
+    SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
+    SmallVector<uint64_t, 2> Indexes;
     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
     extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
 
@@ -333,7 +334,8 @@ MachineLegalizeHelper::fewerElementsVect
 
     MIRBuilder.setInstr(MI);
 
-    SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs, Indexes;
+    SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
+    SmallVector<uint64_t, 2> Indexes;
     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
     extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
 

Modified: llvm/trunk/lib/Target/AArch64/AArch64CallLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64CallLowering.cpp?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64CallLowering.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64CallLowering.cpp Tue Sep 20 10:20:36 2016
@@ -17,7 +17,9 @@
 #include "AArch64ISelLowering.h"
 
 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/Target/TargetRegisterInfo.h"
 #include "llvm/Target/TargetSubtargetInfo.h"
 using namespace llvm;
@@ -30,29 +32,6 @@ AArch64CallLowering::AArch64CallLowering
   : CallLowering(&TLI) {
 }
 
-bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
-                                      const Value *Val, unsigned VReg) const {
-  MachineFunction &MF = MIRBuilder.getMF();
-  const Function &F = *MF.getFunction();
-
-  MachineInstrBuilder MIB = MIRBuilder.buildInstr(AArch64::RET_ReallyLR);
-  assert(MIB.getInstr() && "Unable to build a return instruction?!");
-
-  assert(((Val && VReg) || (!Val && !VReg)) && "Return value without a vreg");
-  if (VReg) {
-    MIRBuilder.setInstr(*MIB.getInstr(), /* Before */ true);
-    const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
-    CCAssignFn *AssignFn = TLI.CCAssignFnForReturn(F.getCallingConv());
-
-    handleAssignments(MIRBuilder, AssignFn, Val->getType(), VReg,
-                      [&](MachineIRBuilder &MIRBuilder, Type *Ty,
-                          unsigned ValReg, unsigned PhysReg) {
-                        MIRBuilder.buildCopy(PhysReg, ValReg);
-                        MIB.addUse(PhysReg, RegState::Implicit);
-                      });
-  }
-  return true;
-}
 
 bool AArch64CallLowering::handleAssignments(MachineIRBuilder &MIRBuilder,
                                             CCAssignFn *AssignFn,
@@ -107,36 +86,130 @@ bool AArch64CallLowering::handleAssignme
   return true;
 }
 
+void AArch64CallLowering::splitToValueTypes(
+    unsigned Reg, Type *Ty, SmallVectorImpl<unsigned> &SplitRegs,
+    SmallVectorImpl<Type *> &SplitTys, const DataLayout &DL,
+    MachineRegisterInfo &MRI, SplitArgTy SplitArg) const {
+  const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
+  LLVMContext &Ctx = Ty->getContext();
+
+  SmallVector<EVT, 4> SplitVTs;
+  SmallVector<uint64_t, 4> Offsets;
+  ComputeValueVTs(TLI, DL, Ty, SplitVTs, &Offsets, 0);
+
+  if (SplitVTs.size() == 1) {
+    // No splitting to do, just forward the input directly.
+    SplitTys.push_back(Ty);
+    SplitRegs.push_back(Reg);
+    return;
+  }
+
+  unsigned FirstRegIdx = SplitRegs.size();
+  for (auto SplitVT : SplitVTs) {
+    Type *SplitTy = SplitVT.getTypeForEVT(Ctx);
+    SplitRegs.push_back(MRI.createGenericVirtualRegister(LLT{*SplitTy, DL}));
+    SplitTys.push_back(SplitTy);
+  }
+
+  SmallVector<uint64_t, 4> BitOffsets;
+  for (auto Offset : Offsets)
+    BitOffsets.push_back(Offset * 8);
+
+  SplitArg(ArrayRef<unsigned>(&SplitRegs[FirstRegIdx], SplitRegs.end()),
+           BitOffsets);
+}
+
+bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
+                                      const Value *Val, unsigned VReg) const {
+  MachineFunction &MF = MIRBuilder.getMF();
+  const Function &F = *MF.getFunction();
+
+  MachineInstrBuilder MIB = MIRBuilder.buildInstr(AArch64::RET_ReallyLR);
+  assert(MIB.getInstr() && "Unable to build a return instruction?!");
+
+  assert(((Val && VReg) || (!Val && !VReg)) && "Return value without a vreg");
+  if (VReg) {
+    MIRBuilder.setInstr(*MIB.getInstr(), /* Before */ true);
+    const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
+    CCAssignFn *AssignFn = TLI.CCAssignFnForReturn(F.getCallingConv());
+    MachineRegisterInfo &MRI = MF.getRegInfo();
+    auto &DL = F.getParent()->getDataLayout();
+
+    SmallVector<Type *, 8> SplitTys;
+    SmallVector<unsigned, 8> SplitRegs;
+    splitToValueTypes(VReg, Val->getType(), SplitRegs, SplitTys, DL, MRI,
+                      [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
+                        MIRBuilder.buildExtract(Regs, Offsets, VReg);
+                      });
+
+    return handleAssignments(MIRBuilder, AssignFn, SplitTys, SplitRegs,
+                             [&](MachineIRBuilder &MIRBuilder, Type *Ty,
+                                 unsigned ValReg, unsigned PhysReg) {
+                               MIRBuilder.buildCopy(PhysReg, ValReg);
+                               MIB.addUse(PhysReg, RegState::Implicit);
+                             });
+  }
+  return true;
+}
+
 bool AArch64CallLowering::lowerFormalArguments(
     MachineIRBuilder &MIRBuilder, const Function::ArgumentListType &Args,
     ArrayRef<unsigned> VRegs) const {
   MachineFunction &MF = MIRBuilder.getMF();
+  MachineBasicBlock &MBB = MIRBuilder.getMBB();
+  MachineRegisterInfo &MRI = MF.getRegInfo();
   const Function &F = *MF.getFunction();
+  auto &DL = F.getParent()->getDataLayout();
+
+  SmallVector<MachineInstr *, 8> Seqs;
+  SmallVector<Type *, 8> SplitTys;
+  SmallVector<unsigned, 8> SplitRegs;
+  unsigned i = 0;
+  for (auto &Arg : Args) {
+    splitToValueTypes(VRegs[i], Arg.getType(), SplitRegs, SplitTys, DL, MRI,
+                      [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
+                        MIRBuilder.buildSequence(VRegs[i], Regs, Offsets);
+                      });
+    ++i;
+  }
 
-  SmallVector<Type *, 8> ArgTys;
-  for (auto &Arg : Args)
-    ArgTys.push_back(Arg.getType());
+  if (!MBB.empty())
+    MIRBuilder.setInstr(*MBB.begin());
 
   const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
   CCAssignFn *AssignFn =
       TLI.CCAssignFnForCall(F.getCallingConv(), /*IsVarArg=*/false);
 
-  return handleAssignments(MIRBuilder, AssignFn, ArgTys, VRegs,
-                           [](MachineIRBuilder &MIRBuilder, Type *Ty,
-                              unsigned ValReg, unsigned PhysReg) {
-                             MIRBuilder.getMBB().addLiveIn(PhysReg);
-                             MIRBuilder.buildCopy(ValReg, PhysReg);
-                           });
+  bool Res = handleAssignments(MIRBuilder, AssignFn, SplitTys, SplitRegs,
+                               [](MachineIRBuilder &MIRBuilder, Type *Ty,
+                                  unsigned ValReg, unsigned PhysReg) {
+                                 MIRBuilder.getMBB().addLiveIn(PhysReg);
+                                 MIRBuilder.buildCopy(ValReg, PhysReg);
+                               });
+
+  // Move back to the end of the basic block.
+  MIRBuilder.setMBB(MBB);
+
+  return Res;
 }
 
 bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
-                                    const MachineOperand &Callee,
-                                    ArrayRef<Type *> ResTys,
-                                    ArrayRef<unsigned> ResRegs,
-                                    ArrayRef<Type *> ArgTys,
+                                    const MachineOperand &Callee, Type *ResTy,
+                                    unsigned ResReg, ArrayRef<Type *> ArgTys,
                                     ArrayRef<unsigned> ArgRegs) const {
   MachineFunction &MF = MIRBuilder.getMF();
   const Function &F = *MF.getFunction();
+  MachineRegisterInfo &MRI = MF.getRegInfo();
+  auto &DL = F.getParent()->getDataLayout();
+
+  SmallVector<Type *, 8> SplitTys;
+  SmallVector<unsigned, 8> SplitRegs;
+  for (unsigned i = 0; i < ArgTys.size(); ++i) {
+    splitToValueTypes(ArgRegs[i], ArgTys[i], SplitRegs, SplitTys, DL, MRI,
+                      [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
+                        MIRBuilder.buildExtract(Regs, Offsets, ArgRegs[i]);
+                      });
+  }
 
   // Find out which ABI gets to decide where things go.
   const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
@@ -146,7 +219,7 @@ bool AArch64CallLowering::lowerCall(Mach
   // And finally we can do the actual assignments. For a call we need to keep
   // track of the registers used because they'll be implicit uses of the BL.
   SmallVector<unsigned, 8> PhysRegs;
-  handleAssignments(MIRBuilder, CallAssignFn, ArgTys, ArgRegs,
+  handleAssignments(MIRBuilder, CallAssignFn, SplitTys, SplitRegs,
                     [&](MachineIRBuilder &MIRBuilder, Type *Ty, unsigned ValReg,
                         unsigned PhysReg) {
                       MIRBuilder.buildCopy(PhysReg, ValReg);
@@ -168,13 +241,27 @@ bool AArch64CallLowering::lowerCall(Mach
   // symmetry with the arugments, the physical register must be an
   // implicit-define of the call instruction.
   CCAssignFn *RetAssignFn = TLI.CCAssignFnForReturn(F.getCallingConv());
-  if (!ResRegs.empty())
-    handleAssignments(MIRBuilder, RetAssignFn, ResTys, ResRegs,
+  if (ResReg) {
+    SplitTys.clear();
+    SplitRegs.clear();
+
+    SmallVector<uint64_t, 8> RegOffsets;
+    splitToValueTypes(ResReg, ResTy, SplitRegs, SplitTys, DL, MRI,
+                      [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
+                        std::copy(Offsets.begin(), Offsets.end(),
+                                  std::back_inserter(RegOffsets));
+                      });
+
+    handleAssignments(MIRBuilder, RetAssignFn, SplitTys, SplitRegs,
                       [&](MachineIRBuilder &MIRBuilder, Type *Ty,
                           unsigned ValReg, unsigned PhysReg) {
                         MIRBuilder.buildCopy(ValReg, PhysReg);
                         MIB.addDef(PhysReg, RegState::Implicit);
                       });
 
+    if (!RegOffsets.empty())
+      MIRBuilder.buildSequence(ResReg, SplitRegs, RegOffsets);
+  }
+
   return true;
 }

Modified: llvm/trunk/lib/Target/AArch64/AArch64CallLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64CallLowering.h?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64CallLowering.h (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64CallLowering.h Tue Sep 20 10:20:36 2016
@@ -35,14 +35,22 @@ class AArch64CallLowering: public CallLo
                             ArrayRef<unsigned> VRegs) const override;
 
   bool lowerCall(MachineIRBuilder &MIRBuilder, const MachineOperand &Callee,
-                 ArrayRef<Type *> ResTys, ArrayRef<unsigned> ResRegs,
-                 ArrayRef<Type *> ArgTys,
+                 Type *ResTy, unsigned ResReg, ArrayRef<Type *> ArgTys,
                  ArrayRef<unsigned> ArgRegs) const override;
 
 private:
   typedef std::function<void(MachineIRBuilder &, Type *, unsigned, unsigned)>
       AssignFnTy;
 
+  typedef std::function<void(ArrayRef<unsigned>, ArrayRef<uint64_t>)>
+      SplitArgTy;
+
+  void splitToValueTypes(unsigned Reg, Type *Ty,
+                         SmallVectorImpl<unsigned> &SplitRegs,
+                         SmallVectorImpl<Type *> &SplitTys,
+                         const DataLayout &DL, MachineRegisterInfo &MRI,
+                         SplitArgTy SplitArg) const;
+
   bool handleAssignments(MachineIRBuilder &MIRBuilder, CCAssignFn *AssignFn,
                          ArrayRef<Type *> ArgsTypes, ArrayRef<unsigned> ArgRegs,
                          AssignFnTy AssignValToReg) const;

Modified: llvm/trunk/test/CodeGen/AArch64/GlobalISel/call-translator.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/call-translator.ll?rev=281977&r1=281976&r2=281977&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/call-translator.ll (original)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/call-translator.ll Tue Sep 20 10:20:36 2016
@@ -51,3 +51,53 @@ define void @test_multiple_args(i64 %in)
   call void @multiple_args_callee(i32 42, i64 %in)
   ret void
 }
+
+
+; CHECK-LABEL: name: test_struct_formal
+; CHECK: [[DBL:%[0-9]+]](s64) = COPY %d0
+; CHECK: [[I64:%[0-9]+]](s64) = COPY %x0
+; CHECK: [[I8:%[0-9]+]](s8) = COPY %w1
+; CHECK: [[ADDR:%[0-9]+]](p0) = COPY %x2
+; CHECK: [[ARG:%[0-9]+]](s192) = G_SEQUENCE [[DBL]](s64), 0, [[I64]](s64), 64, [[I8]](s8), 128
+; CHECK: G_STORE [[ARG]](s192), [[ADDR]](p0)
+; CHECK: RET_ReallyLR
+define void @test_struct_formal({double, i64, i8} %in, {double, i64, i8}* %addr) {
+  store {double, i64, i8} %in, {double, i64, i8}* %addr
+  ret void
+}
+
+
+; CHECK-LABEL: name: test_struct_return
+; CHECK: [[ADDR:%[0-9]+]](p0) = COPY %x0
+; CHECK: [[VAL:%[0-9]+]](s192) = G_LOAD [[ADDR]](p0)
+; CHECK: [[DBL:%[0-9]+]](s64), [[I64:%[0-9]+]](s64), [[I32:%[0-9]+]](s32) = G_EXTRACT [[VAL]](s192), 0, 64, 128
+; CHECK: %d0 = COPY [[DBL]](s64)
+; CHECK: %x0 = COPY [[I64]](s64)
+; CHECK: %w1 = COPY [[I32]](s32)
+; CHECK: RET_ReallyLR implicit %d0, implicit %x0, implicit %w1
+define {double, i64, i32} @test_struct_return({double, i64, i32}* %addr) {
+  %val = load {double, i64, i32}, {double, i64, i32}* %addr
+  ret {double, i64, i32} %val
+}
+
+; CHECK-LABEL: name: test_arr_call
+; CHECK: [[ARG:%[0-9]+]](s256) = G_LOAD
+; CHECK: [[E0:%[0-9]+]](s64), [[E1:%[0-9]+]](s64), [[E2:%[0-9]+]](s64), [[E3:%[0-9]+]](s64) = G_EXTRACT [[ARG]](s256), 0, 64, 128, 192
+; CHECK: %x0 = COPY [[E0]](s64)
+; CHECK: %x1 = COPY [[E1]](s64)
+; CHECK: %x2 = COPY [[E2]](s64)
+; CHECK: %x3 = COPY [[E3]](s64)
+; CHECK: BL @arr_callee, csr_aarch64_aapcs, implicit-def %lr, implicit %sp, implicit %x0, implicit %x1, implicit %x2, implicit %x3, implicit-def %x0, implicit-def %x1, implicit-def %x2, implicit-def %x3
+; CHECK: [[E0:%[0-9]+]](s64) = COPY %x0
+; 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_SEQUENCE [[E0]](s64), 0, [[E1]](s64), 64, [[E2]](s64), 128, [[E3]](s64), 192
+; CHECK: G_EXTRACT [[RES]](s256), 64
+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
+  %res = call [4 x i64] @arr_callee([4 x i64] %arg)
+  %val = extractvalue [4 x i64] %res, 1
+  ret i64 %val
+}




More information about the llvm-commits mailing list