emitx64.c 23.4 KB
Newer Older
Damien's avatar
Damien committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* This code is equivalent to emitx64.c but pre-allocates stack
 * space and uses mov instead of push/pop instructions to access
 * the temporary stack.  It runs in similar time, but uses 3*n
 * more bytes, where n is number of push/pop instructions.
 *
 * This code is preferred because it keeps the stack aligned on a
 * 16 byte boundary.
 *
 * Improvements:
 *  Doesn't call stub functions, does all the work inline.
 *  Has optimisations for loading i64s to stack.
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "misc.h"
#include "lexer.h"
#include "machine.h"
#include "parse.h"
#include "scope.h"
#include "runtime.h"
#include "emit.h"
#include "asmx64.h"

30
#ifdef EMIT_ENABLE_X64
Damien's avatar
Damien committed
31
32
33
34
35
36
37
38
39
40

#define REG_LOCAL_1 (REG_RBX)
#define REG_LOCAL_NUM (1)

typedef enum {
    NEED_TO_PUSH_NOTHING,
    NEED_TO_PUSH_R64,
    NEED_TO_PUSH_I64,
} need_to_push_t;

41
struct _emit_t {
Damien's avatar
Damien committed
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    int pass;
    int stack_start;
    int stack_size;
    bool last_emit_was_return_value;
    need_to_push_t need_to_push;
    int last_r64;
    int64_t last_i64;

    scope_t *scope;

    asm_x64_t *as;
    bool do_native_types;
};

56
57
58
// forward declaration
static const emit_method_table_t emit_x64_method_table;

59
static void emit_x64_set_native_types(emit_t *emit, bool do_native_types) {
Damien's avatar
Damien committed
60
61
62
    emit->do_native_types = do_native_types;
}

63
static void emit_x64_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
Damien's avatar
Damien committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    emit->pass = pass;
    emit->stack_start = 0;
    emit->stack_size = 0;
    emit->last_emit_was_return_value = false;
    emit->need_to_push = NEED_TO_PUSH_NOTHING;
    emit->scope = scope;

    asm_x64_start_pass(emit->as, pass);

    // entry to function
    int num_locals = 0;
    if (pass > PASS_1) {
        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;
    }
    asm_x64_entry(emit->as, num_locals);

    // initialise locals from parameters
    for (int i = 0; i < scope->num_params; i++) {
        if (i == 0) {
            asm_x64_mov_r64_to_r64(emit->as, REG_ARG_1, REG_LOCAL_1);
        } else if (i == 1) {
            asm_x64_mov_r64_to_local(emit->as, REG_ARG_2, i - 1);
        } else if (i == 2) {
            asm_x64_mov_r64_to_local(emit->as, REG_ARG_3, i - 1);
        } else {
            // TODO not implemented
            assert(0);
        }
    }
}

100
static void emit_x64_end_pass(emit_t *emit) {
Damien's avatar
Damien committed
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
    if (!emit->last_emit_was_return_value) {
        asm_x64_exit(emit->as);
    }
    asm_x64_end_pass(emit->as);

    // 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);
    }

    if (emit->pass == PASS_3) {
        py_fun_t f = asm_x64_get_code(emit->as);
        rt_assign_native_code(emit->scope->unique_code_id, f, asm_x64_get_code_size(emit->as), emit->scope->num_params);
    }
}

117
static bool emit_x64_last_emit_was_return_value(emit_t *emit) {
Damien's avatar
Damien committed
118
119
120
    return emit->last_emit_was_return_value;
}

121
static int emit_x64_get_stack_size(emit_t *emit) {
Damien's avatar
Damien committed
122
123
124
    return emit->stack_size;
}

125
static void emit_x64_set_stack_size(emit_t *emit, int size) {
Damien's avatar
Damien committed
126
127
128
    emit->stack_size = size;
}

129
130
131
132
133
134
135
136
137
138
139
140
static void emit_x64_load_id(emit_t *emit, qstr qstr) {
    emit_common_load_id(emit, &emit_x64_method_table, emit->scope, qstr);
}

static void emit_x64_store_id(emit_t *emit, qstr qstr) {
    emit_common_store_id(emit, &emit_x64_method_table, emit->scope, qstr);
}

