Skip to content

Commit fd84b1a

Browse files
committed
[M68k] Add new calling convention M68k_RTD
`M68k_RTD` is really similar to X86's stdcall, in which callee pops the arguments from stack. In LLVM IR it can be written as `m68k_rtdcc`. This patch also improves how ExpandPseudo Pass handles popping stack at function returns in the absent of the RTD instruction. Differential Revision: https://reviews.llvm.org/D149864
1 parent 7f881a2 commit fd84b1a

File tree

9 files changed

+102
-26
lines changed

9 files changed

+102
-26
lines changed

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ enum Kind {
175175
kw_amdgpu_kernel,
176176
kw_amdgpu_gfx,
177177
kw_tailcc,
178+
kw_m68k_rtdcc,
178179

179180
// Attributes:
180181
kw_attributes,

llvm/include/llvm/IR/CallingConv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,9 @@ namespace CallingConv {
245245
/// placement. Preserves active lane values for input VGPRs.
246246
AMDGPU_CS_ChainPreserve = 105,
247247

248+
/// Used for M68k rtd-based CC (similar to X86's stdcall).
249+
M68k_RTD = 106,
250+
248251
/// The highest possible ID. Must be some 2^k - 1.
249252
MaxID = 1023
250253
};

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,7 @@ lltok::Kind LLLexer::LexIdentifier() {
632632
KEYWORD(amdgpu_kernel);
633633
KEYWORD(amdgpu_gfx);
634634
KEYWORD(tailcc);
635+
KEYWORD(m68k_rtdcc);
635636

636637
KEYWORD(cc);
637638
KEYWORD(c);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,7 @@ void LLParser::parseOptionalDLLStorageClass(unsigned &Res) {
19991999
/// ::= 'amdgpu_cs_chain_preserve'
20002000
/// ::= 'amdgpu_kernel'
20012001
/// ::= 'tailcc'
2002+
/// ::= 'm68k_rtdcc'
20022003
/// ::= 'cc' UINT
20032004
///
20042005
bool LLParser::parseOptionalCallingConv(unsigned &CC) {
@@ -2067,6 +2068,7 @@ bool LLParser::parseOptionalCallingConv(unsigned &CC) {
20672068
break;
20682069
case lltok::kw_amdgpu_kernel: CC = CallingConv::AMDGPU_KERNEL; break;
20692070
case lltok::kw_tailcc: CC = CallingConv::Tail; break;
2071+
case lltok::kw_m68k_rtdcc: CC = CallingConv::M68k_RTD; break;
20702072
case lltok::kw_cc: {
20712073
Lex.Lex();
20722074
return parseUInt32(CC);

llvm/lib/IR/AsmWriter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) {
350350
break;
351351
case CallingConv::AMDGPU_KERNEL: Out << "amdgpu_kernel"; break;
352352
case CallingConv::AMDGPU_Gfx: Out << "amdgpu_gfx"; break;
353+
case CallingConv::M68k_RTD: Out << "m68k_rtdcc"; break;
353354
}
354355
}
355356

llvm/lib/Target/M68k/M68kExpandPseudo.cpp

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -258,32 +258,22 @@ bool M68kExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
258258

259259
if (StackAdj == 0) {
260260
MIB = BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS));
261-
} else if (isUInt<16>(StackAdj)) {
262-
263-
if (STI->atLeastM68020()) {
264-
llvm_unreachable("RTD is not implemented");
265-
} else {
266-
// Copy PC from stack to a free address(A0 or A1) register
267-
// TODO check if pseudo expand uses free address register
268-
BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32aj), M68k::A1)
269-
.addReg(M68k::SP);
261+
} else {
262+
// Copy return address from stack to a free address(A0 or A1) register
263+
// TODO check if pseudo expand uses free address register
264+
BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32aj), M68k::A1)
265+
.addReg(M68k::SP);
270266

271-
// Adjust SP
272-
FL->emitSPUpdate(MBB, MBBI, StackAdj, /*InEpilogue=*/true);
267+
// Adjust SP
268+
FL->emitSPUpdate(MBB, MBBI, StackAdj, /*InEpilogue=*/true);
273269

274-
// Put the return address on stack
275-
BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32ja))
276-
.addReg(M68k::SP)
277-
.addReg(M68k::A1);
270+
// Put the return address on stack
271+
BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32ja))
272+
.addReg(M68k::SP)
273+
.addReg(M68k::A1);
278274

279-
// RTS
280-
BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS));
281-
}
282-
} else {
283-
// TODO: RTD can only handle immediates as big as 2**16-1.
284-
// If we need to pop off bytes before the return address, we
285-
// must do it manually.
286-
llvm_unreachable("Stack adjustment size not supported");
275+
// RTS
276+
BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS));
287277
}
288278

289279
// FIXME: Can rest of the operands be ignored, if there is any?

llvm/lib/Target/M68k/M68kISelLowering.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3050,9 +3050,8 @@ M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
30503050

