[M68k][GlobalISel] Implement lowerCall based on M68k calling convention
authorSheng <ox59616e@gmail.com>
Tue, 8 Feb 2022 02:08:21 +0000 (21:08 -0500)
committerMatt Arsenault <Matthew.Arsenault@amd.com>
Tue, 8 Feb 2022 02:18:54 +0000 (21:18 -0500)
This patch implements CallLowering::lowerCall based on M68k calling
convention and adds M68kOutgoingValueHandler and CallReturnHandler to
handle argument passing and returned value.

llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp
llvm/lib/Target/M68k/GISel/M68kCallLowering.h
llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll [new file with mode: 0644]
llvm/test/CodeGen/M68k/GlobalISel/irtranslator-pic.ll [new file with mode: 0644]

index b3d1718..2068e04 100644 (file)
@@ -27,10 +27,12 @@ using namespace llvm;
 M68kCallLowering::M68kCallLowering(const M68kTargetLowering &TLI)
     : CallLowering(&TLI) {}
 
-struct OutgoingArgHandler : public CallLowering::OutgoingValueHandler {
-  OutgoingArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
-                     MachineInstrBuilder MIB)
-      : OutgoingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
+struct M68kOutgoingArgHandler : public CallLowering::OutgoingValueHandler {
+  M68kOutgoingArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
+                         MachineInstrBuilder MIB)
+      : OutgoingValueHandler(MIRBuilder, MRI), MIB(MIB),
+        DL(MIRBuilder.getMF().getDataLayout()),
+        STI(MIRBuilder.getMF().getSubtarget<M68kSubtarget>()) {}
 
   void assignValueToReg(Register ValVReg, Register PhysReg,
                         CCValAssign VA) override {
@@ -41,16 +43,29 @@ struct OutgoingArgHandler : public CallLowering::OutgoingValueHandler {
 
   void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,
                             MachinePointerInfo &MPO, CCValAssign &VA) override {
-    llvm_unreachable("unimplemented");
+    MachineFunction &MF = MIRBuilder.getMF();
+    Register ExtReg = extendRegister(ValVReg, VA);
+
+    auto *MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOStore, MemTy,
+                                        inferAlignFromPtrInfo(MF, MPO));
+    MIRBuilder.buildStore(ExtReg, Addr, *MMO);
   }
 
   Register getStackAddress(uint64_t Size, int64_t Offset,
                            MachinePointerInfo &MPO,
                            ISD::ArgFlagsTy Flags) override {
-    llvm_unreachable("unimplemented");
+    LLT p0 = LLT::pointer(0, DL.getPointerSizeInBits(0));
+    LLT SType = LLT::scalar(DL.getPointerSizeInBits(0));
+    Register StackReg = STI.getRegisterInfo()->getStackRegister();
+    auto SPReg = MIRBuilder.buildCopy(p0, StackReg).getReg(0);
+    auto OffsetReg = MIRBuilder.buildConstant(SType, Offset);
+    auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);
+    MPO = MachinePointerInfo::getStack(MIRBuilder.getMF(), Offset);
+    return AddrReg.getReg(0);
   }
-
   MachineInstrBuilder MIB;
+  const DataLayout &DL;
+  const M68kSubtarget &STI;
 };
 bool M68kCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
                                    const Value *Val, ArrayRef<Register> VRegs,
@@ -72,7 +87,7 @@ bool M68kCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
     setArgFlags(OrigArg, AttributeList::ReturnIndex, DL, F);
     splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv());
     OutgoingValueAssigner ArgAssigner(AssignFn);
-    OutgoingArgHandler ArgHandler(MIRBuilder, MRI, MIB);
+    M68kOutgoingArgHandler ArgHandler(MIRBuilder, MRI, MIB);
     Success = determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgs,
                                             MIRBuilder, F.getCallingConv(),
                                             F.isVarArg());
@@ -144,9 +159,73 @@ Register M68kIncomingValueHandler::getStackAddress(uint64_t Size,
   return AddrReg.getReg(0);
 }
 
