emitx64.c 23.2 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
59
60
61
emit_t *emit_x64_new(uint max_num_labels) {
    emit_t *emit = m_new(emit_t, 1);
    emit->as = asm_x64_new(max_num_labels);
    emit->do_native_types = false;
    return emit;
}
62

63
static void emit_x64_set_native_types(emit_t *emit, bool do_native_types) {
Damien's avatar
Damien committed
64
65
66
    emit->do_native_types = do_native_types;
}

67
static void emit_x64_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
Damien's avatar
Damien committed
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    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);
        }
    }
}

104
static void emit_x64_end_pass(emit_t *emit) {
Damien's avatar
Damien committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    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);
    }
}

121
static bool emit_x64_last_emit_was_return_value(emit_t *emit) {
Damien's avatar
Damien committed
122
123
124
    return emit->last_emit_was_return_value;
}

125
static int emit_x64_get_stack_size(emit_t *emit) {
Damien's avatar
Damien committed
126
127
128
    return emit->stack_size;
}

129
static void emit_x64_set_stack_size(emit_t *emit, int size) {
Damien's avatar
Damien committed
130
131
132
    emit->stack_size = size;
}

133
134
135
136
137
138
139
140
141
142
143
144
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);
}

145
static void adjust_stack(emit_t *emit, int stack_size_delta) {
Damien's avatar
Damien committed
146
147
148
149
150
151
152
    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;
    }
}

153
static void stack_settle(emit_t *emit) {
Damien's avatar
Damien committed
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    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;
}

172
static void emit_pre_raw(emit_t *emit, int stack_size_delta) {
Damien's avatar
Damien committed
173
174
175
176
    adjust_stack(emit, stack_size_delta);
    emit->last_emit_was_return_value = false;
}

177
static void emit_pre(emit_t *emit) {
Damien's avatar
Damien committed
178
179
180
181
    stack_settle(emit);
    emit_pre_raw(emit, 0);
}

182
static void emit_pre_pop_r64(emit_t *emit, int r64) {
Damien's avatar
Damien committed
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
    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;
}

204
static void emit_pre_pop_r64_r64(emit_t *emit, int r64a, int r64b) {
Damien's avatar
Damien committed
205
206
207
208
209
    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);
}

210
static void emit_pre_pop_r64_r64_r64(emit_t *emit, int r64a, int r64b, int r64c) {
Damien's avatar
Damien committed
211
212
213
214
215
216
    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);
}

217
static void emit_post(emit_t *emit) {
Damien's avatar
Damien committed
218
219
}

220
static void emit_post_push_r64(emit_t *emit, int r64) {
Damien's avatar
Damien committed
221
222
223
224
    emit->need_to_push = NEED_TO_PUSH_R64;
    emit->last_r64 = r64;
}

225
static void emit_post_push_i64(emit_t *emit, int64_t i64) {
Damien's avatar
Damien committed
226
227
228
229
    emit->need_to_push = NEED_TO_PUSH_I64;
    emit->last_i64 = i64;
}

230
static void emit_post_push_r64_r64(emit_t *emit, int r64a, int r64b) {
Damien's avatar
Damien committed
231
232
233
234
235
236
    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);
}

237
static void emit_post_push_r64_r64_r64(emit_t *emit, int r64a, int r64b, int r64c) {
Damien's avatar
Damien committed
238
239
240
241
242
243
    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);
}

244
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
245
246
247
248
249
250
251
    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);
}

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

257
static void emit_get_stack_pointer_to_r64_for_push(emit_t *emit, int r64, int n_push) {
Damien's avatar
Damien committed
258
259
260
261
    asm_x64_mov_local_addr_to_r64(emit->as, emit->stack_start + emit->stack_size + n_push - 1, r64);
    adjust_stack(emit, n_push);
}

262
static void emit_call(emit_t *emit, void *fun) {
Damien's avatar
Damien committed
263
264
265
    asm_x64_call_ind(emit->as, fun, REG_RAX);
}

