5 #define __STDC_FORMAT_MACROS
11 #define REGISTER_AREA_SIZE 304
12 #define REGISTER_MULT_SIZE_XMM 8
13 #define REGISTER_MULT_SIZE 6
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 }
43 #define NREG(I) register_table[0][I]
44 #define SREG(I) register_table[1][I]
45 #define MREG(I) register_table[2][I]
51 static void gen_push(const char *reg) {
52 gen_emit("push %%%s", reg);
55 static void gen_pop(const char *reg) {
56 gen_emit("pop %%%s", reg);
59 static void gen_push_xmm(int r) {
60 gen_emit("sub $8, %%rsp");
61 gen_emit("movsd %%xmm%d, (%%rsp)", r);
64 static void gen_pop_xmm(int r) {
65 gen_emit("movsd (%%rsp), %%xmm%d", r);
66 gen_emit("add $8, %%rsp");
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.
79 #define TYPEPUN(TYPE, VALUE) \
80 *(((volatile union { __typeof__(VALUE) *have; TYPE *restrict want; }) { &(VALUE) }).want)
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];
87 if (ret < ptr || ret >= end || !*ret)
88 compile_ice("gen_mapping_table from %s (index: %zu, length: %zu)", func, index, length);
90 return *((void **)ret);
93 #define gen_mapping(TABLE, INDEX, LENGTH) \
94 gen_mapping_table((const void **)(TABLE), (INDEX), (LENGTH), __func__)
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"
101 static const size_t length = sizeof(items)/sizeof(*items);
102 return gen_mapping(items, (type->size - 1) + !!(r == 'a') * 8, length);
105 static const char *gen_load_instruction(data_type_t *type) {
106 static const char *items[] = {
107 "movsbq", "movswq", 0,
111 return gen_mapping(items, type->size - 1, sizeof(items)/sizeof(*items));
114 static void gen_shift_load(data_type_t *type) {
115 if (type->bitfield.size <= 0)
117 gen_emit("shr $%d, %%rax", type->bitfield.offset);
119 gen_emit("mov $0x%" PRIx64 ", %%rcx", (1 << (uint64_t)type->bitfield.size) - 1);
120 gen_emit("and %%rcx, %%rax");
124 static void gen_shift_save(data_type_t *type, char *address) {
125 if (type->bitfield.size <= 0)
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");
142 static void gen_load_global(data_type_t *type, char *label, int offset) {
143 if (type->type == TYPE_ARRAY) {
145 gen_emit("lea %s+%d(%%rip), %%rax", label, offset);
147 gen_emit("lea %s(%%rip), %%rax", label);
150 gen_emit("%s %s+%d(%%rip), %%rax", gen_load_instruction(type), label, offset);
151 gen_shift_load(type);
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");
161 static void gen_cast_bool(data_type_t *type) {
162 if (ast_type_isfloating(type)) {
164 gen_emit("xorpd %%xmm1, %%xmm1");
165 gen_emit("ucomisd %%xmm1, %%xmm0");
166 gen_emit("setne %%al");
169 gen_emit("cmp $0, %%rax");
170 gen_emit("setne %%al");
172 gen_emit("movzb %%al, %%eax");
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);
183 gen_emit("%s %d(%%%s), %%rax", gen_load_instruction(var), offset, base);
188 void gen_boolean_maybe(data_type_t *type) {
189 if (type->type != TYPE_BOOL)
192 gen_emit("test %%rax, %%rax");
193 gen_emit("setne %%al");
196 static void gen_save_global(char *name, data_type_t *type, int offset) {
197 gen_boolean_maybe(type);
199 const char *reg = gen_register_integer(type, 'a');
200 string_t *str = string_create();
203 string_catf(str, "%s+%d(%%rip)", name, offset);
205 string_catf(str, "%s(%%rip)", name);
207 gen_shift_save(type, string_buffer(str));
208 gen_emit("mov %%%s, %s", reg, string_buffer(str));
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);
217 gen_boolean_maybe(type);
219 string_t *str = string_create();
220 const char *reg = gen_register_integer(type, 'a');
223 string_catf(str, "%d(%%rbp)", offset);
225 string_catf(str, "(%%rbp)");
227 gen_shift_save(type, string_buffer(str));
228 gen_emit("mov %%%s, %s", reg, string_buffer(str));
232 static void gen_assignment_dereference_intermediate(data_type_t *type, int offset) {
233 gen_emit("mov (%%rsp), %%rcx");
235 const char *reg = gen_register_integer(type, 'c');
237 gen_emit("mov %%%s, %d(%%rax)", reg, offset);
239 gen_emit("mov %%%s, (%%rax)", reg);
243 void gen_address(ast_t *ast) {
245 case AST_TYPE_VAR_LOCAL:
246 gen_emit("lea %d(%%rbp), %%rax", ast->variable.off);
248 case AST_TYPE_VAR_GLOBAL:
249 gen_emit("lea %s(%%rip), %%rax", ast->variable.label);
251 case AST_TYPE_DEREFERENCE:
252 gen_expression(ast->unary.operand);
254 case AST_TYPE_STRUCT:
255 gen_address(ast->structure);
256 gen_emit("add $%d, %%rax", ast->ctype->offset);
259 compile_ice("gen_address (%s)", ast_type_string(ast->ctype));
263 void gen_address_label(ast_t *ast) {
264 gen_emit("mov $%s, %%rax", ast->gotostmt.where);
267 void gen_goto_computed(ast_t *ast) {
268 gen_expression(ast->unary.operand);
269 gen_emit("jmp *%%rax");
272 static void gen_structure_copy(int size, const char *base) {
274 for (; i < size; i += 8) {
275 gen_emit("movq %d(%%rcx), %%r11", i);
276 gen_emit("movq %%r11, %d(%%%s)", i, base);
279 for (; i < size; i += 4) {
280 gen_emit("movl %d(%%rcx), %%r11", i);
281 gen_emit("movl %%r11d, %d(%%%s)", i, base);
284 for (; i < size; i++) {
285 gen_emit("movb %d(%%rcx), %%r11", i);
286 gen_emit("movb %%r11b, %d(%%%s)", i, base);
290 static void gen_structure_assign(ast_t *left, ast_t *right) {
294 gen_emit("mov %%rax, %%rcx");
296 gen_structure_copy(left->ctype->size, "rax");
301 static int gen_alignment(int n, int align) {
302 int remainder = n % align;
303 return (remainder == 0)
305 : n - remainder + align;
308 static int gen_structure_push(int size) {
309 compile_error("cannot pass structure of size: %d bytes by copy (unimplemented)", size);
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);
321 static void gen_assignment_dereference(ast_t *var) {
323 gen_expression(var->unary.operand);
324 gen_assignment_dereference_intermediate(var->unary.operand->ctype->pointer, 0);
327 static void gen_pointer_arithmetic(char op, ast_t *left, ast_t *right) {
328 gen_expression(left);
331 gen_expression(right);
333 int size = left->ctype->pointer->size;
335 gen_emit("imul $%d, %%rax", size);
337 gen_emit("mov %%rax, %%rcx");
341 case '+': gen_emit("add %%rcx, %%rax"); break;
342 case '-': gen_emit("sub %%rcx, %%rax"); break;
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);
353 case AST_TYPE_VAR_GLOBAL:
354 gen_save_global(structure->variable.name, field, field->offset + offset);
356 case AST_TYPE_STRUCT:
357 gen_assignment_structure(structure->structure, field, offset + structure->ctype->offset);
359 case AST_TYPE_DEREFERENCE:
361 gen_expression(structure->unary.operand);
362 gen_assignment_dereference_intermediate(field, field->offset + offset);
365 compile_ice("gen_assignment_structure");
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);
376 case AST_TYPE_VAR_GLOBAL:
377 gen_load_global(field, structure->variable.name, field->offset + offset);
379 case AST_TYPE_STRUCT:
380 gen_load_structure(structure->structure, field, structure->ctype->offset + offset);
382 case AST_TYPE_DEREFERENCE:
383 gen_expression(structure->unary.operand);
384 gen_load_local(field, SRAX, field->offset + offset);
387 compile_ice("gen_assignment_structure");
392 static void gen_store(ast_t *var) {
394 case AST_TYPE_DEREFERENCE:
395 gen_assignment_dereference(var);
397 case AST_TYPE_STRUCT:
398 gen_assignment_structure(var->structure, var->ctype, 0);
400 case AST_TYPE_VAR_LOCAL:
402 gen_save_local(var->ctype, var->variable.off);
404 case AST_TYPE_VAR_GLOBAL:
405 gen_save_global(var->variable.name, var->ctype, 0);
408 compile_ice("gen_assignment");
412 static void gen_comparision(char *operation, ast_t *ast) {
413 if (ast_type_isfloating(ast->left->ctype)) {
414 gen_expression(ast->left);
416 gen_expression(ast->right);
418 if (ast->left->ctype->type == TYPE_FLOAT)
419 gen_emit("ucomiss %%xmm0, %%xmm1");
421 gen_emit("ucomisd %%xmm0, %%xmm1");
423 gen_expression(ast->left);
425 gen_expression(ast->right);
428 int type = ast->left->ctype->type;
429 if (type == TYPE_LONG || type == TYPE_LLONG)
430 gen_emit("cmp %%rax, %%rcx");
432 gen_emit("cmp %%eax, %%ecx");
434 gen_emit("%s %%al", operation);
435 gen_emit("movzb %%al, %%eax");
438 static const char *gen_binary_instruction(ast_t *ast) {
439 string_t *string = string_create();
440 if (ast_type_isfloating(ast->ctype)) {
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;
447 if (ast->ctype->type == TYPE_DOUBLE || ast->ctype->type == TYPE_LDOUBLE)
448 string_cat(string, 'd');
450 string_cat(string, 's');
451 if (!string_length(string))
454 return string_buffer(string);
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;
466 /* need to be handled specially */
467 case '/': return "@/";
468 case '%': return "@%";
470 return string_buffer(string);
472 compile_ice("gen_binary_instruction");
475 static void gen_binary_arithmetic_integer(ast_t *ast) {
476 const char *op = gen_binary_instruction(ast);
477 gen_expression(ast->left);
479 gen_expression(ast->right);
480 gen_emit("mov %%rax, %%rcx");
485 gen_emit("idiv %%rcx");
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
492 gen_emit("%s %%cl, %%%s", op, gen_register_integer(ast->left->ctype, 'a'));
494 gen_emit("%s %%rcx, %%rax", op);
498 static void gen_binary_arithmetic_floating(ast_t *ast) {
499 const char *op = gen_binary_instruction(ast);
500 gen_expression(ast->left);
502 gen_expression(ast->right);
503 if (ast->ctype->type == TYPE_DOUBLE)
504 gen_emit("movsd %%xmm0, %%xmm1");
506 gen_emit("movss %%xmm0, %%xmm1");
508 gen_emit("%s %%xmm1, %%xmm0", op);
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)
522 else if (ast_type_isinteger(to))
526 void gen_conversion(ast_t *ast) {
527 gen_expression(ast->unary.operand);
528 gen_load_convert(ast->ctype, ast->unary.operand->ctype);
531 void gen_binary(ast_t *ast) {
532 if (ast->ctype->type == TYPE_POINTER) {
533 gen_pointer_arithmetic(ast->type, ast->left, ast->right);
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;
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);
551 compile_ice("gen_binary");
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;
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;
569 gen_emit("movl $0x%" PRIx64 ", %d(%%rbp)", load64 & 0xFFFFFFFF, offset);
570 gen_emit("movl $0x%" PRIx64 ", %d(%%rbp)", load64 >> 32, offset + 4);
573 load32 = TYPEPUN(uint32_t, loadf32);
574 gen_emit("movl $0x%" PRIx32 ", %d(%%rbp)", load32, offset);
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);
583 compile_ice("gen_literal_save");
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);
593 gen_emit("%s $1, %%rax", op);
594 gen_store(ast->unary.operand);
597 void gen_postfix(ast_t *ast, const char *op) {
598 gen_expression(ast->unary.operand);
600 if (ast->ctype->type == TYPE_POINTER)
601 gen_emit("%s $%d, %%rax", op, ast->ctype->pointer->size);
603 gen_emit("%s $1, %%rax", op);
604 gen_store(ast->unary.operand);
608 static void gen_register_area_calculate(list_t *args) {
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)) ++;
615 void gen_je(const char *label) {
616 gen_emit("test %%rax, %%rax");
617 gen_emit("je %s", label);
620 void gen_cast(ast_t *ast) {
621 gen_expression(ast->unary.operand);
622 gen_load_convert(ast->ctype, ast->unary.operand->ctype);
625 void gen_literal(ast_t *ast) {
626 switch (ast->ctype->type) {
629 gen_emit("mov $%d, %%rax", ast->integer);
632 gen_emit("mov $%d, %%rax", ast->integer);
636 gen_emit("mov $%" PRIi64 ", %%rax", (uint64_t)ast->integer);
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");
649 gen_emit("movss %s(%%rip), %%xmm0", ast->floating.label);
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");
664 gen_emit("movsd %s(%%rip), %%xmm0", ast->floating.label);
668 compile_ice("gen_expression (%s)", ast_type_string(ast->ctype));
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");
680 gen_emit("lea %s(%%rip), %%rax", ast->string.label);
683 void gen_variable_local(ast_t *ast) {
685 gen_load_local(ast->ctype, "rbp", ast->variable.off);
688 void gen_variable_global(ast_t *ast) {
689 gen_load_global(ast->ctype, ast->variable.label, 0);
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);
698 static void gen_function_args_classify(list_t *i, list_t *f, list_t *r, list_t *a) {
701 int mi = REGISTER_MULT_SIZE;
702 int mx = REGISTER_MULT_SIZE_XMM;
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)
709 else if (ast_type_isfloating(value->ctype))
710 list_push((xr++ < mx) ? f : r, value);
712 list_push((ir++ < mi) ? i : r, value);
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);
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));
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));
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);
739 static int gen_function_args(list_t *args) {
740 gen_emit("# functiona arguments { ");
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) {
747 rest += gen_structure_push(value->ctype->size);
748 } else if (ast_type_isfloating(value->ctype)) {
749 gen_expression(value);
753 gen_expression(value);
762 static void gen_function_call_default(ast_t *ast) {
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;
768 gen_emit("# function call {");
770 /* deal with arguments */
771 list_t *in = list_create();
772 list_t *fl = list_create();
773 list_t *re = list_create();
775 gen_function_args_classify(in, fl, re, ast->function.call.args);
776 gen_function_args_save(list_length(in), list_length(fl));
778 bool algn = stack % 16;
780 gen_emit("sub $8, %%rsp");
784 int rest = gen_function_args(list_reverse(re));
787 gen_expression(ast->function.call.functionpointer);
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));
800 gen_emit("mov $%d, %%eax", list_length(fl));
803 gen_emit("call *%%r11");
805 gen_emit("call %s", ast->function.name);
807 gen_boolean_maybe(ast->ctype);
810 gen_emit("add $%d, %%rsp", rest);
815 gen_emit("add $8, %%rsp");
819 gen_function_args_restore(list_length(in), list_length(fl));
824 compile_ice("gen_function_call (stack out of alignment)");
827 void gen_function_call(ast_t *ast) {
831 if (!ast->function.name || strcmp(ast->function.name, "__builtin_return_address")) {
832 gen_function_call_default(ast);
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.
842 gen_expression(list_head(ast->function.call.args));
843 loopbeg = ast_label();
844 loopend = ast_label();
845 gen_emit("mov %%rbp, %%r11");
847 gen_emit("test %%rax, %%rax");
848 gen_emit("jz %s", loopend);
849 gen_emit("mov (%%r11), %%r11");
850 gen_emit("dec %%rax");
853 gen_emit("mov 8(%%r11), %%rax");
857 void gen_case(ast_t *ast) {
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);
866 gen_emit("jl %s", gen_label_switch);
867 gen_emit("cmp $%d, %%eax", ast->caseend);
868 gen_emit("jg %s", gen_label_switch);
873 void gen_va_start(ast_t *ast) {
874 gen_expression(ast->ap);
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)");
883 void gen_va_arg(ast_t *ast) {
884 gen_expression(ast->ap);
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");
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");
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");
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");
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");
943 void gen_struct(ast_t *ast) {
944 gen_load_structure(ast->structure, ast->ctype, 0);
947 void gen_bitandor(ast_t *ast) {
948 static const char *instruction[] = { "and", "or" };
949 gen_expression(ast->left);
951 gen_expression(ast->right);
953 gen_emit("%s %%rcx, %%rax", instruction[!!(ast->type == '|')]);
956 void gen_bitnot(ast_t *ast) {
957 gen_expression(ast->left);
958 gen_emit("not %%rax");
961 void gen_negate(ast_t *ast) {
962 gen_expression(ast->unary.operand);
963 if (ast_type_isfloating(ast->ctype)) {
965 gen_emit("xorpd %%xmm1, %%xmm1");
966 if (ast->ctype->type == TYPE_DOUBLE)
967 gen_emit("subsd %%xmm1, %%xmm0");
969 gen_emit("subss %%xmm1, %%xmm0");
973 gen_emit("neg %%rax");
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);
983 gen_expression(ast->right);
984 gen_load_convert(ast->ctype, ast->right->ctype);
985 gen_store(ast->left);
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");
995 static void gen_data_padding(ast_t *ast, int offset) {
996 int d = ast->init.offset - offset;
998 compile_ice("gen_data_padding");
1002 static void gen_data_intermediate(list_t *inits, int size, int offset, int depth) {
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;
1011 gen_data_padding(node, offset);
1012 offset += node->init.type->size;
1013 size -= node->init.type->size;
1015 if (v->type == AST_TYPE_ADDRESS) {
1017 switch (v->unary.operand->type) {
1018 case AST_TYPE_VAR_LOCAL:
1019 label = ast_label();
1020 gen_emit(".data %d", depth + 1);
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);
1027 case AST_TYPE_VAR_GLOBAL:
1028 gen_emit(".quad %s", v->unary.operand->variable.name);
1032 compile_ice("gen_datat_intermediate");
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);
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);
1045 gen_emit(".string \"%s\"", string_quote(v->string.data));
1046 gen_emit(".data %d", depth);
1047 gen_emit(".quad %s", label);
1053 load32 = TYPEPUN(uint32_t, node->init.value->floating.value);
1054 load64 = TYPEPUN(uint64_t, node->init.value->floating.value);
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;
1066 if (node->init.value->type == AST_TYPE_VAR_GLOBAL)
1067 gen_emit(".quad %s", node->init.value->variable.name);
1069 gen_emit(".quad %ld", parse_evaluate(node->init.value));
1073 compile_ice("gen_data_intermediate (%s)", ast_type_string(node->init.type));
1076 gen_data_zero(size);
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);
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);
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");
1104 gen_emit("sub $%d, %%rsp", REGISTER_AREA_SIZE);
1105 return REGISTER_AREA_SIZE;
1108 static void gen_function_parameters(list_t *parameters, int offset) {
1109 gen_emit("# function parameters { ");
1112 int ar = REGISTER_MULT_SIZE_XMM - REGISTER_MULT_SIZE;
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);
1121 } else if (ast_type_isfloating(value->ctype)) {
1122 if (xr >= REGISTER_MULT_SIZE_XMM) {
1123 gen_emit("mov %d(%%rbp), %%rax", ar++ * 8);
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");
1135 gen_emit("mov %d(%%rbp), %%al", ar++ * 8);
1139 if (value->ctype->type == TYPE_BOOL)
1140 gen_emit("movsb %%%s, %%%s", SREG(ir), MREG(ir));
1141 gen_push(NREG(ir++));
1145 value->variable.off = offset;
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);
1158 gen_emit("mov %%rsp, %%rbp");
1162 if (ast->ctype->hasdots) {
1163 gen_register_area_calculate(ast->function.params);
1164 offset -= gen_register_area();
1167 gen_function_parameters(ast->function.params, offset);
1168 offset -= list_length(ast->function.params) * 8;
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);
1176 value->variable.off = offset;
1181 gen_emit("sub $%d, %%rsp", localdata);
1187 void gen_function_epilogue(void) {
1189 gen_emit("# stack misalignment: %d\n", stack);
1193 void gen_return(void) {
1198 void gen_function(ast_t *ast) {