Skip to content

Commit 105e1ed

Browse files
committed
Merge 98212 from mainline.
add support, testcases, and dox for the new GHC calling convention. Patch by David Terei! llvm-svn: 98307
1 parent 48bc24b commit 105e1ed

File tree

9 files changed

+219
-17
lines changed

9 files changed

+219
-17
lines changed

llvm/docs/CodeGenerator.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1678,7 +1678,8 @@
16781678
supported on x86/x86-64 and PowerPC. It is performed if:</p>
16791679

16801680
<ul>
1681-
<li>Caller and callee have the calling convention <tt>fastcc</tt>.</li>
1681+
<li>Caller and callee have the calling convention <tt>fastcc</tt> or
1682+
<tt>cc 10</tt> (GHC call convention).</li>
16821683

16831684
<li>The call is a tail call - in tail position (ret immediately follows call
16841685
and ret uses value of call or is void).</li>

llvm/docs/LangRef.html

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -691,9 +691,9 @@
691691
target, without having to conform to an externally specified ABI
692692
(Application Binary Interface).
693693
<a href="CodeGenerator.html#tailcallopt">Tail calls can only be optimized
694-
when this convention is used.</a> This calling convention does not
695-
support varargs and requires the prototype of all callees to exactly match
696-
the prototype of the function definition.</dd>
694+
when this or the GHC convention is used.</a> This calling convention
695+
does not support varargs and requires the prototype of all callees to
696+
exactly match the prototype of the function definition.</dd>
697697

698698
<dt><b>"<tt>coldcc</tt>" - The cold calling convention</b>:</dt>
699699
<dd>This calling convention attempts to make code in the caller as efficient
@@ -703,6 +703,26 @@
703703
does not support varargs and requires the prototype of all callees to
704704
exactly match the prototype of the function definition.</dd>
705705

706+
<dt><b>"<tt>cc <em>10</em></tt>" - GHC convention</b>:</dt>
707+
<dd>This calling convention has been implemented specifically for use by the
708+
<a href="http://www.haskell.org/ghc">Glasgow Haskell Compiler (GHC)</a>.
709+
It passes everything in registers, going to extremes to achieve this by
710+
disabling callee save registers. This calling convention should not be
711+
used lightly but only for specific situations such as an alternative to
712+
the <em>register pinning</em> performance technique often used when
713+
implementing functional programming languages.At the moment only X86
714+
supports this convention and it has the following limitations:
715+
<ul>
716+
<li>On <em>X86-32</em> only supports up to 4 bit type parameters. No
717+
floating point types are supported.</li>
718+
<li>On <em>X86-64</em> only supports up to 10 bit type parameters and
719+
6 floating point parameters.</li>
720+
</ul>
721+
This calling convention supports
722+
<a href="CodeGenerator.html#tailcallopt">tail call optimization</a> but
723+
requires both the caller and callee are using it.
724+
</dd>
725+
706726
<dt><b>"<tt>cc &lt;<em>n</em>&gt;</tt>" - Numbered convention</b>:</dt>
707727
<dd>Any calling convention may be specified by number, allowing
708728
target-specific calling conventions to be used. Target specific calling