266
static void emit_call_with_i64_arg(emit_t *emit, void *fun, int64_t arg_val, int arg_r64) {
Damien's avatar
Damien committed
267
268
269
270
    asm_x64_mov_i64_to_r64_optimised(emit->as, arg_val, arg_r64);
    asm_x64_call_ind(emit->as, fun, REG_RAX);
}

271
static void emit_x64_label_assign(emit_t *emit, int l) {
Damien's avatar
Damien committed
272
273
274
    asm_x64_label_assign(emit->as, l);
}

275
static void emit_x64_import_name(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
276
277
    assert(0);
}
278
static void emit_x64_import_from(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
279
280
    assert(0);
}
281
static void emit_x64_import_star(emit_t *emit) {
Damien's avatar
Damien committed
282
283
284
    assert(0);
}

285
static void emit_x64_load_const_tok(emit_t *emit, py_token_kind_t tok) {
Damien's avatar
Damien committed
286
287
288
289
290
291
292
293
294
295
296
    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);
}

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

306
static void emit_x64_load_const_int(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
307
308
    assert(0);
}
309
static void emit_x64_load_const_dec(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
310
311
    assert(0);
}
312
static void emit_x64_load_const_id(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
313
314
315
    assert(0);
}

316
static void emit_x64_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
Damien's avatar
Damien committed
317
318
319
320
321
    emit_pre(emit);
    emit_call_with_i64_arg(emit, rt_load_const_str, qstr, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET);
}

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

341
static void emit_x64_load_fast(emit_t *emit, qstr qstr, int local_num) {
Damien's avatar
Damien committed
342
343
344
345
346
347
348
349
350
351
    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);
    }
}

352
static void emit_x64_load_name(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
353
354
355
356
357
    emit_pre(emit);
    emit_call_with_i64_arg(emit, rt_load_name, qstr, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET);
}

358
static void emit_x64_load_global(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
359
360
361
362
363
    emit_pre(emit);
    emit_call_with_i64_arg(emit, rt_load_global, qstr, REG_ARG_1);
    emit_post_push_r64(emit, REG_RET);
}

364
static void emit_x64_load_deref(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
365
366
    assert(0);
}
367
static void emit_x64_load_closure(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
368
369
370
    assert(0);
}

371
static void emit_x64_load_attr(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
372
373
374
375
376
    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);
}

377
static void emit_x64_load_method(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
378
379
380
381
382
    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
}

383
static void emit_x64_load_build_class(emit_t *emit) {
Damien's avatar
Damien committed
384
385
386
   assert(0);
} // basically load __build_class__ from builtins

387
static void emit_x64_store_fast(emit_t *emit, qstr qstr, int local_num) {
Damien's avatar
Damien committed
388
389
390
391
392
393
394
395
396
397
    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);
    }
}

398
static void emit_x64_store_name(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
399
400
401
402
403
    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);
}

404
static void emit_x64_store_global(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
405
406
407
    assert(0);
}

408
static void emit_x64_store_deref(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
409
410
    assert(0);
}
411
static void emit_x64_store_attr(emit_t *emit, qstr qstr) {
Damien's avatar
Damien committed
412
413
    assert(0);
}
414
static void emit_x64_store_locals(emit_t *emit) {
Damien's avatar
Damien committed
415
416
417
    assert(0);
}

418
static void emit_x64_store_subscr(emit_t *emit) {
Damien's avatar
Damien committed
419
420
421
422
    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);
}

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

442
static void emit_x64_dup_top(emit_t *emit) {
Damien's avatar
Damien committed
443
444
445
446
    emit_pre_pop_r64(emit, REG_RAX);
    emit_post_push_r64_r64(emit, REG_RAX, REG_RAX);
}

447
static void emit_x64_dup_top_two(emit_t *emit) {
Damien's avatar
Damien committed
448
449
450
451
    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);
}