static void emit_x64_delete_id(emit_t *emit, qstr qstr) {
    emit_common_delete_id(emit, &emit_x64_method_table, emit->scope, qstr);
}

141
static void adjust_stack(emit_t *emit, int stack_size_delta) {
Damien's avatar
Damien committed
142
143
144
145
146
147
148
    emit->stack_size += stack_size_delta;
    assert(emit->stack_size >= 0);
    if (emit->pass > PASS_1 && emit->stack_size > emit->scope->stack_size) {
        emit->scope->stack_size = emit->stack_size;
    }
}

149
static void stack_settle(emit_t *emit) {
Damien's avatar
Damien committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
    switch (emit->need_to_push) {
        case NEED_TO_PUSH_NOTHING:
            break;

        case NEED_TO_PUSH_R64:
            asm_x64_mov_r64_to_local(emit->as, emit->last_r64, emit->stack_start + emit->stack_size);
            adjust_stack(emit, 1);
            break;

        case NEED_TO_PUSH_I64:
            asm_x64_mov_i64_to_r64_optimised(emit->as, emit->last_i64, REG_RAX);
            asm_x64_mov_r64_to_local(emit->as, REG_RAX, emit->stack_start + emit->stack_size);
            adjust_stack(emit, 1);
            break;
    }
    emit->need_to_push = NEED_TO_PUSH_NOTHING;
}

168
static void emit_pre_raw(emit_t *emit, int stack_size_delta) {
Damien's avatar
Damien committed
169
170
171
172
    adjust_stack(emit, stack_size_delta);
    emit->last_emit_was_return_value = false;
}

173
static void emit_pre(emit_t *emit) {
Damien's avatar
Damien committed
174
175
176
177
    stack_settle(emit);
    emit_pre_raw(emit, 0);
}

178
static void emit_pre_pop_r64(emit_t *emit, int r64) {
Damien's avatar
Damien committed
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
    switch (emit->need_to_push) {
        case NEED_TO_PUSH_NOTHING:
            asm_x64_mov_local_to_r64(emit->as, emit->stack_start + emit->stack_size - 1, r64);
            emit_pre_raw(emit, -1);
            break;

        case NEED_TO_PUSH_R64:
            emit_pre_raw(emit, 0);
            if (emit->last_r64 != r64) {
                asm_x64_mov_r64_to_r64(emit->as, emit->last_r64, r64);
            }
            break;

        case NEED_TO_PUSH_I64:
            emit_pre_raw(emit, 0);
            asm_x64_mov_i64_to_r64_optimised(emit->as, emit->last_i64, r64);
            break;
    }
    emit->need_to_push = NEED_TO_PUSH_NOTHING;
}

200
static void emit_pre_pop_r64_r64(emit_t *emit, int r64a, int r64b) {
Damien's avatar
Damien committed
201
202
203
204
205
    emit_pre_pop_r64(emit, r64a);
    asm_x64_mov_local_to_r64(emit->as, emit->stack_start + emit->stack_size - 1, r64b);
    adjust_stack(emit, -1);
}

206
static void emit_pre_pop_r64_r64_r64(emit_t *emit, int r64a, int r64b, int r64c) {
Damien's avatar
Damien committed
207
208
209
210
211
212
    emit_pre_pop_r64(emit, r64a);
    asm_x64_mov_local_to_r64(emit->as, emit->stack_start + emit->stack_size - 1, r64b);
    asm_x64_mov_local_to_r64(emit->as, emit->stack_start + emit->stack_size - 2, r64c);
    adjust_stack(emit, -2);
}

213
static void emit_post(emit_t *emit) {
Damien's avatar
Damien committed
214
215
}

216
static void emit_post_push_r64(emit_t *emit, int r64) {
Damien's avatar
Damien committed
217
218
219
220
    emit->need_to_push = NEED_TO_PUSH_R64;
    emit->last_r64 = r64;
}

221
static void emit_post_push_i64(emit_t *emit, int64_t i64) {
Damien's avatar
Damien committed
222
223
224
225
    emit->need_to_push = NEED_TO_PUSH_I64;
    emit->last_i64 = i64;
}

