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 @@ -79,6 +79,42 @@ MachineInstrBuilder &MIB; }; + +struct M68kValueAssigner : public CallLowering::ValueAssigner { + M68kValueAssigner(CallingConv::ID CallConv, bool isVarArg, + MachineFunction &MF, LLVMContext &Ctx, bool isIncoming, + CCAssignFn *AssignFn_, + CCAssignFn *AssignFnVarArg_ = nullptr) + : ValueAssigner(isIncoming, AssignFn_, AssignFnVarArg_), + M68kCCState(CallConv, isVarArg, MF, M68kLocs, Ctx) {} + + bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags, + CCState &State) override; + + SmallVector M68kLocs; + CCState M68kCCState; +}; + +struct M68kOutgoingValueAssigner : public M68kValueAssigner { + M68kOutgoingValueAssigner(CallingConv::ID CallConv, bool isVarArg, + MachineFunction &MF, LLVMContext &Ctx, + CCAssignFn *AssignFn_, + CCAssignFn *AssignFnVarArg_ = nullptr) + : M68kValueAssigner(CallConv, isVarArg, MF, Ctx, false, AssignFn_, + AssignFnVarArg_) {} +}; + +struct M68kIncomingValueAssigner : public M68kValueAssigner { + M68kIncomingValueAssigner(CallingConv::ID CallConv, bool isVarArg, + MachineFunction &MF, LLVMContext &Ctx, + CCAssignFn *AssignFn_, + CCAssignFn *AssignFnVarArg_ = nullptr) + : M68kValueAssigner(CallConv, isVarArg, MF, Ctx, true, AssignFn_, + AssignFnVarArg_) {} +}; + } // 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 @@ -67,6 +67,42 @@ const DataLayout &DL; const M68kSubtarget &STI; }; + +// M68k returns i64 value in this way: +// 63 31 0 +// |-------|-------| +// $d0 $d1 +// but GISel allocates the low bits first +// so low bits will go to $d0, high bits to $d1. +// We need to reverse the allocated results. + +bool M68kValueAssigner::assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, + const CallLowering::ArgInfo &Info, + ISD::ArgFlagsTy Flags, CCState &State) { + if (Flags.isSplit()) { + // We need to update the stack offset. + M68kCCState.AllocateStack(State.getNextStackOffset() - + M68kCCState.getNextStackOffset(), + Align(2)); + } + + bool result = ValueAssigner::assignArg( + ValNo, OrigVT, ValVT, LocVT, LocInfo, Info, Flags, + Info.Flags[0].isSplit() ? M68kCCState : State); + if (!result && Flags.isSplitEnd()) { + for (auto It = M68kLocs.rbegin(); It != M68kLocs.rend(); ++It) { + State.addLoc(*It); + } + M68kLocs.clear(); + // Update the stack offset back to the original CCState + State.AllocateStack(M68kCCState.getNextStackOffset() - + State.getNextStackOffset(), + Align(2)); + } + return result; +} + bool M68kCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, ArrayRef VRegs, FunctionLoweringInfo &FLI, @@ -86,7 +122,8 @@ ArgInfo OrigArg{VRegs, Val->getType(), 0}; setArgFlags(OrigArg, AttributeList::ReturnIndex, DL, F); splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv()); - OutgoingValueAssigner ArgAssigner(AssignFn); + M68kOutgoingValueAssigner ArgAssigner(F.getCallingConv(), F.isVarArg(), MF, + F.getContext(), AssignFn); M68kOutgoingArgHandler ArgHandler(MIRBuilder, MRI, MIB); Success = determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgs, MIRBuilder, F.getCallingConv(), @@ -116,7 +153,8 @@ CCAssignFn *AssignFn = TLI.getCCAssignFn(F.getCallingConv(), false, F.isVarArg()); - IncomingValueAssigner ArgAssigner(AssignFn); + M68kIncomingValueAssigner ArgAssigner(F.getCallingConv(), F.isVarArg(), MF, + F.getContext(), AssignFn); FormalArgHandler ArgHandler(MIRBuilder, MRI); return determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgs, MIRBuilder, F.getCallingConv(), @@ -197,7 +235,8 @@ CCAssignFn *AssignFn = TLI.getCCAssignFn(F.getCallingConv(), false, F.isVarArg()); - OutgoingValueAssigner Assigner(AssignFn); + M68kOutgoingValueAssigner Assigner(F.getCallingConv(), F.isVarArg(), MF, + F.getContext(), AssignFn); M68kOutgoingArgHandler Handler(MIRBuilder, MRI, MIB); if (!determineAndHandleAssignments(Handler, Assigner, OutArgs, MIRBuilder, Info.CallConv, Info.IsVarArg)) @@ -214,7 +253,8 @@ CCAssignFn *RetAssignFn = TLI.getCCAssignFn(F.getCallingConv(), true, F.isVarArg()); - OutgoingValueAssigner Assigner(RetAssignFn, RetAssignFn); + M68kOutgoingValueAssigner Assigner(F.getCallingConv(), F.isVarArg(), MF, + F.getContext(), RetAssignFn); CallReturnHandler Handler(MIRBuilder, MRI, MIB); if (!determineAndHandleAssignments(Handler, Assigner, InArgs, MIRBuilder, Info.CallConv, Info.IsVarArg)) diff --git a/llvm/test/CodeGen/M68k/GlobalISel/c-call.ll b/llvm/test/CodeGen/M68k/GlobalISel/c-call.ll --- a/llvm/test/CodeGen/M68k/GlobalISel/c-call.ll +++ b/llvm/test/CodeGen/M68k/GlobalISel/c-call.ll @@ -43,4 +43,33 @@ %3 = call i32 @callee3(i32 %0, i32 %1) ret i32 %3 } -declare i32 @callee3(i32, i32) \ No newline at end of file +declare i32 @callee3(i32, i32) + +define i64 @test_ret_i64(i64 %0) nounwind { +; CHECK-LABEL: test_ret_i64: +; CHECK: ; %bb.0 +; CHECK-NEXT: move.l (8,%sp), %d1 +; CHECK-NEXT: move.l (4,%sp), %d0 +; CHECK-NEXT: rts + ret i64 %0 +} + +define void @test_passing_i64(i64 %0, i64 %1) nounwind { +; CHECK-LABEL: test_passing_i64: +; CHECK: ; %bb.0: +; CHECK-NEXT: suba.l #20, %sp +; CHECK-NEXT: move.l (28,%sp), %d0 +; CHECK-NEXT: move.l (24,%sp), %d1 +; CHECK-NEXT: move.l (36,%sp), %a0 +; CHECK-NEXT: move.l (32,%sp), %a1 +; CHECK-NEXT: move.l %a0, (4,%sp) +; CHECK-NEXT: move.l %a1, (0,%sp) +; CHECK-NEXT: move.l %d0, (12,%sp) +; CHECK-NEXT: move.l %d1, (8,%sp) +; CHECK-NEXT: jsr callee_test_passing_i64 +; CHECK-NEXT: adda.l #20, %sp +; CHECK-NEXT: rts + call void @callee_test_passing_i64(i64 %1, i64 %0) + ret void +} +declare void @callee_test_passing_i64(i64, i64) diff --git a/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-ret.ll b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-ret.ll --- a/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-ret.ll +++ b/llvm/test/CodeGen/M68k/GlobalISel/irtranslator-ret.ll @@ -206,8 +206,8 @@ ; CHECK: [[G_LOAD2:%[0-9]+]]:_(s32) = G_LOAD [[G_F_I2]](p0) ; CHECK: [[G_MERGE_VAL:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[G_LOAD1]](s32), [[G_LOAD2]](s32) ; CHECK: [[G_UNMERGE_VAL1:%[0-9]+]]:_(s32), [[G_UNMERGE_VAL2:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[G_MERGE_VAL]](s64) - ; CHECK: $d0 = COPY [[G_UNMERGE_VAL1]](s32) - ; CHECK: $d1 = COPY [[G_UNMERGE_VAL2]](s32) - ; CHECK: RTS implicit $d0, implicit $d1 + ; CHECK: $d1 = COPY [[G_UNMERGE_VAL1]](s32) + ; CHECK: $d0 = COPY [[G_UNMERGE_VAL2]](s32) + ; CHECK: RTS implicit $d1, implicit $d0 ret i64 %a }