emitnative.c 75.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Essentially normal Python has 1 type: Python objects
// Viper has more than 1 type, and is just a more complicated (a superset of) Python.
// If you declare everything in Viper as a Python object (ie omit type decls) then
// it should in principle be exactly the same as Python native.
// Having types means having more opcodes, like binary_op_nat_nat, binary_op_nat_obj etc.
// In practice we won't have a VM but rather do this in asm which is actually very minimal.

// Because it breaks strict Python equivalence it should be a completely separate
// decorator.  It breaks equivalence because overflow on integers wraps around.
// It shouldn't break equivalence if you don't use the new types, but since the
// type decls might be used in normal Python for other reasons, it's probably safest,
// cleanest and clearest to make it a separate decorator.

// Actually, it does break equivalence because integers default to native integers,
// not Python objects.

// for x in l[0:8]: can be compiled into a native loop if l has pointer type

xbe's avatar
xbe committed
45
#include <stdbool.h>
46
47
48
49
50
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

51
#include "mpconfig.h"
52
#include "nlr.h"
53
#include "misc.h"
54
#include "qstr.h"
55
56
#include "lexer.h"
#include "parse.h"
57
58
#include "obj.h"
#include "emitglue.h"
59
#include "scope.h"
60
#include "runtime0.h"
61
#include "emit.h"
62
#include "runtime.h"
63

64
65
66
67
68
69
70
#if 0 // print debugging info
#define DEBUG_PRINT (1)
#define DEBUG_printf DEBUG_printf
#else // don't print debugging info
#define DEBUG_printf(...) (void)0
#endif

71
// wrapper around everything in this file
72
73
74
75
#if (MICROPY_EMIT_X64 && N_X64) \
    || (MICROPY_EMIT_X86 && N_X86) \
    || (MICROPY_EMIT_THUMB && N_THUMB) \
    || (MICROPY_EMIT_ARM && N_ARM)
76

77
#if N_X64
78
79
80
81
82
83
84

// x64 specific stuff

#include "asmx64.h"

#define EXPORT_FUN(name) emit_native_x64_##name

85
86
87
88
89
#define REG_RET ASM_X64_REG_RAX
#define REG_ARG_1 ASM_X64_REG_RDI
#define REG_ARG_2 ASM_X64_REG_RSI
#define REG_ARG_3 ASM_X64_REG_RDX
#define REG_ARG_4 ASM_X64_REG_RCX
90
91

// caller-save
92
93
94
#define REG_TEMP0 ASM_X64_REG_RAX
#define REG_TEMP1 ASM_X64_REG_RDI
#define REG_TEMP2 ASM_X64_REG_RSI
95
96

// callee-save
97
98
99
#define REG_LOCAL_1 ASM_X64_REG_RBX
#define REG_LOCAL_2 ASM_X64_REG_R12
#define REG_LOCAL_3 ASM_X64_REG_R13
100
#define REG_LOCAL_NUM (3)
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

#define ASM_PASS_COMPUTE    ASM_X64_PASS_COMPUTE
#define ASM_PASS_EMIT       ASM_X64_PASS_EMIT

#define ASM_T               asm_x64_t
#define ASM_NEW             asm_x64_new
#define ASM_FREE            asm_x64_free
#define ASM_GET_CODE        asm_x64_get_code
#define ASM_GET_CODE_SIZE   asm_x64_get_code_size
#define ASM_START_PASS      asm_x64_start_pass
#define ASM_END_PASS        asm_x64_end_pass
#define ASM_ENTRY           asm_x64_entry
#define ASM_EXIT            asm_x64_exit

#define ASM_LABEL_ASSIGN    asm_x64_label_assign
#define ASM_JUMP            asm_x64_jmp_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
    do { \
        asm_x64_test_r8_with_r8(as, reg, reg); \
        asm_x64_jcc_label(as, ASM_X64_CC_JZ, label); \
    } while (0)
#define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \
    do { \
        asm_x64_test_r8_with_r8(as, reg, reg); \
        asm_x64_jcc_label(as, ASM_X64_CC_JNZ, label); \
    } while (0)
#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
    do { \
        asm_x64_cmp_r64_with_r64(as, reg1, reg2); \
        asm_x64_jcc_label(as, ASM_X64_CC_JE, label); \
    } while (0)
132
#define ASM_CALL_IND(as, ptr, idx) asm_x64_call_ind(as, ptr, ASM_X64_REG_RAX)
133
134
135
136
137
138
139
140
141
142

#define ASM_MOV_REG_TO_LOCAL        asm_x64_mov_r64_to_local
#define ASM_MOV_IMM_TO_REG          asm_x64_mov_i64_to_r64_optimised
#define ASM_MOV_ALIGNED_IMM_TO_REG  asm_x64_mov_i64_to_r64_aligned
#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
    do { \
        asm_x64_mov_i64_to_r64_optimised(as, (imm), (reg_temp)); \
        asm_x64_mov_r64_to_local(as, (reg_temp), (local_num)); \
    } while (false)