226
static void emit_post_push_r64_r64(emit_t *emit, int r64a, int r64b) {
Damien's avatar
Damien committed
227
228
229
230
231
232
    asm_x64_mov_r64_to_local(emit->as, r64a, emit->stack_start + emit->stack_size);
    emit->need_to_push = NEED_TO_PUSH_R64;
    emit->last_r64 = r64b;
    adjust_stack(emit, 1);
}

233
static void emit_post_push_r64_r64_r64(emit_t *emit, int r64a, int r64b, int r64c) {
Damien's avatar
Damien committed
234
235
236
237
238
239
    asm_x64_mov_r64_to_local(emit->as, r64a, emit->stack_start + emit->stack_size);
    asm_x64_mov_r64_to_local(emit->as, r64b, emit->stack_start + emit->stack_size + 1);
    asm_x64_mov_r64_to_local(emit->as, r64c, emit->stack_start + emit->stack_size + 2);
    adjust_stack(emit, 3);
}

240
static void emit_post_push_r64_r64_r64_r64(emit_t *emit, int r64a, int r64b, int r64c, int r64d) {
Damien's avatar
Damien committed
241
242
243
244
245
246
247
    asm_x64_mov_r64_to_local(emit->as, r64a, emit->stack_start + emit->stack_size);
    asm_x64_mov_r64_to_local(emit->as, r64b, emit->stack_start + emit->stack_size + 1);
    asm_x64_mov_r64_to_local(emit->as, r64c, emit->stack_start + emit->stack_size + 2);
    asm_x64_mov_r64_to_local(emit->as, r64d, emit->stack_start + emit->stack_size + 3);
    adjust_stack(emit, 4);
}

248
static void emit_get_stack_pointer_to_r64_for_pop(emit_t *emit, int r64, int n_pop) {
Damien's avatar
Damien committed
249
250
251
252
    asm_x64_mov_local_addr_to_r64(emit->as, emit->stack_start + emit->stack_size - 1, r64);
    adjust_stack(emit, -n_pop);
}

253
static void emit_get_stack_pointer_to_r64_for_push(emit_t *emit, int r64, int n_push) {
Damien's avatar
Damien committed
254
255
256
257
    asm_x64_mov_local_addr_to_r64(emit->as, emit->stack_start + emit->stack_size + n_push - 1, r64);
    adjust_stack(emit, n_push);
}

258
static void emit_call(emit_t *emit, void *fun) {
Damien's avatar
Damien committed
259
260
261
    asm_x64_call_ind(emit->as, fun, REG_RAX);
}

262
static void emit_call_with_i64_arg(emit_t *emit, void *fun, int64_t arg_val, int arg_r64) {
Damien's avatar
Damien committed
263
264
265
266
    asm_x64_mov_i64_to_r64_optimised(emit->as, arg_val, arg_r64);
    asm_x64_call_ind(emit->as, fun, REG_RAX);
}

267
static void emit_x64_label_assign(emit_t *emit, int l) {
Damien's avatar
Damien committed
268
269
270
    asm_x64_label_assign(emit->as, l);
}

271
static void emit_x64_import_name(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
272
273
    assert(0);
}
274
static void emit_x64_import_from(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
275
276
    assert(0);
}
277
static void emit_x64_import_star(emit_t *emit) {
Damien's avatar
Damien committed
278
279
280
    assert(0);
}

281
static void emit_x64_load_const_tok(emit_t *emit, py_token_kind_t tok) {
Damien's avatar
Damien committed
282
283
284
285
286
287
288
289
290
291
292
    emit_pre(emit);
    py_obj_t o;
    switch (tok) {
        case PY_TOKEN_KW_NONE: o = py_const_none; break;
        case PY_TOKEN_KW_FALSE: o = py_const_false; break;
        case PY_TOKEN_KW_TRUE: o = py_const_true; break;
        default: assert(0); // shouldn't happen
    }
    emit_post_push_i64(emit, (uint64_t)o);
}

