diff --git a/llvm/lib/Target/M68k/GISel/M68kCallLowering.h b/llvm/lib/Target/M68k/GISel/M68kCallLowering.h --- a/llvm/lib/Target/M68k/GISel/M68kCallLowering.h +++ b/llvm/lib/Target/M68k/GISel/M68kCallLowering.h @@ -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 @@ : 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/lib/Target/M68k/GISel/M68kCallLowering.cpp b/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp --- a/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp +++ b/llvm/lib/Target/M68k/GISel/M68kCallLowering.cpp @@ -27,10 +27,12 @@ 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()) {} void assignValueToReg(Register ValVReg, Register PhysReg, CCValAssign VA) override { @@ -41,16 +43,29 @@ 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 VRegs, @@ -72,7 +87,7 @@ 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 @@ 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(); + const M68kSubtarget &STI = MF.getSubtarget(); + const TargetInstrInfo &TII = *STI.getInstrInfo(); + const M68kRegisterInfo *TRI = STI.getRegisterInfo(); + + SmallVector OutArgs; + for (auto &OrigArg : Info.OrigArgs) + splitToValueTypes(OrigArg, OutArgs, DL, Info.CallConv); + + SmallVector 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; } diff --git a/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-call.ll @@ -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 --- /dev/null +++ b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-pic.ll @@ -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()