#define ASM_MOV_LOCAL_TO_REG        asm_x64_mov_local_to_r64
143
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src))
144
145
#define ASM_MOV_LOCAL_ADDR_TO_REG   asm_x64_mov_local_addr_to_r64

146
147
148
149
150
#define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg))
#define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg))
#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x64_add_r64_r64((as), (reg_dest), (reg_src))
#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x64_sub_r64_r64((as), (reg_dest), (reg_src))

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#elif N_X86

// x86 specific stuff

#include "asmx86.h"

STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
    [MP_F_CONVERT_OBJ_TO_NATIVE] = 2,
    [MP_F_CONVERT_NATIVE_TO_OBJ] = 2,
    [MP_F_LOAD_CONST_INT] = 1,
    [MP_F_LOAD_CONST_DEC] = 1,
    [MP_F_LOAD_CONST_STR] = 1,
    [MP_F_LOAD_CONST_BYTES] = 1,
    [MP_F_LOAD_NAME] = 1,
    [MP_F_LOAD_GLOBAL] = 1,
    [MP_F_LOAD_BUILD_CLASS] = 0,
    [MP_F_LOAD_ATTR] = 2,
    [MP_F_LOAD_METHOD] = 3,
    [MP_F_STORE_NAME] = 2,
    [MP_F_STORE_GLOBAL] = 2,
    [MP_F_STORE_ATTR] = 3,
    [MP_F_OBJ_SUBSCR] = 3,
    [MP_F_OBJ_IS_TRUE] = 1,
    [MP_F_UNARY_OP] = 2,
    [MP_F_BINARY_OP] = 3,
    [MP_F_BUILD_TUPLE] = 2,
    [MP_F_BUILD_LIST] = 2,
    [MP_F_LIST_APPEND] = 2,
    [MP_F_BUILD_MAP] = 1,
    [MP_F_STORE_MAP] = 3,
#if MICROPY_PY_BUILTINS_SET
    [MP_F_BUILD_SET] = 2,
    [MP_F_STORE_SET] = 2,
#endif
    [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3,
    [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3,
    [MP_F_CALL_METHOD_N_KW] = 3,
    [MP_F_GETITER] = 1,
    [MP_F_ITERNEXT] = 1,
    [MP_F_NLR_PUSH] = 1,
    [MP_F_NLR_POP] = 0,
    [MP_F_NATIVE_RAISE] = 1,
    [MP_F_IMPORT_NAME] = 3,
    [MP_F_IMPORT_FROM] = 2,
    [MP_F_IMPORT_ALL] = 1,
#if MICROPY_PY_BUILTINS_SLICE
    [MP_F_NEW_SLICE] = 3,
#endif
    [MP_F_UNPACK_SEQUENCE] = 3,
    [MP_F_UNPACK_EX] = 3,
    [MP_F_DELETE_NAME] = 1,
    [MP_F_DELETE_GLOBAL] = 1,
};

#define EXPORT_FUN(name) emit_native_x86_##name

207
#define REG_RET ASM_X86_REG_EAX
208
209
210
#define REG_ARG_1 ASM_X86_REG_ARG_1
#define REG_ARG_2 ASM_X86_REG_ARG_2
#define REG_ARG_3 ASM_X86_REG_ARG_3
211

212
// caller-save, so can be used as temporaries
213
214
215
#define REG_TEMP0 ASM_X86_REG_EAX
#define REG_TEMP1 ASM_X86_REG_ECX
#define REG_TEMP2 ASM_X86_REG_EDX
216

217
// callee-save, so can be used as locals
218
219
220
#define REG_LOCAL_1 ASM_X86_REG_EBX
#define REG_LOCAL_2 ASM_X86_REG_ESI
#define REG_LOCAL_3 ASM_X86_REG_EDI
221
#define REG_LOCAL_NUM (3)
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

#define ASM_PASS_COMPUTE    ASM_X86_PASS_COMPUTE
#define ASM_PASS_EMIT       ASM_X86_PASS_EMIT

#define ASM_T               asm_x86_t
#define ASM_NEW             asm_x86_new
#define ASM_FREE            asm_x86_free
#define ASM_GET_CODE        asm_x86_get_code
#define ASM_GET_CODE_SIZE   asm_x86_get_code_size
#define ASM_START_PASS      asm_x86_start_pass
#define ASM_END_PASS        asm_x86_end_pass
#define ASM_ENTRY           asm_x86_entry
#define ASM_EXIT            asm_x86_exit

#define ASM_LABEL_ASSIGN    asm_x86_label_assign
#define ASM_JUMP            asm_x86_jmp_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
    do { \
        asm_x86_test_r8_with_r8(as, reg, reg); \
        asm_x86_jcc_label(as, ASM_X86_CC_JZ, label); \
    } while (0)
#define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \
    do { \
        asm_x86_test_r8_with_r8(as, reg, reg); \
        asm_x86_jcc_label(as, ASM_X86_CC_JNZ, label); \
    } while (0)
#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
    do { \
        asm_x86_cmp_r32_with_r32(as, reg1, reg2); \
        asm_x86_jcc_label(as, ASM_X86_CC_JE, label); \
    } while (0)
253
#define ASM_CALL_IND(as, ptr, idx) asm_x86_call_ind(as, ptr, mp_f_n_args[idx], ASM_X86_REG_EAX)
254
255
256
257
258
259
260
261
262
263

#define ASM_MOV_REG_TO_LOCAL        asm_x86_mov_r32_to_local
#define ASM_MOV_IMM_TO_REG          asm_x86_mov_i32_to_r32
#define ASM_MOV_ALIGNED_IMM_TO_REG  asm_x86_mov_i32_to_r32_aligned
#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
    do { \
        asm_x86_mov_i32_to_r32(as, (imm), (reg_temp)); \
        asm_x86_mov_r32_to_local(as, (reg_temp), (local_num)); \
    } while (false)
#define ASM_MOV_LOCAL_TO_REG        asm_x86_mov_local_to_r32
264
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src))
265
#define ASM_MOV_LOCAL_ADDR_TO_REG   asm_x86_mov_local_addr_to_r32
266