293
static void emit_x64_load_const_small_int(emit_t *emit, int arg) {
Damien's avatar
Damien committed
294
295
296
297
298
299
300
301
    emit_pre(emit);
    if (emit->do_native_types) {
        emit_post_push_i64(emit, arg);
    } else {
        emit_post_push_i64(emit, (arg << 1) | 1);
    }
}

302
static void emit_x64_load_const_int(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
303
304
    assert(0);
}
305
static void emit_x64_load_const_dec(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
306
307
    assert(0);
}
308
static void emit_x64_load_const_id(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
309
310
311
    assert(0);
}

312
static void emit_x64_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
Damien's avatar
Damien committed
313
314
315
316
317
    emit_pre(emit);
    emit_call_with_i64_arg(emit, rt_load_const_str, qstr, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET);
}

318
static void emit_x64_load_const_verbatim_start(emit_t *emit) {
Damien's avatar
Damien committed
319
320
    assert(0);
}
321
static void emit_x64_load_const_verbatim_int(emit_t *emit, int val) {
Damien's avatar
Damien committed
322
323
    assert(0);
}
324
static void emit_x64_load_const_verbatim_str(emit_t *emit, const char *str) {
Damien's avatar
Damien committed
325
326
    assert(0);
}
327
static void emit_x64_load_const_verbatim_strn(emit_t *emit, const char *str, int len) {
Damien's avatar
Damien committed
328
329
    assert(0);
}
330
static void emit_x64_load_const_verbatim_quoted_str(emit_t *emit, qstr qstr, bool bytes) {
Damien's avatar
Damien committed
331
332
    assert(0);
}
333
static void emit_x64_load_const_verbatim_end(emit_t *emit) {
Damien's avatar
Damien committed
334
335
336
    assert(0);
}

337
static void emit_x64_load_fast(emit_t *emit, qstr qstr, int local_num) {
Damien's avatar
Damien committed
338
339
340
341
342
343
344
345
346
347
    if (local_num == 0) {
        emit_pre(emit);
        emit_post_push_r64(emit, REG_LOCAL_1);
    } else {
        emit_pre(emit);
        asm_x64_mov_local_to_r64(emit->as, local_num - 1, REG_RAX);
        emit_post_push_r64(emit, REG_RAX);
    }
}

348
static void emit_x64_load_name(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
349
350
351
352
353
    emit_pre(emit);
    emit_call_with_i64_arg(emit, rt_load_name, qstr, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET);
}

354
static void emit_x64_load_global(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
355
356
357
358
359
    emit_pre(emit);
    emit_call_with_i64_arg(emit, rt_load_global, qstr, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET);
}

360
static void emit_x64_load_deref(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
361
362
    assert(0);
}
363
static void emit_x64_load_closure(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
364
365
366
    assert(0);
}

367
static void emit_x64_load_attr(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
368
369
370
371
372
    emit_pre_pop_r64(emit, REG_ARG_1); // arg1 = base
    emit_call_with_i64_arg(emit, rt_load_attr, qstr, REG_ARG_2); // arg2 = attribute name
    emit_post_push_r64(emit, REG_RET);
}

373
static void emit_x64_load_method(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
374
375
376
377
378
    emit_pre_pop_r64(emit, REG_ARG_1); // arg1 = base
    emit_get_stack_pointer_to_r64_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr
    emit_call_with_i64_arg(emit, rt_load_method, qstr, REG_ARG_2); // arg2 = method name
}

379
static void emit_x64_load_build_class(emit_t *emit) {
Damien's avatar
Damien committed
380
381
382
   assert(0);
} // basically load __build_class__ from builtins

383
static void emit_x64_store_fast(emit_t *emit, qstr qstr, int local_num) {
Damien's avatar
Damien committed
384
385
386
387
388
389
390
391
392
393
    if (local_num == 0) {
        emit_pre_pop_r64(emit, REG_LOCAL_1);
        emit_post(emit);
    } else {
        emit_pre_pop_r64(emit, REG_RAX);
        asm_x64_mov_r64_to_local(emit->as, REG_RAX, local_num - 1);
        emit_post(emit);
    }
}

394
static void emit_x64_store_name(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
395
396
397
398
399
    emit_pre_pop_r64(emit, REG_ARG_2);
    emit_call_with_i64_arg(emit, rt_store_name, qstr, REG_ARG_1); // arg1 = name
    emit_post(emit);
}