30513051
/// Determines whether the callee is required to pop its own arguments.
30523052
/// Callee pop is necessary to support tail calls.
3053-
bool M68k::isCalleePop(CallingConv::ID CallingConv, bool IsVarArg,
3054-
bool GuaranteeTCO) {
3055-
return false;
3053+
bool M68k::isCalleePop(CallingConv::ID CC, bool IsVarArg, bool GuaranteeTCO) {
3054+
return CC == CallingConv::M68k_RTD && !IsVarArg;
30563055
}
30573056

30583057
// Return true if it is OK for this CMOV pseudo-opcode to be cascaded
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 2
2+
; RUN: llc -mtriple=m68k %s -stop-after=finalize-isel -o - | FileCheck %s
3+
4+
; We want to make sure caller doesn't pop the stack for callees using
5+
; the M68k_RTD CC. However, we've implemented some frame optimization
6+
; techniques to eliminate as many as frame setup/destroy instructions.
7+
; Therefore, to make test case small and concise, we check the MIR generated
8+
; after ISel instead.
9+
10+
declare dso_local m68k_rtdcc void @callee(i32 noundef)
11+
declare dso_local m68k_rtdcc void @va_callee(i32 noundef, ...)
12+
13+
define dso_local i32 @caller(ptr noundef %y) {
14+
; CHECK-LABEL: name: caller
15+
; CHECK: bb.0.entry:
16+
; CHECK-NEXT: [[MOV32rp:%[0-9]+]]:ar32 = MOV32rp 0, %fixed-stack.0, implicit-def dead $ccr :: (load (s32) from %fixed-stack.0, align 8)
17+
; CHECK-NEXT: [[MOV32rj:%[0-9]+]]:xr32 = MOV32rj killed [[MOV32rp]], implicit-def dead $ccr :: (load (s32) from %ir.y)
18+
; CHECK-NEXT: ADJCALLSTACKDOWN 4, 0, implicit-def dead $sp, implicit-def dead $ccr, implicit $sp
19+
; CHECK-NEXT: [[COPY:%[0-9]+]]:ar32 = COPY $sp
20+
; CHECK-NEXT: MOV32jr [[COPY]], [[MOV32rj]], implicit-def dead $ccr :: (store (s32) into stack, align 2)
21+
; CHECK-NEXT: CALLb @callee, csr_std, implicit $sp, implicit-def $sp
22+
; CHECK-NEXT: ADJCALLSTACKUP 4, 4, implicit-def dead $sp, implicit-def dead $ccr, implicit $sp
23+
; CHECK-NEXT: $d0 = COPY [[MOV32rj]]
24+
; CHECK-NEXT: RET 0, $d0
25+
entry:
26+
%0 = load i32, ptr %y, align 4
27+
call m68k_rtdcc void @callee(i32 noundef %0)
28+
ret i32 %0
29+
}
30+
31+
define dso_local i32 @va_caller(ptr noundef %y) {
32+
; CHECK-LABEL: name: va_caller
33+
; CHECK: bb.0.entry:
34+
; CHECK-NEXT: [[MOV32rp:%[0-9]+]]:ar32 = MOV32rp 0, %fixed-stack.0, implicit-def dead $ccr :: (load (s32) from %fixed-stack.0, align 8)
35+
; CHECK-NEXT: [[MOV32rj:%[0-9]+]]:xr32 = MOV32rj killed [[MOV32rp]], implicit-def dead $ccr :: (load (s32) from %ir.y)
36+
; CHECK-NEXT: ADJCALLSTACKDOWN 4, 0, implicit-def dead $sp, implicit-def dead $ccr, implicit $sp
37+
; CHECK-NEXT: [[COPY:%[0-9]+]]:ar32 = COPY $sp
38+
; CHECK-NEXT: MOV32jr [[COPY]], [[MOV32rj]], implicit-def dead $ccr :: (store (s32) into stack, align 2)
39+
; CHECK-NEXT: CALLb @va_callee, csr_std, implicit $sp, implicit-def $sp
40+
; CHECK-NEXT: ADJCALLSTACKUP 4, 0, implicit-def dead $sp, implicit-def dead $ccr, implicit $sp
41+
; CHECK-NEXT: $d0 = COPY [[MOV32rj]]
42+
; CHECK-NEXT: RET 0, $d0
43+
entry:
44+
%0 = load i32, ptr %y, align 4
45+
call m68k_rtdcc void (i32, ...) @va_callee(i32 noundef %0)
46+
ret i32 %0
47+
}
48+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
2+
; RUN: llc -mtriple=m68k < %s | FileCheck %s
3+
4+
define dso_local m68k_rtdcc i32 @ret(i32 noundef %a, i32 noundef %b, i32 noundef %c) nounwind {
5+
; CHECK-LABEL: ret:
6+
; CHECK: ; %bb.0: ; %entry
7+
; CHECK-NEXT: move.l (8,%sp), %d0
8+
; CHECK-NEXT: add.l (4,%sp), %d0
9+
; CHECK-NEXT: add.l (12,%sp), %d0
10+
; CHECK-NEXT: move.l (%sp), %a1
11+
; CHECK-NEXT: adda.l #12, %sp
12+
; CHECK-NEXT: move.l %a1, (%sp)
13+
; CHECK-NEXT: rts
14+
entry:
15+
%add = add nsw i32 %b, %a
16+
%add1 = add nsw i32 %add, %c
17+
ret i32 %add1
18+
}
19+
20+
define dso_local m68k_rtdcc i32 @va_ret(i32 noundef %a, i32 noundef %b, i32 noundef %c, ...) nounwind {
21+
; CHECK-LABEL: va_ret:
22+
; CHECK: ; %bb.0: ; %entry
23+
; CHECK-NEXT: move.l (8,%sp), %d0
24+
; CHECK-NEXT: add.l (4,%sp), %d0
25+
; CHECK-NEXT: add.l (12,%sp), %d0
26+
; CHECK-NEXT: rts
27+
entry:
28+
%add = add nsw i32 %b, %a
29+
%add1 = add nsw i32 %add, %c
30+
ret i32 %add1
31+
}

0 commit comments

Comments
 (0)