267
268
269
270
271
#define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg))
#define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg))
#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x86_add_r32_r32((as), (reg_dest), (reg_src))
#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x86_sub_r32_r32((as), (reg_dest), (reg_src))

272
#elif N_THUMB
273
274
275
276
277
278
279

// thumb specific stuff

#include "asmthumb.h"

#define EXPORT_FUN(name) emit_native_thumb_##name

280
281
282
283
284
#define REG_RET ASM_THUMB_REG_R0
#define REG_ARG_1 ASM_THUMB_REG_R0
#define REG_ARG_2 ASM_THUMB_REG_R1
#define REG_ARG_3 ASM_THUMB_REG_R2
#define REG_ARG_4 ASM_THUMB_REG_R3
285

286
287
288
#define REG_TEMP0 ASM_THUMB_REG_R0
#define REG_TEMP1 ASM_THUMB_REG_R1
#define REG_TEMP2 ASM_THUMB_REG_R2
289

290
291
292
#define REG_LOCAL_1 ASM_THUMB_REG_R4
#define REG_LOCAL_2 ASM_THUMB_REG_R5
#define REG_LOCAL_3 ASM_THUMB_REG_R6
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#define REG_LOCAL_NUM (3)

#define ASM_PASS_COMPUTE    ASM_THUMB_PASS_COMPUTE
#define ASM_PASS_EMIT       ASM_THUMB_PASS_EMIT

#define ASM_T               asm_thumb_t
#define ASM_NEW             asm_thumb_new
#define ASM_FREE            asm_thumb_free
#define ASM_GET_CODE        asm_thumb_get_code
#define ASM_GET_CODE_SIZE   asm_thumb_get_code_size
#define ASM_START_PASS      asm_thumb_start_pass
#define ASM_END_PASS        asm_thumb_end_pass
#define ASM_ENTRY           asm_thumb_entry
#define ASM_EXIT            asm_thumb_exit

#define ASM_LABEL_ASSIGN    asm_thumb_label_assign
#define ASM_JUMP            asm_thumb_b_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
    do { \
        asm_thumb_cmp_rlo_i8(as, reg, 0); \
313
        asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \
314
315
316
317
    } while (0)
#define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \
    do { \
        asm_thumb_cmp_rlo_i8(as, reg, 0); \
318
        asm_thumb_bcc_label(as, ASM_THUMB_CC_NE, label); \
319
320
321
322
    } while (0)
#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
    do { \
        asm_thumb_cmp_rlo_rlo(as, reg1, reg2); \
323
        asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \
324
    } while (0)
325
#define ASM_CALL_IND(as, ptr, idx) asm_thumb_bl_ind(as, ptr, idx, ASM_THUMB_REG_R3)
326
327
328
329
330
331
332
333
334
335

#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_thumb_mov_local_reg(as, (local_num), (reg))
#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_optimised(as, (reg), (imm))
#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_aligned(as, (reg), (imm))
#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
    do { \
        asm_thumb_mov_reg_i32_optimised(as, (reg_temp), (imm)); \
        asm_thumb_mov_local_reg(as, (local_num), (reg_temp)); \
    } while (false)
#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local(as, (reg), (local_num))
336
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src))
337
#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local_addr(as, (reg), (local_num))
338

339
340
341
342
343
#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift))
#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift))
#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_thumb_add_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src))
#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_thumb_sub_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src))

Fabian Vogt's avatar
Fabian Vogt committed
344
345
346
347
348
349
350
351
#elif N_ARM

// ARM specific stuff

#include "asmarm.h"

#define EXPORT_FUN(name) emit_native_arm_##name