452
static void emit_x64_pop_top(emit_t *emit) {
Damien's avatar
Damien committed
453
454
455
456
    emit_pre_pop_r64(emit, REG_RAX);
    emit_post(emit);
}

457
static void emit_x64_rot_two(emit_t *emit) {
Damien's avatar
Damien committed
458
459
460
    assert(0);
}

461
static void emit_x64_rot_three(emit_t *emit) {
Damien's avatar
Damien committed
462
463
464
465
    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);
}

466
static void emit_x64_jump(emit_t *emit, int label) {
Damien's avatar
Damien committed
467
468
469
470
471
    emit_pre(emit);
    asm_x64_jmp_label(emit->as, label);
    emit_post(emit);
}

472
static void emit_x64_pop_jump_if_false(emit_t *emit, int label) {
Damien's avatar
Damien committed
473
474
475
476
477
478
479
480
481
482
483
484
485
486
    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);
    }
}

487
static void emit_x64_pop_jump_if_true(emit_t *emit, int label) {
Damien's avatar
Damien committed
488
489
    assert(0);
}
490
static void emit_x64_jump_if_true_or_pop(emit_t *emit, int label) {
Damien's avatar
Damien committed
491
492
    assert(0);
}
493
static void emit_x64_jump_if_false_or_pop(emit_t *emit, int label) {
Damien's avatar
Damien committed
494
495
496
    assert(0);
}

497
static void emit_x64_setup_loop(emit_t *emit, int label) {
Damien's avatar
Damien committed
498
499
500
501
    emit_pre(emit);
    emit_post(emit);
}

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

536
static void emit_x64_unary_op(emit_t *emit, rt_unary_op_t op) {
Damien's avatar
Damien committed
537
538
539
540
541
    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);
}

542
static void emit_x64_build_tuple(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
543
544
545
    assert(0);
}

546
static void emit_x64_build_list(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
547
548
549
550
551
552
    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
}

553
static void emit_x64_list_append(emit_t *emit, int list_index) {
Damien's avatar
Damien committed
554
555
556
    assert(0);
}

557
static void emit_x64_build_map(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
558
559
560
561
562
    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
}

563
static void emit_x64_store_map(emit_t *emit) {
Damien's avatar
Damien committed
564
565
566
567
568
    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
}

569
static void emit_x64_map_add(emit_t *emit, int map_index) {
Damien's avatar
Damien committed
570
571
572
    assert(0);
}

573
static void emit_x64_build_set(emit_t *emit, int n_args) {
Damien's avatar
Damien committed
574
575
576
577
578
579
    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
}

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

593
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
594
595
596
597
598
599
    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);
}

600
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
601
602
603
    assert(0);
}

604
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
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
    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);
}

621
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
622
623
624
625
626
627
628
629
630
631
632
633
634
    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);
}

635
static void emit_x64_pop_block(emit_t *emit) {
Damien's avatar
Damien committed
636
637
638
639
    emit_pre(emit);
    emit_post(emit);
}

640
static void emit_x64_binary_op(emit_t *emit, rt_binary_op_t op) {
Damien's avatar
Damien committed
641
642
643
644
645
646
647
648
649
650
651
652
    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);
    }
}

653
static void emit_x64_compare_op(emit_t *emit, rt_compare_op_t op) {
Damien's avatar
Damien committed
654
655
656
657
658
659
660
661
662
663
664
665
666
667
    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);
    }
}

668
static void emit_x64_return_value(emit_t *emit) {
Damien's avatar
Damien committed
669
670
671
672
673
674
    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);
}

675
676
677
678
679
680
681
682
683
684
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);
}

685
const emit_method_table_t emit_x64_method_table = {
686
687
688
689
690
691
692
    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,

693
694
695
696
    emit_x64_load_id,
    emit_x64_store_id,
    emit_x64_delete_id,

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
777
778
779
780
781
    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,
};

#endif // EMIT_ENABLE_X64