+void CallReturnHandler::assignValueToReg(Register ValVReg, Register PhysReg,
+                                         CCValAssign VA) {
+  MIB.addDef(PhysReg, RegState::Implicit);
+  MIRBuilder.buildCopy(ValVReg, PhysReg);
+}
+
 bool M68kCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
                                  CallLoweringInfo &Info) const {
-  return false;
+  MachineFunction &MF = MIRBuilder.getMF();
+  Function &F = MF.getFunction();
+  MachineRegisterInfo &MRI = MF.getRegInfo();
+  auto &DL = F.getParent()->getDataLayout();
+  const M68kTargetLowering &TLI = *getTLI<M68kTargetLowering>();
+  const M68kSubtarget &STI = MF.getSubtarget<M68kSubtarget>();
+  const TargetInstrInfo &TII = *STI.getInstrInfo();
+  const M68kRegisterInfo *TRI = STI.getRegisterInfo();
+
+  SmallVector<ArgInfo, 8> OutArgs;
+  for (auto &OrigArg : Info.OrigArgs)
+    splitToValueTypes(OrigArg, OutArgs, DL, Info.CallConv);
+
+  SmallVector<ArgInfo, 8> InArgs;
+  if (!Info.OrigRet.Ty->isVoidTy())
+    splitToValueTypes(Info.OrigRet, InArgs, DL, Info.CallConv);
+
+  unsigned AdjStackDown = TII.getCallFrameSetupOpcode();
+  auto CallSeqStart = MIRBuilder.buildInstr(AdjStackDown);
+
+  unsigned Opc = TLI.getTargetMachine().isPositionIndependent() ? M68k::CALLq
+                 : Info.Callee.isReg()                          ? M68k::CALLj
+                                                                : M68k::CALLb;
+
+  auto MIB = MIRBuilder.buildInstrNoInsert(Opc)
+                 .add(Info.Callee)
+                 .addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));
+
+  CCAssignFn *AssignFn = TLI.getCCAssignFn(Info.CallConv, false, Info.IsVarArg);
+  OutgoingValueAssigner Assigner(AssignFn);
+  M68kOutgoingArgHandler Handler(MIRBuilder, MRI, MIB);
+  if (!determineAndHandleAssignments(Handler, Assigner, OutArgs, MIRBuilder,
+                                     Info.CallConv, Info.IsVarArg))
+    return false;
+
+  if (Info.Callee.isReg())
+    constrainOperandRegClass(MF, *TRI, MRI, *STI.getInstrInfo(),
+                             *STI.getRegBankInfo(), *MIB, MIB->getDesc(),
+                             Info.Callee, 0);
+
+  MIRBuilder.insertInstr(MIB);
+
+  if (!Info.OrigRet.Ty->isVoidTy()) {
+    CCAssignFn *RetAssignFn =
+        TLI.getCCAssignFn(Info.CallConv, true, Info.IsVarArg);
+
+    OutgoingValueAssigner Assigner(RetAssignFn, RetAssignFn);
+    CallReturnHandler Handler(MIRBuilder, MRI, MIB);
+    if (!determineAndHandleAssignments(Handler, Assigner, InArgs, MIRBuilder,
+                                       Info.CallConv, Info.IsVarArg))
+      return false;
+  }
+
+  CallSeqStart.addImm(Assigner.StackOffset).addImm(0);
+
+  unsigned AdjStackUp = TII.getCallFrameDestroyOpcode();
+  MIRBuilder.buildInstr(AdjStackUp).addImm(Assigner.StackOffset).addImm(0);
+
+  return true;
 }
 
 bool M68kCallLowering::enableBigEndian() const { return true; }
index 24212e6..a1589e9 100644 (file)
@@ -22,6 +22,7 @@
 namespace llvm {
 
 class M68kTargetLowering;
+class MachineInstrBuilder;
 
 class M68kCallLowering : public CallLowering {
   // TODO: We are only supporting return instruction with no value at this time
@@ -67,6 +68,17 @@ struct FormalArgHandler : public M68kIncomingValueHandler {
       : M68kIncomingValueHandler(MIRBuilder, MRI) {}
 };
 
+struct CallReturnHandler : public M68kIncomingValueHandler {
+  CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
+                    MachineInstrBuilder &MIB)
+      : M68kIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}
+
+private:
+  void assignValueToReg(Register ValVReg, Register PhysReg,
+                        CCValAssign VA) override;
+
+  MachineInstrBuilder &MIB;
+};
 } // end namespace llvm
 
 #endif // LLVM_LIB_TARGET_M68K_GLSEL_M68KCALLLOWERING_H