352
353
354
355
356
#define REG_RET ASM_ARM_REG_R0
#define REG_ARG_1 ASM_ARM_REG_R0
#define REG_ARG_2 ASM_ARM_REG_R1
#define REG_ARG_3 ASM_ARM_REG_R2
#define REG_ARG_4 ASM_ARM_REG_R3
357

358
359
360
#define REG_TEMP0 ASM_ARM_REG_R0
#define REG_TEMP1 ASM_ARM_REG_R1
#define REG_TEMP2 ASM_ARM_REG_R2
361

362
363
364
#define REG_LOCAL_1 ASM_ARM_REG_R4
#define REG_LOCAL_2 ASM_ARM_REG_R5
#define REG_LOCAL_3 ASM_ARM_REG_R6
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
#define REG_LOCAL_NUM (3)

#define ASM_PASS_COMPUTE    ASM_ARM_PASS_COMPUTE
#define ASM_PASS_EMIT       ASM_ARM_PASS_EMIT

#define ASM_T               asm_arm_t
#define ASM_NEW             asm_arm_new
#define ASM_FREE            asm_arm_free
#define ASM_GET_CODE        asm_arm_get_code
#define ASM_GET_CODE_SIZE   asm_arm_get_code_size
#define ASM_START_PASS      asm_arm_start_pass
#define ASM_END_PASS        asm_arm_end_pass
#define ASM_ENTRY           asm_arm_entry
#define ASM_EXIT            asm_arm_exit

#define ASM_LABEL_ASSIGN    asm_arm_label_assign
#define ASM_JUMP            asm_arm_b_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
    do { \
        asm_arm_cmp_reg_i8(as, reg, 0); \
385
        asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \
386
387
388
389
    } while (0)
#define ASM_JUMP_IF_REG_NONZERO(as, reg, label) \
    do { \
        asm_arm_cmp_reg_i8(as, reg, 0); \
390
        asm_arm_bcc_label(as, ASM_ARM_CC_NE, label); \
391
392
393
394
    } while (0)
#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
    do { \
        asm_arm_cmp_reg_reg(as, reg1, reg2); \
395
        asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \
396
    } while (0)
397
#define ASM_CALL_IND(as, ptr, idx) asm_arm_bl_ind(as, ptr, idx, ASM_ARM_REG_R3)
398
399
400
401
402
403
404
405
406
407

#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_arm_mov_local_reg(as, (local_num), (reg))
#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm))
#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm))
#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
    do { \
        asm_arm_mov_reg_i32(as, (reg_temp), (imm)); \
        asm_arm_mov_local_reg(as, (local_num), (reg_temp)); \
    } while (false)
#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_arm_mov_reg_local(as, (reg), (local_num))
408
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src))
409
410
#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_arm_mov_reg_local_addr(as, (reg), (local_num))

411
412
413
414
415
416
// TODO someone please implement lsl and asr
#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_((as), (reg_dest), (reg_shift))
#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_((as), (reg_dest), (reg_shift))
#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_arm_add_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_arm_sub_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))

417
418
419
#else

#error unknown native emitter
Fabian Vogt's avatar
Fabian Vogt committed
420

421
422
423
#endif

typedef enum {
424
425
426
427
    STACK_VALUE,
    STACK_REG,
    STACK_IMM,
} stack_info_kind_t;
428
429

typedef enum {
430
431
432
433
    VTYPE_PYOBJ = MP_NATIVE_TYPE_OBJ,
    VTYPE_BOOL = MP_NATIVE_TYPE_BOOL,
    VTYPE_INT = MP_NATIVE_TYPE_INT,
    VTYPE_UINT = MP_NATIVE_TYPE_UINT,
434
435
436
437
438
439
    VTYPE_UNBOUND,
    VTYPE_PTR,
    VTYPE_PTR_NONE,
    VTYPE_BUILTIN_V_INT,
} vtype_kind_t;

440
441
442
443
444
typedef struct _stack_info_t {
    vtype_kind_t vtype;
    stack_info_kind_t kind;
    union {
        int u_reg;
445
        mp_int_t u_imm;
446
447
448
    };
} stack_info_t;

449
450
451
452
struct _emit_t {
    int pass;

    bool do_viper_types;
453

454
455
    vtype_kind_t return_vtype;

456
    mp_uint_t local_vtype_alloc;
457
    vtype_kind_t *local_vtype;
458

459
    mp_uint_t stack_info_alloc;
460
461
    stack_info_t *stack_info;

462
463
464
465
466
467
468
    int stack_start;
    int stack_size;

    bool last_emit_was_return_value;

    scope_t *scope;

469
    ASM_T *as;
470
471
};

472
emit_t *EXPORT_FUN(new)(mp_uint_t max_num_labels) {
473
    emit_t *emit = m_new0(emit_t, 1);
474
    emit->as = ASM_NEW(max_num_labels);
475
476
477
    return emit;
}

