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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
|
/*
* Copyright (C) 2012-2019 Free Software Foundation, Inc.
*
* This file is part of GNU lightning.
*
* GNU lightning is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU lightning is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* Authors:
* Paulo Cesar Pereira de Andrade
*/
#include "mips-cpu.c"
#include "mips-fpu.c"
static const jit_gpr_t abi_gpr_args[] = {
_A0, _A1, _A2, _A3,
#if NEW_ABI
_A4, _A5, _A6, _A7,
#endif
};
static const jit_fpr_t abi_fpr_args[] = {
#if NEW_ABI
_F12, _F13, _F14, _F15, _F16, _F17, _F18, _F19
#else
_F12, _F14
#endif
};
static const int abi_gpr_arg_count =
sizeof(abi_gpr_args) / sizeof(abi_gpr_args[0]);
static const int abi_fpr_arg_count =
sizeof(abi_fpr_args) / sizeof(abi_fpr_args[0]);
struct abi_arg_iterator {
const jit_operand_t *args;
int argc;
int arg_idx;
#if !NEW_ABI
int gpr_used;
int gpr_idx;
int fpr_idx;
#endif
jit_word_t stack_size;
int stack_padding;
};
static size_t page_size;
/*
* Implementation
*/
static jit_bool_t
has_fpu()
{
#if __mips_hard_float
return 1;
#else
return 0;
#endif
}
jit_bool_t
jit_get_cpu(void)
{
page_size = sysconf(_SC_PAGE_SIZE);
/*
* TODO: extensions?
*/
return has_fpu();
}
jit_bool_t
jit_init(jit_state_t * _jit)
{
(void) _jit;
return has_fpu();
}
static size_t
jit_initial_frame_size(void)
{
return 0;
}
static void
reset_abi_arg_iterator(struct abi_arg_iterator *iter, size_t argc,
const jit_operand_t * args)
{
memset(iter, 0, sizeof(*iter));
iter->argc = argc;
iter->args = args;
#if !NEW_ABI
iter->stack_size = 16;
#endif
}
#if !NEW_ABI
static int
jit_operand_abi_sizeof(enum jit_operand_abi abi)
{
switch (abi) {
case JIT_OPERAND_ABI_UINT8:
case JIT_OPERAND_ABI_INT8:
return 1;
case JIT_OPERAND_ABI_UINT16:
case JIT_OPERAND_ABI_INT16:
return 2;
case JIT_OPERAND_ABI_UINT32:
case JIT_OPERAND_ABI_INT32:
return 4;
case JIT_OPERAND_ABI_UINT64:
case JIT_OPERAND_ABI_INT64:
return 8;
case JIT_OPERAND_ABI_POINTER:
return CHOOSE_32_64(4, 8);
case JIT_OPERAND_ABI_FLOAT:
return 4;
case JIT_OPERAND_ABI_DOUBLE:
return 8;
default:
abort();
}
}
#endif
static void
next_abi_arg(struct abi_arg_iterator *iter, jit_operand_t * arg)
{
ASSERT(iter->arg_idx < iter->argc);
enum jit_operand_abi abi = iter->args[iter->arg_idx].abi;
#if NEW_ABI
int idx = iter->arg_idx++;
/*
* on new abi the first eight arguments of any type are passed in
* registers
*/
if (is_gpr_arg(abi) && idx < 8) {
*arg = jit_operand_gpr(abi, abi_gpr_args[idx]);
return;
}
if (is_fpr_arg(abi) && idx < 8) {
*arg = jit_operand_fpr(abi, abi_fpr_args[idx]);
return;
}
*arg = jit_operand_mem(abi, JIT_SP, iter->stack_size);
iter->stack_size += 8;
#else
/*
* O32 argument passing is a bit of a mess
*/
iter->arg_idx++;
if (is_gpr_arg(abi) && iter->gpr_idx < abi_gpr_arg_count) {
*arg = jit_operand_gpr(abi, abi_gpr_args[iter->gpr_idx]);
iter->gpr_used = 1;
iter->gpr_idx++;
return;
}
if (is_fpr_arg(abi) && iter->gpr_idx <= 3) {
if (abi == JIT_OPERAND_ABI_DOUBLE && iter->gpr_idx % 2 != 0)
iter->gpr_idx++;
if (!iter->gpr_used && iter->fpr_idx < abi_fpr_arg_count)
*arg = jit_operand_fpr(abi, abi_fpr_args[iter->fpr_idx]);
else if (abi == JIT_OPERAND_ABI_FLOAT) {
*arg = jit_operand_gpr(abi, abi_gpr_args[iter->gpr_idx]);
} else {
*arg = jit_operand_gpr_pair(abi,
abi_gpr_args[iter->gpr_idx + 0],
abi_gpr_args[iter->gpr_idx + 1]);
}
iter->fpr_idx++;
iter->gpr_idx += abi == JIT_OPERAND_ABI_DOUBLE ? 2 : 1;
return;
}
size_t abi_size = jit_operand_abi_sizeof(abi);
abi_size = jit_align_up(abi_size, 4);
iter->stack_size = jit_align_up(iter->stack_size, abi_size);
*arg = jit_operand_mem(abi, JIT_SP, iter->stack_size);
iter->stack_size += abi_size;
#endif
}
static void
jit_flush(void *fptr, void *tptr)
{
jit_word_t f = (jit_word_t) fptr & -page_size;
jit_word_t t = (((jit_word_t) tptr) + page_size - 1) & -page_size;
/* libgcc's __clear_cache is apparently in some situations a no-op:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90929
*
* use __builtin_ instead, seems to work on real hardware
*/
__builtin___clear_cache((void *) f, (void *) t);
}
static inline size_t
jit_stack_alignment(void)
{
#if NEW_ABI
return 16;
#else
return 8;
#endif
}
static void
jit_try_shorten(jit_state_t * _jit, jit_reloc_t reloc, jit_pointer_t addr)
{
(void) _jit;
(void) reloc;
(void) addr;
}
static void *
bless_function_pointer(void *ptr)
{
return ptr;
}
/*
* Jumps around the veneer
*/
static void
patch_jmp_without_veneer(jit_state_t * _jit, uint32_t * loc)
{
patch_jmp_offset(loc, _jit->pc.ui - loc);
}
static uint32_t *
jmp_without_veneer(jit_state_t * _jit)
{
uint32_t *loc = _jit->pc.ui;
emit_u32(_jit, _BEQ(rn(_ZERO), rn(_ZERO), 0));
/* branch delay slot */
emit_u32(_jit, _NOP(1));
return loc;
}
/*
* Load from pool offset
*/
static void
patch_load_from_pool_offset(uint32_t * loc, int32_t v)
{
/*
* not used by this backend
*/
(void) loc;
(void) v;
abort();
}
static int32_t
read_load_from_pool_offset(uint32_t * loc)
{
/*
* not used by this backend
*/
(void) loc;
abort();
return 0;
}
|