]> pd.if.org Git - lice/blob - gen_amd64.c
autocommit for files dated 2014-11-17 20:15:26
[lice] / gen_amd64.c
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdint.h>
5 #define __STDC_FORMAT_MACROS
6 #include <inttypes.h>
7
8 #include "lice.h"
9 #include "gen.h"
10
11 #define REGISTER_AREA_SIZE     304
12 #define REGISTER_MULT_SIZE_XMM 8
13 #define REGISTER_MULT_SIZE     6
14
15 #define SRDI "rdi"
16 #define SRSI "rsi"
17 #define SRDX "rdx"
18 #define SRCX "rcx"
19 #define SR8  "r8"
20 #define SR9  "r9"
21 #define SEDI "edi"
22 #define SESI "esi"
23 #define SEDX "edx"
24 #define SECX "ecx"
25 #define SR8D "r8d"
26 #define SR9D "r9d"
27 #define SDIL "dil"
28 #define SSIL "sil"
29 #define SDL  "dl"
30 #define SCL  "cl"
31 #define SR8B "r8b"
32 #define SR9B "r9b"
33 #define SRAX "rax"
34 #define SRBX "rbx"
35 #define SR11 "r11"
36
37 static const char *register_table[][REGISTER_MULT_SIZE] = {
38     { SRDI,    SRSI,    SRDX,    SRCX,    SR8,     SR9  },
39     { SEDI,    SESI,    SEDX,    SECX,    SR8D,    SR9D },
40     { SDIL,    SSIL,    SDL,     SCL,     SR8B,    SR9B }
41 };
42
43 #define NREG(I) register_table[0][I]
44 #define SREG(I) register_table[1][I]
45 #define MREG(I) register_table[2][I]
46
47 static int stack = 0;
48 static int gp    = 0;
49 static int fp    = 0;
50
51 static void gen_push(const char *reg) {
52     gen_emit("push %%%s", reg);
53     stack += 8;
54 }
55 static void gen_pop(const char *reg) {
56     gen_emit("pop %%%s", reg);
57     stack -= 8;
58 }
59 static void gen_push_xmm(int r) {
60     gen_emit("sub $8, %%rsp");
61     gen_emit("movsd %%xmm%d, (%%rsp)", r);
62     stack += 8;
63 }
64 static void gen_pop_xmm(int r) {
65     gen_emit("movsd (%%rsp), %%xmm%d", r);
66     gen_emit("add $8, %%rsp");
67     stack -= 8;
68 }
69
70 /*
71  * Technically not the safest, but also can't legally be optimized with
72  * strict aliasing optimizations. Volatile will mark the construction
73  * of the literal from being directly delt with in the optimizer. Plus
74  * aliasing though the use of a union, while it isn't technically legal,
75  * all compilers do deal with it to some extent. Restrict on want will
76  * prevent the compiler from emitting two loads for the same address, since
77  * it is likely already in an register.
78  */
79 #define TYPEPUN(TYPE, VALUE) \
80     *(((volatile union { __typeof__(VALUE) *have; TYPE *restrict want; }) { &(VALUE) }).want)
81
82 static void *gen_mapping_table(const void **table, size_t index, size_t length, const char *func) {
83     const unsigned char **ptr = (const unsigned char **)table;
84     const unsigned char **end = &ptr[length];
85     const unsigned char **ret = &ptr[index];
86
87     if (ret < ptr || ret >= end || !*ret)
88         compile_ice("gen_mapping_table from %s (index: %zu, length: %zu)", func, index, length);
89
90     return *((void **)ret);
91 }
92
93 #define gen_mapping(TABLE, INDEX, LENGTH) \
94     gen_mapping_table((const void **)(TABLE), (INDEX), (LENGTH), __func__)
95
96 static const char *gen_register_integer(data_type_t *type, char r) {
97     static const char *items[] = {
98         "cl", "cx", 0, "ecx", 0, 0, 0, "rcx",
99         "al", "ax", 0, "eax", 0, 0, 0, "rax"
100     };
101     static const size_t length = sizeof(items)/sizeof(*items);
102     return gen_mapping(items, (type->size - 1) + !!(r == 'a') * 8, length);
103 }
104
105 static const char *gen_load_instruction(data_type_t *type) {
106     static const char *items[] = {
107         "movsbq", "movswq", 0,
108         "movslq", 0,        0, 0,
109         "mov"
110     };
111     return gen_mapping(items, type->size - 1, sizeof(items)/sizeof(*items));
112 }
113
114 static void gen_shift_load(data_type_t *type) {
115     if (type->bitfield.size <= 0)
116         return;
117     gen_emit("shr $%d, %%rax", type->bitfield.offset);
118     gen_push(SRCX);
119     gen_emit("mov $0x%" PRIx64 ", %%rcx", (1 << (uint64_t)type->bitfield.size) - 1);
120     gen_emit("and %%rcx, %%rax");
121     gen_pop(SRCX);
122 }
123
124 static void gen_shift_save(data_type_t *type, char *address) {
125     if (type->bitfield.size <= 0)
126         return;
127     gen_push(SRCX);
128     gen_push(SRDI);
129
130     gen_emit("mov $0x%" PRIx64 ", %%rdi", (1 << (uint64_t)type->bitfield.size) - 1);
131     gen_emit("and %%rdi, %%rax");
132     gen_emit("shl $%d, %%rax", type->bitfield.offset);
133     gen_emit("mov %s, %%%s", address, gen_register_integer(type, 'c'));
134     gen_emit("mov $0x%" PRIx64 ", %%rdi", ~(((1 << (uint64_t)type->bitfield.size) - 1) << type->bitfield.offset));
135     gen_emit("and %%rdi, %%rcx");
136     gen_emit("or %%rcx, %%rax");
137
138     gen_pop(SRDI);
139     gen_pop(SRCX);
140 }
141
142 static void gen_load_global(data_type_t *type, char *label, int offset) {
143     if (type->type == TYPE_ARRAY) {
144         if (offset)
145             gen_emit("lea %s+%d(%%rip), %%rax", label, offset);
146         else
147             gen_emit("lea %s(%%rip), %%rax", label);
148         return;
149     }
150     gen_emit("%s %s+%d(%%rip), %%rax", gen_load_instruction(type), label, offset);
151     gen_shift_load(type);
152 }
153
154 static void gen_cast_int(data_type_t *type) {
155     if (type->type == TYPE_FLOAT)
156         gen_emit("cvttss2si %%xmm0, %%eax");
157     else if (type->type == TYPE_DOUBLE)
158         gen_emit("cvttsd2si %%xmm0, %%eax");
159 }
160
161 static void gen_cast_bool(data_type_t *type) {
162     if (ast_type_isfloating(type)) {
163         gen_push_xmm(1);
164         gen_emit("xorpd %%xmm1, %%xmm1");
165         gen_emit("ucomisd %%xmm1, %%xmm0");
166         gen_emit("setne %%al");
167         gen_pop_xmm(1);
168     } else {
169         gen_emit("cmp $0, %%rax");
170         gen_emit("setne %%al");
171     }
172     gen_emit("movzb %%al, %%eax");
173 }
174
175 static void gen_load_local(data_type_t *var, const char *base, int offset) {
176     if (var->type == TYPE_ARRAY) {
177         gen_emit("lea %d(%%%s), %%rax", offset, base);
178     } else if (var->type == TYPE_FLOAT) {
179         gen_emit("movss %d(%%%s), %%xmm0", offset, base);
180     } else if (var->type == TYPE_DOUBLE || var->type == TYPE_LDOUBLE) {
181         gen_emit("movsd %d(%%%s), %%xmm0", offset, base);
182     } else {
183         gen_emit("%s %d(%%%s), %%rax", gen_load_instruction(var), offset, base);
184         gen_shift_load(var);
185     }
186 }
187
188 void gen_boolean_maybe(data_type_t *type) {
189     if (type->type != TYPE_BOOL)
190         return;
191
192     gen_emit("test %%rax, %%rax");
193     gen_emit("setne %%al");
194 }
195
196 static void gen_save_global(char *name, data_type_t *type, int offset) {
197     gen_boolean_maybe(type);
198
199     const char *reg = gen_register_integer(type, 'a');
200     string_t   *str = string_create();
201
202     if (offset != 0)
203         string_catf(str, "%s+%d(%%rip)", name, offset);
204     else
205         string_catf(str, "%s(%%rip)", name);
206
207     gen_shift_save(type, string_buffer(str));
208     gen_emit("mov %%%s, %s", reg, string_buffer(str));
209 }
210
211 void gen_save_local(data_type_t *type, int offset) {
212     if (type->type == TYPE_FLOAT)
213         gen_emit("movss %%xmm0, %d(%%rbp)", offset);
214     else if (type->type == TYPE_DOUBLE || type->type == TYPE_LDOUBLE)
215         gen_emit("movsd %%xmm0, %d(%%rbp)", offset);
216     else {
217         gen_boolean_maybe(type);
218
219         string_t   *str = string_create();
220         const char *reg = gen_register_integer(type, 'a');
221
222         if (offset != 0)
223             string_catf(str, "%d(%%rbp)", offset);
224         else
225             string_catf(str, "(%%rbp)");
226
227         gen_shift_save(type, string_buffer(str));
228         gen_emit("mov %%%s, %s", reg, string_buffer(str));
229     }
230 }
231
232 static void gen_assignment_dereference_intermediate(data_type_t *type, int offset) {
233     gen_emit("mov (%%rsp), %%rcx");
234
235     const char *reg = gen_register_integer(type, 'c');
236     if (offset)
237         gen_emit("mov %%%s, %d(%%rax)", reg, offset);
238     else
239         gen_emit("mov %%%s, (%%rax)", reg);
240     gen_pop(SRAX);
241 }
242
243 void gen_address(ast_t *ast) {
244     switch (ast->type) {
245         case AST_TYPE_VAR_LOCAL:
246             gen_emit("lea %d(%%rbp), %%rax", ast->variable.off);
247             break;
248         case AST_TYPE_VAR_GLOBAL:
249             gen_emit("lea %s(%%rip), %%rax", ast->variable.label);
250             break;
251         case AST_TYPE_DEREFERENCE:
252             gen_expression(ast->unary.operand);
253             break;
254         case AST_TYPE_STRUCT:
255             gen_address(ast->structure);
256             gen_emit("add $%d, %%rax", ast->ctype->offset);
257             break;
258         default:
259             compile_ice("gen_address (%s)", ast_type_string(ast->ctype));
260     }
261 }
262
263 void gen_address_label(ast_t *ast) {
264     gen_emit("mov $%s, %%rax", ast->gotostmt.where);
265 }
266
267 void gen_goto_computed(ast_t *ast) {
268     gen_expression(ast->unary.operand);
269     gen_emit("jmp *%%rax");
270 }
271
272 static void gen_structure_copy(int size, const char *base) {
273     int i = 0;
274     for (; i < size; i += 8) {
275         gen_emit("movq %d(%%rcx), %%r11", i);
276         gen_emit("movq %%r11, %d(%%%s)", i, base);
277     }
278
279     for (; i < size; i += 4) {
280         gen_emit("movl %d(%%rcx), %%r11", i);
281         gen_emit("movl %%r11d, %d(%%%s)", i, base);
282     }
283
284     for (; i < size; i++) {
285         gen_emit("movb %d(%%rcx), %%r11", i);
286         gen_emit("movb %%r11b, %d(%%%s)", i, base);
287     }
288 }
289
290 static void gen_structure_assign(ast_t *left, ast_t *right) {
291     gen_push(SRCX);
292     gen_push(SR11);
293     gen_address(right);
294     gen_emit("mov %%rax, %%rcx");
295     gen_address(left);
296     gen_structure_copy(left->ctype->size, "rax");
297     gen_pop(SR11);
298     gen_pop(SRCX);
299 }
300
301 static int gen_alignment(int n, int align) {
302     int remainder = n % align;
303     return (remainder == 0)
304                 ? n
305                 : n - remainder + align;
306 }
307
308 static int gen_structure_push(int size) {
309     compile_error("cannot pass structure of size: %d bytes by copy (unimplemented)", size);
310 }
311
312 void gen_zero(int start, int end) {
313     for (; start <= end - 8; start += 8)
314       gen_emit("movq $0, %d(%%rbp)", start);
315     for (; start <= end - 4; start += 4)
316         gen_emit("movl $0, %d(%%rbp)", start);
317     for (; start < end; start ++)
318         gen_emit("movb $0, %d(%%rbp)", start);
319 }
320
321 static void gen_assignment_dereference(ast_t *var) {
322     gen_push(SRAX);
323     gen_expression(var->unary.operand);
324     gen_assignment_dereference_intermediate(var->unary.operand->ctype->pointer, 0);
325 }
326
327 static void gen_pointer_arithmetic(char op, ast_t *left, ast_t *right) {
328     gen_expression(left);
329     gen_push(SRCX);
330     gen_push(SRAX);
331     gen_expression(right);
332
333     int size = left->ctype->pointer->size;
334     if (size > 1)
335         gen_emit("imul $%d, %%rax", size);
336
337     gen_emit("mov %%rax, %%rcx");
338     gen_pop(SRAX);
339
340     switch (op) {
341         case '+': gen_emit("add %%rcx, %%rax"); break;
342         case '-': gen_emit("sub %%rcx, %%rax"); break;
343     }
344     gen_pop(SRCX);
345 }
346
347 static void gen_assignment_structure(ast_t *structure, data_type_t *field, int offset) {
348     switch (structure->type) {
349         case AST_TYPE_VAR_LOCAL:
350             gen_ensure_lva(structure);
351             gen_save_local(field, structure->variable.off + field->offset + offset);
352             break;
353         case AST_TYPE_VAR_GLOBAL:
354             gen_save_global(structure->variable.name, field, field->offset + offset);
355             break;
356         case AST_TYPE_STRUCT:
357             gen_assignment_structure(structure->structure, field, offset + structure->ctype->offset);
358             break;
359         case AST_TYPE_DEREFERENCE:
360             gen_push(SRAX);
361             gen_expression(structure->unary.operand);
362             gen_assignment_dereference_intermediate(field, field->offset + offset);
363             break;
364         default:
365             compile_ice("gen_assignment_structure");
366             break;
367     }
368 }
369
370 static void gen_load_structure(ast_t *structure, data_type_t *field, int offset) {
371     switch (structure->type) {
372         case AST_TYPE_VAR_LOCAL:
373             gen_ensure_lva(structure);
374             gen_load_local(field, "rbp", structure->variable.off + field->offset + offset);
375             break;
376         case AST_TYPE_VAR_GLOBAL:
377             gen_load_global(field, structure->variable.name, field->offset + offset);
378             break;
379         case AST_TYPE_STRUCT:
380             gen_load_structure(structure->structure, field, structure->ctype->offset + offset);
381             break;
382         case AST_TYPE_DEREFERENCE:
383             gen_expression(structure->unary.operand);
384             gen_load_local(field, SRAX, field->offset + offset);
385             break;
386         default:
387             compile_ice("gen_assignment_structure");
388             break;
389     }
390 }
391
392 static void gen_store(ast_t *var) {
393     switch (var->type) {
394         case AST_TYPE_DEREFERENCE:
395             gen_assignment_dereference(var);
396             break;
397         case AST_TYPE_STRUCT:
398             gen_assignment_structure(var->structure, var->ctype, 0);
399             break;
400         case AST_TYPE_VAR_LOCAL:
401             gen_ensure_lva(var);
402             gen_save_local(var->ctype, var->variable.off);
403             break;
404         case AST_TYPE_VAR_GLOBAL:
405             gen_save_global(var->variable.name, var->ctype, 0);
406             break;
407         default:
408             compile_ice("gen_assignment");
409     }
410 }
411
412 static void gen_comparision(char *operation, ast_t *ast) {
413     if (ast_type_isfloating(ast->left->ctype)) {
414         gen_expression(ast->left);
415         gen_push_xmm(0);
416         gen_expression(ast->right);
417         gen_pop_xmm(1);
418         if (ast->left->ctype->type == TYPE_FLOAT)
419             gen_emit("ucomiss %%xmm0, %%xmm1");
420         else
421             gen_emit("ucomisd %%xmm0, %%xmm1");
422     } else {
423         gen_expression(ast->left);
424         gen_push(SRAX);
425         gen_expression(ast->right);
426         gen_pop(SRCX);
427
428         int type = ast->left->ctype->type;
429         if (type == TYPE_LONG || type == TYPE_LLONG)
430             gen_emit("cmp %%rax, %%rcx");
431         else
432             gen_emit("cmp %%eax, %%ecx");
433     }
434     gen_emit("%s %%al", operation);
435     gen_emit("movzb %%al, %%eax");
436 }
437
438 static const char *gen_binary_instruction(ast_t *ast) {
439     string_t *string = string_create();
440     if (ast_type_isfloating(ast->ctype)) {
441         switch (ast->type) {
442             case '+': string_catf(string, "adds"); break;
443             case '-': string_catf(string, "subs"); break;
444             case '*': string_catf(string, "muls"); break;
445             case '/': string_catf(string, "divs"); break;
446         }
447         if (ast->ctype->type == TYPE_DOUBLE || ast->ctype->type == TYPE_LDOUBLE)
448             string_cat(string, 'd');
449         else
450             string_cat(string, 's');
451         if (!string_length(string))
452             goto error;
453
454         return string_buffer(string);
455     }
456     /* integer */
457     switch (ast->type) {
458         case '+':              string_catf(string, "add");  break;
459         case '-':              string_catf(string, "sub");  break;
460         case '*':              string_catf(string, "imul"); break;
461         case '^':              string_catf(string, "xor");  break;
462         case AST_TYPE_LSHIFT:  string_catf(string, "sal");  break;
463         case AST_TYPE_RSHIFT:  string_catf(string, "sar");  break;
464         case AST_TYPE_LRSHIFT: string_catf(string, "shr");  break;
465
466         /* need to be handled specially */
467         case '/': return "@/";
468         case '%': return "@%";
469     }
470     return string_buffer(string);
471 error:
472     compile_ice("gen_binary_instruction");
473 }
474
475 static void gen_binary_arithmetic_integer(ast_t *ast) {
476     const char *op = gen_binary_instruction(ast);
477     gen_expression(ast->left);
478     gen_push(SRAX);
479     gen_expression(ast->right);
480     gen_emit("mov %%rax, %%rcx");
481     gen_pop(SRAX);
482
483     if (*op == '@') {
484         gen_emit("cqto");
485         gen_emit("idiv %%rcx");
486         if (op[1] == '%')
487             gen_emit("mov %%edx, %%eax");
488     } else if (ast->type == AST_TYPE_LSHIFT
489         ||     ast->type == AST_TYPE_RSHIFT
490         ||     ast->type == AST_TYPE_LRSHIFT
491     ) {
492         gen_emit("%s %%cl, %%%s", op, gen_register_integer(ast->left->ctype, 'a'));
493     } else {
494         gen_emit("%s %%rcx, %%rax", op);
495     }
496 }
497
498 static void gen_binary_arithmetic_floating(ast_t *ast) {
499     const char *op = gen_binary_instruction(ast);
500     gen_expression(ast->left);
501     gen_push_xmm(0);
502     gen_expression(ast->right);
503     if (ast->ctype->type == TYPE_DOUBLE)
504         gen_emit("movsd %%xmm0, %%xmm1");
505     else
506         gen_emit("movss %%xmm0, %%xmm1");
507     gen_pop_xmm(0);
508     gen_emit("%s %%xmm1, %%xmm0", op);
509 }
510
511 void gen_load_convert(data_type_t *to, data_type_t *from) {
512     if (ast_type_isinteger(from) && to->type == TYPE_FLOAT)
513         gen_emit("cvtsi2ss %%eax, %%xmm0");
514     else if (ast_type_isinteger(from) && to->type == TYPE_DOUBLE)
515         gen_emit("cvtsi2sd %%eax, %%xmm0");
516     else if (from->type == TYPE_FLOAT && to->type == TYPE_DOUBLE)
517         gen_emit("cvtps2pd %%xmm0, %%xmm0");
518     else if (from->type == TYPE_DOUBLE && to->type == TYPE_FLOAT)
519         gen_emit("cvtpd2ps %%xmm0, %%xmm0");
520     else if (to->type == TYPE_BOOL)
521         gen_cast_bool(from);
522     else if (ast_type_isinteger(to))
523         gen_cast_int(from);
524 }
525
526 void gen_conversion(ast_t *ast) {
527     gen_expression(ast->unary.operand);
528     gen_load_convert(ast->ctype, ast->unary.operand->ctype);
529 }
530
531 void gen_binary(ast_t *ast) {
532     if (ast->ctype->type == TYPE_POINTER) {
533         gen_pointer_arithmetic(ast->type, ast->left, ast->right);
534         return;
535     }
536
537     switch (ast->type) {
538         case '<':             gen_comparision("setl",  ast); return;
539         case '>':             gen_comparision("setg",  ast); return;
540         case AST_TYPE_EQUAL:  gen_comparision("sete",  ast); return;
541         case AST_TYPE_GEQUAL: gen_comparision("setge", ast); return;
542         case AST_TYPE_LEQUAL: gen_comparision("setle", ast); return;
543         case AST_TYPE_NEQUAL: gen_comparision("setne", ast); return;
544     }
545
546     if (ast_type_isinteger(ast->ctype))
547         gen_binary_arithmetic_integer(ast);
548     else if (ast_type_isfloating(ast->ctype))
549         gen_binary_arithmetic_floating(ast);
550     else
551         compile_ice("gen_binary");
552 }
553
554 void gen_literal_save(ast_t *ast, data_type_t *type, int offset) {
555     uint64_t load64  = ((uint64_t)ast->integer);
556     uint32_t load32  = ast->integer;
557     float    loadf32 = ast->floating.value;
558     double   loadf64 = ast->floating.value;
559
560     gen_emit("# literal save {");
561     switch (type->type) {
562         case TYPE_BOOL:  gen_emit("movb $%d, %d(%%rbp)", !!ast->integer, offset); break;
563         case TYPE_CHAR:  gen_emit("movb $%d, %d(%%rbp)", load32, offset); break;
564         case TYPE_SHORT: gen_emit("movw $%d, %d(%%rbp)", load32, offset); break;
565         case TYPE_INT:   gen_emit("movl $%d, %d(%%rbp)", load32, offset); break;
566         case TYPE_LONG:
567         case TYPE_LLONG:
568         case TYPE_POINTER:
569             gen_emit("movl $0x%" PRIx64 ", %d(%%rbp)", load64 & 0xFFFFFFFF, offset);
570             gen_emit("movl $0x%" PRIx64 ", %d(%%rbp)", load64 >> 32, offset + 4);
571             break;
572         case TYPE_FLOAT:
573             load32 = TYPEPUN(uint32_t, loadf32);
574             gen_emit("movl $0x%" PRIx32 ", %d(%%rbp)", load32, offset);
575             break;
576         case TYPE_DOUBLE:
577             load64 = TYPEPUN(uint64_t, loadf64);
578             gen_emit("movl $0x%" PRIx64 ", %d(%%rbp)", load64 & 0xFFFFFFFF, offset);
579             gen_emit("movl $0x%" PRIx64 ", %d(%%rbp)", load64 >> 32, offset + 4);
580             break;
581
582         default:
583             compile_ice("gen_literal_save");
584     }
585     gen_emit("# }");
586 }
587
588 void gen_prefix(ast_t *ast, const char *op) {
589     gen_expression(ast->unary.operand);
590     if (ast->ctype->type == TYPE_POINTER)
591         gen_emit("%s $%d, %%rax", op, ast->ctype->pointer->size);
592     else
593         gen_emit("%s $1, %%rax", op);
594     gen_store(ast->unary.operand);
595 }
596
597 void gen_postfix(ast_t *ast, const char *op) {
598     gen_expression(ast->unary.operand);
599     gen_push(SRAX);
600     if (ast->ctype->type == TYPE_POINTER)
601         gen_emit("%s $%d, %%rax", op, ast->ctype->pointer->size);
602     else
603         gen_emit("%s $1, %%rax", op);
604     gen_store(ast->unary.operand);
605     gen_pop(SRAX);
606 }
607
608 static void gen_register_area_calculate(list_t *args) {
609     gp = 0;
610     fp = 0;
611     for (list_iterator_t *it = list_iterator(args); !list_iterator_end(it); )
612         (*((ast_type_isfloating(((ast_t*)list_iterator_next(it))->ctype)) ? &fp : &gp)) ++;
613 }
614
615 void gen_je(const char *label) {
616     gen_emit("test %%rax, %%rax");
617     gen_emit("je %s", label);
618 }
619
620 void gen_cast(ast_t *ast) {
621     gen_expression(ast->unary.operand);
622     gen_load_convert(ast->ctype, ast->unary.operand->ctype);
623 }
624
625 void gen_literal(ast_t *ast) {
626     switch (ast->ctype->type) {
627         case TYPE_CHAR:
628         case TYPE_BOOL:
629             gen_emit("mov $%d, %%rax", ast->integer);
630             break;
631         case TYPE_INT:
632             gen_emit("mov $%d, %%rax", ast->integer);
633             break;
634         case TYPE_LONG:
635         case TYPE_LLONG:
636             gen_emit("mov $%" PRIi64 ", %%rax", (uint64_t)ast->integer);
637             break;
638
639         case TYPE_FLOAT:
640             if (!ast->floating.label) {
641                 ast->floating.label = ast_label();
642                 float  fval = ast->floating.value;
643                 int   *iptr = (int*)&fval;
644                 gen_emit_inline(".data");
645                 gen_label(ast->floating.label);
646                 gen_emit(".long %d", *iptr);
647                 gen_emit_inline(".text");
648             }
649             gen_emit("movss %s(%%rip), %%xmm0", ast->floating.label);
650             break;
651
652         case TYPE_DOUBLE:
653         case TYPE_LDOUBLE:
654             if (!ast->floating.label) {
655                 ast->floating.label = ast_label();
656                 double dval = ast->floating.value;
657                 int   *iptr = (int*)&dval;
658                 gen_emit_inline(".data");
659                 gen_label(ast->floating.label);
660                 gen_emit(".long %d", iptr[0]);
661                 gen_emit(".long %d", iptr[1]);
662                 gen_emit_inline(".text");
663             }
664             gen_emit("movsd %s(%%rip), %%xmm0", ast->floating.label);
665             break;
666
667         default:
668             compile_ice("gen_expression (%s)", ast_type_string(ast->ctype));
669     }
670 }
671
672 void gen_literal_string(ast_t *ast) {
673     if (!ast->string.label) {
674         ast->string.label = ast_label();
675         gen_emit_inline(".data");
676         gen_label(ast->string.label);
677         gen_emit(".string \"%s\"", string_quote(ast->string.data));
678         gen_emit_inline(".text");
679     }
680     gen_emit("lea %s(%%rip), %%rax", ast->string.label);
681 }
682
683 void gen_variable_local(ast_t *ast) {
684     gen_ensure_lva(ast);
685     gen_load_local(ast->ctype, "rbp", ast->variable.off);
686 }
687
688 void gen_variable_global(ast_t *ast) {
689     gen_load_global(ast->ctype, ast->variable.label, 0);
690 }
691
692 void gen_dereference(ast_t *ast) {
693     gen_expression(ast->unary.operand);
694     gen_load_local(ast->unary.operand->ctype->pointer, SRAX, 0);
695     gen_load_convert(ast->ctype, ast->unary.operand->ctype->pointer);
696 }
697
698 static void gen_function_args_classify(list_t *i, list_t *f, list_t *r, list_t *a) {
699     int ir = 0;
700     int xr = 0;
701     int mi = REGISTER_MULT_SIZE;
702     int mx = REGISTER_MULT_SIZE_XMM;
703
704     list_iterator_t *it = list_iterator(a);
705     while (!list_iterator_end(it)) {
706         ast_t *value = list_iterator_next(it);
707         if (value->ctype->type == TYPE_STRUCTURE)
708             list_push(r, value);
709         else if (ast_type_isfloating(value->ctype))
710             list_push((xr++ < mx) ? f : r, value);
711         else
712             list_push((ir++ < mi) ? i : r, value);
713     }
714 }
715
716 static void gen_function_args_save(int in, int fl) {
717     gen_emit("# function args save {");
718     for (int i = 0; i < in; i++)      gen_push(NREG(i));
719     for (int i = 1; i < fl; i++)      gen_push_xmm(i);
720     gen_emit("# }");
721 }
722 static void gen_function_args_restore(int in, int fl) {
723     gen_emit("# function args restore {");
724     for (int i = fl - 1; i >  0; i--) gen_pop_xmm(i);
725     for (int i = in - 1; i >= 0; i--) gen_pop(NREG(i));
726     gen_emit("# }");
727 }
728 static void gen_function_args_popi(int l) {
729     gen_emit("# function args pop {");
730     for (int i = l - 1; i >= 0; i--)  gen_pop(NREG(i));
731     gen_emit("# }");
732 }
733 static void gen_function_args_popf(int l) {
734     gen_emit("# function args pop (xmm registers) {");
735     for (int i = l - 1; i >= 0; i--)  gen_pop_xmm(i);
736     gen_emit("# }");
737 }
738
739 static int gen_function_args(list_t *args) {
740     gen_emit("# functiona arguments { ");
741     int rest = 0;
742     list_iterator_t *it = list_iterator(args);
743     while (!list_iterator_end(it)) {
744         ast_t *value = list_iterator_next(it);
745         if (value->ctype->type == TYPE_STRUCTURE) {
746             gen_address(value);
747             rest += gen_structure_push(value->ctype->size);
748         } else if (ast_type_isfloating(value->ctype)) {
749             gen_expression(value);
750             gen_push_xmm(0);
751             rest += 8;
752         } else {
753             gen_expression(value);
754             gen_push(SRAX);
755             rest += 8;
756         }
757     }
758     gen_emit("# } ");
759     return rest;
760 }
761
762 static void gen_function_call_default(ast_t *ast) {
763     int          save = stack;
764     bool         fptr = (ast->type == AST_TYPE_POINTERCALL);
765     data_type_t *type = fptr ? ast->function.call.functionpointer->ctype->pointer
766                              : ast->function.call.type;
767
768     gen_emit("# function call {");
769
770     /* deal with arguments */
771     list_t *in = list_create();
772     list_t *fl = list_create();
773     list_t *re = list_create();
774
775     gen_function_args_classify(in, fl, re, ast->function.call.args);
776     gen_function_args_save(list_length(in), list_length(fl));
777
778     bool algn = stack % 16;
779     if (algn) {
780         gen_emit("sub $8, %%rsp");
781         stack += 8;
782     }
783
784     int rest = gen_function_args(list_reverse(re));
785
786     if (fptr) {
787         gen_expression(ast->function.call.functionpointer);
788         gen_push(SRAX);
789     }
790
791     gen_function_args(in);
792     gen_function_args(fl);
793     gen_function_args_popf(list_length(fl));
794     gen_function_args_popi(list_length(in));
795
796     if (fptr)
797         gen_pop(SR11);
798
799     if (type->hasdots)
800         gen_emit("mov $%d, %%eax", list_length(fl));
801
802     if (fptr)
803         gen_emit("call *%%r11");
804     else
805         gen_emit("call %s", ast->function.name);
806
807     gen_boolean_maybe(ast->ctype);
808
809     if (rest > 0) {
810         gen_emit("add $%d, %%rsp", rest);
811         stack -= rest;
812     }
813
814     if (algn) {
815         gen_emit("add $8, %%rsp");
816         stack -= 8;
817     }
818
819     gen_function_args_restore(list_length(in), list_length(fl));
820
821     gen_emit("# }");
822
823     if (stack != save)
824         compile_ice("gen_function_call (stack out of alignment)");
825 }
826
827 void gen_function_call(ast_t *ast) {
828     char *loopbeg;
829     char *loopend;
830
831     if (!ast->function.name || strcmp(ast->function.name, "__builtin_return_address")) {
832         gen_function_call_default(ast);
833         return;
834     }
835
836     /*
837      * deal with builtin return address extension. This should be
838      * as easy as emitting the expression for the return address
839      * argument and using some loops.
840      */
841     gen_push(SR11);
842     gen_expression(list_head(ast->function.call.args));
843     loopbeg = ast_label();
844     loopend = ast_label();
845     gen_emit("mov %%rbp, %%r11");
846     gen_label(loopbeg);
847     gen_emit("test %%rax, %%rax");
848     gen_emit("jz %s", loopend);
849     gen_emit("mov (%%r11), %%r11");
850     gen_emit("dec %%rax");
851     gen_jump(loopbeg);
852     gen_label(loopend);
853     gen_emit("mov 8(%%r11), %%rax");
854     gen_pop(SR11);
855 }
856
857 void gen_case(ast_t *ast) {
858     char *skip;
859     gen_jump((skip = ast_label()));
860     gen_label(gen_label_switch);
861     gen_label_switch = ast_label();
862     gen_emit("cmp $%d, %%eax", ast->casebeg);
863     if (ast->casebeg == ast->caseend)
864         gen_emit("jne %s", gen_label_switch);
865     else {
866         gen_emit("jl %s", gen_label_switch);
867         gen_emit("cmp $%d, %%eax", ast->caseend);
868         gen_emit("jg %s", gen_label_switch);
869     }
870     gen_label(skip);
871 }
872
873 void gen_va_start(ast_t *ast) {
874     gen_expression(ast->ap);
875     gen_push(SRCX);
876     gen_emit("movl $%d, (%%rax)", gp * 8);
877     gen_emit("movl $%d, 4(%%rax)", 48 + fp * 16);
878     gen_emit("lea %d(%%rbp), %%rcx", -REGISTER_AREA_SIZE);
879     gen_emit("mov %%rcx, 16(%%rax)");
880     gen_pop(SRCX);
881 }
882
883 void gen_va_arg(ast_t *ast) {
884     gen_expression(ast->ap);
885     gen_emit("nop");
886     gen_push(SRCX);
887     gen_push("rbx");
888     gen_emit("mov 16(%%rax), %%rcx");
889     if (ast_type_isfloating(ast->ctype)) {
890         gen_emit("mov 4(%%rax), %%ebx");
891         gen_emit("add %%rbx, %%rcx");
892         gen_emit("add $16, %%ebx");
893         gen_emit("mov %%ebx, 4(%%rax)");
894         gen_emit("movsd (%%rcx), %%xmm0");
895         if (ast->ctype->type == TYPE_FLOAT)
896             gen_emit("cvtpd2ps %%xmm0, %%xmm0");
897     } else {
898         gen_emit("mov (%%rax), %%ebx");
899         gen_emit("add %%rbx, %%rcx");
900         gen_emit("add $8, %%ebx");
901         gen_emit("mov %%rbx, (%%rax)");
902         gen_emit("mov (%%rcx), %%rax");
903     }
904     gen_pop(SRBX);
905     gen_pop(SRCX);
906 }
907
908 void gen_not(ast_t *ast) {
909     gen_expression(ast->unary.operand);
910     gen_emit("cmp $0, %%rax");
911     gen_emit("sete %%al");
912     gen_emit("movzb %%al, %%eax");
913 }
914
915 void gen_and(ast_t *ast) {
916     char *end = ast_label();
917     gen_expression(ast->left);
918     gen_emit("test %%rax, %%rax");
919     gen_emit("mov $0, %%rax");
920     gen_emit("je %s", end);
921     gen_expression(ast->right);
922     gen_emit("test %%rax, %%rax");
923     gen_emit("mov $0, %%rax");
924     gen_emit("je %s", end);
925     gen_emit("mov $1, %%rax");
926     gen_label(end);
927 }
928
929 void gen_or(ast_t *ast) {
930     char *end = ast_label();
931     gen_expression(ast->left);
932     gen_emit("test %%rax, %%rax");
933     gen_emit("mov $1, %%rax");
934     gen_emit("jne %s", end);
935     gen_expression(ast->right);
936     gen_emit("test %%rax, %%rax");
937     gen_emit("mov $1, %%rax");
938     gen_emit("jne %s", end);
939     gen_emit("mov $0, %%rax");
940     gen_label(end);
941 }
942
943 void gen_struct(ast_t *ast) {
944     gen_load_structure(ast->structure, ast->ctype, 0);
945 }
946
947 void gen_bitandor(ast_t *ast) {
948     static const char *instruction[] = { "and", "or" };
949     gen_expression(ast->left);
950     gen_push(SRAX);
951     gen_expression(ast->right);
952     gen_pop(SRCX);
953     gen_emit("%s %%rcx, %%rax", instruction[!!(ast->type == '|')]);
954 }
955
956 void gen_bitnot(ast_t *ast) {
957     gen_expression(ast->left);
958     gen_emit("not %%rax");
959 }
960
961 void gen_negate(ast_t *ast) {
962     gen_expression(ast->unary.operand);
963     if (ast_type_isfloating(ast->ctype)) {
964         gen_push_xmm(1);
965         gen_emit("xorpd %%xmm1, %%xmm1");
966         if (ast->ctype->type == TYPE_DOUBLE)
967             gen_emit("subsd %%xmm1, %%xmm0");
968         else
969             gen_emit("subss %%xmm1, %%xmm0");
970         gen_pop_xmm(1);
971         return;
972     }
973     gen_emit("neg %%rax");
974 }
975
976 void gen_assign(ast_t *ast) {
977     if (ast->left->ctype->type == TYPE_STRUCTURE) {
978         if (ast->left->ctype->size > 8) {
979             gen_structure_assign(ast->left, ast->right);
980             return;
981         }
982     }
983     gen_expression(ast->right);
984     gen_load_convert(ast->ctype, ast->right->ctype);
985     gen_store(ast->left);
986 }
987
988 int parse_evaluate(ast_t *ast);
989 static void gen_data_zero(int size) {
990     for (; size >= 8; size -= 8) gen_emit(".quad 0");
991     for (; size >= 4; size -= 4) gen_emit(".long 0");
992     for (; size >  0; size --)   gen_emit(".byte 0");
993 }
994
995 static void gen_data_padding(ast_t *ast, int offset) {
996     int d = ast->init.offset - offset;
997     if (d < 0)
998         compile_ice("gen_data_padding");
999     gen_data_zero(d);
1000 }
1001
1002 static void gen_data_intermediate(list_t *inits, int size, int offset, int depth) {
1003     uint64_t load64;
1004     uint32_t load32;
1005
1006     list_iterator_t *it = list_iterator(inits);
1007     while (!list_iterator_end(it) && 0 < size) {
1008         ast_t *node = list_iterator_next(it);
1009         ast_t *v    = node->init.value;
1010
1011         gen_data_padding(node, offset);
1012         offset += node->init.type->size;
1013         size   -= node->init.type->size;
1014
1015         if (v->type == AST_TYPE_ADDRESS) {
1016             char *label;
1017             switch (v->unary.operand->type) {
1018                 case AST_TYPE_VAR_LOCAL:
1019                     label  = ast_label();
1020                     gen_emit(".data %d", depth + 1);
1021                     gen_label(label);
1022                     gen_data_intermediate(v->unary.operand->variable.init, v->unary.operand->ctype->size, 0, depth + 1);
1023                     gen_emit(".data %d", depth);
1024                     gen_emit(".quad %s", label);
1025                     continue;
1026
1027                 case AST_TYPE_VAR_GLOBAL:
1028                     gen_emit(".quad %s", v->unary.operand->variable.name);
1029                     continue;
1030
1031                 default:
1032                     compile_ice("gen_datat_intermediate");
1033             }
1034         }
1035
1036         if (node->init.value->type == AST_TYPE_VAR_LOCAL && node->init.value->variable.init) {
1037             gen_data_intermediate(v->variable.init, v->ctype->size, 0, depth);
1038             continue;
1039         }
1040
1041         if (v->ctype->type == TYPE_ARRAY && v->ctype->pointer->type == TYPE_CHAR) {
1042             char *label = ast_label();
1043             gen_emit(".data %d", depth + 1);
1044             gen_label(label);
1045             gen_emit(".string \"%s\"", string_quote(v->string.data));
1046             gen_emit(".data %d", depth);
1047             gen_emit(".quad %s", label);
1048             continue;
1049         }
1050
1051
1052         /* load alias */
1053         load32 = TYPEPUN(uint32_t, node->init.value->floating.value);
1054         load64 = TYPEPUN(uint64_t, node->init.value->floating.value);
1055
1056         switch (node->init.type->type) {
1057             case TYPE_FLOAT:   gen_emit(".long 0x%"  PRIx32, load32); break;
1058             case TYPE_DOUBLE:  gen_emit(".quad 0x%"  PRIx64, load64); break;
1059             case TYPE_CHAR:    gen_emit(".byte %d",  parse_evaluate(node->init.value)); break;
1060             case TYPE_SHORT:   gen_emit(".short %d", parse_evaluate(node->init.value)); break;
1061             case TYPE_INT:     gen_emit(".long %d",  parse_evaluate(node->init.value)); break;
1062
1063             case TYPE_LONG:
1064             case TYPE_LLONG:
1065             case TYPE_POINTER:
1066                 if (node->init.value->type == AST_TYPE_VAR_GLOBAL)
1067                     gen_emit(".quad %s", node->init.value->variable.name);
1068                 else
1069                     gen_emit(".quad %ld", parse_evaluate(node->init.value));
1070                 break;
1071
1072             default:
1073                 compile_ice("gen_data_intermediate (%s)", ast_type_string(node->init.type));
1074         }
1075     }
1076     gen_data_zero(size);
1077 }
1078
1079 void gen_data(ast_t *ast, int offset, int depth) {
1080     gen_emit(".data %d", depth);
1081     if (!ast->decl.var->ctype->isstatic)
1082         gen_emit_inline(".global %s", ast->decl.var->variable.name);
1083     gen_emit_inline("%s:", ast->decl.var->variable.name);
1084     gen_data_intermediate(ast->decl.init, ast->decl.var->ctype->size, offset, depth);
1085 }
1086
1087 static int gen_register_area(void) {
1088     int top = -REGISTER_AREA_SIZE;
1089     gen_emit("mov %%rdi, %d(%%rsp)", top);
1090     gen_emit("mov %%rsi, %d(%%rsp)", (top += 8));
1091     gen_emit("mov %%rdx, %d(%%rsp)", (top += 8));
1092     gen_emit("mov %%rcx, %d(%%rsp)", (top += 8));
1093     gen_emit("mov %%r8,  %d(%%rsp)", (top += 8));
1094     gen_emit("mov %%r9,  %d(%%rsp)", top + 8);
1095
1096     char *end = ast_label();
1097     for (int i = 0; i < 16; i++) {
1098         gen_emit("test %%al, %%al");
1099         gen_emit("jz %s", end);
1100         gen_emit("movsd %%xmm%d, %d(%%rsp)", i, (top += 16));
1101         gen_emit("sub $1, %%al");
1102     }
1103     gen_label(end);
1104     gen_emit("sub $%d, %%rsp", REGISTER_AREA_SIZE);
1105     return REGISTER_AREA_SIZE;
1106 }
1107
1108 static void gen_function_parameters(list_t *parameters, int offset) {
1109     gen_emit("# function parameters { ");
1110     int ir = 0;
1111     int xr = 0;
1112     int ar = REGISTER_MULT_SIZE_XMM - REGISTER_MULT_SIZE;
1113
1114     for (list_iterator_t *it = list_iterator(parameters); !list_iterator_end(it); ) {
1115         ast_t *value = list_iterator_next(it);
1116         if (value->ctype->type == TYPE_STRUCTURE) {
1117             gen_emit("lea %d(%%rbp), %%rax", ar * 8);
1118             int emit = gen_structure_push(value->ctype->size);
1119             offset -= emit;
1120             ar += emit / 8;
1121         } else if (ast_type_isfloating(value->ctype)) {
1122             if (xr >= REGISTER_MULT_SIZE_XMM) {
1123                 gen_emit("mov %d(%%rbp), %%rax", ar++ * 8);
1124                 gen_push(SRAX);
1125             } else {
1126                 gen_push_xmm(xr++);
1127             }
1128             offset -= 8;
1129         } else {
1130             if (ir >= REGISTER_MULT_SIZE) {
1131                 if (value->ctype->type == TYPE_BOOL) {
1132                     gen_emit("mov %d(%%rbp), %%al", ar++ * 8);
1133                     gen_emit("movzb %%al, %%eax");
1134                 } else {
1135                     gen_emit("mov %d(%%rbp), %%al", ar++ * 8);
1136                 }
1137                 gen_push(SRAX);
1138             } else {
1139                 if (value->ctype->type == TYPE_BOOL)
1140                     gen_emit("movsb %%%s, %%%s", SREG(ir), MREG(ir));
1141                 gen_push(NREG(ir++));
1142             }
1143             offset -= 8;
1144         }
1145         value->variable.off = offset;
1146     }
1147     gen_emit("# }");
1148 }
1149
1150 void gen_function_prologue(ast_t *ast) {
1151     gen_emit("# function prologue {");
1152     gen_emit_inline(".text");
1153     if (!ast->ctype->isstatic)
1154         gen_emit_inline(".global %s", ast->function.name);
1155     gen_emit_inline("%s:", ast->function.name);
1156     gen_emit("nop");
1157     gen_push("rbp");
1158     gen_emit("mov %%rsp, %%rbp");
1159
1160     int offset = 0;
1161
1162     if (ast->ctype->hasdots) {
1163         gen_register_area_calculate(ast->function.params);
1164         offset -= gen_register_area();
1165     }
1166
1167     gen_function_parameters(ast->function.params, offset);
1168     offset -= list_length(ast->function.params) * 8;
1169
1170     int localdata = 0;
1171     for (list_iterator_t *it = list_iterator(ast->function.locals); !list_iterator_end(it); ) {
1172         ast_t *value = list_iterator_next(it);
1173         int    align = gen_alignment(value->ctype->size, 8);
1174
1175         offset -= align;
1176         value->variable.off = offset;
1177         localdata += align;
1178     }
1179
1180     if (localdata) {
1181         gen_emit("sub $%d, %%rsp", localdata);
1182         stack += localdata;
1183     }
1184     gen_emit("# }");
1185 }
1186
1187 void gen_function_epilogue(void) {
1188     if (stack != 0)
1189         gen_emit("# stack misalignment: %d\n", stack);
1190     gen_return();
1191 }
1192
1193 void gen_return(void) {
1194     gen_emit("leave");
1195     gen_emit("ret");
1196 }
1197
1198 void gen_function(ast_t *ast) {
1199     (void)ast;
1200     stack = 8;
1201 }