478
void EXPORT_FUN(free)(emit_t *emit) {
479
    ASM_FREE(emit->as, false);
480
481
    m_del(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc);
    m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc);
482
483
484
    m_del_obj(emit_t, emit);
}

485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
STATIC void emit_native_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
    switch (op) {
        case MP_EMIT_NATIVE_TYPE_ENABLE:
            emit->do_viper_types = arg1;
            break;

        default: {
            vtype_kind_t type;
            switch (arg2) {
                case MP_QSTR_object: type = VTYPE_PYOBJ; break;
                case MP_QSTR_bool: type = VTYPE_BOOL; break;
                case MP_QSTR_int: type = VTYPE_INT; break;
                case MP_QSTR_uint: type = VTYPE_UINT; break;
                default: printf("ViperTypeError: unknown type %s\n", qstr_str(arg2)); return;
            }
            if (op == MP_EMIT_NATIVE_TYPE_RETURN) {
                emit->return_vtype = type;
            } else {
                assert(arg1 < emit->local_vtype_alloc);
                emit->local_vtype[arg1] = type;
            }
            break;
        }
    }
509
510
}

511
STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
512
513
    DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope);

514
515
516
517
518
519
    emit->pass = pass;
    emit->stack_start = 0;
    emit->stack_size = 0;
    emit->last_emit_was_return_value = false;
    emit->scope = scope;

520
521
522
523
    // allocate memory for keeping track of the types of locals
    if (emit->local_vtype_alloc < scope->num_locals) {
        emit->local_vtype = m_renew(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc, scope->num_locals);
        emit->local_vtype_alloc = scope->num_locals;
524
    }
525
526
527

    // allocate memory for keeping track of the objects on the stack
    // XXX don't know stack size on entry, and it should be maximum over all scopes
528
    if (emit->stack_info == NULL) {
529
        emit->stack_info_alloc = scope->stack_size + 50;
530
        emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc);
531
532
    }

533
534
    // set default type for return and arguments
    emit->return_vtype = VTYPE_PYOBJ;
535
    for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) {
536
537
        emit->local_vtype[i] = VTYPE_PYOBJ;
    }
538
539
540
541
542
543
544
545

    // local variables begin unbound, and have unknown type
    for (mp_uint_t i = emit->scope->num_pos_args; i < emit->local_vtype_alloc; i++) {
        emit->local_vtype[i] = VTYPE_UNBOUND;
    }

    // values on stack begin unbound
    for (mp_uint_t i = 0; i < emit->stack_info_alloc; i++) {
546
        emit->stack_info[i].kind = STACK_VALUE;
547
        emit->stack_info[i].vtype = VTYPE_UNBOUND;
548
549
    }

550
    ASM_START_PASS(emit->as, pass == MP_PASS_EMIT ? ASM_PASS_EMIT : ASM_PASS_COMPUTE);
551
552
553

    // entry to function
    int num_locals = 0;
554
    if (pass > MP_PASS_SCOPE) {
555
556
557
558
559
560
561
        num_locals = scope->num_locals - REG_LOCAL_NUM;
        if (num_locals < 0) {
            num_locals = 0;
        }
        emit->stack_start = num_locals;
        num_locals += scope->stack_size;
    }
562
    ASM_ENTRY(emit->as, num_locals);
563
564

    // initialise locals from parameters
565
#if N_X64
566
    for (int i = 0; i < scope->num_pos_args; i++) {
567
        if (i == 0) {
568
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
569
        } else if (i == 1) {
570
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
571
        } else if (i == 2) {
572
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
573
574
        } else if (i == 3) {
            asm_x64_mov_r64_to_local(emit->as, REG_ARG_4, i - REG_LOCAL_NUM);
575
576
577
578
579
        } else {
            // TODO not implemented
            assert(0);
        }
    }
580
581
582
#elif N_X86
    for (int i = 0; i < scope->num_pos_args; i++) {
        if (i == 0) {
583
            asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1);
584
        } else if (i == 1) {
585
            asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2);
586
587
        } else if (i == 2) {
            asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3);
588
        } else {
589
590
            asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0);
            asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM);
591
592
        }
    }
593
#elif N_THUMB
594
    for (int i = 0; i < scope->num_pos_args; i++) {
595
        if (i == 0) {
596
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
597
        } else if (i == 1) {
598
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
599
        } else if (i == 2) {
600
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
601
602
603
604
605
606
607
608
        } else if (i == 3) {
            asm_thumb_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
        } else {
            // TODO not implemented
            assert(0);
        }
    }

609
    asm_thumb_mov_reg_i32(emit->as, ASM_THUMB_REG_R7, (mp_uint_t)mp_fun_table);
