blob: b0ad3f04f303b6ae1f682a33daae0beccf48d604 [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
Damien13ed3a62013-10-08 09:05:10 +010027// Essentially normal Python has 1 type: Python objects
28// Viper has more than 1 type, and is just a more complicated (a superset of) Python.
29// If you declare everything in Viper as a Python object (ie omit type decls) then
30// it should in principle be exactly the same as Python native.
31// Having types means having more opcodes, like binary_op_nat_nat, binary_op_nat_obj etc.
32// In practice we won't have a VM but rather do this in asm which is actually very minimal.
33
34// Because it breaks strict Python equivalence it should be a completely separate
35// decorator. It breaks equivalence because overflow on integers wraps around.
36// It shouldn't break equivalence if you don't use the new types, but since the
37// type decls might be used in normal Python for other reasons, it's probably safest,
38// cleanest and clearest to make it a separate decorator.
39
40// Actually, it does break equivalence because integers default to native integers,
41// not Python objects.
42
43// for x in l[0:8]: can be compiled into a native loop if l has pointer type
44
Damien13ed3a62013-10-08 09:05:10 +010045#include <stdio.h>
46#include <string.h>
47#include <assert.h>
48
Damien George51dfcb42015-01-01 20:27:54 +000049#include "py/nlr.h"
50#include "py/emit.h"
Damien13ed3a62013-10-08 09:05:10 +010051
Damien Georgecdd96df2014-04-06 12:58:40 +010052#if 0 // print debugging info
53#define DEBUG_PRINT (1)
54#define DEBUG_printf DEBUG_printf
55#else // don't print debugging info
56#define DEBUG_printf(...) (void)0
57#endif
58
Damien13ed3a62013-10-08 09:05:10 +010059// wrapper around everything in this file
Damien Georgec90f59e2014-09-06 23:06:36 +010060#if (MICROPY_EMIT_X64 && N_X64) \
61 || (MICROPY_EMIT_X86 && N_X86) \
62 || (MICROPY_EMIT_THUMB && N_THUMB) \
63 || (MICROPY_EMIT_ARM && N_ARM)
Damien13ed3a62013-10-08 09:05:10 +010064
Damien3ef4abb2013-10-12 16:53:13 +010065#if N_X64
Damien13ed3a62013-10-08 09:05:10 +010066
67// x64 specific stuff
68
Damien George51dfcb42015-01-01 20:27:54 +000069#include "py/asmx64.h"
Damien13ed3a62013-10-08 09:05:10 +010070
Damien13ed3a62013-10-08 09:05:10 +010071#define EXPORT_FUN(name) emit_native_x64_##name
72
Damien George0b610de2014-09-29 16:25:04 +010073#define REG_RET ASM_X64_REG_RAX
74#define REG_ARG_1 ASM_X64_REG_RDI
75#define REG_ARG_2 ASM_X64_REG_RSI
76#define REG_ARG_3 ASM_X64_REG_RDX
77#define REG_ARG_4 ASM_X64_REG_RCX
Damien Georgec90f59e2014-09-06 23:06:36 +010078
Damien George81057362014-09-07 01:06:19 +010079// caller-save
Damien George0b610de2014-09-29 16:25:04 +010080#define REG_TEMP0 ASM_X64_REG_RAX
81#define REG_TEMP1 ASM_X64_REG_RDI
82#define REG_TEMP2 ASM_X64_REG_RSI
Damien George81057362014-09-07 01:06:19 +010083
84// callee-save
Damien George0b610de2014-09-29 16:25:04 +010085#define REG_LOCAL_1 ASM_X64_REG_RBX
86#define REG_LOCAL_2 ASM_X64_REG_R12
87#define REG_LOCAL_3 ASM_X64_REG_R13
Damien George81057362014-09-07 01:06:19 +010088#define REG_LOCAL_NUM (3)
Damien Georgec90f59e2014-09-06 23:06:36 +010089
90#define ASM_PASS_COMPUTE ASM_X64_PASS_COMPUTE
91#define ASM_PASS_EMIT ASM_X64_PASS_EMIT
92
93#define ASM_T asm_x64_t
94#define ASM_NEW asm_x64_new
95#define ASM_FREE asm_x64_free
96#define ASM_GET_CODE asm_x64_get_code
97#define ASM_GET_CODE_SIZE asm_x64_get_code_size
98#define ASM_START_PASS asm_x64_start_pass
99#define ASM_END_PASS asm_x64_end_pass
100#define ASM_ENTRY asm_x64_entry
101#define ASM_EXIT asm_x64_exit
102
103#define ASM_LABEL_ASSIGN asm_x64_label_assign
104#define ASM_JUMP asm_x64_jmp_label
105#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
106 do { \
107 asm_x64_test_r8_with_r8(as, reg, reg); \
108 asm_x64_jcc_label(as, ASM_X64_CC_JZ, label); \
109 } while (0)
110#define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \
111 do { \
112 asm_x64_test_r8_with_r8(as, reg, reg); \
113 asm_x64_jcc_label(as, ASM_X64_CC_JNZ, label); \
114 } while (0)
115#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
116 do { \
117 asm_x64_cmp_r64_with_r64(as, reg1, reg2); \
118 asm_x64_jcc_label(as, ASM_X64_CC_JE, label); \
119 } while (0)
Damien George0b610de2014-09-29 16:25:04 +0100120#define ASM_CALL_IND(as, ptr, idx) asm_x64_call_ind(as, ptr, ASM_X64_REG_RAX)
Damien Georgec90f59e2014-09-06 23:06:36 +0100121
122#define ASM_MOV_REG_TO_LOCAL asm_x64_mov_r64_to_local
123#define ASM_MOV_IMM_TO_REG asm_x64_mov_i64_to_r64_optimised
124#define ASM_MOV_ALIGNED_IMM_TO_REG asm_x64_mov_i64_to_r64_aligned
125#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
126 do { \
127 asm_x64_mov_i64_to_r64_optimised(as, (imm), (reg_temp)); \
128 asm_x64_mov_r64_to_local(as, (reg_temp), (local_num)); \
129 } while (false)
130#define ASM_MOV_LOCAL_TO_REG asm_x64_mov_local_to_r64
Damien George3112cde2014-09-29 18:45:42 +0100131#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src))
Damien Georgec90f59e2014-09-06 23:06:36 +0100132#define ASM_MOV_LOCAL_ADDR_TO_REG asm_x64_mov_local_addr_to_r64
133
Damien George3112cde2014-09-29 18:45:42 +0100134#define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg))
135#define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg))
Damien George1ef23482014-10-12 14:21:06 +0100136#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x64_or_r64_r64((as), (reg_dest), (reg_src))
137#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x64_xor_r64_r64((as), (reg_dest), (reg_src))
138#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_x64_and_r64_r64((as), (reg_dest), (reg_src))
Damien George3112cde2014-09-29 18:45:42 +0100139#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x64_add_r64_r64((as), (reg_dest), (reg_src))
140#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x64_sub_r64_r64((as), (reg_dest), (reg_src))
141
Damien George91cfd412014-10-12 16:59:29 +0100142#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem64_to_r64((as), (reg_base), 0, (reg_dest))
Damien George4cd9ced2015-01-15 14:41:41 +0000143#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (word_offset), (reg_dest))
Damien George91cfd412014-10-12 16:59:29 +0100144#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem8_to_r64zx((as), (reg_base), 0, (reg_dest))
145#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 0, (reg_dest))
146
147#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 0)
Damien George4cd9ced2015-01-15 14:41:41 +0000148#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (word_offset))
Damien George91cfd412014-10-12 16:59:29 +0100149#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), 0)
150#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 0)
Damien Georgee9dac3b2014-09-29 22:10:41 +0100151
Damien Georgec90f59e2014-09-06 23:06:36 +0100152#elif N_X86
153
154// x86 specific stuff
155
Damien George51dfcb42015-01-01 20:27:54 +0000156#include "py/asmx86.h"
Damien Georgec90f59e2014-09-06 23:06:36 +0100157
158STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
159 [MP_F_CONVERT_OBJ_TO_NATIVE] = 2,
160 [MP_F_CONVERT_NATIVE_TO_OBJ] = 2,
Damien Georgec90f59e2014-09-06 23:06:36 +0100161 [MP_F_LOAD_CONST_STR] = 1,
162 [MP_F_LOAD_CONST_BYTES] = 1,
163 [MP_F_LOAD_NAME] = 1,
164 [MP_F_LOAD_GLOBAL] = 1,
165 [MP_F_LOAD_BUILD_CLASS] = 0,
166 [MP_F_LOAD_ATTR] = 2,
167 [MP_F_LOAD_METHOD] = 3,
168 [MP_F_STORE_NAME] = 2,
169 [MP_F_STORE_GLOBAL] = 2,
170 [MP_F_STORE_ATTR] = 3,
171 [MP_F_OBJ_SUBSCR] = 3,
172 [MP_F_OBJ_IS_TRUE] = 1,
173 [MP_F_UNARY_OP] = 2,
174 [MP_F_BINARY_OP] = 3,
175 [MP_F_BUILD_TUPLE] = 2,
176 [MP_F_BUILD_LIST] = 2,
177 [MP_F_LIST_APPEND] = 2,
178 [MP_F_BUILD_MAP] = 1,
179 [MP_F_STORE_MAP] = 3,
180#if MICROPY_PY_BUILTINS_SET
181 [MP_F_BUILD_SET] = 2,
182 [MP_F_STORE_SET] = 2,
183#endif
184 [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3,
185 [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3,
186 [MP_F_CALL_METHOD_N_KW] = 3,
187 [MP_F_GETITER] = 1,
188 [MP_F_ITERNEXT] = 1,
189 [MP_F_NLR_PUSH] = 1,
190 [MP_F_NLR_POP] = 0,
191 [MP_F_NATIVE_RAISE] = 1,
192 [MP_F_IMPORT_NAME] = 3,
193 [MP_F_IMPORT_FROM] = 2,
194 [MP_F_IMPORT_ALL] = 1,
195#if MICROPY_PY_BUILTINS_SLICE
196 [MP_F_NEW_SLICE] = 3,
197#endif
198 [MP_F_UNPACK_SEQUENCE] = 3,
199 [MP_F_UNPACK_EX] = 3,
200 [MP_F_DELETE_NAME] = 1,
201 [MP_F_DELETE_GLOBAL] = 1,
Damien George99957382015-04-03 14:38:41 +0000202 [MP_F_NEW_CELL] = 1,
203 [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,
Damien Georgec90f59e2014-09-06 23:06:36 +0100204};
205
206#define EXPORT_FUN(name) emit_native_x86_##name
207
Damien George0b610de2014-09-29 16:25:04 +0100208#define REG_RET ASM_X86_REG_EAX
Damien George6eae8612014-09-08 22:16:35 +0000209#define REG_ARG_1 ASM_X86_REG_ARG_1
210#define REG_ARG_2 ASM_X86_REG_ARG_2
211#define REG_ARG_3 ASM_X86_REG_ARG_3
Damien George81057362014-09-07 01:06:19 +0100212
Damien George25d90412014-09-06 23:24:32 +0000213// caller-save, so can be used as temporaries
Damien George0b610de2014-09-29 16:25:04 +0100214#define REG_TEMP0 ASM_X86_REG_EAX
215#define REG_TEMP1 ASM_X86_REG_ECX
216#define REG_TEMP2 ASM_X86_REG_EDX
Damien Georgec90f59e2014-09-06 23:06:36 +0100217
Damien George25d90412014-09-06 23:24:32 +0000218// callee-save, so can be used as locals
Damien George0b610de2014-09-29 16:25:04 +0100219#define REG_LOCAL_1 ASM_X86_REG_EBX
220#define REG_LOCAL_2 ASM_X86_REG_ESI
221#define REG_LOCAL_3 ASM_X86_REG_EDI
Damien George25d90412014-09-06 23:24:32 +0000222#define REG_LOCAL_NUM (3)
Damien Georgec90f59e2014-09-06 23:06:36 +0100223
224#define ASM_PASS_COMPUTE ASM_X86_PASS_COMPUTE
225#define ASM_PASS_EMIT ASM_X86_PASS_EMIT
226
227#define ASM_T asm_x86_t
228#define ASM_NEW asm_x86_new
229#define ASM_FREE asm_x86_free
230#define ASM_GET_CODE asm_x86_get_code
231#define ASM_GET_CODE_SIZE asm_x86_get_code_size
232#define ASM_START_PASS asm_x86_start_pass
233#define ASM_END_PASS asm_x86_end_pass
234#define ASM_ENTRY asm_x86_entry
235#define ASM_EXIT asm_x86_exit
236
237#define ASM_LABEL_ASSIGN asm_x86_label_assign
238#define ASM_JUMP asm_x86_jmp_label
239#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
240 do { \
241 asm_x86_test_r8_with_r8(as, reg, reg); \
242 asm_x86_jcc_label(as, ASM_X86_CC_JZ, label); \
243 } while (0)
244#define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \
245 do { \
246 asm_x86_test_r8_with_r8(as, reg, reg); \
247 asm_x86_jcc_label(as, ASM_X86_CC_JNZ, label); \
248 } while (0)
249#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
250 do { \
251 asm_x86_cmp_r32_with_r32(as, reg1, reg2); \
252 asm_x86_jcc_label(as, ASM_X86_CC_JE, label); \
253 } while (0)
Damien George0b610de2014-09-29 16:25:04 +0100254#define ASM_CALL_IND(as, ptr, idx) asm_x86_call_ind(as, ptr, mp_f_n_args[idx], ASM_X86_REG_EAX)
Damien Georgec90f59e2014-09-06 23:06:36 +0100255
256#define ASM_MOV_REG_TO_LOCAL asm_x86_mov_r32_to_local
257#define ASM_MOV_IMM_TO_REG asm_x86_mov_i32_to_r32
258#define ASM_MOV_ALIGNED_IMM_TO_REG asm_x86_mov_i32_to_r32_aligned
259#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
260 do { \
261 asm_x86_mov_i32_to_r32(as, (imm), (reg_temp)); \
262 asm_x86_mov_r32_to_local(as, (reg_temp), (local_num)); \
263 } while (false)
264#define ASM_MOV_LOCAL_TO_REG asm_x86_mov_local_to_r32
Damien George3112cde2014-09-29 18:45:42 +0100265#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src))
Damien Georgec90f59e2014-09-06 23:06:36 +0100266#define ASM_MOV_LOCAL_ADDR_TO_REG asm_x86_mov_local_addr_to_r32
Damien13ed3a62013-10-08 09:05:10 +0100267
Damien George3112cde2014-09-29 18:45:42 +0100268#define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg))
269#define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg))
Damien George1ef23482014-10-12 14:21:06 +0100270#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x86_or_r32_r32((as), (reg_dest), (reg_src))
271#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x86_xor_r32_r32((as), (reg_dest), (reg_src))
272#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_x86_and_r32_r32((as), (reg_dest), (reg_src))
Damien George3112cde2014-09-29 18:45:42 +0100273#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x86_add_r32_r32((as), (reg_dest), (reg_src))
274#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x86_sub_r32_r32((as), (reg_dest), (reg_src))
275
Damien George91cfd412014-10-12 16:59:29 +0100276#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest))
Damien George99957382015-04-03 14:38:41 +0000277#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (word_offset), (reg_dest))
Damien George3c34d412014-10-12 16:10:25 +0000278#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem8_to_r32zx((as), (reg_base), 0, (reg_dest))
279#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 0, (reg_dest))
Damien George91cfd412014-10-12 16:59:29 +0100280
281#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0)
Damien George99957382015-04-03 14:38:41 +0000282#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (word_offset))
Damien George91cfd412014-10-12 16:59:29 +0100283#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), 0)
284#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 0)
Damien Georgee9dac3b2014-09-29 22:10:41 +0100285
Damien3ef4abb2013-10-12 16:53:13 +0100286#elif N_THUMB
Damien13ed3a62013-10-08 09:05:10 +0100287
288// thumb specific stuff
289
Damien George51dfcb42015-01-01 20:27:54 +0000290#include "py/asmthumb.h"
Damien13ed3a62013-10-08 09:05:10 +0100291
Damien13ed3a62013-10-08 09:05:10 +0100292#define EXPORT_FUN(name) emit_native_thumb_##name
293
Damien George0b610de2014-09-29 16:25:04 +0100294#define REG_RET ASM_THUMB_REG_R0
295#define REG_ARG_1 ASM_THUMB_REG_R0
296#define REG_ARG_2 ASM_THUMB_REG_R1
297#define REG_ARG_3 ASM_THUMB_REG_R2
298#define REG_ARG_4 ASM_THUMB_REG_R3
Damien George81057362014-09-07 01:06:19 +0100299
Damien George0b610de2014-09-29 16:25:04 +0100300#define REG_TEMP0 ASM_THUMB_REG_R0
301#define REG_TEMP1 ASM_THUMB_REG_R1
302#define REG_TEMP2 ASM_THUMB_REG_R2
Damien Georgec90f59e2014-09-06 23:06:36 +0100303
Damien George0b610de2014-09-29 16:25:04 +0100304#define REG_LOCAL_1 ASM_THUMB_REG_R4
305#define REG_LOCAL_2 ASM_THUMB_REG_R5
306#define REG_LOCAL_3 ASM_THUMB_REG_R6
Damien Georgec90f59e2014-09-06 23:06:36 +0100307#define REG_LOCAL_NUM (3)
308
309#define ASM_PASS_COMPUTE ASM_THUMB_PASS_COMPUTE
310#define ASM_PASS_EMIT ASM_THUMB_PASS_EMIT
311
312#define ASM_T asm_thumb_t
313#define ASM_NEW asm_thumb_new
314#define ASM_FREE asm_thumb_free
315#define ASM_GET_CODE asm_thumb_get_code
316#define ASM_GET_CODE_SIZE asm_thumb_get_code_size
317#define ASM_START_PASS asm_thumb_start_pass
318#define ASM_END_PASS asm_thumb_end_pass
319#define ASM_ENTRY asm_thumb_entry
320#define ASM_EXIT asm_thumb_exit
321
322#define ASM_LABEL_ASSIGN asm_thumb_label_assign
323#define ASM_JUMP asm_thumb_b_label
324#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
325 do { \
326 asm_thumb_cmp_rlo_i8(as, reg, 0); \
Damien George0b610de2014-09-29 16:25:04 +0100327 asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \
Damien Georgec90f59e2014-09-06 23:06:36 +0100328 } while (0)
329#define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \
330 do { \
331 asm_thumb_cmp_rlo_i8(as, reg, 0); \
Damien George0b610de2014-09-29 16:25:04 +0100332 asm_thumb_bcc_label(as, ASM_THUMB_CC_NE, label); \
Damien Georgec90f59e2014-09-06 23:06:36 +0100333 } while (0)
334#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
335 do { \
336 asm_thumb_cmp_rlo_rlo(as, reg1, reg2); \
Damien George0b610de2014-09-29 16:25:04 +0100337 asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \
Damien Georgec90f59e2014-09-06 23:06:36 +0100338 } while (0)
Damien George0b610de2014-09-29 16:25:04 +0100339#define ASM_CALL_IND(as, ptr, idx) asm_thumb_bl_ind(as, ptr, idx, ASM_THUMB_REG_R3)
Damien Georgec90f59e2014-09-06 23:06:36 +0100340
341#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_thumb_mov_local_reg(as, (local_num), (reg))
342#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_optimised(as, (reg), (imm))
343#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_aligned(as, (reg), (imm))
344#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
345 do { \
346 asm_thumb_mov_reg_i32_optimised(as, (reg_temp), (imm)); \
347 asm_thumb_mov_local_reg(as, (local_num), (reg_temp)); \
348 } while (false)
349#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local(as, (reg), (local_num))
Damien George3112cde2014-09-29 18:45:42 +0100350#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src))
Damien Georgec90f59e2014-09-06 23:06:36 +0100351#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local_addr(as, (reg), (local_num))
Damien13ed3a62013-10-08 09:05:10 +0100352
Damien George3112cde2014-09-29 18:45:42 +0100353#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift))
354#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift))
Damien George1ef23482014-10-12 14:21:06 +0100355#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ORR, (reg_dest), (reg_src))
356#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_EOR, (reg_dest), (reg_src))
357#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_AND, (reg_dest), (reg_src))
Damien George3112cde2014-09-29 18:45:42 +0100358#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_thumb_add_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src))
359#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_thumb_sub_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src))
360
Damien George91cfd412014-10-12 16:59:29 +0100361#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)
Damien George4cd9ced2015-01-15 14:41:41 +0000362#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), (word_offset))
Damien George91cfd412014-10-12 16:59:29 +0100363#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrb_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)
364#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrh_rlo_rlo_i5((as), (reg_dest), (reg_base), 0)
365
Damien Georgee9dac3b2014-09-29 22:10:41 +0100366#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0)
Damien George4cd9ced2015-01-15 14:41:41 +0000367#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), (word_offset))
Damien Georgee9dac3b2014-09-29 22:10:41 +0100368#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_thumb_strb_rlo_rlo_i5((as), (reg_src), (reg_base), 0)
369#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_thumb_strh_rlo_rlo_i5((as), (reg_src), (reg_base), 0)
370
Fabian Vogtfe3d16e2014-08-16 22:55:53 +0200371#elif N_ARM
372
373// ARM specific stuff
374
Damien George51dfcb42015-01-01 20:27:54 +0000375#include "py/asmarm.h"
Fabian Vogtfe3d16e2014-08-16 22:55:53 +0200376
Fabian Vogtfe3d16e2014-08-16 22:55:53 +0200377#define EXPORT_FUN(name) emit_native_arm_##name
378
Damien George0b610de2014-09-29 16:25:04 +0100379#define REG_RET ASM_ARM_REG_R0
380#define REG_ARG_1 ASM_ARM_REG_R0
381#define REG_ARG_2 ASM_ARM_REG_R1
382#define REG_ARG_3 ASM_ARM_REG_R2
383#define REG_ARG_4 ASM_ARM_REG_R3
Damien George81057362014-09-07 01:06:19 +0100384
Damien George0b610de2014-09-29 16:25:04 +0100385#define REG_TEMP0 ASM_ARM_REG_R0
386#define REG_TEMP1 ASM_ARM_REG_R1
387#define REG_TEMP2 ASM_ARM_REG_R2
Damien Georgec90f59e2014-09-06 23:06:36 +0100388
Damien George0b610de2014-09-29 16:25:04 +0100389#define REG_LOCAL_1 ASM_ARM_REG_R4
390#define REG_LOCAL_2 ASM_ARM_REG_R5
391#define REG_LOCAL_3 ASM_ARM_REG_R6
Damien Georgec90f59e2014-09-06 23:06:36 +0100392#define REG_LOCAL_NUM (3)
393
394#define ASM_PASS_COMPUTE ASM_ARM_PASS_COMPUTE
395#define ASM_PASS_EMIT ASM_ARM_PASS_EMIT
396
397#define ASM_T asm_arm_t
398#define ASM_NEW asm_arm_new
399#define ASM_FREE asm_arm_free
400#define ASM_GET_CODE asm_arm_get_code
401#define ASM_GET_CODE_SIZE asm_arm_get_code_size
402#define ASM_START_PASS asm_arm_start_pass
403#define ASM_END_PASS asm_arm_end_pass
404#define ASM_ENTRY asm_arm_entry
405#define ASM_EXIT asm_arm_exit
406
407#define ASM_LABEL_ASSIGN asm_arm_label_assign
408#define ASM_JUMP asm_arm_b_label
409#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
410 do { \
411 asm_arm_cmp_reg_i8(as, reg, 0); \
Damien George0b610de2014-09-29 16:25:04 +0100412 asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \
Damien Georgec90f59e2014-09-06 23:06:36 +0100413 } while (0)
414#define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \
415 do { \
416 asm_arm_cmp_reg_i8(as, reg, 0); \
Damien George0b610de2014-09-29 16:25:04 +0100417 asm_arm_bcc_label(as, ASM_ARM_CC_NE, label); \
Damien Georgec90f59e2014-09-06 23:06:36 +0100418 } while (0)
419#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
420 do { \
421 asm_arm_cmp_reg_reg(as, reg1, reg2); \
Damien George0b610de2014-09-29 16:25:04 +0100422 asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \
Damien Georgec90f59e2014-09-06 23:06:36 +0100423 } while (0)
Damien George0b610de2014-09-29 16:25:04 +0100424#define ASM_CALL_IND(as, ptr, idx) asm_arm_bl_ind(as, ptr, idx, ASM_ARM_REG_R3)
Damien Georgec90f59e2014-09-06 23:06:36 +0100425
426#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_arm_mov_local_reg(as, (local_num), (reg))
427#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm))
428#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm))
429#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
430 do { \
431 asm_arm_mov_reg_i32(as, (reg_temp), (imm)); \
432 asm_arm_mov_local_reg(as, (local_num), (reg_temp)); \
433 } while (false)
434#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_arm_mov_reg_local(as, (reg), (local_num))
Damien George3112cde2014-09-29 18:45:42 +0100435#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src))
Damien Georgec90f59e2014-09-06 23:06:36 +0100436#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_arm_mov_reg_local_addr(as, (reg), (local_num))
437
Fabian Vogte5268962014-10-04 00:53:46 +0200438#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_reg_reg((as), (reg_dest), (reg_shift))
439#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_reg_reg((as), (reg_dest), (reg_shift))
Damien George1ef23482014-10-12 14:21:06 +0100440#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_arm_orr_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
441#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_arm_eor_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
442#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_arm_and_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
Damien George3112cde2014-09-29 18:45:42 +0100443#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_arm_add_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
444#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_arm_sub_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
445
Damien George91cfd412014-10-12 16:59:29 +0100446#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base))
447#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_arm_ldrb_reg_reg((as), (reg_dest), (reg_base))
448#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_arm_ldrh_reg_reg((as), (reg_dest), (reg_base))
449
Fabian Vogte5268962014-10-04 00:53:46 +0200450#define ASM_STORE_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base))
451#define ASM_STORE8_REG_REG(as, reg_value, reg_base) asm_arm_strb_reg_reg((as), (reg_value), (reg_base))
452#define ASM_STORE16_REG_REG(as, reg_value, reg_base) asm_arm_strh_reg_reg((as), (reg_value), (reg_base))
Damien Georgee9dac3b2014-09-29 22:10:41 +0100453
Damien Georgec90f59e2014-09-06 23:06:36 +0100454#else
455
456#error unknown native emitter
Fabian Vogtfe3d16e2014-08-16 22:55:53 +0200457
Damien13ed3a62013-10-08 09:05:10 +0100458#endif
459
460typedef enum {
Damienff8ed772013-10-08 22:18:32 +0100461 STACK_VALUE,
462 STACK_REG,
463 STACK_IMM,
464} stack_info_kind_t;
Damien13ed3a62013-10-08 09:05:10 +0100465
Damien Georgee9dac3b2014-09-29 22:10:41 +0100466// these enums must be distinct and the bottom 2 bits
467// must correspond to the correct MP_NATIVE_TYPE_xxx value
Damien13ed3a62013-10-08 09:05:10 +0100468typedef enum {
Damien Georgee9dac3b2014-09-29 22:10:41 +0100469 VTYPE_PYOBJ = 0x00 | MP_NATIVE_TYPE_OBJ,
470 VTYPE_BOOL = 0x00 | MP_NATIVE_TYPE_BOOL,
471 VTYPE_INT = 0x00 | MP_NATIVE_TYPE_INT,
472 VTYPE_UINT = 0x00 | MP_NATIVE_TYPE_UINT,
473
474 VTYPE_PTR = 0x10 | MP_NATIVE_TYPE_UINT, // pointer to word sized entity
475 VTYPE_PTR8 = 0x20 | MP_NATIVE_TYPE_UINT,
476 VTYPE_PTR16 = 0x30 | MP_NATIVE_TYPE_UINT,
477 VTYPE_PTR_NONE = 0x40 | MP_NATIVE_TYPE_UINT,
478
479 VTYPE_UNBOUND = 0x50 | MP_NATIVE_TYPE_OBJ,
480 VTYPE_BUILTIN_CAST = 0x60 | MP_NATIVE_TYPE_OBJ,
Damien13ed3a62013-10-08 09:05:10 +0100481} vtype_kind_t;
482
Damienff8ed772013-10-08 22:18:32 +0100483typedef struct _stack_info_t {
484 vtype_kind_t vtype;
485 stack_info_kind_t kind;
486 union {
487 int u_reg;
Damien George40f3c022014-07-03 13:25:24 +0100488 mp_int_t u_imm;
Damien George32444b72015-01-24 23:14:12 +0000489 } data;
Damienff8ed772013-10-08 22:18:32 +0100490} stack_info_t;
491
Damien13ed3a62013-10-08 09:05:10 +0100492struct _emit_t {
493 int pass;
494
495 bool do_viper_types;
Damienff8ed772013-10-08 22:18:32 +0100496
Damien George2ac4af62014-08-15 16:45:41 +0100497 vtype_kind_t return_vtype;
498
Damien George7ff996c2014-09-08 23:05:16 +0100499 mp_uint_t local_vtype_alloc;
Damien13ed3a62013-10-08 09:05:10 +0100500 vtype_kind_t *local_vtype;
Damienff8ed772013-10-08 22:18:32 +0100501
Damien George7ff996c2014-09-08 23:05:16 +0100502 mp_uint_t stack_info_alloc;
Damienff8ed772013-10-08 22:18:32 +0100503 stack_info_t *stack_info;
Damien George21ca2d72014-10-19 19:00:51 +0100504 vtype_kind_t saved_stack_vtype;
Damienff8ed772013-10-08 22:18:32 +0100505
Damien13ed3a62013-10-08 09:05:10 +0100506 int stack_start;
507 int stack_size;
508
509 bool last_emit_was_return_value;
510
Damien13ed3a62013-10-08 09:05:10 +0100511 scope_t *scope;
512
Damien Georgec90f59e2014-09-06 23:06:36 +0100513 ASM_T *as;
Damien13ed3a62013-10-08 09:05:10 +0100514};
515
Damien George7ff996c2014-09-08 23:05:16 +0100516emit_t *EXPORT_FUN(new)(mp_uint_t max_num_labels) {
Damien George36db6bc2014-05-07 17:24:22 +0100517 emit_t *emit = m_new0(emit_t, 1);
Damien Georgec90f59e2014-09-06 23:06:36 +0100518 emit->as = ASM_NEW(max_num_labels);
Damien13ed3a62013-10-08 09:05:10 +0100519 return emit;
520}
521
Damien George41d02b62014-01-24 22:42:28 +0000522void EXPORT_FUN(free)(emit_t *emit) {
Damien Georgec90f59e2014-09-06 23:06:36 +0100523 ASM_FREE(emit->as, false);
Damien George36db6bc2014-05-07 17:24:22 +0100524 m_del(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc);
525 m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc);
Paul Sokolovskyf46d87a2014-01-24 16:20:11 +0200526 m_del_obj(emit_t, emit);
527}
528
Damien George2ac4af62014-08-15 16:45:41 +0100529STATIC void emit_native_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
530 switch (op) {
531 case MP_EMIT_NATIVE_TYPE_ENABLE:
532 emit->do_viper_types = arg1;
533 break;
534
535 default: {
536 vtype_kind_t type;
537 switch (arg2) {
538 case MP_QSTR_object: type = VTYPE_PYOBJ; break;
539 case MP_QSTR_bool: type = VTYPE_BOOL; break;
540 case MP_QSTR_int: type = VTYPE_INT; break;
541 case MP_QSTR_uint: type = VTYPE_UINT; break;
Damien Georgee9dac3b2014-09-29 22:10:41 +0100542 case MP_QSTR_ptr: type = VTYPE_PTR; break;
543 case MP_QSTR_ptr8: type = VTYPE_PTR8; break;
544 case MP_QSTR_ptr16: type = VTYPE_PTR16; break;
Damien George2ac4af62014-08-15 16:45:41 +0100545 default: printf("ViperTypeError: unknown type %s\n", qstr_str(arg2)); return;
546 }
547 if (op == MP_EMIT_NATIVE_TYPE_RETURN) {
548 emit->return_vtype = type;
549 } else {
550 assert(arg1 < emit->local_vtype_alloc);
551 emit->local_vtype[arg1] = type;
552 }
553 break;
554 }
555 }
Damien13ed3a62013-10-08 09:05:10 +0100556}
557
Damien Georgefa5950e2015-04-03 15:03:24 +0000558STATIC void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest);
Damien George4cd9ced2015-01-15 14:41:41 +0000559STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg);
Damien Georgefa5950e2015-04-03 15:03:24 +0000560STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num);
Damien George4cd9ced2015-01-15 14:41:41 +0000561STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num);
Damien Georgefa5950e2015-04-03 15:03:24 +0000562
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200563STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
Damien Georged6230f62014-09-23 14:10:03 +0000564 DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope);
565
Damien13ed3a62013-10-08 09:05:10 +0100566 emit->pass = pass;
567 emit->stack_start = 0;
568 emit->stack_size = 0;
569 emit->last_emit_was_return_value = false;
Damien13ed3a62013-10-08 09:05:10 +0100570 emit->scope = scope;
571
Damien George36db6bc2014-05-07 17:24:22 +0100572 // allocate memory for keeping track of the types of locals
573 if (emit->local_vtype_alloc < scope->num_locals) {
574 emit->local_vtype = m_renew(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc, scope->num_locals);
575 emit->local_vtype_alloc = scope->num_locals;
Damienff8ed772013-10-08 22:18:32 +0100576 }
Damien George36db6bc2014-05-07 17:24:22 +0100577
578 // allocate memory for keeping track of the objects on the stack
579 // XXX don't know stack size on entry, and it should be maximum over all scopes
Damien George51229af2015-03-26 17:54:12 +0000580 // XXX this is such a big hack and really needs to be fixed
Damienff8ed772013-10-08 22:18:32 +0100581 if (emit->stack_info == NULL) {
Damien George51229af2015-03-26 17:54:12 +0000582 emit->stack_info_alloc = scope->stack_size + 200;
Damienff8ed772013-10-08 22:18:32 +0100583 emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc);
Damien13ed3a62013-10-08 09:05:10 +0100584 }
585
Damien George2ac4af62014-08-15 16:45:41 +0100586 // set default type for return and arguments
587 emit->return_vtype = VTYPE_PYOBJ;
Damien Georgea5190a72014-08-15 22:39:08 +0100588 for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) {
Damien George2ac4af62014-08-15 16:45:41 +0100589 emit->local_vtype[i] = VTYPE_PYOBJ;
590 }
Damien Georgea5190a72014-08-15 22:39:08 +0100591
592 // local variables begin unbound, and have unknown type
593 for (mp_uint_t i = emit->scope->num_pos_args; i < emit->local_vtype_alloc; i++) {
594 emit->local_vtype[i] = VTYPE_UNBOUND;
595 }
596
597 // values on stack begin unbound
598 for (mp_uint_t i = 0; i < emit->stack_info_alloc; i++) {
Damien George2ac4af62014-08-15 16:45:41 +0100599 emit->stack_info[i].kind = STACK_VALUE;
Damien Georgea5190a72014-08-15 22:39:08 +0100600 emit->stack_info[i].vtype = VTYPE_UNBOUND;
Damien13ed3a62013-10-08 09:05:10 +0100601 }
602
Damien Georgec90f59e2014-09-06 23:06:36 +0100603 ASM_START_PASS(emit->as, pass == MP_PASS_EMIT ? ASM_PASS_EMIT : ASM_PASS_COMPUTE);
Damien13ed3a62013-10-08 09:05:10 +0100604
605 // entry to function
606 int num_locals = 0;
Damien George36db6bc2014-05-07 17:24:22 +0100607 if (pass > MP_PASS_SCOPE) {
Damien13ed3a62013-10-08 09:05:10 +0100608 num_locals = scope->num_locals - REG_LOCAL_NUM;
609 if (num_locals < 0) {
610 num_locals = 0;
611 }
612 emit->stack_start = num_locals;
613 num_locals += scope->stack_size;
614 }
Damien Georgec90f59e2014-09-06 23:06:36 +0100615 ASM_ENTRY(emit->as, num_locals);
Damien13ed3a62013-10-08 09:05:10 +0100616
617 // initialise locals from parameters
Damien3ef4abb2013-10-12 16:53:13 +0100618#if N_X64
Damien George2827d622014-04-27 15:50:52 +0100619 for (int i = 0; i < scope->num_pos_args; i++) {
Damien13ed3a62013-10-08 09:05:10 +0100620 if (i == 0) {
Damien George3112cde2014-09-29 18:45:42 +0100621 ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
Damien13ed3a62013-10-08 09:05:10 +0100622 } else if (i == 1) {
Damien George3112cde2014-09-29 18:45:42 +0100623 ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
Damien13ed3a62013-10-08 09:05:10 +0100624 } else if (i == 2) {
Damien George3112cde2014-09-29 18:45:42 +0100625 ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
Damien George81057362014-09-07 01:06:19 +0100626 } else if (i == 3) {
627 asm_x64_mov_r64_to_local(emit->as, REG_ARG_4, i - REG_LOCAL_NUM);
Damien13ed3a62013-10-08 09:05:10 +0100628 } else {
629 // TODO not implemented
630 assert(0);
631 }
632 }
Damien Georgec90f59e2014-09-06 23:06:36 +0100633#elif N_X86
634 for (int i = 0; i < scope->num_pos_args; i++) {
Damien Georgec90f59e2014-09-06 23:06:36 +0100635 if (i == 0) {
Damien George03281b32014-09-06 22:38:50 +0000636 asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1);
Damien Georgec90f59e2014-09-06 23:06:36 +0100637 } else if (i == 1) {
Damien George03281b32014-09-06 22:38:50 +0000638 asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2);
Damien George25d90412014-09-06 23:24:32 +0000639 } else if (i == 2) {
640 asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3);
Damien Georgec90f59e2014-09-06 23:06:36 +0100641 } else {
Damien George03281b32014-09-06 22:38:50 +0000642 asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0);
643 asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM);
Damien Georgec90f59e2014-09-06 23:06:36 +0100644 }
645 }
Damien3ef4abb2013-10-12 16:53:13 +0100646#elif N_THUMB
Damien George2827d622014-04-27 15:50:52 +0100647 for (int i = 0; i < scope->num_pos_args; i++) {
Damien13ed3a62013-10-08 09:05:10 +0100648 if (i == 0) {
Damien George3112cde2014-09-29 18:45:42 +0100649 ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
Damien13ed3a62013-10-08 09:05:10 +0100650 } else if (i == 1) {
Damien George3112cde2014-09-29 18:45:42 +0100651 ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
Damien13ed3a62013-10-08 09:05:10 +0100652 } else if (i == 2) {
Damien George3112cde2014-09-29 18:45:42 +0100653 ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
Damien13ed3a62013-10-08 09:05:10 +0100654 } else if (i == 3) {
655 asm_thumb_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
656 } else {
657 // TODO not implemented
658 assert(0);
659 }
660 }
661
Damien Georgee9dac3b2014-09-29 22:10:41 +0100662 // TODO don't load r7 if we don't need it
Damien George0b610de2014-09-29 16:25:04 +0100663 asm_thumb_mov_reg_i32(emit->as, ASM_THUMB_REG_R7, (mp_uint_t)mp_fun_table);
Fabian Vogtfe3d16e2014-08-16 22:55:53 +0200664#elif N_ARM
665 for (int i = 0; i < scope->num_pos_args; i++) {
666 if (i == 0) {
Damien George3112cde2014-09-29 18:45:42 +0100667 ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
Fabian Vogtfe3d16e2014-08-16 22:55:53 +0200668 } else if (i == 1) {
Damien George3112cde2014-09-29 18:45:42 +0100669 ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
Fabian Vogtfe3d16e2014-08-16 22:55:53 +0200670 } else if (i == 2) {
Damien George3112cde2014-09-29 18:45:42 +0100671 ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
Fabian Vogtfe3d16e2014-08-16 22:55:53 +0200672 } else if (i == 3) {
673 asm_arm_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
674 } else {
675 // TODO not implemented
676 assert(0);
677 }
678 }
679
Damien Georgee9dac3b2014-09-29 22:10:41 +0100680 // TODO don't load r7 if we don't need it
Damien George0b610de2014-09-29 16:25:04 +0100681 asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table);
Damien Georgec90f59e2014-09-06 23:06:36 +0100682#else
683 #error not implemented
Damien13ed3a62013-10-08 09:05:10 +0100684#endif
Damien George4cd9ced2015-01-15 14:41:41 +0000685
686 // initialise closed over variables
687 for (int i = 0; i < scope->id_info_len; i++) {
688 id_info_t *id = &scope->id_info[i];
689 if (id->kind == ID_INFO_KIND_CELL) {
Damien Georgefa5950e2015-04-03 15:03:24 +0000690 if (emit->local_vtype[id->local_num] != VTYPE_UNBOUND) {
691 emit_native_load_fast(emit, id->qst, id->local_num);
692 vtype_kind_t vtype;
693 emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
694 }
Damien George4cd9ced2015-01-15 14:41:41 +0000695 ASM_CALL_IND(emit->as, mp_fun_table[MP_F_NEW_CELL], MP_F_NEW_CELL);
696 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
697 emit_native_store_fast(emit, id->qst, id->local_num);
698 }
699 }
Damien13ed3a62013-10-08 09:05:10 +0100700}
701
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200702STATIC void emit_native_end_pass(emit_t *emit) {
Damien13ed3a62013-10-08 09:05:10 +0100703 if (!emit->last_emit_was_return_value) {
Damien Georgec90f59e2014-09-06 23:06:36 +0100704 ASM_EXIT(emit->as);
Damien13ed3a62013-10-08 09:05:10 +0100705 }
Damien Georgec90f59e2014-09-06 23:06:36 +0100706 ASM_END_PASS(emit->as);
Damien13ed3a62013-10-08 09:05:10 +0100707
708 // check stack is back to zero size
709 if (emit->stack_size != 0) {
710 printf("ERROR: stack size not back to zero; got %d\n", emit->stack_size);
711 }
712
Damien George36db6bc2014-05-07 17:24:22 +0100713 if (emit->pass == MP_PASS_EMIT) {
Damien Georgec90f59e2014-09-06 23:06:36 +0100714 void *f = ASM_GET_CODE(emit->as);
715 mp_uint_t f_len = ASM_GET_CODE_SIZE(emit->as);
Damien George2ac4af62014-08-15 16:45:41 +0100716
717 // compute type signature
Damien Georgee9dac3b2014-09-29 22:10:41 +0100718 // note that the lower 2 bits of a vtype are tho correct MP_NATIVE_TYPE_xxx
Damien George2ac4af62014-08-15 16:45:41 +0100719 mp_uint_t type_sig = emit->return_vtype & 3;
720 for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) {
721 type_sig |= (emit->local_vtype[i] & 3) << (i * 2 + 2);
722 }
723
724 mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, emit->scope->num_pos_args, type_sig);
Damien13ed3a62013-10-08 09:05:10 +0100725 }
726}
727
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200728STATIC bool emit_native_last_emit_was_return_value(emit_t *emit) {
Damien13ed3a62013-10-08 09:05:10 +0100729 return emit->last_emit_was_return_value;
730}
731
Damien Georged6230f62014-09-23 14:10:03 +0000732STATIC void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) {
Damien Georged6230f62014-09-23 14:10:03 +0000733 assert((mp_int_t)emit->stack_size + stack_size_delta >= 0);
Damien13ed3a62013-10-08 09:05:10 +0100734 emit->stack_size += stack_size_delta;
Damien George36db6bc2014-05-07 17:24:22 +0100735 if (emit->pass > MP_PASS_SCOPE && emit->stack_size > emit->scope->stack_size) {
Damien13ed3a62013-10-08 09:05:10 +0100736 emit->scope->stack_size = emit->stack_size;
737 }
Damien George21ca2d72014-10-19 19:00:51 +0100738#ifdef DEBUG_PRINT
739 DEBUG_printf(" adjust_stack; stack_size=%d+%d; stack now:", emit->stack_size - stack_size_delta, stack_size_delta);
740 for (int i = 0; i < emit->stack_size; i++) {
741 stack_info_t *si = &emit->stack_info[i];
Damien George32444b72015-01-24 23:14:12 +0000742 DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->data.u_reg);
Damien George21ca2d72014-10-19 19:00:51 +0100743 }
744 DEBUG_printf("\n");
745#endif
Damien13ed3a62013-10-08 09:05:10 +0100746}
747
Damien Georged6230f62014-09-23 14:10:03 +0000748STATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {
Damien George21ca2d72014-10-19 19:00:51 +0100749 DEBUG_printf("adjust_stack_size(" INT_FMT ")\n", delta);
Damien Georged6230f62014-09-23 14:10:03 +0000750 // If we are adjusting the stack in a positive direction (pushing) then we
751 // need to fill in values for the stack kind and vtype of the newly-pushed
752 // entries. These should be set to "value" (ie not reg or imm) because we
753 // should only need to adjust the stack due to a jump to this part in the
754 // code (and hence we have settled the stack before the jump).
755 for (mp_int_t i = 0; i < delta; i++) {
756 stack_info_t *si = &emit->stack_info[emit->stack_size + i];
757 si->kind = STACK_VALUE;
Damien George21ca2d72014-10-19 19:00:51 +0100758 // TODO we don't know the vtype to use here. At the moment this is a
759 // hack to get the case of multi comparison working.
760 if (delta == 1) {
761 si->vtype = emit->saved_stack_vtype;
762 } else {
763 si->vtype = VTYPE_PYOBJ;
764 }
Damien Georged6230f62014-09-23 14:10:03 +0000765 }
766 adjust_stack(emit, delta);
767}
768
769STATIC void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000770 (void)emit;
771 (void)source_line;
Damien Georged6230f62014-09-23 14:10:03 +0000772}
773
Damienff8ed772013-10-08 22:18:32 +0100774/*
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200775STATIC void emit_pre_raw(emit_t *emit, int stack_size_delta) {
Damien13ed3a62013-10-08 09:05:10 +0100776 adjust_stack(emit, stack_size_delta);
777 emit->last_emit_was_return_value = false;
778}
Damienff8ed772013-10-08 22:18:32 +0100779*/
Damien13ed3a62013-10-08 09:05:10 +0100780
Damienff8ed772013-10-08 22:18:32 +0100781// this must be called at start of emit functions
Damien Georgece8f07a2014-03-27 23:30:26 +0000782STATIC void emit_native_pre(emit_t *emit) {
Damienff8ed772013-10-08 22:18:32 +0100783 emit->last_emit_was_return_value = false;
784 // settle the stack
785 /*
786 if (regs_needed != 0) {
787 for (int i = 0; i < emit->stack_size; i++) {
788 switch (emit->stack_info[i].kind) {
789 case STACK_VALUE:
790 break;
791
792 case STACK_REG:
793 // TODO only push reg if in regs_needed
794 emit->stack_info[i].kind = STACK_VALUE;
Damien George32444b72015-01-24 23:14:12 +0000795 ASM_MOV_REG_TO_LOCAL(emit->as, emit->stack_info[i].data.u_reg, emit->stack_start + i);
Damienff8ed772013-10-08 22:18:32 +0100796 break;
797
798 case STACK_IMM:
799 // don't think we ever need to push imms for settling
800 //ASM_MOV_IMM_TO_LOCAL(emit->last_imm, emit->stack_start + i);
801 break;
802 }
803 }
804 }
805 */
Damien13ed3a62013-10-08 09:05:10 +0100806}
807
Damien George3112cde2014-09-29 18:45:42 +0100808// depth==0 is top, depth==1 is before top, etc
809STATIC stack_info_t *peek_stack(emit_t *emit, mp_uint_t depth) {
810 return &emit->stack_info[emit->stack_size - 1 - depth];
811}
812
813// depth==0 is top, depth==1 is before top, etc
814STATIC vtype_kind_t peek_vtype(emit_t *emit, mp_uint_t depth) {
815 return peek_stack(emit, depth)->vtype;
Damienff8ed772013-10-08 22:18:32 +0100816}
Damien13ed3a62013-10-08 09:05:10 +0100817
Damiend2755ec2013-10-16 23:58:48 +0100818// pos=1 is TOS, pos=2 is next, etc
819// use pos=0 for no skipping
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200820STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) {
Damiend2755ec2013-10-16 23:58:48 +0100821 skip_stack_pos = emit->stack_size - skip_stack_pos;
Damienff8ed772013-10-08 22:18:32 +0100822 for (int i = 0; i < emit->stack_size; i++) {
Damiend2755ec2013-10-16 23:58:48 +0100823 if (i != skip_stack_pos) {
824 stack_info_t *si = &emit->stack_info[i];
Damien George32444b72015-01-24 23:14:12 +0000825 if (si->kind == STACK_REG && si->data.u_reg == reg_needed) {
Damiend2755ec2013-10-16 23:58:48 +0100826 si->kind = STACK_VALUE;
Damien George32444b72015-01-24 23:14:12 +0000827 ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
Damiend2755ec2013-10-16 23:58:48 +0100828 }
Damienff8ed772013-10-08 22:18:32 +0100829 }
830 }
831}
Damien13ed3a62013-10-08 09:05:10 +0100832
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200833STATIC void need_reg_all(emit_t *emit) {
Damienff8ed772013-10-08 22:18:32 +0100834 for (int i = 0; i < emit->stack_size; i++) {
835 stack_info_t *si = &emit->stack_info[i];
836 if (si->kind == STACK_REG) {
837 si->kind = STACK_VALUE;
Damien George32444b72015-01-24 23:14:12 +0000838 ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
Damienff8ed772013-10-08 22:18:32 +0100839 }
Damien13ed3a62013-10-08 09:05:10 +0100840 }
841}
842
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200843STATIC void need_stack_settled(emit_t *emit) {
Damien Georged6230f62014-09-23 14:10:03 +0000844 DEBUG_printf(" need_stack_settled; stack_size=%d\n", emit->stack_size);
Damiend2755ec2013-10-16 23:58:48 +0100845 for (int i = 0; i < emit->stack_size; i++) {
846 stack_info_t *si = &emit->stack_info[i];
847 if (si->kind == STACK_REG) {
Damien George32444b72015-01-24 23:14:12 +0000848 DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i);
Damiend2755ec2013-10-16 23:58:48 +0100849 si->kind = STACK_VALUE;
Damien George32444b72015-01-24 23:14:12 +0000850 ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
Damiend2755ec2013-10-16 23:58:48 +0100851 }
852 }
853 for (int i = 0; i < emit->stack_size; i++) {
854 stack_info_t *si = &emit->stack_info[i];
855 if (si->kind == STACK_IMM) {
Damien George32444b72015-01-24 23:14:12 +0000856 DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i);
Damien George02d95d72014-08-29 20:05:32 +0100857 si->kind = STACK_VALUE;
Damien George32444b72015-01-24 23:14:12 +0000858 ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + i, REG_TEMP0);
Damiend2755ec2013-10-16 23:58:48 +0100859 }
860 }
861}
862
863// pos=1 is TOS, pos=2 is next, etc
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200864STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int reg_dest) {
Damiend2755ec2013-10-16 23:58:48 +0100865 need_reg_single(emit, reg_dest, pos);
866 stack_info_t *si = &emit->stack_info[emit->stack_size - pos];
Damienff8ed772013-10-08 22:18:32 +0100867 *vtype = si->vtype;
868 switch (si->kind) {
869 case STACK_VALUE:
Damien Georgec90f59e2014-09-06 23:06:36 +0100870 ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - pos, reg_dest);
Damien13ed3a62013-10-08 09:05:10 +0100871 break;
872
Damienff8ed772013-10-08 22:18:32 +0100873 case STACK_REG:
Damien George32444b72015-01-24 23:14:12 +0000874 if (si->data.u_reg != reg_dest) {
875 ASM_MOV_REG_REG(emit->as, reg_dest, si->data.u_reg);
Damien13ed3a62013-10-08 09:05:10 +0100876 }
877 break;
878
Damienff8ed772013-10-08 22:18:32 +0100879 case STACK_IMM:
Damien George32444b72015-01-24 23:14:12 +0000880 ASM_MOV_IMM_TO_REG(emit->as, si->data.u_imm, reg_dest);
Damien13ed3a62013-10-08 09:05:10 +0100881 break;
882 }
Damien13ed3a62013-10-08 09:05:10 +0100883}
884
Damien Georgee9dac3b2014-09-29 22:10:41 +0100885// does an efficient X=pop(); discard(); push(X)
886// needs a (non-temp) register in case the poped element was stored in the stack
887STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) {
888 stack_info_t *si = &emit->stack_info[emit->stack_size - 2];
889 si[0] = si[1];
890 if (si->kind == STACK_VALUE) {
891 // if folded element was on the stack we need to put it in a register
892 ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - 1, reg_dest);
893 si->kind = STACK_REG;
Damien George32444b72015-01-24 23:14:12 +0000894 si->data.u_reg = reg_dest;
Damien Georgee9dac3b2014-09-29 22:10:41 +0100895 }
896 adjust_stack(emit, -1);
897}
898
899// If stacked value is in a register and the register is not r1 or r2, then
900// *reg_dest is set to that register. Otherwise the value is put in *reg_dest.
901STATIC void emit_pre_pop_reg_flexible(emit_t *emit, vtype_kind_t *vtype, int *reg_dest, int not_r1, int not_r2) {
Damien George3112cde2014-09-29 18:45:42 +0100902 emit->last_emit_was_return_value = false;
903 stack_info_t *si = peek_stack(emit, 0);
Damien George32444b72015-01-24 23:14:12 +0000904 if (si->kind == STACK_REG && si->data.u_reg != not_r1 && si->data.u_reg != not_r2) {
Damien George3112cde2014-09-29 18:45:42 +0100905 *vtype = si->vtype;
Damien George32444b72015-01-24 23:14:12 +0000906 *reg_dest = si->data.u_reg;
Damien George3112cde2014-09-29 18:45:42 +0100907 need_reg_single(emit, *reg_dest, 1);
908 } else {
909 emit_access_stack(emit, 1, vtype, *reg_dest);
910 }
911 adjust_stack(emit, -1);
912}
913
Damien Georgee6ce10a2014-09-06 18:38:20 +0100914STATIC void emit_pre_pop_discard(emit_t *emit) {
Damien Georgeccc85ea2014-05-10 13:40:46 +0100915 emit->last_emit_was_return_value = false;
916 adjust_stack(emit, -1);
917}
918
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200919STATIC void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest) {
Damiend2755ec2013-10-16 23:58:48 +0100920 emit->last_emit_was_return_value = false;
921 emit_access_stack(emit, 1, vtype, reg_dest);
922 adjust_stack(emit, -1);
923}
924
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200925STATIC void emit_pre_pop_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb) {
Damien13ed3a62013-10-08 09:05:10 +0100926 emit_pre_pop_reg(emit, vtypea, rega);
Damienff8ed772013-10-08 22:18:32 +0100927 emit_pre_pop_reg(emit, vtypeb, regb);
Damien13ed3a62013-10-08 09:05:10 +0100928}
929
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200930STATIC void emit_pre_pop_reg_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb, vtype_kind_t *vtypec, int regc) {
Damien13ed3a62013-10-08 09:05:10 +0100931 emit_pre_pop_reg(emit, vtypea, rega);
Damienff8ed772013-10-08 22:18:32 +0100932 emit_pre_pop_reg(emit, vtypeb, regb);
933 emit_pre_pop_reg(emit, vtypec, regc);
Damien13ed3a62013-10-08 09:05:10 +0100934}
935
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200936STATIC void emit_post(emit_t *emit) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000937 (void)emit;
Damien13ed3a62013-10-08 09:05:10 +0100938}
939
Damien Georgee9dac3b2014-09-29 22:10:41 +0100940STATIC void emit_post_top_set_vtype(emit_t *emit, vtype_kind_t new_vtype) {
941 stack_info_t *si = &emit->stack_info[emit->stack_size - 1];
942 si->vtype = new_vtype;
943}
944
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200945STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) {
Damienff8ed772013-10-08 22:18:32 +0100946 stack_info_t *si = &emit->stack_info[emit->stack_size];
947 si->vtype = vtype;
948 si->kind = STACK_REG;
Damien George32444b72015-01-24 23:14:12 +0000949 si->data.u_reg = reg;
Damien13ed3a62013-10-08 09:05:10 +0100950 adjust_stack(emit, 1);
951}
952
Damien George40f3c022014-07-03 13:25:24 +0100953STATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) {
Damienff8ed772013-10-08 22:18:32 +0100954 stack_info_t *si = &emit->stack_info[emit->stack_size];
955 si->vtype = vtype;
956 si->kind = STACK_IMM;
Damien George32444b72015-01-24 23:14:12 +0000957 si->data.u_imm = imm;
Damienff8ed772013-10-08 22:18:32 +0100958 adjust_stack(emit, 1);
959}
960
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200961STATIC void emit_post_push_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb) {
Damienff8ed772013-10-08 22:18:32 +0100962 emit_post_push_reg(emit, vtypea, rega);
963 emit_post_push_reg(emit, vtypeb, regb);
964}
965
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200966STATIC void emit_post_push_reg_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb, vtype_kind_t vtypec, int regc) {
Damienff8ed772013-10-08 22:18:32 +0100967 emit_post_push_reg(emit, vtypea, rega);
968 emit_post_push_reg(emit, vtypeb, regb);
969 emit_post_push_reg(emit, vtypec, regc);
Damien13ed3a62013-10-08 09:05:10 +0100970}
971
Paul Sokolovsky520e2f52014-02-12 18:31:30 +0200972STATIC void emit_post_push_reg_reg_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb, vtype_kind_t vtypec, int regc, vtype_kind_t vtyped, int regd) {
Damienff8ed772013-10-08 22:18:32 +0100973 emit_post_push_reg(emit, vtypea, rega);
974 emit_post_push_reg(emit, vtypeb, regb);
975 emit_post_push_reg(emit, vtypec, regc);
976 emit_post_push_reg(emit, vtyped, regd);
Damien13ed3a62013-10-08 09:05:10 +0100977}
978
Damien George7fe21912014-08-16 22:31:57 +0100979STATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) {
Damiend2755ec2013-10-16 23:58:48 +0100980 need_reg_all(emit);
Damien Georgec90f59e2014-09-06 23:06:36 +0100981 ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
Damien13ed3a62013-10-08 09:05:10 +0100982}
983
Damien George7fe21912014-08-16 22:31:57 +0100984STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) {
Damieneb19efb2013-10-10 22:06:54 +0100985 need_reg_all(emit);
Damien Georgec90f59e2014-09-06 23:06:36 +0100986 ASM_MOV_IMM_TO_REG(emit->as, arg_val, arg_reg);
987 ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
Damien13ed3a62013-10-08 09:05:10 +0100988}
989
Damien George40f3c022014-07-03 13:25:24 +0100990// the first arg is stored in the code aligned on a mp_uint_t boundary
Damien George7fe21912014-08-16 22:31:57 +0100991STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) {
Damien Georgea32c1e42014-05-07 18:30:52 +0100992 need_reg_all(emit);
Damien Georgec90f59e2014-09-06 23:06:36 +0100993 ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val, arg_reg);
994 ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
Damien Georgea32c1e42014-05-07 18:30:52 +0100995}
996
Damien George7fe21912014-08-16 22:31:57 +0100997STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2) {
Damien Georgecd82e022014-02-02 13:11:48 +0000998 need_reg_all(emit);
Damien Georgec90f59e2014-09-06 23:06:36 +0100999 ASM_MOV_IMM_TO_REG(emit->as, arg_val1, arg_reg1);
1000 ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2);
1001 ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
Damien Georgecd82e022014-02-02 13:11:48 +00001002}
1003
Damien George40f3c022014-07-03 13:25:24 +01001004// the first arg is stored in the code aligned on a mp_uint_t boundary
Damien George7fe21912014-08-16 22:31:57 +01001005STATIC void emit_call_with_3_imm_args_and_first_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2, mp_int_t arg_val3, int arg_reg3) {
Damien Georgecdd96df2014-04-06 12:58:40 +01001006 need_reg_all(emit);
Damien Georgec90f59e2014-09-06 23:06:36 +01001007 ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val1, arg_reg1);
1008 ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2);
1009 ASM_MOV_IMM_TO_REG(emit->as, arg_val3, arg_reg3);
1010 ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
Damien Georgecdd96df2014-04-06 12:58:40 +01001011}
1012
Damien George86de21b2014-08-16 22:06:11 +01001013// vtype of all n_pop objects is VTYPE_PYOBJ
1014// Will convert any items that are not VTYPE_PYOBJ to this type and put them back on the stack.
1015// If any conversions of non-immediate values are needed, then it uses REG_ARG_1, REG_ARG_2 and REG_RET.
1016// Otherwise, it does not use any temporary registers (but may use reg_dest before loading it with stack pointer).
1017STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_pop) {
1018 need_reg_all(emit);
Damien13ed3a62013-10-08 09:05:10 +01001019
Damien George86de21b2014-08-16 22:06:11 +01001020 // First, store any immediate values to their respective place on the stack.
1021 for (mp_uint_t i = 0; i < n_pop; i++) {
1022 stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];
1023 // must push any imm's to stack
1024 // must convert them to VTYPE_PYOBJ for viper code
1025 if (si->kind == STACK_IMM) {
1026 si->kind = STACK_VALUE;
1027 switch (si->vtype) {
1028 case VTYPE_PYOBJ:
Damien George32444b72015-01-24 23:14:12 +00001029 ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
Damien George86de21b2014-08-16 22:06:11 +01001030 break;
1031 case VTYPE_BOOL:
Damien George32444b72015-01-24 23:14:12 +00001032 if (si->data.u_imm == 0) {
Damien Georgec90f59e2014-09-06 23:06:36 +01001033 ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
Damien George86de21b2014-08-16 22:06:11 +01001034 } else {
Damien Georgec90f59e2014-09-06 23:06:36 +01001035 ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
Damien George86de21b2014-08-16 22:06:11 +01001036 }
1037 si->vtype = VTYPE_PYOBJ;
1038 break;
1039 case VTYPE_INT:
1040 case VTYPE_UINT:
Damien George32444b72015-01-24 23:14:12 +00001041 ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (si->data.u_imm << 1) | 1, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
Damien George86de21b2014-08-16 22:06:11 +01001042 si->vtype = VTYPE_PYOBJ;
1043 break;
1044 default:
1045 // not handled
1046 assert(0);
1047 }
1048 }
1049
1050 // verify that this value is on the stack
1051 assert(si->kind == STACK_VALUE);
Damien13ed3a62013-10-08 09:05:10 +01001052 }
Damien George86de21b2014-08-16 22:06:11 +01001053
1054 // Second, convert any non-VTYPE_PYOBJ to that type.
1055 for (mp_uint_t i = 0; i < n_pop; i++) {
1056 stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];
1057 if (si->vtype != VTYPE_PYOBJ) {
1058 mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i;
Damien Georgec90f59e2014-09-06 23:06:36 +01001059 ASM_MOV_LOCAL_TO_REG(emit->as, local_num, REG_ARG_1);
Damien George7fe21912014-08-16 22:31:57 +01001060 emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type
Damien Georgec90f59e2014-09-06 23:06:36 +01001061 ASM_MOV_REG_TO_LOCAL(emit->as, REG_RET, local_num);
Damien George86de21b2014-08-16 22:06:11 +01001062 si->vtype = VTYPE_PYOBJ;
Damien Georgee9dac3b2014-09-29 22:10:41 +01001063 DEBUG_printf(" convert_native_to_obj(local_num=" UINT_FMT ")\n", local_num);
Damien George86de21b2014-08-16 22:06:11 +01001064 }
1065 }
1066
1067 // Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest.
1068 adjust_stack(emit, -n_pop);
Damien Georgec90f59e2014-09-06 23:06:36 +01001069 ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest);
Damien George86de21b2014-08-16 22:06:11 +01001070}
1071
1072// vtype of all n_push objects is VTYPE_PYOBJ
1073STATIC void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_push) {
1074 need_reg_all(emit);
1075 for (mp_uint_t i = 0; i < n_push; i++) {
1076 emit->stack_info[emit->stack_size + i].kind = STACK_VALUE;
1077 emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ;
1078 }
Damien Georgec90f59e2014-09-06 23:06:36 +01001079 ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest);
Damien George86de21b2014-08-16 22:06:11 +01001080 adjust_stack(emit, n_push);
1081}
1082
Damien George7ff996c2014-09-08 23:05:16 +01001083STATIC void emit_native_label_assign(emit_t *emit, mp_uint_t l) {
Damien Georged6230f62014-09-23 14:10:03 +00001084 DEBUG_printf("label_assign(" UINT_FMT ")\n", l);
Damien Georgece8f07a2014-03-27 23:30:26 +00001085 emit_native_pre(emit);
Damiend2755ec2013-10-16 23:58:48 +01001086 // need to commit stack because we can jump here from elsewhere
1087 need_stack_settled(emit);
Damien Georgec90f59e2014-09-06 23:06:36 +01001088 ASM_LABEL_ASSIGN(emit->as, l);
Damien6ba13142013-11-02 20:34:54 +00001089 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001090}
1091
Damien Georgecdd96df2014-04-06 12:58:40 +01001092STATIC void emit_native_import_name(emit_t *emit, qstr qst) {
1093 DEBUG_printf("import_name %s\n", qstr_str(qst));
1094 vtype_kind_t vtype_fromlist;
1095 vtype_kind_t vtype_level;
1096 emit_pre_pop_reg_reg(emit, &vtype_fromlist, REG_ARG_2, &vtype_level, REG_ARG_3); // arg2 = fromlist, arg3 = level
1097 assert(vtype_fromlist == VTYPE_PYOBJ);
1098 assert(vtype_level == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01001099 emit_call_with_imm_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name
Damien Georgecdd96df2014-04-06 12:58:40 +01001100 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien13ed3a62013-10-08 09:05:10 +01001101}
1102
Damien Georgecdd96df2014-04-06 12:58:40 +01001103STATIC void emit_native_import_from(emit_t *emit, qstr qst) {
1104 DEBUG_printf("import_from %s\n", qstr_str(qst));
1105 emit_native_pre(emit);
1106 vtype_kind_t vtype_module;
1107 emit_access_stack(emit, 1, &vtype_module, REG_ARG_1); // arg1 = module
1108 assert(vtype_module == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01001109 emit_call_with_imm_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name
Damien Georgecdd96df2014-04-06 12:58:40 +01001110 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien13ed3a62013-10-08 09:05:10 +01001111}
1112
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001113STATIC void emit_native_import_star(emit_t *emit) {
Damien Georgecdd96df2014-04-06 12:58:40 +01001114 DEBUG_printf("import_star\n");
1115 vtype_kind_t vtype_module;
1116 emit_pre_pop_reg(emit, &vtype_module, REG_ARG_1); // arg1 = module
1117 assert(vtype_module == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01001118 emit_call(emit, MP_F_IMPORT_ALL);
Damien Georgecdd96df2014-04-06 12:58:40 +01001119 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001120}
1121
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001122STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
Damien Georged6230f62014-09-23 14:10:03 +00001123 DEBUG_printf("load_const_tok(tok=%u)\n", tok);
Damien Georgece8f07a2014-03-27 23:30:26 +00001124 emit_native_pre(emit);
Damien George39dc1452014-10-03 19:52:22 +01001125 vtype_kind_t vtype;
Damien George40f3c022014-07-03 13:25:24 +01001126 mp_uint_t val;
Damien13ed3a62013-10-08 09:05:10 +01001127 if (emit->do_viper_types) {
1128 switch (tok) {
Damiend99b0522013-12-21 18:17:45 +00001129 case MP_TOKEN_KW_NONE: vtype = VTYPE_PTR_NONE; val = 0; break;
1130 case MP_TOKEN_KW_FALSE: vtype = VTYPE_BOOL; val = 0; break;
1131 case MP_TOKEN_KW_TRUE: vtype = VTYPE_BOOL; val = 1; break;
Damien George3da677e2015-01-29 15:13:40 +00001132 no_other_choice1:
1133 case MP_TOKEN_ELLIPSIS: vtype = VTYPE_PYOBJ; val = (mp_uint_t)&mp_const_ellipsis_obj; break;
1134 default: assert(0); goto no_other_choice1; // to help flow control analysis
Damien13ed3a62013-10-08 09:05:10 +01001135 }
1136 } else {
1137 vtype = VTYPE_PYOBJ;
1138 switch (tok) {
Damien George40f3c022014-07-03 13:25:24 +01001139 case MP_TOKEN_KW_NONE: val = (mp_uint_t)mp_const_none; break;
1140 case MP_TOKEN_KW_FALSE: val = (mp_uint_t)mp_const_false; break;
1141 case MP_TOKEN_KW_TRUE: val = (mp_uint_t)mp_const_true; break;
Damien George3da677e2015-01-29 15:13:40 +00001142 no_other_choice2:
1143 case MP_TOKEN_ELLIPSIS: val = (mp_uint_t)&mp_const_ellipsis_obj; break;
1144 default: assert(0); goto no_other_choice2; // to help flow control analysis
Damien13ed3a62013-10-08 09:05:10 +01001145 }
1146 }
1147 emit_post_push_imm(emit, vtype, val);
1148}
1149
Damien George40f3c022014-07-03 13:25:24 +01001150STATIC void emit_native_load_const_small_int(emit_t *emit, mp_int_t arg) {
Damien Georged6230f62014-09-23 14:10:03 +00001151 DEBUG_printf("load_const_small_int(int=" INT_FMT ")\n", arg);
Damien Georgece8f07a2014-03-27 23:30:26 +00001152 emit_native_pre(emit);
Damien13ed3a62013-10-08 09:05:10 +01001153 if (emit->do_viper_types) {
1154 emit_post_push_imm(emit, VTYPE_INT, arg);
1155 } else {
Damien George2686f9b2015-04-01 00:12:43 +01001156 emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(arg));
Damien13ed3a62013-10-08 09:05:10 +01001157 }
1158}
1159
Damien George7ff996c2014-09-08 23:05:16 +01001160STATIC void emit_native_load_const_str(emit_t *emit, qstr qst, bool bytes) {
Damien Georgece8f07a2014-03-27 23:30:26 +00001161 emit_native_pre(emit);
Damien Georgebb295462014-09-12 23:15:06 +01001162 // TODO: Eventually we want to be able to work with raw pointers in viper to
1163 // do native array access. For now we just load them as any other object.
1164 /*
Damien13ed3a62013-10-08 09:05:10 +01001165 if (emit->do_viper_types) {
1166 // not implemented properly
1167 // load a pointer to the asciiz string?
1168 assert(0);
Damien George7ff996c2014-09-08 23:05:16 +01001169 emit_post_push_imm(emit, VTYPE_PTR, (mp_uint_t)qstr_str(qst));
Damien Georgebb295462014-09-12 23:15:06 +01001170 } else
1171 */
1172 {
Damien Georgeb601d952014-06-30 05:17:25 +01001173 if (bytes) {
Damien George7ff996c2014-09-08 23:05:16 +01001174 emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_BYTES, qst, REG_ARG_1);
Damien Georgeb601d952014-06-30 05:17:25 +01001175 } else {
Damien George7ff996c2014-09-08 23:05:16 +01001176 emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_STR, qst, REG_ARG_1);
Damien Georgeb601d952014-06-30 05:17:25 +01001177 }
Damien13ed3a62013-10-08 09:05:10 +01001178 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1179 }
1180}
1181
Damien Georgedab13852015-01-13 15:55:54 +00001182STATIC void emit_native_load_const_obj(emit_t *emit, void *obj) {
1183 emit_native_pre(emit);
Damien George2127e9a2015-01-14 00:11:09 +00001184 need_reg_single(emit, REG_RET, 0);
Damien Georgedab13852015-01-13 15:55:54 +00001185 ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)obj, REG_RET);
1186 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1187}
1188
Damien George3558f622014-04-20 17:50:40 +01001189STATIC void emit_native_load_null(emit_t *emit) {
1190 emit_native_pre(emit);
1191 emit_post_push_imm(emit, VTYPE_PYOBJ, 0);
1192}
1193
Damien George0abb5602015-01-16 12:24:49 +00001194STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
1195 DEBUG_printf("load_fast(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
Damien13ed3a62013-10-08 09:05:10 +01001196 vtype_kind_t vtype = emit->local_vtype[local_num];
1197 if (vtype == VTYPE_UNBOUND) {
Damien George7ff996c2014-09-08 23:05:16 +01001198 printf("ViperTypeError: local %s used before type known\n", qstr_str(qst));
Damien13ed3a62013-10-08 09:05:10 +01001199 }
Damien Georgece8f07a2014-03-27 23:30:26 +00001200 emit_native_pre(emit);
Damien3ef4abb2013-10-12 16:53:13 +01001201#if N_X64
Damien13ed3a62013-10-08 09:05:10 +01001202 if (local_num == 0) {
1203 emit_post_push_reg(emit, vtype, REG_LOCAL_1);
Damien George81057362014-09-07 01:06:19 +01001204 } else if (local_num == 1) {
1205 emit_post_push_reg(emit, vtype, REG_LOCAL_2);
1206 } else if (local_num == 2) {
1207 emit_post_push_reg(emit, vtype, REG_LOCAL_3);
Damien13ed3a62013-10-08 09:05:10 +01001208 } else {
Damien George0b610de2014-09-29 16:25:04 +01001209 need_reg_single(emit, REG_TEMP0, 0);
1210 asm_x64_mov_local_to_r64(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
1211 emit_post_push_reg(emit, vtype, REG_TEMP0);
Damien13ed3a62013-10-08 09:05:10 +01001212 }
Damien Georgec90f59e2014-09-06 23:06:36 +01001213#elif N_X86
1214 if (local_num == 0) {
1215 emit_post_push_reg(emit, vtype, REG_LOCAL_1);
Damien George03281b32014-09-06 22:38:50 +00001216 } else if (local_num == 1) {
1217 emit_post_push_reg(emit, vtype, REG_LOCAL_2);
Damien George25d90412014-09-06 23:24:32 +00001218 } else if (local_num == 2) {
1219 emit_post_push_reg(emit, vtype, REG_LOCAL_3);
Damien Georgec90f59e2014-09-06 23:06:36 +01001220 } else {
Damien George0b610de2014-09-29 16:25:04 +01001221 need_reg_single(emit, REG_TEMP0, 0);
1222 asm_x86_mov_local_to_r32(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
1223 emit_post_push_reg(emit, vtype, REG_TEMP0);
Damien Georgec90f59e2014-09-06 23:06:36 +01001224 }
Damien3ef4abb2013-10-12 16:53:13 +01001225#elif N_THUMB
Damien13ed3a62013-10-08 09:05:10 +01001226 if (local_num == 0) {
1227 emit_post_push_reg(emit, vtype, REG_LOCAL_1);
1228 } else if (local_num == 1) {
1229 emit_post_push_reg(emit, vtype, REG_LOCAL_2);
1230 } else if (local_num == 2) {
1231 emit_post_push_reg(emit, vtype, REG_LOCAL_3);
1232 } else {
Damien George0b610de2014-09-29 16:25:04 +01001233 need_reg_single(emit, REG_TEMP0, 0);
1234 asm_thumb_mov_reg_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
1235 emit_post_push_reg(emit, vtype, REG_TEMP0);
Damien13ed3a62013-10-08 09:05:10 +01001236 }
Fabian Vogtfe3d16e2014-08-16 22:55:53 +02001237#elif N_ARM
1238 if (local_num == 0) {
1239 emit_post_push_reg(emit, vtype, REG_LOCAL_1);
1240 } else if (local_num == 1) {
1241 emit_post_push_reg(emit, vtype, REG_LOCAL_2);
1242 } else if (local_num == 2) {
1243 emit_post_push_reg(emit, vtype, REG_LOCAL_3);
1244 } else {
Damien George0b610de2014-09-29 16:25:04 +01001245 need_reg_single(emit, REG_TEMP0, 0);
1246 asm_arm_mov_reg_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
1247 emit_post_push_reg(emit, vtype, REG_TEMP0);
Fabian Vogtfe3d16e2014-08-16 22:55:53 +02001248 }
Damien Georgec90f59e2014-09-06 23:06:36 +01001249#else
1250 #error not implemented
Damien13ed3a62013-10-08 09:05:10 +01001251#endif
1252}
1253
Damien George7ff996c2014-09-08 23:05:16 +01001254STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
Damien George4cd9ced2015-01-15 14:41:41 +00001255 DEBUG_printf("load_deref(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
1256 need_reg_single(emit, REG_RET, 0);
1257 emit_native_load_fast(emit, qst, local_num);
1258 vtype_kind_t vtype;
1259 int reg_base = REG_RET;
1260 emit_pre_pop_reg_flexible(emit, &vtype, &reg_base, -1, -1);
1261 ASM_LOAD_REG_REG_OFFSET(emit->as, REG_RET, reg_base, 1);
1262 // closed over vars are always Python objects
1263 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien9ecbcff2013-12-11 00:41:43 +00001264}
1265
Damien George7ff996c2014-09-08 23:05:16 +01001266STATIC void emit_native_load_name(emit_t *emit, qstr qst) {
Damien Georged6230f62014-09-23 14:10:03 +00001267 DEBUG_printf("load_name(%s)\n", qstr_str(qst));
Damien Georgece8f07a2014-03-27 23:30:26 +00001268 emit_native_pre(emit);
Damien George7ff996c2014-09-08 23:05:16 +01001269 emit_call_with_imm_arg(emit, MP_F_LOAD_NAME, qst, REG_ARG_1);
Damien13ed3a62013-10-08 09:05:10 +01001270 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1271}
1272
Damien George7ff996c2014-09-08 23:05:16 +01001273STATIC void emit_native_load_global(emit_t *emit, qstr qst) {
Damien Georgee9dac3b2014-09-29 22:10:41 +01001274 DEBUG_printf("load_global(%s)\n", qstr_str(qst));
Damien Georgece8f07a2014-03-27 23:30:26 +00001275 emit_native_pre(emit);
Damien Georgee9dac3b2014-09-29 22:10:41 +01001276 // check for builtin casting operators
1277 if (emit->do_viper_types && qst == MP_QSTR_int) {
1278 emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_INT);
1279 } else if (emit->do_viper_types && qst == MP_QSTR_uint) {
1280 emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_UINT);
1281 } else if (emit->do_viper_types && qst == MP_QSTR_ptr) {
1282 emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR);
1283 } else if (emit->do_viper_types && qst == MP_QSTR_ptr8) {
1284 emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR8);
1285 } else if (emit->do_viper_types && qst == MP_QSTR_ptr16) {
1286 emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR16);
1287 } else {
1288 emit_call_with_imm_arg(emit, MP_F_LOAD_GLOBAL, qst, REG_ARG_1);
1289 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1290 }
Damien13ed3a62013-10-08 09:05:10 +01001291}
1292
Damien George7ff996c2014-09-08 23:05:16 +01001293STATIC void emit_native_load_attr(emit_t *emit, qstr qst) {
Damien13ed3a62013-10-08 09:05:10 +01001294 // depends on type of subject:
1295 // - integer, function, pointer to integers: error
1296 // - pointer to structure: get member, quite easy
Damien Georged17926d2014-03-30 13:35:08 +01001297 // - Python object: call mp_load_attr, and needs to be typed to convert result
Damien13ed3a62013-10-08 09:05:10 +01001298 vtype_kind_t vtype_base;
1299 emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
1300 assert(vtype_base == VTYPE_PYOBJ);
Damien George7ff996c2014-09-08 23:05:16 +01001301 emit_call_with_imm_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name
Damien13ed3a62013-10-08 09:05:10 +01001302 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1303}
1304
Damien George7ff996c2014-09-08 23:05:16 +01001305STATIC void emit_native_load_method(emit_t *emit, qstr qst) {
Damien13ed3a62013-10-08 09:05:10 +01001306 vtype_kind_t vtype_base;
1307 emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
1308 assert(vtype_base == VTYPE_PYOBJ);
1309 emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr
Damien George7ff996c2014-09-08 23:05:16 +01001310 emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name
Damien13ed3a62013-10-08 09:05:10 +01001311}
1312
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001313STATIC void emit_native_load_build_class(emit_t *emit) {
Damien Georgece8f07a2014-03-27 23:30:26 +00001314 emit_native_pre(emit);
Damien George7fe21912014-08-16 22:31:57 +01001315 emit_call(emit, MP_F_LOAD_BUILD_CLASS);
Damien7f5dacf2013-10-10 11:24:39 +01001316 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien13ed3a62013-10-08 09:05:10 +01001317}
1318
Damien George729f7b42014-04-17 22:10:53 +01001319STATIC void emit_native_load_subscr(emit_t *emit) {
Damien George91cfd412014-10-12 16:59:29 +01001320 DEBUG_printf("load_subscr\n");
1321 // need to compile: base[index]
1322
1323 // pop: index, base
1324 // optimise case where index is an immediate
1325 vtype_kind_t vtype_base = peek_vtype(emit, 1);
1326
1327 if (vtype_base == VTYPE_PYOBJ) {
1328 // standard Python call
1329 vtype_kind_t vtype_index;
1330 emit_pre_pop_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1);
1331 assert(vtype_index == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01001332 emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_SENTINEL, REG_ARG_3);
Damien George729f7b42014-04-17 22:10:53 +01001333 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1334 } else {
Damien George91cfd412014-10-12 16:59:29 +01001335 // viper load
1336 // TODO The different machine architectures have very different
1337 // capabilities and requirements for loads, so probably best to
1338 // write a completely separate load-optimiser for each one.
1339 stack_info_t *top = peek_stack(emit, 0);
1340 if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
1341 // index is an immediate
Damien George32444b72015-01-24 23:14:12 +00001342 mp_int_t index_value = top->data.u_imm;
Damien George91cfd412014-10-12 16:59:29 +01001343 emit_pre_pop_discard(emit); // discard index
1344 int reg_base = REG_ARG_1;
1345 int reg_index = REG_ARG_2;
1346 emit_pre_pop_reg_flexible(emit, &vtype_base, &reg_base, reg_index, reg_index);
1347 switch (vtype_base) {
1348 case VTYPE_PTR8: {
1349 // pointer to 8-bit memory
1350 // TODO optimise to use thumb ldrb r1, [r2, r3]
1351 if (index_value != 0) {
1352 // index is non-zero
1353 #if N_THUMB
1354 if (index_value > 0 && index_value < 32) {
1355 asm_thumb_ldrb_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);
1356 break;
1357 }
1358 #endif
1359 ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index);
1360 ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base
1361 reg_base = reg_index;
1362 }
1363 ASM_LOAD8_REG_REG(emit->as, REG_RET, reg_base); // load from (base+index)
1364 break;
1365 }
1366 case VTYPE_PTR16: {
1367 // pointer to 16-bit memory
1368 if (index_value != 0) {
1369 // index is a non-zero immediate
1370 #if N_THUMB
1371 if (index_value > 0 && index_value < 32) {
1372 asm_thumb_ldrh_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);
1373 break;
1374 }
1375 #endif
1376 ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index);
1377 ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base
1378 reg_base = reg_index;
1379 }
1380 ASM_LOAD16_REG_REG(emit->as, REG_RET, reg_base); // load from (base+2*index)
1381 break;
1382 }
1383 default:
1384 printf("ViperTypeError: can't load from type %d\n", vtype_base);
1385 }
1386 } else {
1387 // index is not an immediate
1388 vtype_kind_t vtype_index;
1389 int reg_index = REG_ARG_2;
1390 emit_pre_pop_reg_flexible(emit, &vtype_index, &reg_index, REG_ARG_1, REG_ARG_1);
1391 emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
1392 switch (vtype_base) {
1393 case VTYPE_PTR8: {
1394 // pointer to 8-bit memory
1395 // TODO optimise to use thumb ldrb r1, [r2, r3]
1396 assert(vtype_index == VTYPE_INT);
1397 ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1398 ASM_LOAD8_REG_REG(emit->as, REG_RET, REG_ARG_1); // store value to (base+index)
1399 break;
1400 }
1401 case VTYPE_PTR16: {
1402 // pointer to 16-bit memory
1403 assert(vtype_index == VTYPE_INT);
1404 ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1405 ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1406 ASM_LOAD16_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+2*index)
1407 break;
1408 }
1409 default:
1410 printf("ViperTypeError: can't load from type %d\n", vtype_base);
1411 }
1412 }
1413 emit_post_push_reg(emit, VTYPE_INT, REG_RET);
Damien George729f7b42014-04-17 22:10:53 +01001414 }
1415}
1416
Damien George7ff996c2014-09-08 23:05:16 +01001417STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
Damien13ed3a62013-10-08 09:05:10 +01001418 vtype_kind_t vtype;
Damien3ef4abb2013-10-12 16:53:13 +01001419#if N_X64
Damien13ed3a62013-10-08 09:05:10 +01001420 if (local_num == 0) {
1421 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
Damien George81057362014-09-07 01:06:19 +01001422 } else if (local_num == 1) {
1423 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
1424 } else if (local_num == 2) {
1425 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
Damien13ed3a62013-10-08 09:05:10 +01001426 } else {
Damien George0b610de2014-09-29 16:25:04 +01001427 emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
1428 asm_x64_mov_r64_to_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
Damien13ed3a62013-10-08 09:05:10 +01001429 }
Damien Georgec90f59e2014-09-06 23:06:36 +01001430#elif N_X86
1431 if (local_num == 0) {
1432 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
Damien George03281b32014-09-06 22:38:50 +00001433 } else if (local_num == 1) {
1434 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
Damien George25d90412014-09-06 23:24:32 +00001435 } else if (local_num == 2) {
1436 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
Damien Georgec90f59e2014-09-06 23:06:36 +01001437 } else {
Damien George0b610de2014-09-29 16:25:04 +01001438 emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
1439 asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
Damien Georgec90f59e2014-09-06 23:06:36 +01001440 }
Damien3ef4abb2013-10-12 16:53:13 +01001441#elif N_THUMB
Damien13ed3a62013-10-08 09:05:10 +01001442 if (local_num == 0) {
1443 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
1444 } else if (local_num == 1) {
1445 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
1446 } else if (local_num == 2) {
1447 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
1448 } else {
Damien George0b610de2014-09-29 16:25:04 +01001449 emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
1450 asm_thumb_mov_local_reg(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
Damien13ed3a62013-10-08 09:05:10 +01001451 }
Fabian Vogtfe3d16e2014-08-16 22:55:53 +02001452#elif N_ARM
1453 if (local_num == 0) {
1454 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
1455 } else if (local_num == 1) {
1456 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
1457 } else if (local_num == 2) {
1458 emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
1459 } else {
Damien George0b610de2014-09-29 16:25:04 +01001460 emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
1461 asm_arm_mov_local_reg(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
Fabian Vogtfe3d16e2014-08-16 22:55:53 +02001462 }
Damien Georgec90f59e2014-09-06 23:06:36 +01001463#else
1464 #error not implemented
Damien13ed3a62013-10-08 09:05:10 +01001465#endif
1466
1467 emit_post(emit);
1468
1469 // check types
1470 if (emit->local_vtype[local_num] == VTYPE_UNBOUND) {
1471 // first time this local is assigned, so give it a type of the object stored in it
1472 emit->local_vtype[local_num] = vtype;
1473 } else if (emit->local_vtype[local_num] != vtype) {
1474 // type of local is not the same as object stored in it
Damien George7ff996c2014-09-08 23:05:16 +01001475 printf("ViperTypeError: type mismatch, local %s has type %d but source object has type %d\n", qstr_str(qst), emit->local_vtype[local_num], vtype);
Damien13ed3a62013-10-08 09:05:10 +01001476 }
1477}
1478
Damien George7ff996c2014-09-08 23:05:16 +01001479STATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
Damien George4cd9ced2015-01-15 14:41:41 +00001480 DEBUG_printf("store_deref(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
1481 need_reg_single(emit, REG_TEMP0, 0);
1482 need_reg_single(emit, REG_TEMP1, 0);
1483 emit_native_load_fast(emit, qst, local_num);
1484 vtype_kind_t vtype;
1485 int reg_base = REG_TEMP0;
1486 emit_pre_pop_reg_flexible(emit, &vtype, &reg_base, -1, -1);
1487 int reg_src = REG_TEMP1;
1488 emit_pre_pop_reg_flexible(emit, &vtype, &reg_src, reg_base, reg_base);
1489 ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, reg_base, 1);
1490 emit_post(emit);
Damien9ecbcff2013-12-11 00:41:43 +00001491}
1492
Damien George7ff996c2014-09-08 23:05:16 +01001493STATIC void emit_native_store_name(emit_t *emit, qstr qst) {
Damien Georged17926d2014-03-30 13:35:08 +01001494 // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type))
Damien13ed3a62013-10-08 09:05:10 +01001495 vtype_kind_t vtype;
1496 emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
1497 assert(vtype == VTYPE_PYOBJ);
Damien George7ff996c2014-09-08 23:05:16 +01001498 emit_call_with_imm_arg(emit, MP_F_STORE_NAME, qst, REG_ARG_1); // arg1 = name
Damien13ed3a62013-10-08 09:05:10 +01001499 emit_post(emit);
1500}
1501
Damien George7ff996c2014-09-08 23:05:16 +01001502STATIC void emit_native_store_global(emit_t *emit, qstr qst) {
Damien George3112cde2014-09-29 18:45:42 +01001503 vtype_kind_t vtype = peek_vtype(emit, 0);
Damien Georgee6c0dff2014-08-15 23:47:59 +01001504 if (vtype == VTYPE_PYOBJ) {
1505 emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
1506 } else {
1507 emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
Damien George7fe21912014-08-16 22:31:57 +01001508 emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type
Damien George3112cde2014-09-29 18:45:42 +01001509 ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);
Damien Georgee6c0dff2014-08-15 23:47:59 +01001510 }
Damien George7ff996c2014-09-08 23:05:16 +01001511 emit_call_with_imm_arg(emit, MP_F_STORE_GLOBAL, qst, REG_ARG_1); // arg1 = name
Damien Georgee6c0dff2014-08-15 23:47:59 +01001512 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001513}
1514
Damien George7ff996c2014-09-08 23:05:16 +01001515STATIC void emit_native_store_attr(emit_t *emit, qstr qst) {
Damien7f5dacf2013-10-10 11:24:39 +01001516 vtype_kind_t vtype_base, vtype_val;
1517 emit_pre_pop_reg_reg(emit, &vtype_base, REG_ARG_1, &vtype_val, REG_ARG_3); // arg1 = base, arg3 = value
1518 assert(vtype_base == VTYPE_PYOBJ);
1519 assert(vtype_val == VTYPE_PYOBJ);
Damien George7ff996c2014-09-08 23:05:16 +01001520 emit_call_with_imm_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name
Damien7f5dacf2013-10-10 11:24:39 +01001521 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001522}
1523
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001524STATIC void emit_native_store_subscr(emit_t *emit) {
Damien Georgee9dac3b2014-09-29 22:10:41 +01001525 DEBUG_printf("store_subscr\n");
1526 // need to compile: base[index] = value
1527
1528 // pop: index, base, value
1529 // optimise case where index is an immediate
1530 vtype_kind_t vtype_base = peek_vtype(emit, 1);
1531
1532 if (vtype_base == VTYPE_PYOBJ) {
1533 // standard Python call
1534 vtype_kind_t vtype_index, vtype_value;
1535 emit_pre_pop_reg_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1, &vtype_value, REG_ARG_3);
1536 assert(vtype_index == VTYPE_PYOBJ);
1537 assert(vtype_value == VTYPE_PYOBJ);
1538 emit_call(emit, MP_F_OBJ_SUBSCR);
1539 } else {
Damien Georgedfef4242014-09-29 21:41:41 +00001540 // viper store
1541 // TODO The different machine architectures have very different
1542 // capabilities and requirements for stores, so probably best to
1543 // write a completely separate store-optimiser for each one.
Damien Georgee9dac3b2014-09-29 22:10:41 +01001544 stack_info_t *top = peek_stack(emit, 0);
1545 if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
1546 // index is an immediate
Damien George32444b72015-01-24 23:14:12 +00001547 mp_int_t index_value = top->data.u_imm;
Damien Georgee9dac3b2014-09-29 22:10:41 +01001548 emit_pre_pop_discard(emit); // discard index
1549 vtype_kind_t vtype_value;
1550 int reg_base = REG_ARG_1;
1551 int reg_index = REG_ARG_2;
1552 int reg_value = REG_ARG_3;
1553 emit_pre_pop_reg_flexible(emit, &vtype_base, &reg_base, reg_index, reg_value);
Damien Georgedfef4242014-09-29 21:41:41 +00001554 #if N_X86
1555 // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
1556 emit_pre_pop_reg(emit, &vtype_value, reg_value);
1557 #else
Damien Georgee9dac3b2014-09-29 22:10:41 +01001558 emit_pre_pop_reg_flexible(emit, &vtype_value, &reg_value, reg_base, reg_index);
Damien Georgedfef4242014-09-29 21:41:41 +00001559 #endif
Damien Georgee9dac3b2014-09-29 22:10:41 +01001560 switch (vtype_base) {
1561 case VTYPE_PTR8: {
1562 // pointer to 8-bit memory
1563 // TODO optimise to use thumb strb r1, [r2, r3]
1564 if (index_value != 0) {
1565 // index is non-zero
1566 #if N_THUMB
1567 if (index_value > 0 && index_value < 32) {
1568 asm_thumb_strb_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value);
1569 break;
1570 }
1571 #endif
1572 ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index);
Fabian Vogte5268962014-10-04 00:53:46 +02001573 #if N_ARM
1574 asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
1575 return;
1576 #endif
Damien Georgee9dac3b2014-09-29 22:10:41 +01001577 ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base
1578 reg_base = reg_index;
1579 }
1580 ASM_STORE8_REG_REG(emit->as, reg_value, reg_base); // store value to (base+index)
1581 break;
1582 }
1583 case VTYPE_PTR16: {
1584 // pointer to 16-bit memory
1585 if (index_value != 0) {
1586 // index is a non-zero immediate
1587 #if N_THUMB
1588 if (index_value > 0 && index_value < 32) {
1589 asm_thumb_strh_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value);
1590 break;
1591 }
1592 #endif
1593 ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index);
Fabian Vogte5268962014-10-04 00:53:46 +02001594 #if N_ARM
1595 asm_arm_strh_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
1596 return;
1597 #endif
Damien Georgee9dac3b2014-09-29 22:10:41 +01001598 ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base
1599 reg_base = reg_index;
1600 }
1601 ASM_STORE16_REG_REG(emit->as, reg_value, reg_base); // store value to (base+2*index)
1602 break;
1603 }
1604 default:
1605 printf("ViperTypeError: can't store to type %d\n", vtype_base);
1606 }
1607 } else {
1608 // index is not an immediate
1609 vtype_kind_t vtype_index, vtype_value;
1610 int reg_index = REG_ARG_2;
1611 int reg_value = REG_ARG_3;
1612 emit_pre_pop_reg_flexible(emit, &vtype_index, &reg_index, REG_ARG_1, reg_value);
1613 emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
Damien Georgedfef4242014-09-29 21:41:41 +00001614 #if N_X86
1615 // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
1616 emit_pre_pop_reg(emit, &vtype_value, reg_value);
1617 #else
Damien Georgee9dac3b2014-09-29 22:10:41 +01001618 emit_pre_pop_reg_flexible(emit, &vtype_value, &reg_value, REG_ARG_1, reg_index);
Damien Georgedfef4242014-09-29 21:41:41 +00001619 #endif
Damien Georgee9dac3b2014-09-29 22:10:41 +01001620 switch (vtype_base) {
1621 case VTYPE_PTR8: {
1622 // pointer to 8-bit memory
1623 // TODO optimise to use thumb strb r1, [r2, r3]
1624 assert(vtype_index == VTYPE_INT);
Fabian Vogte5268962014-10-04 00:53:46 +02001625 #if N_ARM
1626 asm_arm_strb_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
1627 break;
1628 #endif
Damien Georgee9dac3b2014-09-29 22:10:41 +01001629 ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1630 ASM_STORE8_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+index)
1631 break;
1632 }
1633 case VTYPE_PTR16: {
1634 // pointer to 16-bit memory
1635 assert(vtype_index == VTYPE_INT);
Fabian Vogte5268962014-10-04 00:53:46 +02001636 #if N_ARM
1637 asm_arm_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
1638 break;
1639 #endif
Damien Georgee9dac3b2014-09-29 22:10:41 +01001640 ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1641 ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1642 ASM_STORE16_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+2*index)
1643 break;
1644 }
1645 default:
1646 printf("ViperTypeError: can't store to type %d\n", vtype_base);
1647 }
1648 }
1649
1650 }
Damien13ed3a62013-10-08 09:05:10 +01001651}
1652
Damien George7ff996c2014-09-08 23:05:16 +01001653STATIC void emit_native_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
Damien George2cc54732015-04-03 14:29:30 +01001654 // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL
1655 // to mark deleted vars but then every var would need to be checked on
1656 // each access. Very inefficient, so just set value to None to enable GC.
1657 emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE);
1658 emit_native_store_fast(emit, qst, local_num);
Damien13ed3a62013-10-08 09:05:10 +01001659}
1660
Damien George7ff996c2014-09-08 23:05:16 +01001661STATIC void emit_native_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
Damien Georgee6ce10a2014-09-06 18:38:20 +01001662 // TODO implement me!
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001663 (void)emit;
1664 (void)qst;
1665 (void)local_num;
Damien9ecbcff2013-12-11 00:41:43 +00001666}
1667
Damien Georgee6ce10a2014-09-06 18:38:20 +01001668STATIC void emit_native_delete_name(emit_t *emit, qstr qst) {
1669 emit_native_pre(emit);
1670 emit_call_with_imm_arg(emit, MP_F_DELETE_NAME, qst, REG_ARG_1);
1671 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001672}
1673
Damien Georgee6ce10a2014-09-06 18:38:20 +01001674STATIC void emit_native_delete_global(emit_t *emit, qstr qst) {
1675 emit_native_pre(emit);
1676 emit_call_with_imm_arg(emit, MP_F_DELETE_GLOBAL, qst, REG_ARG_1);
1677 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001678}
1679
Damien Georgee6ce10a2014-09-06 18:38:20 +01001680STATIC void emit_native_delete_attr(emit_t *emit, qstr qst) {
Damien George780e54c2014-06-22 18:35:04 +01001681 vtype_kind_t vtype_base;
1682 emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
1683 assert(vtype_base == VTYPE_PYOBJ);
Damien Georgee6ce10a2014-09-06 18:38:20 +01001684 emit_call_with_2_imm_args(emit, MP_F_STORE_ATTR, qst, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg2 = attribute name, arg3 = value (null for delete)
Damien George780e54c2014-06-22 18:35:04 +01001685 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001686}
1687
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001688STATIC void emit_native_delete_subscr(emit_t *emit) {
Damien George729f7b42014-04-17 22:10:53 +01001689 vtype_kind_t vtype_index, vtype_base;
1690 emit_pre_pop_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1); // index, base
1691 assert(vtype_index == VTYPE_PYOBJ);
1692 assert(vtype_base == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01001693 emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3);
Damien13ed3a62013-10-08 09:05:10 +01001694}
1695
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001696STATIC void emit_native_dup_top(emit_t *emit) {
Damien Georged6230f62014-09-23 14:10:03 +00001697 DEBUG_printf("dup_top\n");
Damien13ed3a62013-10-08 09:05:10 +01001698 vtype_kind_t vtype;
Damien George21ca2d72014-10-19 19:00:51 +01001699 int reg = REG_TEMP0;
1700 emit_pre_pop_reg_flexible(emit, &vtype, &reg, -1, -1);
1701 emit_post_push_reg_reg(emit, vtype, reg, vtype, reg);
Damien13ed3a62013-10-08 09:05:10 +01001702}
1703
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001704STATIC void emit_native_dup_top_two(emit_t *emit) {
Damien13ed3a62013-10-08 09:05:10 +01001705 vtype_kind_t vtype0, vtype1;
1706 emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1);
1707 emit_post_push_reg_reg_reg_reg(emit, vtype1, REG_TEMP1, vtype0, REG_TEMP0, vtype1, REG_TEMP1, vtype0, REG_TEMP0);
1708}
1709
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001710STATIC void emit_native_pop_top(emit_t *emit) {
Damien Georged6230f62014-09-23 14:10:03 +00001711 DEBUG_printf("pop_top\n");
Damien Georgee6ce10a2014-09-06 18:38:20 +01001712 emit_pre_pop_discard(emit);
Damien13ed3a62013-10-08 09:05:10 +01001713 emit_post(emit);
1714}
1715
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001716STATIC void emit_native_rot_two(emit_t *emit) {
Damien Georged6230f62014-09-23 14:10:03 +00001717 DEBUG_printf("rot_two\n");
Damienff8ed772013-10-08 22:18:32 +01001718 vtype_kind_t vtype0, vtype1;
1719 emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1);
1720 emit_post_push_reg_reg(emit, vtype0, REG_TEMP0, vtype1, REG_TEMP1);
Damien13ed3a62013-10-08 09:05:10 +01001721}
1722
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001723STATIC void emit_native_rot_three(emit_t *emit) {
Damien Georged6230f62014-09-23 14:10:03 +00001724 DEBUG_printf("rot_three\n");
Damien13ed3a62013-10-08 09:05:10 +01001725 vtype_kind_t vtype0, vtype1, vtype2;
1726 emit_pre_pop_reg_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1, &vtype2, REG_TEMP2);
1727 emit_post_push_reg_reg_reg(emit, vtype0, REG_TEMP0, vtype2, REG_TEMP2, vtype1, REG_TEMP1);
1728}
1729
Damien George7ff996c2014-09-08 23:05:16 +01001730STATIC void emit_native_jump(emit_t *emit, mp_uint_t label) {
Damien Georged6230f62014-09-23 14:10:03 +00001731 DEBUG_printf("jump(label=" UINT_FMT ")\n", label);
Damien Georgece8f07a2014-03-27 23:30:26 +00001732 emit_native_pre(emit);
Damien Georgea32c1e42014-05-07 18:30:52 +01001733 // need to commit stack because we are jumping elsewhere
1734 need_stack_settled(emit);
Damien Georgec90f59e2014-09-06 23:06:36 +01001735 ASM_JUMP(emit->as, label);
Damien13ed3a62013-10-08 09:05:10 +01001736 emit_post(emit);
1737}
1738
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001739STATIC void emit_native_jump_helper(emit_t *emit, bool pop) {
Damien George3112cde2014-09-29 18:45:42 +01001740 vtype_kind_t vtype = peek_vtype(emit, 0);
Damien George6f813482014-09-29 16:41:37 +01001741 switch (vtype) {
1742 case VTYPE_PYOBJ:
1743 emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
1744 if (!pop) {
1745 adjust_stack(emit, 1);
1746 }
1747 emit_call(emit, MP_F_OBJ_IS_TRUE);
1748 break;
1749 case VTYPE_BOOL:
1750 case VTYPE_INT:
1751 case VTYPE_UINT:
1752 emit_pre_pop_reg(emit, &vtype, REG_RET);
1753 if (!pop) {
1754 adjust_stack(emit, 1);
1755 }
1756 break;
1757 default:
1758 printf("ViperTypeError: expecting a bool or pyobj, got %d\n", vtype);
1759 assert(0);
Damien13ed3a62013-10-08 09:05:10 +01001760 }
Damien George21ca2d72014-10-19 19:00:51 +01001761 // For non-pop need to save the vtype so that emit_native_adjust_stack_size
1762 // can use it. This is a bit of a hack.
1763 if (!pop) {
1764 emit->saved_stack_vtype = vtype;
1765 }
Damien Georgea32c1e42014-05-07 18:30:52 +01001766 // need to commit stack because we may jump elsewhere
1767 need_stack_settled(emit);
Damien13ed3a62013-10-08 09:05:10 +01001768}
1769
Damien George63f38322015-02-28 15:04:06 +00001770STATIC void emit_native_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) {
1771 DEBUG_printf("pop_jump_if(cond=%u, label=" UINT_FMT ")\n", cond, label);
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001772 emit_native_jump_helper(emit, true);
Damien George63f38322015-02-28 15:04:06 +00001773 if (cond) {
1774 ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
1775 } else {
1776 ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label);
1777 }
Damien1a6633a2013-11-03 13:58:19 +00001778 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001779}
Damien1a6633a2013-11-03 13:58:19 +00001780
Damien George63f38322015-02-28 15:04:06 +00001781STATIC void emit_native_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) {
1782 DEBUG_printf("jump_if_or_pop(cond=%u, label=" UINT_FMT ")\n", cond, label);
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001783 emit_native_jump_helper(emit, false);
Damien George63f38322015-02-28 15:04:06 +00001784 if (cond) {
1785 ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
1786 } else {
1787 ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label);
1788 }
Damien Georgea32c1e42014-05-07 18:30:52 +01001789 adjust_stack(emit, -1);
1790 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001791}
1792
Damien George7ff996c2014-09-08 23:05:16 +01001793STATIC void emit_native_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001794 (void)except_depth;
Damien George25c84642014-05-30 15:20:41 +01001795 emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly
Damien13ed3a62013-10-08 09:05:10 +01001796}
Damien Georgea32c1e42014-05-07 18:30:52 +01001797
Damien George7ff996c2014-09-08 23:05:16 +01001798STATIC void emit_native_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001799 (void)except_depth;
Damien Georgea32c1e42014-05-07 18:30:52 +01001800 emit_native_jump(emit, label); // TODO properly
Damien13ed3a62013-10-08 09:05:10 +01001801}
Damien Georgea32c1e42014-05-07 18:30:52 +01001802
Damien George7ff996c2014-09-08 23:05:16 +01001803STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) {
Damien13ed3a62013-10-08 09:05:10 +01001804 // not supported, or could be with runtime call
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001805 (void)emit;
1806 (void)label;
Damien13ed3a62013-10-08 09:05:10 +01001807 assert(0);
1808}
Damien Georgeb601d952014-06-30 05:17:25 +01001809
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001810STATIC void emit_native_with_cleanup(emit_t *emit) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001811 (void)emit;
Damien13ed3a62013-10-08 09:05:10 +01001812 assert(0);
1813}
Damien Georgeb601d952014-06-30 05:17:25 +01001814
Damien George7ff996c2014-09-08 23:05:16 +01001815STATIC void emit_native_setup_except(emit_t *emit, mp_uint_t label) {
Damien Georgeb601d952014-06-30 05:17:25 +01001816 emit_native_pre(emit);
1817 // need to commit stack because we may jump elsewhere
1818 need_stack_settled(emit);
Damien George40f3c022014-07-03 13:25:24 +01001819 emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf
Damien George7fe21912014-08-16 22:31:57 +01001820 emit_call(emit, MP_F_NLR_PUSH);
Damien Georgec90f59e2014-09-06 23:06:36 +01001821 ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
Damien Georgeb601d952014-06-30 05:17:25 +01001822 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001823}
Damien Georgeb601d952014-06-30 05:17:25 +01001824
Damien George7ff996c2014-09-08 23:05:16 +01001825STATIC void emit_native_setup_finally(emit_t *emit, mp_uint_t label) {
Damien Georgee6ce10a2014-09-06 18:38:20 +01001826 emit_native_setup_except(emit, label);
Damien13ed3a62013-10-08 09:05:10 +01001827}
Damien Georgeb601d952014-06-30 05:17:25 +01001828
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001829STATIC void emit_native_end_finally(emit_t *emit) {
Damien Georgeb6e6b522015-01-21 17:00:01 +00001830 // logic:
1831 // exc = pop_stack
1832 // if exc == None: pass
1833 // else: raise exc
1834 // the check if exc is None is done in the MP_F_NATIVE_RAISE stub
1835 vtype_kind_t vtype;
1836 emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
1837 emit_call(emit, MP_F_NATIVE_RAISE);
Damien Georgee6ce10a2014-09-06 18:38:20 +01001838 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001839}
Damiend2755ec2013-10-16 23:58:48 +01001840
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001841STATIC void emit_native_get_iter(emit_t *emit) {
Damien13ed3a62013-10-08 09:05:10 +01001842 // perhaps the difficult one, as we want to rewrite for loops using native code
1843 // in cases where we iterate over a Python object, can we use normal runtime calls?
Damiend2755ec2013-10-16 23:58:48 +01001844
1845 vtype_kind_t vtype;
1846 emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
1847 assert(vtype == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01001848 emit_call(emit, MP_F_GETITER);
Damiend2755ec2013-10-16 23:58:48 +01001849 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien13ed3a62013-10-08 09:05:10 +01001850}
Damiend2755ec2013-10-16 23:58:48 +01001851
Damien George7ff996c2014-09-08 23:05:16 +01001852STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) {
Damien Georgece8f07a2014-03-27 23:30:26 +00001853 emit_native_pre(emit);
Damiend2755ec2013-10-16 23:58:48 +01001854 vtype_kind_t vtype;
1855 emit_access_stack(emit, 1, &vtype, REG_ARG_1);
1856 assert(vtype == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01001857 emit_call(emit, MP_F_ITERNEXT);
Damien Georgec90f59e2014-09-06 23:06:36 +01001858 ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1);
1859 ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label);
Damiend2755ec2013-10-16 23:58:48 +01001860 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1861}
1862
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001863STATIC void emit_native_for_iter_end(emit_t *emit) {
Damiend2755ec2013-10-16 23:58:48 +01001864 // adjust stack counter (we get here from for_iter ending, which popped the value for us)
Damien Georgece8f07a2014-03-27 23:30:26 +00001865 emit_native_pre(emit);
Damiend2755ec2013-10-16 23:58:48 +01001866 adjust_stack(emit, -1);
1867 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01001868}
1869
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001870STATIC void emit_native_pop_block(emit_t *emit) {
Damien Georgece8f07a2014-03-27 23:30:26 +00001871 emit_native_pre(emit);
Damien George7fe21912014-08-16 22:31:57 +01001872 emit_call(emit, MP_F_NLR_POP);
Damien George40f3c022014-07-03 13:25:24 +01001873 adjust_stack(emit, -(mp_int_t)(sizeof(nlr_buf_t) / sizeof(mp_uint_t)));
Damien13ed3a62013-10-08 09:05:10 +01001874 emit_post(emit);
1875}
1876
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02001877STATIC void emit_native_pop_except(emit_t *emit) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +00001878 (void)emit;
Damien Georgeb601d952014-06-30 05:17:25 +01001879 /*
1880 emit_native_pre(emit);
Damien George7fe21912014-08-16 22:31:57 +01001881 emit_call(emit, MP_F_NLR_POP);
Damien George40f3c022014-07-03 13:25:24 +01001882 adjust_stack(emit, -(mp_int_t)(sizeof(nlr_buf_t) / sizeof(mp_uint_t)));
Damien Georgeb601d952014-06-30 05:17:25 +01001883 emit_post(emit);
1884 */
Damien13ed3a62013-10-08 09:05:10 +01001885}
1886
Damien Georged17926d2014-03-30 13:35:08 +01001887STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {
Damien Georged6230f62014-09-23 14:10:03 +00001888 vtype_kind_t vtype;
1889 emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
1890 assert(vtype == VTYPE_PYOBJ);
Damien Georgeb601d952014-06-30 05:17:25 +01001891 if (op == MP_UNARY_OP_NOT) {
Damien Georged6230f62014-09-23 14:10:03 +00001892 // we need to synthesise this operation by converting to bool first
1893 emit_call_with_imm_arg(emit, MP_F_UNARY_OP, MP_UNARY_OP_BOOL, REG_ARG_1);
Damien George3112cde2014-09-29 18:45:42 +01001894 ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);
Damien Georgeb601d952014-06-30 05:17:25 +01001895 }
Damien Georged6230f62014-09-23 14:10:03 +00001896 emit_call_with_imm_arg(emit, MP_F_UNARY_OP, op, REG_ARG_1);
1897 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien13ed3a62013-10-08 09:05:10 +01001898}
1899
Damien Georged17926d2014-03-30 13:35:08 +01001900STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
Damien Georged6230f62014-09-23 14:10:03 +00001901 DEBUG_printf("binary_op(" UINT_FMT ")\n", op);
Damien George3112cde2014-09-29 18:45:42 +01001902 vtype_kind_t vtype_lhs = peek_vtype(emit, 1);
1903 vtype_kind_t vtype_rhs = peek_vtype(emit, 0);
Damien13ed3a62013-10-08 09:05:10 +01001904 if (vtype_lhs == VTYPE_INT && vtype_rhs == VTYPE_INT) {
Damien George3112cde2014-09-29 18:45:42 +01001905 #if N_X64 || N_X86
1906 // special cases for x86 and shifting
1907 if (op == MP_BINARY_OP_LSHIFT
1908 || op == MP_BINARY_OP_INPLACE_LSHIFT
1909 || op == MP_BINARY_OP_RSHIFT
1910 || op == MP_BINARY_OP_INPLACE_RSHIFT) {
1911 #if N_X64
1912 emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X64_REG_RCX, &vtype_lhs, REG_RET);
1913 #else
1914 emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X86_REG_ECX, &vtype_lhs, REG_RET);
1915 #endif
1916 if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
1917 ASM_LSL_REG(emit->as, REG_RET);
1918 } else {
1919 ASM_ASR_REG(emit->as, REG_RET);
1920 }
1921 emit_post_push_reg(emit, VTYPE_INT, REG_RET);
1922 return;
1923 }
1924 #endif
1925 int reg_rhs = REG_ARG_3;
Damien Georgee9dac3b2014-09-29 22:10:41 +01001926 emit_pre_pop_reg_flexible(emit, &vtype_rhs, &reg_rhs, REG_RET, REG_ARG_2);
Damien George3112cde2014-09-29 18:45:42 +01001927 emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2);
1928 if (0) {
1929 // dummy
1930 #if !(N_X64 || N_X86)
1931 } else if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
1932 ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
Damien Georgebc1d3692014-01-11 09:47:06 +00001933 emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
Damien George3112cde2014-09-29 18:45:42 +01001934 } else if (op == MP_BINARY_OP_RSHIFT || op == MP_BINARY_OP_INPLACE_RSHIFT) {
1935 ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
1936 emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
1937 #endif
Damien George1ef23482014-10-12 14:21:06 +01001938 } else if (op == MP_BINARY_OP_OR || op == MP_BINARY_OP_INPLACE_OR) {
1939 ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
1940 emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
1941 } else if (op == MP_BINARY_OP_XOR || op == MP_BINARY_OP_INPLACE_XOR) {
1942 ASM_XOR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
1943 emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
1944 } else if (op == MP_BINARY_OP_AND || op == MP_BINARY_OP_INPLACE_AND) {
1945 ASM_AND_REG_REG(emit->as, REG_ARG_2, reg_rhs);
1946 emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
Damien George3112cde2014-09-29 18:45:42 +01001947 } else if (op == MP_BINARY_OP_ADD || op == MP_BINARY_OP_INPLACE_ADD) {
1948 ASM_ADD_REG_REG(emit->as, REG_ARG_2, reg_rhs);
1949 emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
1950 } else if (op == MP_BINARY_OP_SUBTRACT || op == MP_BINARY_OP_INPLACE_SUBTRACT) {
1951 ASM_SUB_REG_REG(emit->as, REG_ARG_2, reg_rhs);
1952 emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
1953 } else if (MP_BINARY_OP_LESS <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
1954 // comparison ops are (in enum order):
1955 // MP_BINARY_OP_LESS
1956 // MP_BINARY_OP_MORE
1957 // MP_BINARY_OP_EQUAL
1958 // MP_BINARY_OP_LESS_EQUAL
1959 // MP_BINARY_OP_MORE_EQUAL
1960 // MP_BINARY_OP_NOT_EQUAL
Damien George21ca2d72014-10-19 19:00:51 +01001961 need_reg_single(emit, REG_RET, 0);
Damien George3112cde2014-09-29 18:45:42 +01001962 #if N_X64
1963 asm_x64_xor_r64_r64(emit->as, REG_RET, REG_RET);
1964 asm_x64_cmp_r64_with_r64(emit->as, reg_rhs, REG_ARG_2);
1965 static byte ops[6] = {
1966 ASM_X64_CC_JL,
1967 ASM_X64_CC_JG,
1968 ASM_X64_CC_JE,
1969 ASM_X64_CC_JLE,
1970 ASM_X64_CC_JGE,
1971 ASM_X64_CC_JNE,
1972 };
1973 asm_x64_setcc_r8(emit->as, ops[op - MP_BINARY_OP_LESS], REG_RET);
1974 #elif N_X86
1975 asm_x86_xor_r32_r32(emit->as, REG_RET, REG_RET);
1976 asm_x86_cmp_r32_with_r32(emit->as, reg_rhs, REG_ARG_2);
1977 static byte ops[6] = {
1978 ASM_X86_CC_JL,
1979 ASM_X86_CC_JG,
1980 ASM_X86_CC_JE,
1981 ASM_X86_CC_JLE,
1982 ASM_X86_CC_JGE,
1983 ASM_X86_CC_JNE,
1984 };
1985 asm_x86_setcc_r8(emit->as, ops[op - MP_BINARY_OP_LESS], REG_RET);
1986 #elif N_THUMB
1987 asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs);
1988 static uint16_t ops[6] = {
1989 ASM_THUMB_OP_ITE_GE,
1990 ASM_THUMB_OP_ITE_GT,
1991 ASM_THUMB_OP_ITE_EQ,
1992 ASM_THUMB_OP_ITE_GT,
1993 ASM_THUMB_OP_ITE_GE,
1994 ASM_THUMB_OP_ITE_EQ,
1995 };
1996 static byte ret[6] = { 0, 1, 1, 0, 1, 0, };
1997 asm_thumb_op16(emit->as, ops[op - MP_BINARY_OP_LESS]);
1998 asm_thumb_mov_rlo_i8(emit->as, REG_RET, ret[op - MP_BINARY_OP_LESS]);
1999 asm_thumb_mov_rlo_i8(emit->as, REG_RET, ret[op - MP_BINARY_OP_LESS] ^ 1);
2000 #elif N_ARM
Fabian Vogte5268962014-10-04 00:53:46 +02002001 asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs);
2002 static uint ccs[6] = {
2003 ASM_ARM_CC_LT,
2004 ASM_ARM_CC_GT,
2005 ASM_ARM_CC_EQ,
2006 ASM_ARM_CC_LE,
2007 ASM_ARM_CC_GE,
2008 ASM_ARM_CC_NE,
2009 };
2010 asm_arm_setcc_reg(emit->as, REG_RET, ccs[op - MP_BINARY_OP_LESS]);
Damien George3112cde2014-09-29 18:45:42 +01002011 #else
2012 #error not implemented
2013 #endif
Damien Georgebc1d3692014-01-11 09:47:06 +00002014 emit_post_push_reg(emit, VTYPE_BOOL, REG_RET);
2015 } else {
2016 // TODO other ops not yet implemented
2017 assert(0);
2018 }
Damien13ed3a62013-10-08 09:05:10 +01002019 } else if (vtype_lhs == VTYPE_PYOBJ && vtype_rhs == VTYPE_PYOBJ) {
Damien George3112cde2014-09-29 18:45:42 +01002020 emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_3, &vtype_lhs, REG_ARG_2);
Damien Georged6230f62014-09-23 14:10:03 +00002021 bool invert = false;
2022 if (op == MP_BINARY_OP_NOT_IN) {
2023 invert = true;
2024 op = MP_BINARY_OP_IN;
2025 } else if (op == MP_BINARY_OP_IS_NOT) {
2026 invert = true;
2027 op = MP_BINARY_OP_IS;
2028 }
Damien George7fe21912014-08-16 22:31:57 +01002029 emit_call_with_imm_arg(emit, MP_F_BINARY_OP, op, REG_ARG_1);
Damien Georged6230f62014-09-23 14:10:03 +00002030 if (invert) {
Damien George3112cde2014-09-29 18:45:42 +01002031 ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);
Damien Georged6230f62014-09-23 14:10:03 +00002032 emit_call_with_imm_arg(emit, MP_F_UNARY_OP, MP_UNARY_OP_NOT, REG_ARG_1);
2033 }
Damien13ed3a62013-10-08 09:05:10 +01002034 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2035 } else {
2036 printf("ViperTypeError: can't do binary op between types %d and %d\n", vtype_lhs, vtype_rhs);
Damien Georgea5190a72014-08-15 22:39:08 +01002037 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien13ed3a62013-10-08 09:05:10 +01002038 }
2039}
2040
Damien George7ff996c2014-09-08 23:05:16 +01002041STATIC void emit_native_build_tuple(emit_t *emit, mp_uint_t n_args) {
Damiend2755ec2013-10-16 23:58:48 +01002042 // for viper: call runtime, with types of args
2043 // if wrapped in byte_array, or something, allocates memory and fills it
Damien Georgece8f07a2014-03-27 23:30:26 +00002044 emit_native_pre(emit);
Damien Georgecd82e022014-02-02 13:11:48 +00002045 emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items
Damien George7fe21912014-08-16 22:31:57 +01002046 emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE, n_args, REG_ARG_1);
Damiend2755ec2013-10-16 23:58:48 +01002047 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple
Damien13ed3a62013-10-08 09:05:10 +01002048}
2049
Damien George7ff996c2014-09-08 23:05:16 +01002050STATIC void emit_native_build_list(emit_t *emit, mp_uint_t n_args) {
Damien Georgece8f07a2014-03-27 23:30:26 +00002051 emit_native_pre(emit);
Damien Georgecd82e022014-02-02 13:11:48 +00002052 emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items
Damien George7fe21912014-08-16 22:31:57 +01002053 emit_call_with_imm_arg(emit, MP_F_BUILD_LIST, n_args, REG_ARG_1);
Damien13ed3a62013-10-08 09:05:10 +01002054 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new list
2055}
2056
Damien George7ff996c2014-09-08 23:05:16 +01002057STATIC void emit_native_list_append(emit_t *emit, mp_uint_t list_index) {
Damiend2755ec2013-10-16 23:58:48 +01002058 // only used in list comprehension
2059 vtype_kind_t vtype_list, vtype_item;
2060 emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2);
2061 emit_access_stack(emit, list_index, &vtype_list, REG_ARG_1);
2062 assert(vtype_list == VTYPE_PYOBJ);
2063 assert(vtype_item == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01002064 emit_call(emit, MP_F_LIST_APPEND);
Damiend2755ec2013-10-16 23:58:48 +01002065 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01002066}
2067
Damien George7ff996c2014-09-08 23:05:16 +01002068STATIC void emit_native_build_map(emit_t *emit, mp_uint_t n_args) {
Damien Georgece8f07a2014-03-27 23:30:26 +00002069 emit_native_pre(emit);
Damien George7fe21912014-08-16 22:31:57 +01002070 emit_call_with_imm_arg(emit, MP_F_BUILD_MAP, n_args, REG_ARG_1);
Damien13ed3a62013-10-08 09:05:10 +01002071 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new map
2072}
2073
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02002074STATIC void emit_native_store_map(emit_t *emit) {
Damien13ed3a62013-10-08 09:05:10 +01002075 vtype_kind_t vtype_key, vtype_value, vtype_map;
2076 emit_pre_pop_reg_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3, &vtype_map, REG_ARG_1); // key, value, map
2077 assert(vtype_key == VTYPE_PYOBJ);
2078 assert(vtype_value == VTYPE_PYOBJ);
2079 assert(vtype_map == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01002080 emit_call(emit, MP_F_STORE_MAP);
Damien13ed3a62013-10-08 09:05:10 +01002081 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map
2082}
2083
Damien George7ff996c2014-09-08 23:05:16 +01002084STATIC void emit_native_map_add(emit_t *emit, mp_uint_t map_index) {
Damiend2755ec2013-10-16 23:58:48 +01002085 // only used in list comprehension
2086 vtype_kind_t vtype_map, vtype_key, vtype_value;
2087 emit_pre_pop_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3);
2088 emit_access_stack(emit, map_index, &vtype_map, REG_ARG_1);
2089 assert(vtype_map == VTYPE_PYOBJ);
2090 assert(vtype_key == VTYPE_PYOBJ);
2091 assert(vtype_value == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01002092 emit_call(emit, MP_F_STORE_MAP);
Damiend2755ec2013-10-16 23:58:48 +01002093 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01002094}
2095
Damien Georgee37dcaa2014-12-27 17:07:16 +00002096#if MICROPY_PY_BUILTINS_SET
Damien George7ff996c2014-09-08 23:05:16 +01002097STATIC void emit_native_build_set(emit_t *emit, mp_uint_t n_args) {
Damien Georgece8f07a2014-03-27 23:30:26 +00002098 emit_native_pre(emit);
Damien Georgecd82e022014-02-02 13:11:48 +00002099 emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items
Damien George7fe21912014-08-16 22:31:57 +01002100 emit_call_with_imm_arg(emit, MP_F_BUILD_SET, n_args, REG_ARG_1);
Damien13ed3a62013-10-08 09:05:10 +01002101 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new set
2102}
2103
Damien George7ff996c2014-09-08 23:05:16 +01002104STATIC void emit_native_set_add(emit_t *emit, mp_uint_t set_index) {
Damiend2755ec2013-10-16 23:58:48 +01002105 // only used in set comprehension
2106 vtype_kind_t vtype_set, vtype_item;
2107 emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2);
2108 emit_access_stack(emit, set_index, &vtype_set, REG_ARG_1);
2109 assert(vtype_set == VTYPE_PYOBJ);
2110 assert(vtype_item == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01002111 emit_call(emit, MP_F_STORE_SET);
Damiend2755ec2013-10-16 23:58:48 +01002112 emit_post(emit);
Damien13ed3a62013-10-08 09:05:10 +01002113}
Damien Georgee37dcaa2014-12-27 17:07:16 +00002114#endif
Damiend2755ec2013-10-16 23:58:48 +01002115
Damien George83204f32014-12-27 17:20:41 +00002116#if MICROPY_PY_BUILTINS_SLICE
Damien George7ff996c2014-09-08 23:05:16 +01002117STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) {
Damien Georgecdd96df2014-04-06 12:58:40 +01002118 DEBUG_printf("build_slice %d\n", n_args);
Damien Georgeb601d952014-06-30 05:17:25 +01002119 if (n_args == 2) {
2120 vtype_kind_t vtype_start, vtype_stop;
2121 emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop
2122 assert(vtype_start == VTYPE_PYOBJ);
2123 assert(vtype_stop == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01002124 emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, (mp_uint_t)mp_const_none, REG_ARG_3); // arg3 = step
Damien Georgeb601d952014-06-30 05:17:25 +01002125 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2126 } else {
2127 assert(n_args == 3);
2128 vtype_kind_t vtype_start, vtype_stop, vtype_step;
2129 emit_pre_pop_reg_reg_reg(emit, &vtype_step, REG_ARG_3, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop, arg3 = step
2130 assert(vtype_start == VTYPE_PYOBJ);
2131 assert(vtype_stop == VTYPE_PYOBJ);
2132 assert(vtype_step == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01002133 emit_call(emit, MP_F_NEW_SLICE);
Damien Georgeb601d952014-06-30 05:17:25 +01002134 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2135 }
Damien13ed3a62013-10-08 09:05:10 +01002136}
Damien George83204f32014-12-27 17:20:41 +00002137#endif
Damien Georgecdd96df2014-04-06 12:58:40 +01002138
Damien George7ff996c2014-09-08 23:05:16 +01002139STATIC void emit_native_unpack_sequence(emit_t *emit, mp_uint_t n_args) {
Damien Georgecdd96df2014-04-06 12:58:40 +01002140 DEBUG_printf("unpack_sequence %d\n", n_args);
2141 vtype_kind_t vtype_base;
2142 emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
2143 assert(vtype_base == VTYPE_PYOBJ);
2144 emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_args); // arg3 = dest ptr
Damien George7fe21912014-08-16 22:31:57 +01002145 emit_call_with_imm_arg(emit, MP_F_UNPACK_SEQUENCE, n_args, REG_ARG_2); // arg2 = n_args
Damien13ed3a62013-10-08 09:05:10 +01002146}
Damien Georgecdd96df2014-04-06 12:58:40 +01002147
Damien George7ff996c2014-09-08 23:05:16 +01002148STATIC void emit_native_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {
Damien Georgea32c1e42014-05-07 18:30:52 +01002149 DEBUG_printf("unpack_ex %d %d\n", n_left, n_right);
2150 vtype_kind_t vtype_base;
2151 emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
2152 assert(vtype_base == VTYPE_PYOBJ);
Damien Georgeb601d952014-06-30 05:17:25 +01002153 emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr
Damien George7fe21912014-08-16 22:31:57 +01002154 emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right
Damien13ed3a62013-10-08 09:05:10 +01002155}
2156
Damien George7ff996c2014-09-08 23:05:16 +01002157STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
Damien13ed3a62013-10-08 09:05:10 +01002158 // call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them
Damien Georgece8f07a2014-03-27 23:30:26 +00002159 emit_native_pre(emit);
Damien Georgea32c1e42014-05-07 18:30:52 +01002160 if (n_pos_defaults == 0 && n_kw_defaults == 0) {
Damien George7fe21912014-08-16 22:31:57 +01002161 emit_call_with_3_imm_args_and_first_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, (mp_uint_t)scope->raw_code, REG_ARG_1, (mp_uint_t)MP_OBJ_NULL, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3);
Damien Georgea32c1e42014-05-07 18:30:52 +01002162 } else {
2163 vtype_kind_t vtype_def_tuple, vtype_def_dict;
2164 emit_pre_pop_reg_reg(emit, &vtype_def_dict, REG_ARG_3, &vtype_def_tuple, REG_ARG_2);
2165 assert(vtype_def_tuple == VTYPE_PYOBJ);
2166 assert(vtype_def_dict == VTYPE_PYOBJ);
Damien George7fe21912014-08-16 22:31:57 +01002167 emit_call_with_imm_arg_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, (mp_uint_t)scope->raw_code, REG_ARG_1);
Damien Georgea32c1e42014-05-07 18:30:52 +01002168 }
Damien13ed3a62013-10-08 09:05:10 +01002169 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2170}
2171
Damien George7ff996c2014-09-08 23:05:16 +01002172STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
Damien George4cd9ced2015-01-15 14:41:41 +00002173 emit_native_pre(emit);
2174 if (n_pos_defaults == 0 && n_kw_defaults == 0) {
2175 emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over);
2176 ASM_MOV_IMM_TO_REG(emit->as, n_closed_over, REG_ARG_2);
2177 } else {
2178 emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over + 2);
2179 ASM_MOV_IMM_TO_REG(emit->as, 0x100 | n_closed_over, REG_ARG_2);
2180 }
2181 ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)scope->raw_code, REG_ARG_1);
2182 ASM_CALL_IND(emit->as, mp_fun_table[MP_F_MAKE_CLOSURE_FROM_RAW_CODE], MP_F_MAKE_CLOSURE_FROM_RAW_CODE);
2183 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien13ed3a62013-10-08 09:05:10 +01002184}
2185
Damien George7ff996c2014-09-08 23:05:16 +01002186STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
Damien Georged6230f62014-09-23 14:10:03 +00002187 DEBUG_printf("call_function(n_pos=" UINT_FMT ", n_kw=" UINT_FMT ", star_flags=" UINT_FMT ")\n", n_positional, n_keyword, star_flags);
2188
Damien Georgee9dac3b2014-09-29 22:10:41 +01002189 // TODO: in viper mode, call special runtime routine with type info for args,
2190 // and wanted type info for return, to remove need for boxing/unboxing
2191
Damien George922ddd62014-04-09 12:43:17 +01002192 assert(!star_flags);
Damien Georgecd82e022014-02-02 13:11:48 +00002193
Damien Georgee9dac3b2014-09-29 22:10:41 +01002194 emit_native_pre(emit);
2195 vtype_kind_t vtype_fun = peek_vtype(emit, n_positional + 2 * n_keyword);
2196 if (vtype_fun == VTYPE_BUILTIN_CAST) {
2197 // casting operator
2198 assert(n_positional == 1 && n_keyword == 0);
2199 DEBUG_printf(" cast to %d\n", vtype_fun);
Damien George32444b72015-01-24 23:14:12 +00002200 vtype_kind_t vtype_cast = peek_stack(emit, 1)->data.u_imm;
Damien Georgee9dac3b2014-09-29 22:10:41 +01002201 switch (peek_vtype(emit, 0)) {
2202 case VTYPE_PYOBJ: {
2203 vtype_kind_t vtype;
2204 emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
2205 emit_pre_pop_discard(emit);
2206 emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, MP_NATIVE_TYPE_UINT, REG_ARG_2); // arg2 = type
2207 emit_post_push_reg(emit, vtype_cast, REG_RET);
2208 break;
2209 }
2210 case VTYPE_BOOL:
2211 case VTYPE_INT:
2212 case VTYPE_UINT:
2213 case VTYPE_PTR:
2214 case VTYPE_PTR8:
2215 case VTYPE_PTR16:
2216 case VTYPE_PTR_NONE:
2217 emit_fold_stack_top(emit, REG_ARG_1);
2218 emit_post_top_set_vtype(emit, vtype_cast);
2219 break;
2220 default:
2221 assert(!"TODO: convert obj to int");
2222 }
2223 } else {
2224 if (n_positional != 0 || n_keyword != 0) {
2225 emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword); // pointer to args
2226 }
Damien13ed3a62013-10-08 09:05:10 +01002227 emit_pre_pop_reg(emit, &vtype_fun, REG_ARG_1); // the function
2228 assert(vtype_fun == VTYPE_PYOBJ);
Damien Georgee9dac3b2014-09-29 22:10:41 +01002229 emit_call_with_imm_arg(emit, MP_F_NATIVE_CALL_FUNCTION_N_KW, n_positional | (n_keyword << 8), REG_ARG_2);
2230 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
Damien Georgecd82e022014-02-02 13:11:48 +00002231 }
Damien13ed3a62013-10-08 09:05:10 +01002232}
2233
Damien George7ff996c2014-09-08 23:05:16 +01002234STATIC void emit_native_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
Damien George922ddd62014-04-09 12:43:17 +01002235 assert(!star_flags);
Damien Georgece8f07a2014-03-27 23:30:26 +00002236 emit_native_pre(emit);
Damien Georgecdd96df2014-04-06 12:58:40 +01002237 emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2 + n_positional + 2 * n_keyword); // pointer to items, including meth and self
Damien George7fe21912014-08-16 22:31:57 +01002238 emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, n_positional, REG_ARG_1, n_keyword, REG_ARG_2);
Damien13ed3a62013-10-08 09:05:10 +01002239 emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2240}
2241
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02002242STATIC void emit_native_return_value(emit_t *emit) {
Damien Georgecdd96df2014-04-06 12:58:40 +01002243 DEBUG_printf("return_value\n");
Damien13ed3a62013-10-08 09:05:10 +01002244 if (emit->do_viper_types) {
Damien Georgee9dac3b2014-09-29 22:10:41 +01002245 if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) {
2246 emit_pre_pop_discard(emit);
Damien Georgee6c0dff2014-08-15 23:47:59 +01002247 if (emit->return_vtype == VTYPE_PYOBJ) {
Damien Georgec90f59e2014-09-06 23:06:36 +01002248 ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_RET);
Damien Georgee9dac3b2014-09-29 22:10:41 +01002249 } else {
2250 ASM_MOV_IMM_TO_REG(emit->as, 0, REG_RET);
Damien Georgee6c0dff2014-08-15 23:47:59 +01002251 }
Damien Georgee9dac3b2014-09-29 22:10:41 +01002252 } else {
2253 vtype_kind_t vtype;
2254 emit_pre_pop_reg(emit, &vtype, REG_RET);
2255 if (vtype != emit->return_vtype) {
2256 printf("ViperTypeError: incompatible return type\n");
2257 }
Damien George2ac4af62014-08-15 16:45:41 +01002258 }
Damien13ed3a62013-10-08 09:05:10 +01002259 } else {
Damien Georgee9dac3b2014-09-29 22:10:41 +01002260 vtype_kind_t vtype;
2261 emit_pre_pop_reg(emit, &vtype, REG_RET);
Damien13ed3a62013-10-08 09:05:10 +01002262 assert(vtype == VTYPE_PYOBJ);
2263 }
2264 emit->last_emit_was_return_value = true;
Damien Georgec90f59e2014-09-06 23:06:36 +01002265 //ASM_BREAK_POINT(emit->as); // to insert a break-point for debugging
2266 ASM_EXIT(emit->as);
Damien13ed3a62013-10-08 09:05:10 +01002267}
2268
Damien George7ff996c2014-09-08 23:05:16 +01002269STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) {
Damien Georgeb601d952014-06-30 05:17:25 +01002270 assert(n_args == 1);
Damien George86de21b2014-08-16 22:06:11 +01002271 vtype_kind_t vtype_exc;
2272 emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise
2273 if (vtype_exc != VTYPE_PYOBJ) {
2274 printf("ViperTypeError: must raise an object\n");
2275 }
2276 // TODO probably make this 1 call to the runtime (which could even call convert, native_raise(obj, type))
Damien George7fe21912014-08-16 22:31:57 +01002277 emit_call(emit, MP_F_NATIVE_RAISE);
Damien13ed3a62013-10-08 09:05:10 +01002278}
Damien Georgeb601d952014-06-30 05:17:25 +01002279
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02002280STATIC void emit_native_yield_value(emit_t *emit) {
Damien13ed3a62013-10-08 09:05:10 +01002281 // not supported (for now)
Damien Georgeff8dd3f2015-01-20 12:47:20 +00002282 (void)emit;
Damien13ed3a62013-10-08 09:05:10 +01002283 assert(0);
2284}
Paul Sokolovsky520e2f52014-02-12 18:31:30 +02002285STATIC void emit_native_yield_from(emit_t *emit) {
Damien13ed3a62013-10-08 09:05:10 +01002286 // not supported (for now)
Damien Georgeff8dd3f2015-01-20 12:47:20 +00002287 (void)emit;
Damien13ed3a62013-10-08 09:05:10 +01002288 assert(0);
2289}
2290
Damien Georgeb601d952014-06-30 05:17:25 +01002291STATIC void emit_native_start_except_handler(emit_t *emit) {
2292 // This instruction follows an nlr_pop, so the stack counter is back to zero, when really
2293 // it should be up by a whole nlr_buf_t. We then want to pop the nlr_buf_t here, but save
2294 // the first 2 elements, so we can get the thrown value.
2295 adjust_stack(emit, 2);
2296 vtype_kind_t vtype_nlr;
2297 emit_pre_pop_reg(emit, &vtype_nlr, REG_ARG_1); // get the thrown value
Damien Georgee6ce10a2014-09-06 18:38:20 +01002298 emit_pre_pop_discard(emit); // discard the linked-list pointer in the nlr_buf
Damien Georgeb601d952014-06-30 05:17:25 +01002299 emit_post_push_reg_reg_reg(emit, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1); // push the 3 exception items
2300}
2301
2302STATIC void emit_native_end_except_handler(emit_t *emit) {
Damien Georgee6ce10a2014-09-06 18:38:20 +01002303 adjust_stack(emit, -2);
Damien Georgeb601d952014-06-30 05:17:25 +01002304}
2305
Damien13ed3a62013-10-08 09:05:10 +01002306const emit_method_table_t EXPORT_FUN(method_table) = {
Damien George2ac4af62014-08-15 16:45:41 +01002307 emit_native_set_native_type,
Damien13ed3a62013-10-08 09:05:10 +01002308 emit_native_start_pass,
2309 emit_native_end_pass,
2310 emit_native_last_emit_was_return_value,
Damien Georged66ae182014-04-10 17:28:54 +00002311 emit_native_adjust_stack_size,
Damien George08335002014-01-18 23:24:36 +00002312 emit_native_set_source_line,
Damien13ed3a62013-10-08 09:05:10 +01002313
Damien George542bd6b2015-03-26 14:42:40 +00002314 {
2315 emit_native_load_fast,
2316 emit_native_load_deref,
2317 emit_native_load_name,
2318 emit_native_load_global,
2319 },
2320 {
2321 emit_native_store_fast,
2322 emit_native_store_deref,
2323 emit_native_store_name,
2324 emit_native_store_global,
2325 },
2326 {
2327 emit_native_delete_fast,
2328 emit_native_delete_deref,
2329 emit_native_delete_name,
2330 emit_native_delete_global,
2331 },
Damien13ed3a62013-10-08 09:05:10 +01002332
2333 emit_native_label_assign,
2334 emit_native_import_name,
2335 emit_native_import_from,
2336 emit_native_import_star,
2337 emit_native_load_const_tok,
2338 emit_native_load_const_small_int,
Damien13ed3a62013-10-08 09:05:10 +01002339 emit_native_load_const_str,
Damien Georgedab13852015-01-13 15:55:54 +00002340 emit_native_load_const_obj,
Damien George3558f622014-04-20 17:50:40 +01002341 emit_native_load_null,
Damien13ed3a62013-10-08 09:05:10 +01002342 emit_native_load_attr,
2343 emit_native_load_method,
2344 emit_native_load_build_class,
Damien George729f7b42014-04-17 22:10:53 +01002345 emit_native_load_subscr,
Damien13ed3a62013-10-08 09:05:10 +01002346 emit_native_store_attr,
Damien13ed3a62013-10-08 09:05:10 +01002347 emit_native_store_subscr,
Damien13ed3a62013-10-08 09:05:10 +01002348 emit_native_delete_attr,
2349 emit_native_delete_subscr,
2350 emit_native_dup_top,
2351 emit_native_dup_top_two,
2352 emit_native_pop_top,
2353 emit_native_rot_two,
2354 emit_native_rot_three,
2355 emit_native_jump,
Damien George63f38322015-02-28 15:04:06 +00002356 emit_native_pop_jump_if,
2357 emit_native_jump_if_or_pop,
Damien13ed3a62013-10-08 09:05:10 +01002358 emit_native_break_loop,
2359 emit_native_continue_loop,
2360 emit_native_setup_with,
2361 emit_native_with_cleanup,
2362 emit_native_setup_except,
2363 emit_native_setup_finally,
2364 emit_native_end_finally,
2365 emit_native_get_iter,
2366 emit_native_for_iter,
2367 emit_native_for_iter_end,
2368 emit_native_pop_block,
2369 emit_native_pop_except,
2370 emit_native_unary_op,
2371 emit_native_binary_op,
Damien13ed3a62013-10-08 09:05:10 +01002372 emit_native_build_tuple,
2373 emit_native_build_list,
2374 emit_native_list_append,
2375 emit_native_build_map,
2376 emit_native_store_map,
2377 emit_native_map_add,
Damien Georgee37dcaa2014-12-27 17:07:16 +00002378 #if MICROPY_PY_BUILTINS_SET
Damien13ed3a62013-10-08 09:05:10 +01002379 emit_native_build_set,
2380 emit_native_set_add,
Damien Georgee37dcaa2014-12-27 17:07:16 +00002381 #endif
Damien George83204f32014-12-27 17:20:41 +00002382 #if MICROPY_PY_BUILTINS_SLICE
Damien13ed3a62013-10-08 09:05:10 +01002383 emit_native_build_slice,
Damien George83204f32014-12-27 17:20:41 +00002384 #endif
Damien13ed3a62013-10-08 09:05:10 +01002385 emit_native_unpack_sequence,
2386 emit_native_unpack_ex,
2387 emit_native_make_function,
2388 emit_native_make_closure,
2389 emit_native_call_function,
2390 emit_native_call_method,
2391 emit_native_return_value,
2392 emit_native_raise_varargs,
2393 emit_native_yield_value,
2394 emit_native_yield_from,
Damien Georgeb601d952014-06-30 05:17:25 +01002395
2396 emit_native_start_except_handler,
2397 emit_native_end_except_handler,
Damien13ed3a62013-10-08 09:05:10 +01002398};
2399
Damien Georgec90f59e2014-09-06 23:06:36 +01002400#endif