400
static void emit_x64_store_global(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
401
402
403
    assert(0);
}

404
static void emit_x64_store_deref(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
405
406
    assert(0);
}
407
static void emit_x64_store_attr(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
408
409
    assert(0);
}
410
static void emit_x64_store_locals(emit_t *emit) {
Damien's avatar
Damien committed
411
412
413
    assert(0);
}

414
static void emit_x64_store_subscr(emit_t *emit) {
Damien's avatar
Damien committed
415
416
417
418
    emit_pre_pop_r64_r64_r64(emit, REG_ARG_2, REG_ARG_1, REG_ARG_3); // index, base, value to store
    emit_call(emit, rt_store_subscr);
}

419
static void emit_x64_delete_fast(emit_t *emit, qstr qstr, int local_num) {
Damien's avatar
Damien committed
420
421
    assert(0);
}
422
static void emit_x64_delete_name(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
423
424
    assert(0);
}
425
static void emit_x64_delete_global(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
426
427
    assert(0);
}
428
static void emit_x64_delete_deref(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
429
430
    assert(0);
}
431
static void emit_x64_delete_attr(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
432
433
    assert(0);
}
434
static void emit_x64_delete_subscr(emit_t *emit) {
Damien's avatar
Damien committed
435
436
437
    assert(0);
}

438
static void emit_x64_dup_top(emit_t *emit) {
Damien's avatar
Damien committed
439
440
441
442
    emit_pre_pop_r64(emit, REG_RAX);
    emit_post_push_r64_r64(emit, REG_RAX, REG_RAX);
}

443
static void emit_x64_dup_top_two(emit_t *emit) {
Damien's avatar
Damien committed
444
445
446
447
    emit_pre_pop_r64_r64(emit, REG_RAX, REG_RDI);
    emit_post_push_r64_r64_r64_r64(emit, REG_RDI, REG_RAX, REG_RDI, REG_RAX);
}

448
static void emit_x64_pop_top(emit_t *emit) {
Damien's avatar
Damien committed
449
450
451
452
    emit_pre_pop_r64(emit, REG_RAX);
    emit_post(emit);
}

453
static void emit_x64_rot_two(emit_t *emit) {
Damien's avatar
Damien committed
454
455
456
    assert(0);
}

457
static void emit_x64_rot_three(emit_t *emit) {
Damien's avatar
Damien committed
458
459
460
461
    emit_pre_pop_r64_r64_r64(emit, REG_RAX, REG_RDI, REG_RSI);
    emit_post_push_r64_r64_r64(emit, REG_RAX, REG_RSI, REG_RDI);
}

462
static void emit_x64_jump(emit_t *emit, int label) {
Damien's avatar
Damien committed
463
464
465
466
467
    emit_pre(emit);
    asm_x64_jmp_label(emit->as, label);
    emit_post(emit);
}

468
static void emit_x64_pop_jump_if_false(emit_t *emit, int label) {
Damien's avatar
Damien committed
469
470
471
472
473
474
475
476
477
478
479
480
481
482
    if (emit->do_native_types) {
        emit_pre_pop_r64(emit, REG_RET);
        asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
        asm_x64_jcc_label(emit->as, JCC_JZ, label);
        emit_post(emit);
    } else {
        emit_pre_pop_r64(emit, REG_ARG_1);
        emit_call(emit, rt_is_true);
        asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
        asm_x64_jcc_label(emit->as, JCC_JZ, label);
        emit_post(emit);
    }
}

483
static void emit_x64_pop_jump_if_true(emit_t *emit, int label) {
Damien's avatar
Damien committed
484
485
    assert(0);
}
486
static void emit_x64_jump_if_true_or_pop(emit_t *emit, int label) {
Damien's avatar
Damien committed
487
488
    assert(0);
}
489
static void emit_x64_jump_if_false_or_pop(emit_t *emit, int label) {
Damien's avatar
Damien committed
490
491
492
    assert(0);
}

493
static void emit_x64_setup_loop(emit_t *emit, int label) {
Damien's avatar
Damien committed
494
495
496
497
    emit_pre(emit);
    emit_post(emit);
}

