1/*
2** FFI C call handling.
3** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#ifndef _LJ_CCALL_H
7#define _LJ_CCALL_H
8
9#include "lj_obj.h"
10#include "lj_ctype.h"
11
12#if LJ_HASFFI
13
14/* -- C calling conventions ----------------------------------------------- */
15
16#if LJ_TARGET_X86ORX64
17
18#if LJ_TARGET_X86
19#define CCALL_NARG_GPR 2 /* For fastcall arguments. */
20#define CCALL_NARG_FPR 0
21#define CCALL_NRET_GPR 2
22#define CCALL_NRET_FPR 1 /* For FP results on x87 stack. */
23#define CCALL_ALIGN_STACKARG 0 /* Don't align argument on stack. */
24#elif LJ_ABI_WIN
25#define CCALL_NARG_GPR 4
26#define CCALL_NARG_FPR 4
27#define CCALL_NRET_GPR 1
28#define CCALL_NRET_FPR 1
29#define CCALL_SPS_EXTRA 4
30#else
31#define CCALL_NARG_GPR 6
32#define CCALL_NARG_FPR 8
33#define CCALL_NRET_GPR 2
34#define CCALL_NRET_FPR 2
35#define CCALL_VECTOR_REG 1 /* Pass vectors in registers. */
36#endif
37
38#define CCALL_SPS_FREE 1
39#define CCALL_ALIGN_CALLSTATE 16
40
41typedef LJ_ALIGN(16) union FPRArg {
42 double d[2];
43 float f[4];
44 uint8_t b[16];
45 uint16_t s[8];
46 int i[4];
47 int64_t l[2];
48} FPRArg;
49
50typedef intptr_t GPRArg;
51
52#elif LJ_TARGET_ARM
53
54#define CCALL_NARG_GPR 4
55#define CCALL_NRET_GPR 2 /* For softfp double. */
56#if LJ_ABI_SOFTFP
57#define CCALL_NARG_FPR 0
58#define CCALL_NRET_FPR 0
59#else
60#define CCALL_NARG_FPR 8
61#define CCALL_NRET_FPR 4
62#endif
63#define CCALL_SPS_FREE 0
64
65typedef intptr_t GPRArg;
66typedef union FPRArg {
67 double d;
68 float f[2];
69} FPRArg;
70
71#elif LJ_TARGET_ARM64
72
73#define CCALL_NARG_GPR 8
74#define CCALL_NRET_GPR 2
75#define CCALL_NARG_FPR 8
76#define CCALL_NRET_FPR 4
77#define CCALL_SPS_FREE 0
78
79typedef intptr_t GPRArg;
80typedef union FPRArg {
81 double d;
82 struct { LJ_ENDIAN_LOHI(float f; , float g;) };
83 struct { LJ_ENDIAN_LOHI(uint32_t lo; , uint32_t hi;) };
84} FPRArg;
85
86#elif LJ_TARGET_PPC
87
88#define CCALL_NARG_GPR 8
89#define CCALL_NARG_FPR (LJ_ABI_SOFTFP ? 0 : 8)
90#define CCALL_NRET_GPR 4 /* For complex double. */
91#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 1)
92#define CCALL_SPS_EXTRA 4
93#define CCALL_SPS_FREE 0
94
95typedef intptr_t GPRArg;
96typedef double FPRArg;
97
98#elif LJ_TARGET_MIPS32
99
100#define CCALL_NARG_GPR 4
101#define CCALL_NARG_FPR (LJ_ABI_SOFTFP ? 0 : 2)
102#define CCALL_NRET_GPR (LJ_ABI_SOFTFP ? 4 : 2)
103#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 2)
104#define CCALL_SPS_EXTRA 7
105#define CCALL_SPS_FREE 1
106
107typedef intptr_t GPRArg;
108typedef union FPRArg {
109 double d;
110 struct { LJ_ENDIAN_LOHI(float f; , float g;) };
111} FPRArg;
112
113#elif LJ_TARGET_MIPS64
114
115/* FP args are positional and overlay the GPR array. */
116#define CCALL_NARG_GPR 8
117#define CCALL_NARG_FPR 0
118#define CCALL_NRET_GPR 2
119#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 2)
120#define CCALL_SPS_EXTRA 3
121#define CCALL_SPS_FREE 1
122
123typedef intptr_t GPRArg;
124typedef union FPRArg {
125 double d;
126 struct { LJ_ENDIAN_LOHI(float f; , float g;) };
127} FPRArg;
128
129#else
130#error "Missing calling convention definitions for this architecture"
131#endif
132
133#ifndef CCALL_SPS_EXTRA
134#define CCALL_SPS_EXTRA 0
135#endif
136#ifndef CCALL_VECTOR_REG
137#define CCALL_VECTOR_REG 0
138#endif
139#ifndef CCALL_ALIGN_STACKARG
140#define CCALL_ALIGN_STACKARG 1
141#endif
142#ifndef CCALL_ALIGN_CALLSTATE
143#define CCALL_ALIGN_CALLSTATE 8
144#endif
145
146#define CCALL_NUM_GPR \
147 (CCALL_NARG_GPR > CCALL_NRET_GPR ? CCALL_NARG_GPR : CCALL_NRET_GPR)
148#define CCALL_NUM_FPR \
149 (CCALL_NARG_FPR > CCALL_NRET_FPR ? CCALL_NARG_FPR : CCALL_NRET_FPR)
150
151/* Check against constants in lj_ctype.h. */
152LJ_STATIC_ASSERT(CCALL_NUM_GPR <= CCALL_MAX_GPR);
153LJ_STATIC_ASSERT(CCALL_NUM_FPR <= CCALL_MAX_FPR);
154
155#define CCALL_MAXSTACK 32
156
157/* -- C call state -------------------------------------------------------- */
158
159typedef LJ_ALIGN(CCALL_ALIGN_CALLSTATE) struct CCallState {
160 void (*func)(void); /* Pointer to called function. */
161 uint32_t spadj; /* Stack pointer adjustment. */
162 uint8_t nsp; /* Number of stack slots. */
163 uint8_t retref; /* Return value by reference. */
164#if LJ_TARGET_X64
165 uint8_t ngpr; /* Number of arguments in GPRs. */
166 uint8_t nfpr; /* Number of arguments in FPRs. */
167#elif LJ_TARGET_X86
168 uint8_t resx87; /* Result on x87 stack: 1:float, 2:double. */
169#elif LJ_TARGET_ARM64
170 void *retp; /* Aggregate return pointer in x8. */
171#elif LJ_TARGET_PPC
172 uint8_t nfpr; /* Number of arguments in FPRs. */
173#endif
174#if LJ_32
175 int32_t align1;
176#endif
177#if CCALL_NUM_FPR
178 FPRArg fpr[CCALL_NUM_FPR]; /* Arguments/results in FPRs. */
179#endif
180 GPRArg gpr[CCALL_NUM_GPR]; /* Arguments/results in GPRs. */
181 GPRArg stack[CCALL_MAXSTACK]; /* Stack slots. */
182} CCallState;
183
184/* -- C call handling ----------------------------------------------------- */
185
186/* Really belongs to lj_vm.h. */
187LJ_ASMF void LJ_FASTCALL lj_vm_ffi_call(CCallState *cc);
188
189LJ_FUNC CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o);
190LJ_FUNC int lj_ccall_func(lua_State *L, GCcdata *cd);
191
192#endif
193
194#endif
195