diff --git a/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll
new file mode 100644 (file)
index 0000000..f4ff258
--- /dev/null
@@ -0,0 +1,320 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+; RUN: llc -mtriple=m68k -O0 -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s
+
+%struct.A = type { i8, i16, i32 }
+
+declare void @trivial_callee()
+define void @test_trivial_call() {
+  ; CHECK-LABEL: name: test_trivial_call
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   CALLb @trivial_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void @trivial_callee()
+  ret void
+}
+
+declare i32 @ret_i32_callee()
+define i32 @test_ret_i32() {
+  ; CHECK-LABEL: name: test_ret_i32
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   CALLb @ret_i32_callee, csr_std, implicit $sp, implicit-def $d0
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $d0
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   $d0 = COPY [[COPY]](s32)
+  ; CHECK-NEXT:   RTS implicit $d0
+  %res = call i32 @ret_i32_callee()
+  ret i32 %res
+}
+
+declare i16 @ret_i16_callee()
+define i16 @test_ret_i16() nounwind {
+  ; CHECK-LABEL: name: test_ret_i16
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   CALLb @ret_i16_callee, csr_std, implicit $sp, implicit-def $wd0
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s16) = COPY $wd0
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   $wd0 = COPY [[COPY]](s16)
+  ; CHECK-NEXT:   RTS implicit $wd0
+  %1 = call i16 @ret_i16_callee()
+  ret i16 %1
+}
+
+declare i8 @ret_i8_callee()
+define i8 @test_ret_i8() nounwind {
+  ; CHECK-LABEL: name: test_ret_i8
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   CALLb @ret_i8_callee, csr_std, implicit $sp, implicit-def $bd0
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s8) = COPY $bd0
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   $bd0 = COPY [[COPY]](s8)
+  ; CHECK-NEXT:   RTS implicit $bd0
+  %1 = call i8 @ret_i8_callee()
+  ret i8 %1
+}
+
+declare void @sret_callee(%struct.A* sret(%struct.A))
+define void @test_sret(%struct.A* sret(%struct.A) %0) nounwind {
+  ; CHECK-LABEL: name: test_sret
+  ; CHECK: bb.1 (%ir-block.1):
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; CHECK-NEXT:   [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.0, align 8)
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 4, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s32)
+  ; CHECK-NEXT:   G_STORE [[LOAD]](p0), [[PTR_ADD]](p0) :: (store (p0) into stack, align 1)
+  ; CHECK-NEXT:   CALLb @sret_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 4, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void @sret_callee(%struct.A* sret(%struct.A) %0)
+  ret void
+}
+
+declare void @arg_i32_i16_i8_callee(i32, i16, i8)
+define void @test_arg_i32_i16_i8() nounwind {
+  ; CHECK-LABEL: name: test_arg_i32_i16_i8
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s16) = G_CONSTANT i16 1
+  ; CHECK-NEXT:   [[C2:%[0-9]+]]:_(s8) = G_CONSTANT i8 2
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 12, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C3]](s32)
+  ; CHECK-NEXT:   G_STORE [[C]](s32), [[PTR_ADD]](p0) :: (store (s32) into stack, align 1)
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+  ; CHECK-NEXT:   [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY1]], [[C4]](s32)
+  ; CHECK-NEXT:   [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[C1]](s16)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT]](s32), [[PTR_ADD1]](p0) :: (store (s16) into stack + 4, align 1)
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+  ; CHECK-NEXT:   [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY2]], [[C5]](s32)
+  ; CHECK-NEXT:   [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[C2]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT1]](s32), [[PTR_ADD2]](p0) :: (store (s8) into stack + 8)
+  ; CHECK-NEXT:   CALLb @arg_i32_i16_i8_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 12, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void @arg_i32_i16_i8_callee(i32 0, i16 1, i8 2)
+  ret void
+}
+
+declare void @arg_struct_callee(%struct.A)
+define void @test_arg_struct(%struct.A *%0) nounwind {
+  ; CHECK-LABEL: name: test_arg_struct
+  ; CHECK: bb.1 (%ir-block.1):
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; CHECK-NEXT:   [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.0, align 8)
+  ; CHECK-NEXT:   [[LOAD1:%[0-9]+]]:_(s8) = G_LOAD [[LOAD]](p0) :: (load (s8) from %ir.0, align 2)
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
+  ; CHECK-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s32)
+  ; CHECK-NEXT:   [[LOAD2:%[0-9]+]]:_(s16) = G_LOAD [[PTR_ADD]](p0) :: (load (s16) from %ir.0 + 2)
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+  ; CHECK-NEXT:   [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C1]](s32)
+  ; CHECK-NEXT:   [[LOAD3:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD1]](p0) :: (load (s32) from %ir.0 + 4, align 2)
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 12, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C2]](s32)
+  ; CHECK-NEXT:   [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD1]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT]](s32), [[PTR_ADD2]](p0) :: (store (s8) into stack)
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+  ; CHECK-NEXT:   [[PTR_ADD3:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY1]], [[C3]](s32)
+  ; CHECK-NEXT:   [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD2]](s16)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT1]](s32), [[PTR_ADD3]](p0) :: (store (s16) into stack + 4, align 1)
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+  ; CHECK-NEXT:   [[PTR_ADD4:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY2]], [[C4]](s32)
+  ; CHECK-NEXT:   G_STORE [[LOAD3]](s32), [[PTR_ADD4]](p0) :: (store (s32) into stack + 8, align 1)
+  ; CHECK-NEXT:   CALLb @arg_struct_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 12, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  %2 = load %struct.A, %struct.A* %0
+  call void @arg_struct_callee(%struct.A %2)
+  ret void
+}
+
+declare void @arg_array_callee([8 x i8])
+define void @test_arg_array([8 x i8] *%0) nounwind {
+  ; CHECK-LABEL: name: test_arg_array
+  ; CHECK: bb.1 (%ir-block.1):
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; CHECK-NEXT:   [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.0, align 8)
+  ; CHECK-NEXT:   [[LOAD1:%[0-9]+]]:_(s8) = G_LOAD [[LOAD]](p0) :: (load (s8) from %ir.0)
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; CHECK-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s32)
+  ; CHECK-NEXT:   [[LOAD2:%[0-9]+]]:_(s8) = G_LOAD [[PTR_ADD]](p0) :: (load (s8) from %ir.0 + 1)
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
+  ; CHECK-NEXT:   [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C1]](s32)
+  ; CHECK-NEXT:   [[LOAD3:%[0-9]+]]:_(s8) = G_LOAD [[PTR_ADD1]](p0) :: (load (s8) from %ir.0 + 2)
+  ; CHECK-NEXT:   [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
+  ; CHECK-NEXT:   [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C2]](s32)
+  ; CHECK-NEXT:   [[LOAD4:%[0-9]+]]:_(s8) = G_LOAD [[PTR_ADD2]](p0) :: (load (s8) from %ir.0 + 3)
+  ; CHECK-NEXT:   [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+  ; CHECK-NEXT:   [[PTR_ADD3:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C3]](s32)
+  ; CHECK-NEXT:   [[LOAD5:%[0-9]+]]:_(s8) = G_LOAD [[PTR_ADD3]](p0) :: (load (s8) from %ir.0 + 4)
+  ; CHECK-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
+  ; CHECK-NEXT:   [[PTR_ADD4:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C4]](s32)
+  ; CHECK-NEXT:   [[LOAD6:%[0-9]+]]:_(s8) = G_LOAD [[PTR_ADD4]](p0) :: (load (s8) from %ir.0 + 5)
+  ; CHECK-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 6
+  ; CHECK-NEXT:   [[PTR_ADD5:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C5]](s32)
+  ; CHECK-NEXT:   [[LOAD7:%[0-9]+]]:_(s8) = G_LOAD [[PTR_ADD5]](p0) :: (load (s8) from %ir.0 + 6)
+  ; CHECK-NEXT:   [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 7
+  ; CHECK-NEXT:   [[PTR_ADD6:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C6]](s32)
+  ; CHECK-NEXT:   [[LOAD8:%[0-9]+]]:_(s8) = G_LOAD [[PTR_ADD6]](p0) :: (load (s8) from %ir.0 + 7)
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 32, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C7:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[PTR_ADD7:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C7]](s32)
+  ; CHECK-NEXT:   [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD1]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT]](s32), [[PTR_ADD7]](p0) :: (store (s8) into stack)
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C8:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+  ; CHECK-NEXT:   [[PTR_ADD8:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY1]], [[C8]](s32)
+  ; CHECK-NEXT:   [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD2]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT1]](s32), [[PTR_ADD8]](p0) :: (store (s8) into stack + 4)
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C9:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+  ; CHECK-NEXT:   [[PTR_ADD9:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY2]], [[C9]](s32)
+  ; CHECK-NEXT:   [[ANYEXT2:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD3]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT2]](s32), [[PTR_ADD9]](p0) :: (store (s8) into stack + 8)
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C10:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
+  ; CHECK-NEXT:   [[PTR_ADD10:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY3]], [[C10]](s32)
+  ; CHECK-NEXT:   [[ANYEXT3:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD4]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT3]](s32), [[PTR_ADD10]](p0) :: (store (s8) into stack + 12)
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C11:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+  ; CHECK-NEXT:   [[PTR_ADD11:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY4]], [[C11]](s32)
+  ; CHECK-NEXT:   [[ANYEXT4:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD5]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT4]](s32), [[PTR_ADD11]](p0) :: (store (s8) into stack + 16)
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C12:%[0-9]+]]:_(s32) = G_CONSTANT i32 20
+  ; CHECK-NEXT:   [[PTR_ADD12:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY5]], [[C12]](s32)
+  ; CHECK-NEXT:   [[ANYEXT5:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD6]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT5]](s32), [[PTR_ADD12]](p0) :: (store (s8) into stack + 20)
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C13:%[0-9]+]]:_(s32) = G_CONSTANT i32 24
+  ; CHECK-NEXT:   [[PTR_ADD13:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY6]], [[C13]](s32)
+  ; CHECK-NEXT:   [[ANYEXT6:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD7]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT6]](s32), [[PTR_ADD13]](p0) :: (store (s8) into stack + 24)
+  ; CHECK-NEXT:   [[COPY7:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C14:%[0-9]+]]:_(s32) = G_CONSTANT i32 28
+  ; CHECK-NEXT:   [[PTR_ADD14:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY7]], [[C14]](s32)
+  ; CHECK-NEXT:   [[ANYEXT7:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD8]](s8)
+  ; CHECK-NEXT:   G_STORE [[ANYEXT7]](s32), [[PTR_ADD14]](p0) :: (store (s8) into stack + 28)
+  ; CHECK-NEXT:   CALLb @arg_array_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 32, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  %2 = load [8 x i8], [8 x i8]* %0
+  call void @arg_array_callee([8 x i8] %2)
+  ret void
+}
+
+declare void @arg_pass_struct_by_ptr_callee(%struct.A*)
+define void @test_arg_pass_struct_by_ptr(%struct.A *%0) nounwind {
+  ; CHECK-LABEL: name: test_arg_pass_struct_by_ptr
+  ; CHECK: bb.1 (%ir-block.1):
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; CHECK-NEXT:   [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.0, align 8)
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 4, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s32)
+  ; CHECK-NEXT:   G_STORE [[LOAD]](p0), [[PTR_ADD]](p0) :: (store (p0) into stack, align 1)
+  ; CHECK-NEXT:   CALLb @arg_pass_struct_by_ptr_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 4, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void @arg_pass_struct_by_ptr_callee(%struct.A *%0)
+  ret void
+}
+
+declare void @arg_pass_integer_byval_callee(i32* byval(i32), i16* byval(i16), i8* byval(i8))
+define void @test_arg_pass_integer_byval(i32 *%0, i16 *%1, i8 *%2) nounwind {
+  ; CHECK-LABEL: name: test_arg_pass_integer_byval
+  ; CHECK: bb.1 (%ir-block.3):
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.2
+  ; CHECK-NEXT:   [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.2, align 8)
+  ; CHECK-NEXT:   [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.1
+  ; CHECK-NEXT:   [[LOAD1:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX1]](p0) :: (load (p0) from %fixed-stack.1)
+  ; CHECK-NEXT:   [[FRAME_INDEX2:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; CHECK-NEXT:   [[LOAD2:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX2]](p0) :: (load (p0) from %fixed-stack.0, align 8)
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 12, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s32)
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+  ; CHECK-NEXT:   G_MEMCPY [[PTR_ADD]](p0), [[LOAD]](p0), [[C1]](s32), 0 :: (dereferenceable store (s32) into stack, align 2), (dereferenceable load (s32) from %ir.0, align 2)
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+  ; CHECK-NEXT:   [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY1]], [[C2]](s32)
+  ; CHECK-NEXT:   [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
+  ; CHECK-NEXT:   G_MEMCPY [[PTR_ADD1]](p0), [[LOAD1]](p0), [[C3]](s32), 0 :: (dereferenceable store (s16) into stack + 4), (dereferenceable load (s16) from %ir.1)
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+  ; CHECK-NEXT:   [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY2]], [[C4]](s32)
+  ; CHECK-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; CHECK-NEXT:   G_MEMCPY [[PTR_ADD2]](p0), [[LOAD2]](p0), [[C5]](s32), 0 :: (dereferenceable store (s8) into stack + 8), (dereferenceable load (s8) from %ir.2)
+  ; CHECK-NEXT:   CALLb @arg_pass_integer_byval_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 12, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void @arg_pass_integer_byval_callee(i32* byval(i32) %0, i16* byval(i16) %1, i8* byval(i8) %2)
+  ret void
+}
+
+declare void @arg_pass_struct_byval_callee(%struct.A* byval(%struct.A))
+define void @test_arg_pass_struct_byval(%struct.A *%0) nounwind {
+  ; CHECK-LABEL: name: test_arg_pass_struct_byval
+  ; CHECK: bb.1 (%ir-block.1):
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; CHECK-NEXT:   [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.0, align 8)
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 8, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s32)
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+  ; CHECK-NEXT:   G_MEMCPY [[PTR_ADD]](p0), [[LOAD]](p0), [[C1]](s32), 0 :: (dereferenceable store (s64) into stack, align 2), (dereferenceable load (s64) from %ir.0, align 2)
+  ; CHECK-NEXT:   CALLb @arg_pass_struct_byval_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 8, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void @arg_pass_struct_byval_callee(%struct.A* byval(%struct.A) %0)
+  ret void
+}
+
+declare void @arg_pass_array_byval_callee([32 x i8]* byval([32 x i8]))
+define void @test_arg_pass_array_byval([32 x i8] *%0) nounwind {
+  ; CHECK-LABEL: name: test_arg_pass_array_byval
+  ; CHECK: bb.1 (%ir-block.1):
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; CHECK-NEXT:   [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.0, align 8)
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 32, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $sp
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s32)
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 32
+  ; CHECK-NEXT:   G_MEMCPY [[PTR_ADD]](p0), [[LOAD]](p0), [[C1]](s32), 0 :: (dereferenceable store (s256) into stack, align 1), (dereferenceable load (s256) from %ir.0, align 1)
+  ; CHECK-NEXT:   CALLb @arg_pass_array_byval_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 32, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void @arg_pass_array_byval_callee([32 x i8]* byval([32 x i8]) %0)
+  ret void
+}
+
+define void @test_indirect_call(void() *%fptr) nounwind {
+  ; CHECK-LABEL: name: test_indirect_call
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; CHECK-NEXT:   [[LOAD:%[0-9]+]]:ar32(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.0, align 8)
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   CALLj [[LOAD]](p0), csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void %fptr()
+  ret void
+}
diff --git a/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-pic.ll b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-pic.ll
new file mode 100644 (file)
index 0000000..fa50b56
--- /dev/null
@@ -0,0 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+; RUN: llc -mtriple=m68k --relocation-model=pic -O0 -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s
+
+define void @test_pic() nounwind {
+  ; CHECK-LABEL: name: test_pic
+  ; CHECK: bb.1 (%ir-block.0):
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   CALLq @test_pic_callee, csr_std, implicit $sp
+  ; CHECK-NEXT:   ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit-def $ccr, implicit $sp
+  ; CHECK-NEXT:   RTS
+  call void @test_pic_callee()
+  ret void
+}
+declare void @test_pic_callee()