498
static void emit_x64_break_loop(emit_t *emit, int label) {
Damien's avatar
Damien committed
499
500
    assert(0);
}
501
static void emit_x64_continue_loop(emit_t *emit, int label) {
Damien's avatar
Damien committed
502
503
    assert(0);
}
504
static void emit_x64_setup_with(emit_t *emit, int label) {
Damien's avatar
Damien committed
505
506
    assert(0);
}
507
static void emit_x64_with_cleanup(emit_t *emit) {
Damien's avatar
Damien committed
508
509
    assert(0);
}
510
static void emit_x64_setup_except(emit_t *emit, int label) {
Damien's avatar
Damien committed
511
512
    assert(0);
}
513
static void emit_x64_setup_finally(emit_t *emit, int label) {
Damien's avatar
Damien committed
514
515
    assert(0);
}
516
static void emit_x64_end_finally(emit_t *emit) {
Damien's avatar
Damien committed
517
518
    assert(0);
}
519
static void emit_x64_get_iter(emit_t *emit) {
Damien's avatar
Damien committed
520
521
    assert(0);
} // tos = getiter(tos)
522
static void emit_x64_for_iter(emit_t *emit, int label) {
Damien's avatar
Damien committed
523
524
    assert(0);
}
525
static void emit_x64_for_iter_end(emit_t *emit) {
Damien's avatar
Damien committed
526
527
    assert(0);
}
528
static void emit_x64_pop_except(emit_t *emit) {
Damien's avatar
Damien committed
529
530
531
    assert(0);
}

532
static void emit_x64_unary_op(emit_t *emit, rt_unary_op_t op) {
Damien's avatar
Damien committed
533
534
535
536
537
    emit_pre_pop_r64(emit, REG_ARG_2);
    emit_call_with_i64_arg(emit, rt_unary_op, op, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET);
}

538
static void emit_x64_build_tuple(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
539
540
541
    assert(0);
}

542
static void emit_x64_build_list(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
543
544
545
546
547
548
    emit_pre(emit);
    emit_get_stack_pointer_to_r64_for_pop(emit, REG_ARG_2, n_args); // pointer to items in reverse order
    emit_call_with_i64_arg(emit, rt_build_list, n_args, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET); // new list
}

549
static void emit_x64_list_append(emit_t *emit, int list_index) {
Damien's avatar
Damien committed
550
551
552
    assert(0);
}

553
static void emit_x64_build_map(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
554
555
556
557
558
    emit_pre(emit);
    emit_call_with_i64_arg(emit, rt_build_map, n_args, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET); // new map
}

559
static void emit_x64_store_map(emit_t *emit) {
Damien's avatar
Damien committed
560
561
562
563
564
    emit_pre_pop_r64_r64_r64(emit, REG_ARG_2, REG_ARG_3, REG_ARG_1); // key, value, map
    emit_call(emit, rt_store_map);
    emit_post_push_r64(emit, REG_RET); // map
}

565
static void emit_x64_map_add(emit_t *emit, int map_index) {
Damien's avatar
Damien committed
566
567
568
    assert(0);
}

569
static void emit_x64_build_set(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
570
571
572
573
574
575
    emit_pre(emit);
    emit_get_stack_pointer_to_r64_for_pop(emit, REG_ARG_2, n_args); // pointer to items in reverse order
    emit_call_with_i64_arg(emit, rt_build_set, n_args, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET); // new set
}

576
static void emit_x64_set_add(emit_t *emit, int set_index) {
Damien's avatar
Damien committed
577
578
    assert(0);
}
579
static void emit_x64_build_slice(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
580
581
    assert(0);
}
582
static void emit_x64_unpack_sequence(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
583
584
    assert(0);
}
585
static void emit_x64_unpack_ex(emit_t *emit, int n_left, int n_right) {
Damien's avatar
Damien committed
586
587
588
    assert(0);
}

589
static void emit_x64_make_function(emit_t *emit, scope_t *scope, int n_dict_params, int n_default_params) {
Damien's avatar
Damien committed
590
591
592
593
594
595
    assert(n_default_params == 0 && n_dict_params == 0);
    emit_pre(emit);
    emit_call_with_i64_arg(emit, rt_make_function_from_id, scope->unique_code_id, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET);
}