Fabian Vogt's avatar
Fabian Vogt committed
610
611
612
#elif N_ARM
    for (int i = 0; i < scope->num_pos_args; i++) {
        if (i == 0) {
613
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
Fabian Vogt's avatar
Fabian Vogt committed
614
        } else if (i == 1) {
615
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
Fabian Vogt's avatar
Fabian Vogt committed
616
        } else if (i == 2) {
617
            ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
Fabian Vogt's avatar
Fabian Vogt committed
618
619
620
621
622
623
624
625
        } else if (i == 3) {
            asm_arm_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
        } else {
            // TODO not implemented
            assert(0);
        }
    }

626
    asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table);
627
628
#else
    #error not implemented
629
630
631
#endif
}

632
STATIC void emit_native_end_pass(emit_t *emit) {
Fabian Vogt's avatar
Fabian Vogt committed
633
    if (!emit->last_emit_was_return_value) {
634
        ASM_EXIT(emit->as);
Fabian Vogt's avatar
Fabian Vogt committed
635
    }
636
    ASM_END_PASS(emit->as);
637
638
639
640
641
642

    // check stack is back to zero size
    if (emit->stack_size != 0) {
        printf("ERROR: stack size not back to zero; got %d\n", emit->stack_size);
    }

643
    if (emit->pass == MP_PASS_EMIT) {
644
645
        void *f = ASM_GET_CODE(emit->as);
        mp_uint_t f_len = ASM_GET_CODE_SIZE(emit->as);
646
647
648
649
650
651
652
653
654

        // compute type signature
        // TODO check that viper types here convert correctly to valid types for emit glue
        mp_uint_t type_sig = emit->return_vtype & 3;
        for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) {
            type_sig |= (emit->local_vtype[i] & 3) << (i * 2 + 2);
        }

        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);
655
656
657
    }
}

658
STATIC bool emit_native_last_emit_was_return_value(emit_t *emit) {
659
660
661
    return emit->last_emit_was_return_value;
}

662
663
664
STATIC void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) {
    DEBUG_printf("  adjust_stack; stack_size=%d, delta=%d\n", emit->stack_size, stack_size_delta);
    assert((mp_int_t)emit->stack_size + stack_size_delta >= 0);
665
    emit->stack_size += stack_size_delta;
666
    if (emit->pass > MP_PASS_SCOPE && emit->stack_size > emit->scope->stack_size) {
667
668
669
670
        emit->scope->stack_size = emit->stack_size;
    }
}

671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
STATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {
    // If we are adjusting the stack in a positive direction (pushing) then we
    // need to fill in values for the stack kind and vtype of the newly-pushed
    // entries.  These should be set to "value" (ie not reg or imm) because we
    // should only need to adjust the stack due to a jump to this part in the
    // code (and hence we have settled the stack before the jump).
    for (mp_int_t i = 0; i < delta; i++) {
        stack_info_t *si = &emit->stack_info[emit->stack_size + i];
        si->kind = STACK_VALUE;
        si->vtype = VTYPE_PYOBJ; // XXX we don't know the vtype...
    }
    adjust_stack(emit, delta);
}

STATIC void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) {
}

688
/*
689
STATIC void emit_pre_raw(emit_t *emit, int stack_size_delta) {
690
691
692
    adjust_stack(emit, stack_size_delta);
    emit->last_emit_was_return_value = false;
}
693
*/
694

695
// this must be called at start of emit functions
696
STATIC void emit_native_pre(emit_t *emit) {
697
698
699
700
701
702
703
704
705
706
707
708
    emit->last_emit_was_return_value = false;
    // settle the stack
    /*
    if (regs_needed != 0) {
        for (int i = 0; i < emit->stack_size; i++) {
            switch (emit->stack_info[i].kind) {
                case STACK_VALUE:
                    break;

                case STACK_REG:
                    // TODO only push reg if in regs_needed
                    emit->stack_info[i].kind = STACK_VALUE;
709
                    ASM_MOV_REG_TO_LOCAL(emit->as, emit->stack_info[i].u_reg, emit->stack_start + i);
710
711
712
713
714
715
716
717
718
719
                    break;

                case STACK_IMM:
                    // don't think we ever need to push imms for settling
                    //ASM_MOV_IMM_TO_LOCAL(emit->last_imm, emit->stack_start + i);
                    break;
            }
        }
    }
    */
720
721
}

722
723
724
725
726
727
728
729
// depth==0 is top, depth==1 is before top, etc
STATIC stack_info_t *peek_stack(emit_t *emit, mp_uint_t depth) {
    return &emit->stack_info[emit->stack_size - 1 - depth];
}

// depth==0 is top, depth==1 is before top, etc
STATIC vtype_kind_t peek_vtype(emit_t *emit, mp_uint_t depth) {
    return peek_stack(emit, depth)->vtype;
730
}
731

732
733
// pos=1 is TOS, pos=2 is next, etc
// use pos=0 for no skipping
734
STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) {
735
736
737
738
739
740
    skip_stack_pos = emit->stack_size - skip_stack_pos;
    for (int i = 0; i < emit->stack_size; i++) {
        if (i != skip_stack_pos) {
            stack_info_t *si = &emit->stack_info[i];
            if (si->kind == STACK_REG && si->u_reg == reg_needed) {
                si->kind = STACK_VALUE;
741
                ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
742
743
744
745
746
            }
        }
    }
}

