1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
/*
* Copyright (C) 1998-2000 Hewlett-Packard Co
* Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
#ifndef __GCC_MULTIREG_RETVALS__
/*
* gcc currently does not conform to the ia-64 calling
* convention as far as returning function values are
* concerned. Instead of returning values up to 32 bytes in
* size in r8-r11, gcc returns any value bigger than a
* doubleword via a structure that's allocated by the caller
* and whose address is passed into the function. Since
* SAL_PROC returns values according to the calling
* convention, this stub takes care of copying r8-r11 to the
* place where gcc expects them.
*/
.text
.psr abi64
.psr lsb
.lsb
.align 16
.global ia64_sal_stub
ia64_sal_stub:
/*
* Sheesh, the Cygnus backend passes the pointer to a return value structure in
* in0 whereas the HP backend passes it in r8. Don't you hate those little
* differences...
*/
#ifdef GCC_RETVAL_POINTER_IN_R8
adds r2=-24,sp
adds sp=-48,sp
mov r14=rp
;;
st8 [r2]=r8,8 // save pointer to return value
addl r3=@ltoff(ia64_sal),gp
;;
ld8 r3=[r3]
st8 [r2]=gp,8 // save global pointer
;;
ld8 r3=[r3] // fetch the value of ia64_sal
st8 [r2]=r14 // save return pointer
;;
ld8 r2=[r3],8 // load function's entry point
;;
ld8 gp=[r3] // load function's global pointer
;;
mov b6=r2
br.call.sptk.few rp=b6
.ret0: adds r2=24,sp
;;
ld8 r3=[r2],8 // restore pointer to return value
;;
ld8 gp=[r2],8 // restore global pointer
st8 [r3]=r8,8
;;
ld8 r14=[r2] // restore return pointer
st8 [r3]=r9,8
;;
mov rp=r14
st8 [r3]=r10,8
;;
st8 [r3]=r11,8
adds sp=48,sp
br.sptk.few rp
#else
/*
* On input:
* in0 = pointer to return value structure
* in1 = index of SAL function to call
* in2..inN = remaining args to SAL call
*/
/*
* We allocate one input and eight output register such that the br.call instruction
* will rename in1-in7 to in0-in6---exactly what we want because SAL doesn't want to
* see the pointer to the return value structure.
*/
alloc r15=ar.pfs,1,0,8,0
adds r2=-24,sp
adds sp=-48,sp
mov r14=rp
;;
st8 [r2]=r15,8 // save ar.pfs
addl r3=@ltoff(ia64_sal),gp
;;
ld8 r3=[r3] // get address of ia64_sal
st8 [r2]=gp,8 // save global pointer
;;
ld8 r3=[r3] // get value of ia64_sal
st8 [r2]=r14,8 // save return address (rp)
;;
ld8 r2=[r3],8 // load function's entry point
;;
ld8 gp=[r3] // load function's global pointer
mov b6=r2
br.call.sptk.few rp=b6 // make SAL call
.ret0: adds r2=24,sp
;;
ld8 r15=[r2],8 // restore ar.pfs
;;
ld8 gp=[r2],8 // restore global pointer
st8 [in0]=r8,8 // store 1. dword of return value
;;
ld8 r14=[r2] // restore return address (rp)
st8 [in0]=r9,8 // store 2. dword of return value
;;
mov rp=r14
st8 [in0]=r10,8 // store 3. dword of return value
;;
st8 [in0]=r11,8
adds sp=48,sp // pop stack frame
mov ar.pfs=r15
br.ret.sptk.few rp
#endif
.endp ia64_sal_stub
#endif /* __GCC_MULTIREG_RETVALS__ */
|