596
static void emit_x64_make_closure(emit_t *emit, scope_t *scope, int n_dict_params, int n_default_params) {
Damien's avatar
Damien committed
597
598
599
    assert(0);
}

600
static void emit_x64_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) {
Damien's avatar
Damien committed
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
    assert(n_keyword == 0 && !have_star_arg && !have_dbl_star_arg);
    if (n_positional == 0) {
        emit_pre_pop_r64(emit, REG_ARG_1); // the function
        emit_call(emit, rt_call_function_0);
    } else if (n_positional == 1) {
        emit_pre_pop_r64_r64(emit, REG_ARG_2, REG_ARG_1); // the single argument, the function
        emit_call(emit, rt_call_function_1);
    } else if (n_positional == 2) {
        emit_pre_pop_r64_r64_r64(emit, REG_ARG_3, REG_ARG_2, REG_ARG_1); // the second argument, the first argument, the function
        emit_call(emit, rt_call_function_2);
    } else {
        assert(0);
    }
    emit_post_push_r64(emit, REG_RET);
}

617
static void emit_x64_call_method(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) {
Damien's avatar
Damien committed
618
619
620
621
622
623
624
625
626
627
628
629
630
    assert(n_keyword == 0 && !have_star_arg && !have_dbl_star_arg);
    if (n_positional == 0) {
        emit_pre_pop_r64_r64(emit, REG_ARG_2, REG_ARG_1); // the self object (or NULL), the method
        emit_call(emit, rt_call_method_1);
    } else if (n_positional == 1) {
        emit_pre_pop_r64_r64_r64(emit, REG_ARG_3, REG_ARG_2, REG_ARG_1); // the first argument, the self object (or NULL), the method
        emit_call(emit, rt_call_method_2);
    } else {
        assert(0);
    }
    emit_post_push_r64(emit, REG_RET);
}

631
static void emit_x64_pop_block(emit_t *emit) {
Damien's avatar
Damien committed
632
633
634
635
    emit_pre(emit);
    emit_post(emit);
}

636
static void emit_x64_binary_op(emit_t *emit, rt_binary_op_t op) {
Damien's avatar
Damien committed
637
638
639
640
641
642
643
644
645
646
647
648
    if (emit->do_native_types) {
        assert(op == RT_BINARY_OP_ADD);
        emit_pre_pop_r64_r64(emit, REG_ARG_2, REG_RET);
        asm_x64_add_r64_to_r64(emit->as, REG_ARG_2, REG_RET);
        emit_post_push_r64(emit, REG_RET);
    } else {
        emit_pre_pop_r64_r64(emit, REG_ARG_3, REG_ARG_2);
        emit_call_with_i64_arg(emit, rt_binary_op, op, REG_ARG_1);
        emit_post_push_r64(emit, REG_RET);
    }
}

649
static void emit_x64_compare_op(emit_t *emit, rt_compare_op_t op) {
Damien's avatar
Damien committed
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    if (emit->do_native_types) {
        assert(op == RT_COMPARE_OP_LESS);
        emit_pre_pop_r64_r64(emit, REG_ARG_3, REG_ARG_2);
        asm_x64_xor_r64_to_r64(emit->as, REG_RET, REG_RET);
        asm_x64_cmp_r64_with_r64(emit->as, REG_ARG_3, REG_ARG_2);
        asm_x64_setcc_r8(emit->as, JCC_JL, REG_RET);
        emit_post_push_r64(emit, REG_RET);
    } else {
        emit_pre_pop_r64_r64(emit, REG_ARG_3, REG_ARG_2);
        emit_call_with_i64_arg(emit, rt_compare_op, op, REG_ARG_1);
        emit_post_push_r64(emit, REG_RET);
    }
}

664
static void emit_x64_return_value(emit_t *emit) {
Damien's avatar
Damien committed
665
666
667
668
669
670
    emit_pre_pop_r64(emit, REG_RAX);
    emit->last_emit_was_return_value = true;
    //asm_x64_call_ind(emit->as, 0, REG_RAX); to seg fault for debugging with gdb
    asm_x64_exit(emit->as);
}