747
STATIC void need_reg_all(emit_t *emit) {
748
749
    for (int i = 0; i < emit->stack_size; i++) {
        stack_info_t *si = &emit->stack_info[i];
750
        if (si->kind == STACK_REG) {
751
            si->kind = STACK_VALUE;
752
            ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
753
754
755
        }
    }
}
756

757
STATIC void need_stack_settled(emit_t *emit) {
758
    DEBUG_printf("  need_stack_settled; stack_size=%d\n", emit->stack_size);
759
760
761
    for (int i = 0; i < emit->stack_size; i++) {
        stack_info_t *si = &emit->stack_info[i];
        if (si->kind == STACK_REG) {
762
            DEBUG_printf("    reg(%u) to local(%u)\n", si->u_reg, emit->stack_start + i);
763
            si->kind = STACK_VALUE;
764
            ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
765
        }
766
    }
767
768
769
    for (int i = 0; i < emit->stack_size; i++) {
        stack_info_t *si = &emit->stack_info[i];
        if (si->kind == STACK_IMM) {
770
            DEBUG_printf("    imm(" INT_FMT ") to local(%u)\n", si->u_imm, emit->stack_start + i);
771
            si->kind = STACK_VALUE;
772
            ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->u_imm, emit->stack_start + i, REG_TEMP0);
773
774
        }
    }
775
776
}

777
// pos=1 is TOS, pos=2 is next, etc
778
STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int reg_dest) {
779
780
    need_reg_single(emit, reg_dest, pos);
    stack_info_t *si = &emit->stack_info[emit->stack_size - pos];
781
782
783
    *vtype = si->vtype;
    switch (si->kind) {
        case STACK_VALUE:
784
            ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - pos, reg_dest);
785
786
            break;

787
788
        case STACK_REG:
            if (si->u_reg != reg_dest) {
789
                ASM_MOV_REG_REG(emit->as, reg_dest, si->u_reg);
790
791
792
            }
            break;

793
        case STACK_IMM:
794
            ASM_MOV_IMM_TO_REG(emit->as, si->u_imm, reg_dest);
795
796
797
798
            break;
    }
}

799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
// If stacked value is in a register, then *reg_dest is set to that register.
// Otherwise, the value is put in *reg_dest.
STATIC void emit_pre_pop_reg_flexible(emit_t *emit, vtype_kind_t *vtype, int *reg_dest) {
    emit->last_emit_was_return_value = false;
    stack_info_t *si = peek_stack(emit, 0);
    if (si->kind == STACK_REG) {
        *vtype = si->vtype;
        *reg_dest = si->u_reg;
        need_reg_single(emit, *reg_dest, 1);
    } else {
        emit_access_stack(emit, 1, vtype, *reg_dest);
    }
    adjust_stack(emit, -1);
}

814
STATIC void emit_pre_pop_discard(emit_t *emit) {
815
816
817
818
    emit->last_emit_was_return_value = false;
    adjust_stack(emit, -1);
}

819
STATIC void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest) {
820
821
822
823
824
    emit->last_emit_was_return_value = false;
    emit_access_stack(emit, 1, vtype, reg_dest);
    adjust_stack(emit, -1);
}

825
STATIC void emit_pre_pop_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb) {
826
    emit_pre_pop_reg(emit, vtypea, rega);
827
    emit_pre_pop_reg(emit, vtypeb, regb);
828
829
}

830
STATIC 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) {
831
    emit_pre_pop_reg(emit, vtypea, rega);
832
833
    emit_pre_pop_reg(emit, vtypeb, regb);
    emit_pre_pop_reg(emit, vtypec, regc);
834
835
}

836
STATIC void emit_post(emit_t *emit) {
837
838
}

839
STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) {
840
841
842
843
844
    stack_info_t *si = &emit->stack_info[emit->stack_size];
    si->vtype = vtype;
    si->kind = STACK_REG;
    si->u_reg = reg;
    adjust_stack(emit, 1);
845
846
}

847
STATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) {
848
849
850
851
852
    stack_info_t *si = &emit->stack_info[emit->stack_size];
    si->vtype = vtype;
    si->kind = STACK_IMM;
    si->u_imm = imm;
    adjust_stack(emit, 1);
853
854
}

855
STATIC void emit_post_push_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb) {
856
857
    emit_post_push_reg(emit, vtypea, rega);
    emit_post_push_reg(emit, vtypeb, regb);
858
859
}

860
STATIC 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) {
861
862
863
    emit_post_push_reg(emit, vtypea, rega);
    emit_post_push_reg(emit, vtypeb, regb);
    emit_post_push_reg(emit, vtypec, regc);
864
865
}