llvm/include/llvm/CallingConv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ namespace CallingConv {
4444
// call does not break any live ranges in the caller side.
4545
Cold = 9,
4646

47+
// GHC - Calling convention used by the Glasgow Haskell Compiler (GHC).
48+
GHC = 10,
49+
4750
// Target - This is the start of the target-specific calling conventions,
4851
// e.g. fastcall and thiscall on X86.
4952
FirstTargetCC = 64,

llvm/lib/Target/X86/X86CallingConv.td

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,20 @@ def CC_X86_Win64_C : CallingConv<[
221221
CCIfType<[v8i8, v4i16, v2i32, v1i64], CCAssignToStack<8, 8>>
222222
]>;
223223

224+
def CC_X86_64_GHC : CallingConv<[
225+
// Promote i8/i16/i32 arguments to i64.
226+
CCIfType<[i8, i16, i32], CCPromoteToType<i64>>,
227+
228+
// Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, R6, SpLim
229+
CCIfType<[i64],
230+
CCAssignToReg<[R13, RBP, R12, RBX, R14, RSI, RDI, R8, R9, R15]>>,
231+
232+
// Pass in STG registers: F1, F2, F3, F4, D1, D2
233+
CCIfType<[f32, f64, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
234+
CCIfSubtarget<"hasSSE1()",
235+
CCAssignToReg<[XMM1, XMM2, XMM3, XMM4, XMM5, XMM6]>>>
236+
]>;
237+
224238
//===----------------------------------------------------------------------===//
225239
// X86 C Calling Convention
226240
//===----------------------------------------------------------------------===//
@@ -320,3 +334,11 @@ def CC_X86_32_FastCC : CallingConv<[
320334
// Otherwise, same as everything else.
321335
CCDelegateTo<CC_X86_32_Common>
322336
]>;
337+
338+
def CC_X86_32_GHC : CallingConv<[
339+
// Promote i8/i16 arguments to i32.
340+
CCIfType<[i8, i16], CCPromoteToType<i32>>,
341+
342+
// Pass in STG registers: Base, Sp, Hp, R1
343+
CCIfType<[i32], CCAssignToReg<[EBX, EBP, EDI, ESI]>>
344+
]>;

llvm/lib/Target/X86/X86FastISel.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ bool X86FastISel::isTypeLegal(const Type *Ty, EVT &VT, bool AllowI1) {
172172
CCAssignFn *X86FastISel::CCAssignFnForCall(CallingConv::ID CC,
173173
bool isTaillCall) {
174174
if (Subtarget->is64Bit()) {
175-
if (Subtarget->isTargetWin64())
175+
if (CC == CallingConv::GHC)
176+
return CC_X86_64_GHC;
177+
else if (Subtarget->isTargetWin64())
176178
return CC_X86_Win64_C;
177179
else
178180
return CC_X86_64_C;
@@ -182,6 +184,8 @@ CCAssignFn *X86FastISel::CCAssignFnForCall(CallingConv::ID CC,
182184
return CC_X86_32_FastCall;
183185
else if (CC == CallingConv::Fast)
184186
return CC_X86_32_FastCC;
187+
else if (CC == CallingConv::GHC)
188+
return CC_X86_32_GHC;
185189
else
186190
return CC_X86_32_C;
187191
}

llvm/lib/Target/X86/X86ISelLowering.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,14 +1378,18 @@ bool X86TargetLowering::IsCalleePop(bool IsVarArg, CallingConv::ID CallingConv){
13781378
return !Subtarget->is64Bit();
13791379
case CallingConv::Fast:
13801380
return GuaranteedTailCallOpt;
1381+
case CallingConv::GHC:
1382+
return GuaranteedTailCallOpt;
13811383
}
13821384
}
13831385

13841386
/// CCAssignFnForNode - Selects the correct CCAssignFn for a the
13851387
/// given CallingConvention value.
13861388
CCAssignFn *X86TargetLowering::CCAssignFnForNode(CallingConv::ID CC) const {
13871389
if (Subtarget->is64Bit()) {
1388-
if (Subtarget->isTargetWin64())
1390+
if (CC == CallingConv::GHC)
1391+
return CC_X86_64_GHC;
1392+
else if (Subtarget->isTargetWin64())
13891393
return CC_X86_Win64_C;
13901394
else
13911395
return CC_X86_64_C;
@@ -1395,6 +1399,8 @@ CCAssignFn *X86TargetLowering::CCAssignFnForNode(CallingConv::ID CC) const {
13951399
return CC_X86_32_FastCall;
13961400
else if (CC == CallingConv::Fast)
13971401
return CC_X86_32_FastCC;
1402+
else if (CC == CallingConv::GHC)
1403+
return CC_X86_32_GHC;
13981404
else
13991405
return CC_X86_32_C;
14001406
}
@@ -1412,10 +1418,16 @@ CreateCopyOfByValArgument(SDValue Src, SDValue Dst, SDValue Chain,
14121418
/*AlwaysInline=*/true, NULL, 0, NULL, 0);
14131419
}
14141420

1421+
/// IsTailCallConvention - Return true if the calling convention is one that
1422+
/// supports tail call optimization.
1423+
static bool IsTailCallConvention(CallingConv::ID CC) {
1424+
return (CC == CallingConv::Fast || CC == CallingConv::GHC);
1425+
}
1426+
14151427
/// FuncIsMadeTailCallSafe - Return true if the function is being made into
14161428
/// a tailcall target by changing its ABI.
14171429
static bool FuncIsMadeTailCallSafe(CallingConv::ID CC) {
1418-
return GuaranteedTailCallOpt && CC == CallingConv::Fast;
1430+
return GuaranteedTailCallOpt && IsTailCallConvention(CC);
14191431
}
14201432

14211433
SDValue
@@ -1479,8 +1491,8 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
14791491
bool Is64Bit = Subtarget->is64Bit();
14801492
bool IsWin64 = Subtarget->isTargetWin64();
14811493

1482-
assert(!(isVarArg && CallConv == CallingConv::Fast) &&
1483-
"Var args not supported with calling convention fastcc");
1494+
assert(!(isVarArg && IsTailCallConvention(CallConv)) &&
1495+
"Var args not supported with calling convention fastcc or ghc");
14841496

14851497
// Assign locations to all of the incoming arguments.
14861498
SmallVector<CCValAssign, 16> ArgLocs;
@@ -1683,7 +1695,7 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain,
16831695
} else {
16841696
BytesToPopOnReturn = 0; // Callee pops nothing.
16851697
// If this is an sret function, the return should pop the hidden pointer.
1686-
if (!Is64Bit && CallConv != CallingConv::Fast && ArgsAreStructReturn(Ins))
1698+
if (!Is64Bit && !IsTailCallConvention(CallConv) && ArgsAreStructReturn(Ins))
16871699
BytesToPopOnReturn = 4;
16881700
}
16891701

@@ -1779,8 +1791,8 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
17791791
++NumTailCalls;
17801792
}
17811793

1782-
assert(!(isVarArg && CallConv == CallingConv::Fast) &&
1783-
"Var args not supported with calling convention fastcc");
1794+
assert(!(isVarArg && IsTailCallConvention(CallConv)) &&
1795+
"Var args not supported with calling convention fastcc or ghc");
17841796

17851797
// Analyze operands of the call, assigning locations to each operand.
17861798
SmallVector<CCValAssign, 16> ArgLocs;
@@ -1794,7 +1806,7 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
17941806
// This is a sibcall. The memory operands are available in caller's
17951807
// own caller's stack.
17961808
NumBytes = 0;
1797-
else if (GuaranteedTailCallOpt && CallConv == CallingConv::Fast)
1809+
else if (GuaranteedTailCallOpt && IsTailCallConvention(CallConv))
17981810
NumBytes = GetAlignedArgumentStackSize(NumBytes, DAG);
17991811

18001812
int FPDiff = 0;
@@ -2150,7 +2162,7 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee,
21502162
unsigned NumBytesForCalleeToPush;
21512163
if (IsCalleePop(isVarArg, CallConv))
21522164
NumBytesForCalleeToPush = NumBytes; // Callee pops everything
2153-
else if (!Is64Bit && CallConv != CallingConv::Fast && IsStructRet)
2165+
else if (!Is64Bit && !IsTailCallConvention(CallConv) && IsStructRet)
21542166
// If this is a call to a struct-return function, the callee
21552167
// pops the hidden struct pointer, so we have to push it back.
21562168
// This is common for Darwin/X86, Linux & Mingw32 targets.
@@ -2288,14 +2300,14 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
22882300
const SmallVectorImpl<ISD::OutputArg> &Outs,
22892301
const SmallVectorImpl<ISD::InputArg> &Ins,
22902302
SelectionDAG& DAG) const {
2291-
if (CalleeCC != CallingConv::Fast &&
2303+
if (!IsTailCallConvention(CalleeCC) &&
22922304
CalleeCC != CallingConv::C)
22932305
return false;
22942306

22952307
// If -tailcallopt is specified, make fastcc functions tail-callable.
22962308
const Function *CallerF = DAG.getMachineFunction().getFunction();
22972309
if (GuaranteedTailCallOpt) {
2298-
if (CalleeCC == CallingConv::Fast &&
2310+
if (IsTailCallConvention(CalleeCC) &&
22992311
CallerF->getCallingConv() == CalleeCC)
23002312
return true;
23012313
return false;

llvm/lib/Target/X86/X86RegisterInfo.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,13 +294,20 @@ X86RegisterInfo::getCrossCopyRegClass(const TargetRegisterClass *RC) const {
294294
const unsigned *
295295
X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
296296
bool callsEHReturn = false;
297+
bool ghcCall = false;
297298

298299
if (MF) {
299300
const MachineFrameInfo *MFI = MF->getFrameInfo();
300301
const MachineModuleInfo *MMI = MFI->getMachineModuleInfo();
301302
callsEHReturn = (MMI ? MMI->callsEHReturn() : false);
303+
const Function *F = MF->getFunction();
304+
ghcCall = (F ? F->getCallingConv() == CallingConv::GHC : false);
302305
}
303306

307+
static const unsigned GhcCalleeSavedRegs[] = {
308+
0
309+
};
310+
304311
static const unsigned CalleeSavedRegs32Bit[] = {
305312
X86::ESI, X86::EDI, X86::EBX, X86::EBP, 0
306313
};
@@ -326,7 +333,9 @@ X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
326333
X86::XMM14, X86::XMM15, 0
327334
};
328335

329-
if (Is64Bit) {
336+
if (ghcCall) {
337+
return GhcCalleeSavedRegs;
338+
} else if (Is64Bit) {
330339
if (IsWin64)
331340
return CalleeSavedRegsWin64;
332341
else

llvm/test/CodeGen/X86/ghc-cc.ll

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
; RUN: llc < %s -tailcallopt -mtriple=i686-linux-gnu | FileCheck %s
2+
3+
; Test the GHC call convention works (x86-32)
4+
5+
@base = external global i32 ; assigned to register: EBX
6+
@sp = external global i32 ; assigned to register: EBP
7+
@hp = external global i32 ; assigned to register: EDI
8+
@r1 = external global i32 ; assigned to register: ESI
9+
10+
define void @zap(i32 %a, i32 %b) nounwind {
11+
entry:
12+
; CHECK: movl {{[0-9]*}}(%esp), %ebx
13+
; CHECK-NEXT: movl {{[0-9]*}}(%esp), %ebp
14+
; CHECK-NEXT: call addtwo
15+
%0 = call cc 10 i32 @addtwo(i32 %a, i32 %b)
16+
; CHECK: call foo
17+
call void @foo() nounwind
18+
ret void
19+
}
20+
21+
define cc 10 i32 @addtwo(i32 %x, i32 %y) nounwind {
22+
entry:
23+
; CHECK: leal (%ebx,%ebp), %eax
24+
%0 = add i32 %x, %y
25+
; CHECK-NEXT: ret
26+
ret i32 %0
27+
}
28+
29+
define cc 10 void @foo() nounwind {
30+
entry:
31+
; CHECK: movl base, %ebx
32+
; CHECK-NEXT: movl sp, %ebp
33+
; CHECK-NEXT: movl hp, %edi
34+
; CHECK-NEXT: movl r1, %esi
35+
%0 = load i32* @r1
36+
%1 = load i32* @hp
37+
%2 = load i32* @sp
38+
%3 = load i32* @base
39+
; CHECK: jmp bar
40+
tail call cc 10 void @bar( i32 %3, i32 %2, i32 %1, i32 %0 ) nounwind
41+
ret void
42+
}
43+
44+
declare cc 10 void @bar(i32, i32, i32, i32)
45+

llvm/test/CodeGen/X86/ghc-cc64.ll

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
; RUN: llc < %s -tailcallopt -mtriple=x86_64-linux-gnu | FileCheck %s
2+
3+
; Check the GHC call convention works (x86-64)
4+
5+
@base = external global i64 ; assigned to register: R13
6+
@sp = external global i64 ; assigned to register: RBP
7+
@hp = external global i64 ; assigned to register: R12
8+
@r1 = external global i64 ; assigned to register: RBX
9+
@r2 = external global i64 ; assigned to register: R14
10+
@r3 = external global i64 ; assigned to register: RSI
11+
@r4 = external global i64 ; assigned to register: RDI
12+
@r5 = external global i64 ; assigned to register: R8
13+
@r6 = external global i64 ; assigned to register: R9
14+
@splim = external global i64 ; assigned to register: R15
15+
16+
@f1 = external global float ; assigned to register: XMM1
17+
@f2 = external global float ; assigned to register: XMM2
18+
@f3 = external global float ; assigned to register: XMM3
19+
@f4 = external global float ; assigned to register: XMM4
20+
@d1 = external global double ; assigned to register: XMM5
21+
@d2 = external global double ; assigned to register: XMM6
22+
23+
define void @zap(i64 %a, i64 %b) nounwind {
24+
entry:
25+
; CHECK: movq %rdi, %r13
26+
; CHECK-NEXT: movq %rsi, %rbp
27+
; CHECK-NEXT: callq addtwo
28+
%0 = call cc 10 i64 @addtwo(i64 %a, i64 %b)
29+
; CHECK: callq foo
30+
call void @foo() nounwind
31+
ret void
32+
}
33+
34+
define cc 10 i64 @addtwo(i64 %x, i64 %y) nounwind {
35+
entry:
36+
; CHECK: leaq (%r13,%rbp), %rax
37+
%0 = add i64 %x, %y
38+
; CHECK-NEXT: ret
39+
ret i64 %0
40+
}
41+
42+
define cc 10 void @foo() nounwind {
43+
entry:
44+
; CHECK: movq base(%rip), %r13
45+
; CHECK-NEXT: movq sp(%rip), %rbp
46+
; CHECK-NEXT: movq hp(%rip), %r12
47+
; CHECK-NEXT: movq r1(%rip), %rbx
48+
; CHECK-NEXT: movq r2(%rip), %r14
49+
; CHECK-NEXT: movq r3(%rip), %rsi
50+
; CHECK-NEXT: movq r4(%rip), %rdi
51+
; CHECK-NEXT: movq r5(%rip), %r8
52+
; CHECK-NEXT: movq r6(%rip), %r9
53+
; CHECK-NEXT: movq splim(%rip), %r15
54+
; CHECK-NEXT: movss f1(%rip), %xmm1
55+
; CHECK-NEXT: movss f2(%rip), %xmm2
56+
; CHECK-NEXT: movss f3(%rip), %xmm3
57+
; CHECK-NEXT: movss f4(%rip), %xmm4
58+
; CHECK-NEXT: movsd d1(%rip), %xmm5
59+
; CHECK-NEXT: movsd d2(%rip), %xmm6
60+
%0 = load double* @d2
61+
%1 = load double* @d1
62+
%2 = load float* @f4
63+
%3 = load float* @f3
64+
%4 = load float* @f2
65+
%5 = load float* @f1
66+
%6 = load i64* @splim
67+
%7 = load i64* @r6
68+
%8 = load i64* @r5
69+
%9 = load i64* @r4
70+
%10 = load i64* @r3
71+
%11 = load i64* @r2
72+
%12 = load i64* @r1
73+
%13 = load i64* @hp
74+
%14 = load i64* @sp
75+
%15 = load i64* @base
76+
; CHECK: jmp bar
77+
tail call cc 10 void @bar( i64 %15, i64 %14, i64 %13, i64 %12, i64 %11,
78+
i64 %10, i64 %9, i64 %8, i64 %7, i64 %6,
79+
float %5, float %4, float %3, float %2, double %1,
80+
double %0 ) nounwind
81+
ret void
82+
}
83+
84+
declare cc 10 void @bar(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64,
85+
float, float, float, float, double, double)
86+

0 commit comments

Comments
 (0)