671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
static void emit_x64_raise_varargs(emit_t *emit, int n_args) {
    assert(0);
}
static void emit_x64_yield_value(emit_t *emit) {
    assert(0);
}
static void emit_x64_yield_from(emit_t *emit) {
    assert(0);
}

static const emit_method_table_t emit_x64_method_table = {
    emit_x64_set_native_types,
    emit_x64_start_pass,
    emit_x64_end_pass,
    emit_x64_last_emit_was_return_value,
    emit_x64_get_stack_size,
    emit_x64_set_stack_size,

689
690
691
692
    emit_x64_load_id,
    emit_x64_store_id,
    emit_x64_delete_id,

693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
    emit_x64_label_assign,
    emit_x64_import_name,
    emit_x64_import_from,
    emit_x64_import_star,
    emit_x64_load_const_tok,
    emit_x64_load_const_small_int,
    emit_x64_load_const_int,
    emit_x64_load_const_dec,
    emit_x64_load_const_id,
    emit_x64_load_const_str,
    emit_x64_load_const_verbatim_start,
    emit_x64_load_const_verbatim_int,
    emit_x64_load_const_verbatim_str,
    emit_x64_load_const_verbatim_strn,
    emit_x64_load_const_verbatim_quoted_str,
    emit_x64_load_const_verbatim_end,
    emit_x64_load_fast,
    emit_x64_load_name,
    emit_x64_load_global,
    emit_x64_load_deref,
    emit_x64_load_closure,
    emit_x64_load_attr,
    emit_x64_load_method,
    emit_x64_load_build_class,
    emit_x64_store_fast,
    emit_x64_store_name,
    emit_x64_store_global,
    emit_x64_store_deref,
    emit_x64_store_attr,
    emit_x64_store_locals,
    emit_x64_store_subscr,
    emit_x64_delete_fast,
    emit_x64_delete_name,
    emit_x64_delete_global,
    emit_x64_delete_deref,
    emit_x64_delete_attr,
    emit_x64_delete_subscr,
    emit_x64_dup_top,
    emit_x64_dup_top_two,
    emit_x64_pop_top,
    emit_x64_rot_two,
    emit_x64_rot_three,
    emit_x64_jump,
    emit_x64_pop_jump_if_true,
    emit_x64_pop_jump_if_false,
    emit_x64_jump_if_true_or_pop,
    emit_x64_jump_if_false_or_pop,
    emit_x64_setup_loop,
    emit_x64_break_loop,
    emit_x64_continue_loop,
    emit_x64_setup_with,
    emit_x64_with_cleanup,
    emit_x64_setup_except,
    emit_x64_setup_finally,
    emit_x64_end_finally,
    emit_x64_get_iter,
    emit_x64_for_iter,
    emit_x64_for_iter_end,
    emit_x64_pop_block,
    emit_x64_pop_except,
    emit_x64_unary_op,
    emit_x64_binary_op,
    emit_x64_compare_op,
    emit_x64_build_tuple,
    emit_x64_build_list,
    emit_x64_list_append,
    emit_x64_build_map,
    emit_x64_store_map,
    emit_x64_map_add,
    emit_x64_build_set,
    emit_x64_set_add,
    emit_x64_build_slice,
    emit_x64_unpack_sequence,
    emit_x64_unpack_ex,
    emit_x64_make_function,
    emit_x64_make_closure,
    emit_x64_call_function,
    emit_x64_call_method,
    emit_x64_return_value,
    emit_x64_raise_varargs,
    emit_x64_yield_value,
    emit_x64_yield_from,
};

777
void emit_x64_new(emit_t **emit_out, const emit_method_table_t **emit_method_table_out, uint max_num_labels) {
778
    emit_t *emit = m_new(emit_t, 1);
779
    emit->as = asm_x64_new(max_num_labels);
780
781
782
783
    emit->do_native_types = false;

    *emit_out = emit;
    *emit_method_table_out = &emit_x64_method_table;
Damien's avatar
Damien committed
784
785
}

786
#endif // EMIT_ENABLE_X64