866
STATIC 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) {
867
868
869
870
    emit_post_push_reg(emit, vtypea, rega);
    emit_post_push_reg(emit, vtypeb, regb);
    emit_post_push_reg(emit, vtypec, regc);
    emit_post_push_reg(emit, vtyped, regd);
871
872
}

873
STATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) {
874
    need_reg_all(emit);
875
    ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
876
877
}

878
STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) {
879
    need_reg_all(emit);
880
881
    ASM_MOV_IMM_TO_REG(emit->as, arg_val, arg_reg);
    ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
882
883
}

884
// the first arg is stored in the code aligned on a mp_uint_t boundary
885
STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) {
886
    need_reg_all(emit);
887
888
    ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val, arg_reg);
    ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
889
890
}

891
STATIC 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) {
892
    need_reg_all(emit);
893
894
895
    ASM_MOV_IMM_TO_REG(emit->as, arg_val1, arg_reg1);
    ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2);
    ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
896
897
}

898
// the first arg is stored in the code aligned on a mp_uint_t boundary
899
STATIC 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) {
900
    need_reg_all(emit);
901
902
903
904
    ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val1, arg_reg1);
    ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2);
    ASM_MOV_IMM_TO_REG(emit->as, arg_val3, arg_reg3);
    ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
905
906
}

907
908
909
910
911
912
// vtype of all n_pop objects is VTYPE_PYOBJ
// Will convert any items that are not VTYPE_PYOBJ to this type and put them back on the stack.
// If any conversions of non-immediate values are needed, then it uses REG_ARG_1, REG_ARG_2 and REG_RET.
// Otherwise, it does not use any temporary registers (but may use reg_dest before loading it with stack pointer).
STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_pop) {
    need_reg_all(emit);
913

914
915
916
917
918
919
920
921
922
    // First, store any immediate values to their respective place on the stack.
    for (mp_uint_t i = 0; i < n_pop; i++) {
        stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];
        // must push any imm's to stack
        // must convert them to VTYPE_PYOBJ for viper code
        if (si->kind == STACK_IMM) {
            si->kind = STACK_VALUE;
            switch (si->vtype) {
                case VTYPE_PYOBJ:
923
                    ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
924
925
926
                    break;
                case VTYPE_BOOL:
                    if (si->u_imm == 0) {
927
                        ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
928
                    } else {
929
                        ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
930
931
932
933
934
                    }
                    si->vtype = VTYPE_PYOBJ;
                    break;
                case VTYPE_INT:
                case VTYPE_UINT:
935
                    ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (si->u_imm << 1) | 1, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
                    si->vtype = VTYPE_PYOBJ;
                    break;
                default:
                    // not handled
                    assert(0);
            }
        }

        // verify that this value is on the stack
        assert(si->kind == STACK_VALUE);
    }

    // Second, convert any non-VTYPE_PYOBJ to that type.
    for (mp_uint_t i = 0; i < n_pop; i++) {
        stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];
        if (si->vtype != VTYPE_PYOBJ) {
            mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i;
953
            ASM_MOV_LOCAL_TO_REG(emit->as, local_num, REG_ARG_1);
954
            emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type
955
            ASM_MOV_REG_TO_LOCAL(emit->as, REG_RET, local_num);
956
957
958
959
960
961
            si->vtype = VTYPE_PYOBJ;
        }
    }

    // Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest.
    adjust_stack(emit, -n_pop);
962
    ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest);
963
964
965
966
967
968
969
970
}

// vtype of all n_push objects is VTYPE_PYOBJ
STATIC void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_push) {
    need_reg_all(emit);
    for (mp_uint_t i = 0; i < n_push; i++) {
        emit->stack_info[emit->stack_size + i].kind = STACK_VALUE;
        emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ;
971
    }
972
    ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest);
973
974
975
    adjust_stack(emit, n_push);
}

976
977
STATIC void emit_native_load_id(emit_t *emit, qstr qst) {
    emit_common_load_id(emit, &EXPORT_FUN(method_table), emit->scope, qst);
978
979
}

980
981
STATIC void emit_native_store_id(emit_t *emit, qstr qst) {
    emit_common_store_id(emit, &EXPORT_FUN(method_table), emit->scope, qst);
982
983
}

984
985
STATIC void emit_native_delete_id(emit_t *emit, qstr qst) {
    emit_common_delete_id(emit, &EXPORT_FUN(method_table), emit->scope, qst);
986
987
}

988
STATIC void emit_native_label_assign(emit_t *emit, mp_uint_t l) {
989
    DEBUG_printf("label_assign(" UINT_FMT ")\n", l);
990
    emit_native_pre(emit);
991
992
    // need to commit stack because we can jump here from elsewhere
    need_stack_settled(emit);
993
    ASM_LABEL_ASSIGN(emit->as, l);
994
    emit_post(emit);
995
996
}

997
998
999
1000
STATIC void emit_native_import_name(emit_t *emit, qstr qst) {
    DEBUG_printf("import_name %s\n", qstr_str(qst));
    vtype_kind_t vtype_fromlist;
    vtype_kind_t vtype_level;