1 /*
2 * Copyright (c) 2006 - 2010, Nils R. Weller
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Emit GAS code from intermediate x86 code
28 */
29 #include "x86_emit_gas.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <assert.h>
35 #include <ctype.h>
36 #include "scope.h"
37 #include "type.h"
38 #include "decl.h"
39 #include "icode.h"
40 #include "subexpr.h"
41 #include "token.h"
42 #include "functions.h"
43 #include "control.h"
44 #include "symlist.h"
45 #include "typemap.h"
46 #include "dwarf.h"
47 #include "cc1_main.h"
48 #include "x86_gen.h"
49 #include "amd64_gen.h"
50 #include "amd64_emit_gas.h"
51 #include "expr.h"
52 #include "inlineasm.h"
53 #include "error.h"
54 #include "n_libc.h"
55
56 static FILE *out;
57 static size_t data_segment_offset;
58 static size_t bss_segment_offset;
59 static size_t data_thread_segment_offset;
60 static size_t bss_thread_segment_offset;
61
62 void as_print_string_init(FILE *, size_t howmany, struct ty_string *str);
63
64 static void
65 emit_setsection(int value);
66
67 static int
init(FILE * fd,struct scope * s)68 init(FILE *fd, struct scope *s) {
69 (void) s;
70 out = fd;
71
72 /* XXX this is kludgy & assumes regs are already init'ed */
73 x86_fprs[0].name = "st"; /* gas doesn't recognize st(0) :-( */
74 x86_fprs[1].name = "st(1)";
75 x86_fprs[2].name = "st(2)";
76 x86_fprs[3].name = "st(3)";
77 x86_fprs[4].name = "st(4)";
78 x86_fprs[5].name = "st(5)";
79 x86_fprs[6].name = "st(6)";
80 x86_fprs[7].name = "st(7)";
81 return 0;
82 }
83
84 int osx_call_renamed; /* XXX Change emit_call() instead */
85
86
87 struct osx_fcall {
88 char *name;
89 int nonlazy;
90 int renamed;
91 struct decl *dec;
92 struct osx_fcall *next;
93 };
94
95 #define FCALL_HTAB_SIZE 128
96
97 static struct osx_fcall *fcall_htab[FCALL_HTAB_SIZE];
98 static struct osx_fcall *fcall_htab_tail[FCALL_HTAB_SIZE];
99
100 static void
add_osx_fcall(const char * name,struct decl * dec,int nonlazy)101 add_osx_fcall(const char *name, struct decl *dec, int nonlazy) {
102 unsigned int key = 0;
103 const char *p;
104 struct osx_fcall *f;
105
106 for (p = name; *p != 0; ++p) {
107 key = 33 * key + *p;
108 }
109 key &= (FCALL_HTAB_SIZE - 1);
110
111 /* Check whether the function has already been called */
112 for (f = fcall_htab[key]; f != NULL; f = f->next) {
113 if (f->nonlazy != nonlazy) {
114 /*
115 * One is a function call and one is a
116 * function pointer reference
117 */
118 continue;
119 }
120 if (strcmp(f->name, name) == 0) {
121 /* Yes, don't redeclare */
122 return;
123 }
124 }
125
126 /* Create new symbol entry */
127 f = n_xmalloc(sizeof *f);
128 f->name = n_xstrdup(name);
129 f->nonlazy = nonlazy;
130 f->renamed = osx_call_renamed;
131 f->dec = dec;
132 f->next = NULL;
133
134 if (fcall_htab[key] == NULL) {
135 fcall_htab[key] = fcall_htab_tail[key] = f;
136 } else {
137 fcall_htab_tail[key]->next = f;
138 fcall_htab_tail[key] = f;
139 }
140 }
141
142
143 static void
144 print_mem_operand(struct vreg *vr, struct token *constant);
145 struct reg *
146 get_smaller_reg(struct reg *r, size_t size);
147 void
148 do_attribute_alias(struct decl *dec);
149
150
151 /*
152 * Turns either a byte size into an assembler instruction size postfix.
153 * If a type argument is supplied (non-null), it will ensure that ``long long''
154 * is mapped to ``dword'', as that type is really dealt with as two
155 * dwords rather than a qword.
156 */
157 int
size_to_gaspostfix(size_t size,struct type * type)158 size_to_gaspostfix(size_t size, struct type *type) {
159 int is_fp = 0;
160
161 if (type != NULL) {
162 if (IS_FLOATING(type->code) && type->tlist == NULL) {
163 is_fp = 1;
164 } else {
165 is_fp = 0;
166 if (type->tlist == NULL) {
167 if (IS_LLONG(type->code)) {
168 if (backend->arch != ARCH_AMD64) {
169 size = 4;
170 }
171 }
172 }
173 }
174 }
175 /* XXXXXXXXX long double :( */
176 if (size == /*10*/12 || size == 10
177 || size == 16) return 't'; /* long double */
178 else if (size == 8) {
179 if (type != NULL
180 && IS_FLOATING(type->code)
181 && type->tlist == NULL) {
182 return 'l'; /* double */
183 } else {
184 return backend->arch == ARCH_AMD64? 'q': 'l';
185 }
186 }
187 else if (size == 4 && is_fp) return 's'; /* float */
188 else if (size == 4) return 'l'; /* long word (dword) */
189 else if (size == 2) return 'w'; /* word */
190 else if (size == 1) return 'b'; /* byte */
191 else if (type && type->tlist) {
192 return backend->arch == ARCH_AMD64? 'q': 'l'; /* XXX BUG!!!? array? */
193 } else {
194 printf("bad size for size_to_gaspostfix(): %lu\n",
195 (unsigned long)size);
196 abort();
197 }
198 return 0;
199 }
200
201 static void
202 print_init_list(struct decl *dec, struct initializer *init);
203 static void
204 print_reg_assign(struct reg *dest,
205 struct reg *srcreg, size_t src_size, struct type *src_type);
206
207 static void
print_init_expr(struct type * dt,struct expr * ex)208 print_init_expr(struct type *dt, struct expr *ex) {
209 struct tyval *cv;
210 int is_addr_as_int = 0;
211
212 cv = ex->const_value;
213 #if 0
214 as_align_for_type(out, dt);
215 x_fprintf(out, "\t");
216 #endif
217 if (cv && (cv->str || cv->address)) {
218 if (dt->tlist == NULL) {
219 /*
220 * This must be a stupid construct like
221 * static size_t foo = (size_t)&const_addr;
222 * because otherwise the address/string would
223 * have a pointer or array type node
224 */
225 is_addr_as_int = 1;
226 }
227 }
228
229 if (dt->tlist == NULL && !is_addr_as_int) {
230 switch (dt->code) {
231 case TY_CHAR:
232 case TY_UCHAR:
233 case TY_SCHAR:
234 case TY_BOOL:
235 x_fprintf(out, ".byte ");
236 cross_print_value_by_type(out, ex->const_value->value,
237 TY_UCHAR, 'x');
238 break;
239 case TY_SHORT:
240 x_fprintf(out, ".word ");
241 cross_print_value_by_type(out, ex->const_value->value,
242 dt->code, 'x');
243 break;
244 case TY_USHORT:
245 x_fprintf(out, ".word ");
246 cross_print_value_by_type(out, ex->const_value->value,
247 dt->code, 'x');
248 break;
249 case TY_INT:
250 case TY_ENUM:
251 x_fprintf(out, ".long ");
252 cross_print_value_by_type(out, ex->const_value->value,
253 dt->code, 'x');
254 break;
255 case TY_UINT:
256 x_fprintf(out, ".long ");
257 cross_print_value_by_type(out, ex->const_value->value,
258 dt->code, 'x');
259 break;
260 case TY_LONG:
261 case TY_LLONG:
262 if (backend->arch != ARCH_AMD64
263 && dt->code == TY_LLONG) {
264 x_fprintf(out, ".long ");
265 cross_print_value_chunk(out,
266 ex->const_value->value,
267 TY_LLONG, TY_UINT, 0, 0);
268 x_fputc('\n', out);
269 x_fprintf(out, "\t.long ");
270 cross_print_value_chunk(out,
271 ex->const_value->value,
272 TY_LLONG, TY_UINT, 0, 1);
273 } else if (backend->arch == ARCH_AMD64) {
274 x_fprintf(out, ".quad ");
275 cross_print_value_by_type(out,
276 ex->const_value->value,
277 TY_LONG, 'd');
278 } else {
279 x_fprintf(out, ".long ");
280 cross_print_value_by_type(out,
281 ex->const_value->value,
282 TY_LONG, 'd');
283 }
284 break;
285 case TY_ULONG:
286 case TY_ULLONG:
287 if (backend->arch != ARCH_AMD64
288 && dt->code == TY_ULLONG) {
289 x_fprintf(out, ".long ");
290 cross_print_value_chunk(out,
291 ex->const_value->value,
292 TY_ULLONG, TY_UINT, 0, 0);
293 x_fputc('\n', out);
294 x_fprintf(out, "\t.long ");
295 cross_print_value_chunk(out,
296 ex->const_value->value,
297 TY_ULLONG, TY_UINT, 0, 1);
298 } else if (backend->arch == ARCH_AMD64) {
299 x_fprintf(out, ".quad ");
300 cross_print_value_by_type(out,
301 ex->const_value->value,
302 TY_ULONG, 'd');
303 } else {
304 x_fprintf(out, ".long ");
305 cross_print_value_by_type(out,
306 ex->const_value->value,
307 TY_ULONG, 'd');
308 }
309 break;
310 case TY_FLOAT:
311 x_fprintf(out, ".long ");
312 cross_print_value_by_type(out,
313 ex->const_value->value,
314 TY_UINT, 'x');
315 break;
316 case TY_DOUBLE:
317 x_fprintf(out, ".long ");
318 cross_print_value_chunk(out,
319 ex->const_value->value,
320 TY_DOUBLE, TY_UINT, 0, 0);
321 x_fputc('\n', out);
322 x_fprintf(out, "\t.long ");
323 cross_print_value_chunk(out,
324 ex->const_value->value,
325 TY_DOUBLE, TY_UINT, 0, 1);
326 break;
327 case TY_LDOUBLE:
328 x_fprintf(out, ".long ");
329 cross_print_value_chunk(out,
330 ex->const_value->value,
331 TY_LDOUBLE, TY_UINT, 0, 0);
332 x_fputc('\n', out);
333 x_fprintf(out, "\t.long ");
334 cross_print_value_chunk(out,
335 ex->const_value->value,
336 TY_LDOUBLE, TY_UINT, 0, 1);
337 x_fputc('\n', out);
338 x_fprintf(out, ".word ");
339 cross_print_value_chunk(out,
340 ex->const_value->value,
341 TY_LDOUBLE, TY_UINT, TY_USHORT, 2);
342 if (sysflag == OS_OSX || backend->arch == ARCH_AMD64) {
343 /* 02/23/09: Pad to 16 */
344 x_fprintf(out, "\n\t.space 6\n");
345 } else {
346 /* 02/23/09: Pad to 12 */
347 x_fprintf(out, "\n\t.zero 2\n");
348 }
349 break;
350 default:
351 printf("print_init_expr: "
352 "unsupported datatype %d\n",
353 dt->code);
354 unimpl();
355 }
356 } else {
357 if (is_addr_as_int || dt->tlist->type == TN_POINTER_TO) {
358 if (backend->arch == ARCH_AMD64) {
359 x_fprintf(out, ".quad ");
360 } else {
361 x_fprintf(out, ".long ");
362 }
363 if (cv->is_nullptr_const) {
364 x_fprintf(out, "0");
365 } else if (cv->str) {
366 x_fprintf(out, "._Str%lu", cv->str->count);
367 } else if (cv->value) {
368 cross_print_value_by_type(out,
369 cv->value, TY_ULONG, 'x');
370 } else if (cv->address) {
371 /* XXX */
372 char *sign;
373
374 if (cv->address->diff < 0) {
375 /* sign = "-"*/
376 /*
377 * 08/02/09: The address difference is
378 * already negative, and the code below
379 * unconditionally used +, so we got
380 * constructs like
381 *
382 * -+-10
383 *
384 * Without the extra sign, we now get
385 *
386 * +-10
387 *
388 * which looks goofy but works right
389 * (``add minus 10'')
390 */
391 sign = "";
392 } else {
393 sign = "";
394 }
395 if (cv->address->dec != NULL) {
396 /* Static variable */
397 x_fprintf(out, "%s%s%s+%ld",
398 sysflag == OS_OSX? "_": "",
399 cv->address->dec->dtype->name,
400 sign,
401 cv->address->diff);
402 } else {
403 /* Label */
404 x_fprintf(out, ".%s%s+%ld",
405 cv->address->labelname,
406 sign,
407 cv->address->diff);
408 }
409 }
410 } else if (dt->tlist->type == TN_ARRAY_OF) {
411 size_t arrsize;
412 struct tyval *cv;
413
414 /*
415 * This has to be a string because only in
416 * char buf[] = "hello"; will an aggregate
417 * initializer ever be stored as INIT_EXPR
418 */
419
420 cv = ex->const_value;
421 arrsize = dt->tlist->arrarg_const;
422 as_print_string_init(out, arrsize, cv->str);
423
424 if (arrsize >= cv->str->size) {
425 if (arrsize > cv->str->size) {
426 if (sysflag == OS_OSX) {
427 x_fprintf(out, "\n\t.space %lu\n",
428 arrsize - cv->str->size);
429 } else {
430 x_fprintf(out, "\n\t.zero %lu\n",
431 arrsize - cv->str->size);
432 }
433 }
434 } else {
435 /* Do not null-terminate */
436 ;
437 }
438 }
439 }
440 x_fputc('\n', out);
441 }
442
443 /* XXX may be adaptable for different platforms */
444 static void
print_init_list(struct decl * dec,struct initializer * init)445 print_init_list(struct decl *dec, struct initializer *init) {
446 struct sym_entry *se = NULL;
447 struct sym_entry *startse = NULL;
448
449 if (dec
450 && dec->dtype->code == TY_STRUCT
451 && dec->dtype->tlist == NULL) {
452 se = dec->dtype->tstruc->scope->slist;
453 }
454
455 for (; init != NULL; init = init->next) {
456 if (init->type == INIT_NESTED) {
457 struct decl *nested_dec = NULL;
458 struct decl *storage_unit = NULL;
459 struct type_node *saved_tlist = NULL;
460
461 if (se == NULL) {
462 /*
463 * May be an array of structs, in
464 * which case the struct declaration
465 * is needed for alignment
466 */
467 if (dec
468 && dec->dtype->code == TY_STRUCT) {
469 nested_dec = alloc_decl();
470 nested_dec->dtype = dec->dtype;
471 saved_tlist = dec->dtype->tlist;
472 dec->dtype->tlist = NULL;
473 }
474 } else {
475 nested_dec = se->dec;
476 }
477
478 print_init_list(nested_dec, init->data);
479
480 if (saved_tlist != NULL) {
481 dec->dtype->tlist = saved_tlist;
482 free(nested_dec);
483 }
484
485 /*
486 * 10/08/08: If this is a bitfield initializer, match
487 * (skip) all affected bitfield declarations in this
488 * struct. This is important for alignment
489 */
490 if (se != NULL && se->dec->dtype->tbit != NULL) {
491 storage_unit = se->dec->dtype->tbit->bitfield_storage_unit;
492 /*
493 * Skip all but last initialized bitfield, which is needed
494 * for alignment below
495 */
496 if (se->next == NULL) {
497 /*
498 * This is already the last struct member, which
499 * also happens to be a bitfield
500 */
501 ;
502 } else {
503 do {
504 se = se->next;
505 } while (se != NULL
506 && se->next != NULL
507 && se->dec->dtype->tbit != NULL
508 && se->dec->dtype->tbit->bitfield_storage_unit == storage_unit);
509
510 if (se != NULL
511 && (se->dec->dtype->tbit == NULL
512 || se->dec->dtype->tbit->bitfield_storage_unit != storage_unit)) {
513 /* Move back to last BF member - so we can align for next member */
514 se = se->prev;
515 }
516 }
517 }
518 } else if (init->type == INIT_EXPR) {
519 struct expr *ex;
520
521 ex = init->data;
522 print_init_expr(ex->const_value->type, ex);
523 if (se != NULL && se->dec->dtype->tbit != NULL) {
524 /*
525 * Skip alignment stuff below, UNLESS
526 * we are dealing with the last member
527 * of the struct, in which case we may
528 * have to pad to align for the start
529 * of the struct
530 */
531 if (se->next != NULL) {
532 continue;
533 }
534 }
535 } else if (init->type == INIT_NULL) {
536 if (init->varinit && init->left_type->tbit != NULL) {
537 #if 0
538 if (se->next != NULL) {
539 continue;
540 }
541 #endif
542 continue;
543 } else {
544 /* XXX cross-comp */
545 if (sysflag == OS_OSX) {
546 x_fprintf(out, "\t.space %lu\n",
547 (unsigned long)*(size_t *)init->data);
548 } else {
549 x_fprintf(out, "\t.zero %lu\n",
550 (unsigned long)*(size_t *)init->data);
551 }
552 #if 0
553 x_fprintf(out, "\ttimes %lu db 0\n",
554 (unsigned long)*(size_t *)init->data);
555 #endif
556 startse = se;
557 /*
558 * 02/26/10: Skipping the struct members after
559 * this NULL initializer was wrong if there are
560 * further initialized members!
561 * We have to distinguish between initializers
562 * that were created to implicitly initialize
563 * the remainder of a struct;
564 *
565 * struct foo x = { 0 };
566 *
567 * ... and initializers that were created to
568 * be overwritten with variable initializiers
569 * at runtime;
570 *
571 * struct foo x = { func(), 123, 456 };
572 */
573 if (init->varinit == NULL) {
574 for (; se != NULL && se->next != NULL; se = se->next) {
575 ;
576 }
577 }
578 }
579 }
580
581 if (se != NULL) {
582 /* May need alignment */
583 struct decl *d = NULL;
584 struct type *ty = NULL;
585 size_t nbytes;
586
587 if (se->next != NULL) {
588 /* We may have to align for the next member */
589 if (se->next->dec->dtype->tbit != NULL) {
590 /* Don't align bitfields! */
591 ;
592 } else {
593 d = se->next->dec;
594 ty = d->dtype;
595 }
596 } else if (dec->dtype->tstruc->scope->slist->next) {
597 /*
598 * We've reached the end of the struct and
599 * may have to pad the struct, such that if
600 * we have an array of structs, every element
601 * is properly aligned.
602 *
603 * Note that we have to use the whole struct
604 * alignment, not just first member alignment
605 */
606 ty = dec->dtype;
607 if (init->type == INIT_NULL) {
608 /*
609 * 08/08/07: Now the alignment is
610 * hopefully done correctly for zero
611 * initializers. Previously we called
612 * calc_align_bytes() for the last
613 * member of a zero initializer, which
614 * was wrong
615 */
616 size_t curoff = startse->dec->offset +
617 *(size_t *)init->data;
618 size_t alignto = backend->get_align_type(ty);
619 size_t tmp = 0;
620
621 while ((curoff + tmp) % alignto) {
622 ++tmp;
623 }
624 if (tmp > 0) {
625 if (sysflag == OS_OSX) {
626 x_fprintf(out, "\t.space %lu\n",
627 (unsigned long)tmp);
628 } else {
629 x_fprintf(out, "\t.zero %lu\n",
630 (unsigned long)tmp);
631 }
632 }
633 } else {
634 d = dec->dtype->tstruc->scope->slist->dec;
635 }
636 }
637
638
639 if (d != NULL) {
640 unsigned long offset;
641
642
643 /*
644 * 10/08/08: Handle bitfields
645 */
646 if (se->dec->dtype->tbit != NULL) {
647 /*
648 * Align for next member. We are at
649 *
650 * address_of_storage_unit + size_of_storage_unit
651 *
652 * We only get here if the last bitfield in the
653 * current unit is processed, so we have to account
654 * for the entire partial storage unit.
655 *
656 * Note that we're setting the offset AFTER the current
657 * item because calc_align_bytes() doesn't do this for
658 * us
659 */
660 offset = se->dec->dtype->tbit->bitfield_storage_unit->offset
661 + backend->get_sizeof_type(se->dec->dtype->tbit->
662 bitfield_storage_unit->dtype, NULL);
663 } else {
664 offset = se->dec->offset;
665 }
666
667 nbytes = calc_align_bytes(/*se->dec->*/offset,
668 se->dec->dtype, ty, 1);
669 if (nbytes) {
670 if (sysflag == OS_OSX) {
671 x_fprintf(out, "\t.space %lu\n",
672 (unsigned long)nbytes);
673 } else {
674 x_fprintf(out, "\t.zero %lu\n",
675 (unsigned long)nbytes);
676 }
677 }
678 }
679 se = se->next;
680 }
681 }
682 }
683
684 static void
emit_static_init_vars(struct decl * list)685 emit_static_init_vars(struct decl *list) {
686 struct decl *d;
687 #if 0
688 struct decl **dv;
689 #endif
690 size_t size;
691 #if 0
692 int i;
693 #endif
694
695 if (list) {
696 emit_setsection(SECTION_INIT);
697 if (backend->arch == ARCH_AMD64) {
698 /* XXX */
699 x_fprintf(out, "\t.align 16\n");
700 }
701 }
702 for (d = list; d != NULL; d = d->next) {
703
704 /*
705 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
706 * will always be 0 since we output immediately. Maybe
707 * do this in gen_finish_output() instead?
708 */
709 if (d->dtype->storage == TOK_KEY_STATIC
710 && d->references == 0) {
711 continue;
712 }
713 if (d->invalid) {
714 continue;
715 }
716
717 /* Constant initializer expression */
718 size = backend->get_sizeof_decl(d, NULL);
719
720 if (sysflag != OS_OSX) {
721 x_fprintf(out, "\t.type %s, @object\n", d->dtype->name);
722 x_fprintf(out, "\t.size %s, %lu\n",
723 d->dtype->name, size);
724 x_fprintf(out, "%s:\n", d->dtype->name);
725 } else {
726 x_fprintf(out, "_%s:\n", d->dtype->name);
727 }
728 print_init_list(d, d->init);
729
730 if (d->next != NULL) {
731 unsigned long align;
732
733 align = calc_align_bytes(data_segment_offset,
734 d->dtype, d->next->dtype, 0);
735 if (align) {
736 if (sysflag == OS_OSX) {
737 x_fprintf(out, "\t.space %lu\n", align);
738 } else {
739 x_fprintf(out, "\t.zero %lu\n", align);
740 }
741 data_segment_offset += align;
742 }
743 }
744 data_segment_offset += size;
745 }
746 }
747
748 static void
emit_static_uninit_vars(struct decl * list)749 emit_static_uninit_vars(struct decl *list) {
750 struct decl *d;
751 size_t size;
752
753 if (list != NULL) {
754 if (!use_common_variables && sysflag != OS_OSX) {
755 emit_setsection(SECTION_UNINIT);
756 if (backend->arch == ARCH_AMD64) {
757 /* XXX */
758 x_fprintf(out, "\t.align 16\n");
759 }
760 }
761 if (sysflag == OS_OSX) {
762 }
763 for (d = list; d != NULL; d = d->next) {
764 if (d->dtype->storage == TOK_KEY_STATIC
765 && d->references == 0) {
766 continue;
767 }
768
769 if (d->invalid) {
770 continue;
771 }
772
773 size = backend->get_sizeof_decl(d, NULL);
774 #if 1 /* 02/03/08: No more common variables! */
775 /* 05/17/09: Enabled (for compatibility of course), but optionally */
776 /* 07/07/09: This was sadly done for static variables too, which should
777 * of course not be shared */
778 if (use_common_variables
779 && d->dtype->storage != TOK_KEY_STATIC
780 && sysflag != OS_OSX) {
781 x_fprintf(out, ".comm %s,%lu,4\n", /* XXX */
782 d->dtype->name, size);
783 continue;
784 }
785 #endif
786 if (sysflag != OS_OSX) {
787 x_fprintf(out, "\t.type %s, @object\n", d->dtype->name);
788 x_fprintf(out, "\t.size %s, %lu\n",
789 d->dtype->name, size);
790 }
791
792 if (sysflag == OS_OSX) {
793 /*
794 * 07/07/09: XXXXXXXXXXXXXXXXXXXX This should
795 * most likely not be common for static
796 * variables
797 */
798 x_fprintf(out, "\t.zerofill __DATA, __common, %s%s, %lu, 2\n",
799 IS_ASM_RENAMED(d->dtype->flags)? "": "_",
800 d->dtype->name, size);
801 } else {
802 x_fprintf(out, "%s:\n", d->dtype->name);
803 x_fprintf(out, "\t.space %lu\n", size);
804 }
805
806 if (d->next != NULL) {
807 unsigned long align;
808
809 align = calc_align_bytes(bss_segment_offset,
810 d->dtype, d->next->dtype, 0);
811 if (align) {
812 /* XXX wrong? */
813 x_fprintf(out, "\t.space %lu\n", align);
814 bss_segment_offset += align;
815 }
816 }
817 bss_segment_offset += size;
818 }
819 }
820 }
821
822 static void
emit_static_init_thread_vars(struct decl * list)823 emit_static_init_thread_vars(struct decl *list) {
824 struct decl *d;
825 size_t size;
826
827 if (list != NULL) {
828 emit_setsection(SECTION_INIT_THREAD);
829 if (backend->arch == ARCH_AMD64) {
830 /* XXX */
831 x_fprintf(out, "\t.align 16\n");
832 }
833 for (d = list; d != NULL; d = d->next) {
834 /*
835 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
836 * will always be 0 since we output immediately. Maybe
837 * do this in gen_finish_output() instead?
838 */
839 if (d->dtype->storage == TOK_KEY_STATIC
840 && d->references == 0) {
841 continue;
842 }
843 if (d->invalid) {
844 continue;
845 }
846
847 /* Constant initializer expression */
848 size = backend->get_sizeof_decl(d, NULL);
849 if (sysflag != OS_OSX) {
850 x_fprintf(out, "\t.type %s, @object\n", d->dtype->name);
851 x_fprintf(out, "\t.size %s, %lu\n",
852 d->dtype->name, size);
853 }
854 x_fprintf(out, "%s:\n", d->dtype->name);
855 print_init_list(d, d->init);
856
857 if (d->next != NULL) {
858 unsigned long align;
859
860 align = calc_align_bytes(data_thread_segment_offset,
861 d->dtype, d->next->dtype, 0);
862 if (align) {
863 if (sysflag == OS_OSX) {
864 x_fprintf(out, "\t.space %lu\n", align);
865 } else {
866 x_fprintf(out, "\t.zero %lu\n", align);
867 }
868 data_thread_segment_offset += align;
869 }
870 }
871 data_thread_segment_offset += size;
872 }
873 }
874 }
875
876 static void
emit_static_uninit_thread_vars(struct decl * list)877 emit_static_uninit_thread_vars(struct decl *list) {
878 struct decl *d;
879 size_t size;
880
881 if (list != NULL) {
882 emit_setsection(SECTION_UNINIT_THREAD);
883 if (backend->arch == ARCH_AMD64) {
884 /* XXX */
885 x_fprintf(out, "\t.align 16\n");
886 }
887 for (d = list; d != NULL; d = d->next) {
888 if (d->dtype->storage == TOK_KEY_STATIC
889 && d->references == 0) {
890 continue;
891 }
892 if (d->invalid) {
893 continue;
894 }
895
896 size = backend->get_sizeof_decl(d, NULL);
897 if (sysflag != OS_OSX) {
898 x_fprintf(out, "\t.type %s, @object\n", d->dtype->name);
899 x_fprintf(out, "\t.size %s, %lu\n", d->dtype->name, size);
900 }
901 x_fprintf(out, "%s:\n", d->dtype->name);
902 x_fprintf(out, "\t.space %lu\n", size);
903 if (d->next != NULL) {
904 unsigned long align;
905
906 align = calc_align_bytes(bss_thread_segment_offset,
907 d->dtype, d->next->dtype, 0);
908 if (align) {
909 /* XXX wrong? */
910 x_fprintf(out, "\t.space %lu\n", align);
911 bss_thread_segment_offset += align;
912 }
913 }
914 bss_thread_segment_offset += size;
915 }
916 }
917 }
918
919
920
921 static void
emit_finish_program(void)922 emit_finish_program(void) {
923 if (sysflag == OS_OSX) {
924 int i;
925
926 /*
927 * First generate function call references
928 */
929 x_fprintf(out, ".section __IMPORT,__jump_table,symbol_stubs,"
930 "self_modifying_code+pure_instructions,5\n");
931 for (i = 0; i < FCALL_HTAB_SIZE; ++i) {
932 struct osx_fcall *c;
933
934 for (c = fcall_htab[i]; c != NULL; c = c->next) {
935 if (c->nonlazy) {
936 /* Not a call */
937 continue;
938 }
939 x_fprintf(out, "L_%s$stub:\n",
940 c->name);
941 x_fprintf(out, "\t.indirect_symbol %s%s\n",
942 c->renamed? "": "_",
943 c->name);
944 x_fprintf(out, "\thlt ; hlt ; hlt ; hlt ; hlt\n");
945 }
946 }
947
948 /*
949 * Then generate nonlazy function pointer references
950 */
951 x_fprintf(out, ".section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
952 for (i = 0; i < FCALL_HTAB_SIZE; ++i) {
953 struct osx_fcall *c;
954
955 for (c = fcall_htab[i]; c != NULL; c = c->next) {
956 if (!c->nonlazy) {
957 /* Lazy reference */
958 continue;
959 }
960 if (c->dec && c->dec->dtype->is_def) {
961 /*
962 * Symbol has a definition, so we must declare
963 * the indirect pointer in the data section
964 */
965 continue;
966 }
967 if (c->dec && c->dec->dtype->storage == TOK_KEY_STATIC) {
968 /*
969 * May be local variable - don't declare as
970 * indirect
971 */
972 continue;
973 }
974 x_fprintf(out, "L_%s$non_lazy_ptr:\n",
975 c->name);
976 x_fprintf(out, "\t.indirect_symbol %s%s\n",
977 c->renamed? "": "_",
978 c->name);
979 x_fprintf(out, "\t.long 0\n");
980 }
981 }
982
983 /*
984 * Generate references to variables and function which are
985 * locally defined. Those OF COURSE don't work with
986 * indirect_symbol.
987 */
988 x_fprintf(out, ".data\n");
989 x_fprintf(out, ".align 2\n");
990 for (i = 0; i < FCALL_HTAB_SIZE; ++i) {
991 struct osx_fcall *c;
992
993 for (c = fcall_htab[i]; c != NULL; c = c->next) {
994 if ((c->dec == NULL || !c->dec->dtype->is_def)
995 && (c->dec == NULL || c->dec->dtype->storage != TOK_KEY_STATIC)) {
996 /*
997 * We only want to output symbols with a
998 * local definition
999 */
1000 continue;
1001 }
1002 x_fprintf(out, "L_%s$non_lazy_ptr:\n",
1003 c->name);
1004 x_fprintf(out, "\t.long %s%s\n",
1005 c->renamed? "": "_",
1006 c->name);
1007 }
1008 }
1009 }
1010 }
1011
1012
1013 static void
emit_stupidtrace(struct stupidtrace_entry * ent)1014 emit_stupidtrace(struct stupidtrace_entry *ent) {
1015 static unsigned long count;
1016
1017 x_fprintf(out, "\tpush $_Envstr0\n");
1018 x_fprintf(out, "\tcall getenv\n");
1019 x_fprintf(out, "\tadd $4, %%esp\n");
1020 x_fprintf(out, "\tcmp $0, %%eax\n");
1021 x_fprintf(out, "\tje _Strace_label%lu\n", ++count);
1022 x_fprintf(out, "\tpush $%s\n", ent->bufname);
1023 x_fprintf(out, "\tcall puts\n");
1024 x_fprintf(out, "\tadd $4, %%esp\n");
1025 x_fprintf(out, "_Strace_label%lu:\n", count);
1026 }
1027
1028
1029 static void
emit_finish_stupidtrace(struct stupidtrace_entry * ent)1030 emit_finish_stupidtrace(struct stupidtrace_entry *ent) {
1031 static int init;
1032
1033 emit_setsection(SECTION_TEXT);
1034 if (!init) {
1035 x_fprintf(out, "_Envstr0:\n\t.asciz \"NWCC_STUPIDTRACE\"\n");
1036 init = 1;
1037 }
1038 x_fprintf(out, "%s:\n\t.asciz \"--- (trace) --- %s\"\n", ent->bufname, ent->func->proto->dtype->name);
1039 }
1040
1041
1042
1043 void
do_attribute_alias(struct decl * dec)1044 do_attribute_alias(struct decl *dec) {
1045 struct attrib *a;
1046
1047 if ((a = lookup_attr(dec->dtype->attributes, ATTRF_ALIAS)) != NULL) {
1048 x_fprintf(out, ".set %s, %s\n", dec->dtype->name, a->parg);
1049 }
1050 }
1051
1052 static void
emit_extern_decls(void)1053 emit_extern_decls(void) {
1054
1055 /*
1056 * 05/17/09: For attribute alias: Any non-static alias declaration
1057 * introduces a new GLOBAL declaration and an alias setting for
1058 * another symbol
1059 *
1060 * void foo() __attribute__("bar");
1061 */
1062 if (used_attribute_alias) {
1063 struct sym_entry *se;
1064
1065 for (se = extern_vars; se != NULL; se = se->next) {
1066 struct attrib *a;
1067
1068 if (se->dec->invalid) {
1069 continue;
1070 }
1071 if (se->dec->has_symbol
1072 || se->dec->dtype->is_def
1073 || se->dec->has_def) {
1074 continue;
1075 }
1076 a = lookup_attr(se->dec->dtype->attributes, ATTRF_ALIAS);
1077 if (a != NULL) {
1078 x_fprintf(out, "\t.global %s\n",
1079 se->dec->dtype->name);
1080 x_fprintf(out, "\t.set %s, %s\n",
1081 se->dec->dtype->name, a->parg);
1082 }
1083 }
1084 }
1085 }
1086
1087 static void
1088 #if 0
1089 emit_extern_decls(void) {
1090 #endif
emit_global_extern_decls(struct decl ** d,int ndecls)1091 emit_global_extern_decls(struct decl **d, int ndecls) {
1092 int i;
1093
1094 /* Generate external references */
1095 if (ndecls > 0) {
1096 for (i = 0; i < ndecls; ++i) {
1097 if (d[i]->references == 0
1098 && (!d[i]->dtype->is_func
1099 || !d[i]->dtype->is_def)) {
1100 /* Unneeded declaration */
1101 continue;
1102 }
1103 if (d[i]->invalid) {
1104 continue;
1105 }
1106
1107 if (d[i]->has_def) {
1108 /*
1109 * extern declaration overriden by later
1110 * definition
1111 */
1112 continue;
1113 }
1114
1115 if (d[i]->dtype->is_func
1116 && d[i]->dtype->is_def) {
1117 d[i]->has_symbol = 1;
1118 /* XXX hm what about extern/static inline? */
1119 if (!IS_INLINE(d[i]->dtype->flags)) {
1120 if (sysflag == OS_OSX) {
1121 x_fprintf(out, ".globl %s%s\n",
1122 IS_ASM_RENAMED(d[i]->dtype->flags)? "": "_",
1123 d[i]->dtype->name,
1124 d[i]);
1125 } else {
1126 x_fprintf(out, ".globl %s\n",
1127 d[i]->dtype->name,
1128 d[i]);
1129 do_attribute_alias(d[i]);
1130 }
1131 }
1132 }
1133 }
1134 }
1135 }
1136
1137 static void
emit_global_static_decls(struct decl ** dv,int ndecls)1138 emit_global_static_decls(struct decl **dv, int ndecls) {
1139 int i;
1140
1141 for (i = 0; i < ndecls; ++i) {
1142 if (dv[i]->dtype->storage != TOK_KEY_STATIC) {
1143 struct type_node *tn = NULL;
1144
1145 if (dv[i]->invalid) {
1146 continue;
1147 }
1148 if (dv[i]->dtype->is_func) {
1149 for (tn = dv[i]->dtype->tlist;
1150 tn != NULL;
1151 tn = tn->next) {
1152 if (tn->type == TN_FUNCTION) {
1153 if (tn->ptrarg) {
1154 continue;
1155 } else {
1156 break;
1157 }
1158 }
1159 }
1160 }
1161
1162 if (tn != NULL) {
1163 tn->ptrarg = 1;
1164 }
1165 if (dv[i]->has_symbol) continue;
1166 if (sysflag == OS_OSX) {
1167 x_fprintf(out, ".globl %s%s\n",
1168 IS_ASM_RENAMED(dv[i]->dtype->flags)? "": "_",
1169 dv[i]->dtype->name);
1170 } else {
1171 x_fprintf(out, ".globl %s\n",
1172 dv[i]->dtype->name);
1173 do_attribute_alias(dv[i]);
1174 }
1175 dv[i]->has_symbol = 1;
1176 }
1177 }
1178 }
1179
1180 static void
emit_struct_inits(struct init_with_name * list)1181 emit_struct_inits(struct init_with_name *list) {
1182 struct init_with_name *in;
1183
1184 if (list != NULL) {
1185 emit_setsection(SECTION_INIT);
1186 for (in = list; in != NULL; in = in->next) {
1187 x_fprintf(out, ".%s:\n", in->name);
1188 print_init_list(in->dec, in->init);
1189 }
1190 }
1191 }
1192
1193 static void
emit_fp_constants(struct ty_float * list)1194 emit_fp_constants(struct ty_float *list) {
1195 if (list != NULL) {
1196 struct ty_float *tf;
1197
1198 emit_setsection(SECTION_INIT);
1199 for (tf = list; tf != NULL; tf = tf->next) {
1200 /* XXX cross-compilation */
1201 /* XXX VERY mips-like */
1202 int size = 0;
1203
1204 switch (tf->num->type) {
1205 case TY_FLOAT:
1206 x_fprintf(out, "\t.align 4\n");
1207 size = 4;
1208 break;
1209 case TY_DOUBLE:
1210 case TY_LDOUBLE:
1211 x_fprintf(out, "\t.align 8\n");
1212 if (tf->num->type == TY_DOUBLE) {
1213 size = 8;
1214 } else {
1215 size = 10;
1216 }
1217 }
1218
1219 if (sysflag != OS_OSX) {
1220 x_fprintf(out, "\t.type _Float%lu, @object\n", tf->count);
1221 x_fprintf(out, "\t.size _Float%lu, %d\n", tf->count, size);
1222 }
1223 x_fprintf(out, "_Float%lu:\n", tf->count);
1224
1225 switch (tf->num->type) {
1226 case TY_FLOAT:
1227 x_fprintf(out, "\t.long ");
1228 cross_print_value_by_type(out,
1229 tf->num->value, TY_UINT, 'x');
1230 break;
1231 case TY_DOUBLE:
1232 x_fprintf(out, "\t.long ");
1233 cross_print_value_chunk(out,
1234 tf->num->value,
1235 TY_DOUBLE, TY_UINT, 0, 0);
1236 x_fprintf(out, "\n\t.long ");
1237 cross_print_value_chunk(out,
1238 tf->num->value,
1239 TY_DOUBLE, TY_UINT, 0, 1);
1240 break;
1241 case TY_LDOUBLE:
1242 x_fprintf(out, "\t.long ");
1243 cross_print_value_chunk(out,
1244 tf->num->value,
1245 TY_DOUBLE, TY_UINT, 0, 0);
1246 x_fprintf(out, "\n\t.long ");
1247 cross_print_value_chunk(out,
1248 tf->num->value,
1249 TY_DOUBLE, TY_UINT, 0, 1);
1250 x_fprintf(out, "\n\t.word ");
1251 cross_print_value_chunk(out,
1252 tf->num->value,
1253 TY_DOUBLE, TY_UINT, TY_USHORT, 2);
1254 break;
1255 default:
1256 printf("bad floating point constant - "
1257 "code %d\n", tf->num->type);
1258 abort();
1259 }
1260 x_fputc('\n', out);
1261 }
1262 }
1263 }
1264
1265 static void
emit_support_buffers(void)1266 emit_support_buffers(void) {
1267 static int have_fbuf = 0;
1268 static int have_x87cw = 0;
1269
1270 if (/*float_const != NULL
1271 ||*/ (x87cw_old.var_backed != NULL
1272 #if ! REMOVE_FLOATBUF
1273 || floatbuf.var_backed != NULL
1274 #endif
1275 )
1276 && (!have_fbuf || !have_x87cw)) {
1277 emit_setsection(SECTION_INIT);
1278
1279 #if ! REMOVE_FLOATBUF
1280 if (floatbuf.var_backed != NULL && !have_fbuf) {
1281 x_fprintf(out, "\t.align 8\n");
1282 x_fprintf(out, "%s:\n\t.long 0x0\n\t.long 0x0\n",
1283 floatbuf.type->name);
1284 have_fbuf = 1;
1285 }
1286 #endif
1287
1288 if (x87cw_old.var_backed != NULL && !have_x87cw) {
1289 x_fprintf(out, "\t%s:\n\t.word 0x0\n", x87cw_old.type->name);
1290 x_fprintf(out, "\t%s:\n\t.word 0x0\n", x87cw_new.type->name);
1291 have_x87cw = 1;
1292 }
1293 }
1294 if (amd64_need_negmask) {
1295 x86_emit_gas.setsection(SECTION_INIT);
1296 x_fprintf(out, "\t.align 8\n"); /* XXX 16 too large - is 8 right?! */
1297 if (amd64_need_negmask & 1) {
1298 x_fprintf(out, "_SSE_Negmask:\n");
1299 x_fprintf(out, "\t.long 0x80000000\n");
1300 x_fprintf(out, "\t.align 8\n"); /* XXX 16 too large - is 8 right?! */
1301 }
1302 if (amd64_need_negmask & 2) {
1303 x_fprintf(out, "_SSE_Negmask_double:\n");
1304 x_fprintf(out, "\t.long 0x00000000\n");
1305 x_fprintf(out, "\t.long 0x80000000\n");
1306 }
1307 }
1308
1309 if (amd64_need_ulong_float_mask) {
1310 x86_emit_gas.setsection(SECTION_INIT);
1311 x_fprintf(out, "_Ulong_float_mask:\n");
1312 x_fprintf(out, "\t.long 1602224128\n");
1313 }
1314 }
1315
1316 static void
emit_strings(struct ty_string * list)1317 emit_strings(struct ty_string *list) {
1318 if (list != NULL) {
1319 struct ty_string *str;
1320
1321 emit_setsection(SECTION_RODATA);
1322 for (str = list; str != NULL; str = str->next) {
1323 x_fprintf(out, "._Str%lu:\n", str->count);
1324 as_print_string_init(out, str->size, str);
1325 }
1326 }
1327
1328 #if 0
1329 if (unimpl_instr) {
1330 x_fprintf(out,"\t_Unimpl_msg db 'ERROR: Use of unimplemented'\n"
1331 "\t db 'compiler feature (probably)'\n"
1332 "\t db 'floating point - check %d\n'\n");
1333 }
1334 #endif
1335 }
1336
1337 static void
emit_comment(const char * fmt,...)1338 emit_comment(const char *fmt, ...) {
1339 int rc;
1340 va_list va;
1341
1342 va_start(va, fmt);
1343 x_fprintf(out, "# ");
1344 rc = vfprintf(out, fmt, va);
1345 va_end(va);
1346 x_fputc('\n', out);
1347
1348 if (rc == EOF || fflush(out) == EOF) {
1349 perror("vfprintf");
1350 exit(EXIT_FAILURE);
1351 }
1352 }
1353
1354 static void
emit_dwarf2_line(struct token * tok)1355 emit_dwarf2_line(struct token *tok) {
1356 (void) tok;
1357 unimpl();
1358 #if 0
1359 x_fprintf(out, "\t[loc %d %d 0]\n",
1360 tok->fileid, tok->line);
1361 #endif
1362 }
1363
1364 static void
emit_dwarf2_files(void)1365 emit_dwarf2_files(void) {
1366 struct dwarf_in_file *inf;
1367
1368 x_fprintf(out, "[file \"%s\"]\n",
1369 input_file);
1370
1371 for (inf = dwarf_files; inf != NULL; inf = inf->next) {
1372 x_fprintf(out, "[file %d \"%s\"]\n",
1373 inf->id, inf->name);
1374 }
1375 }
1376
1377 static void
emit_inlineasm(struct inline_asm_stmt * stmt)1378 emit_inlineasm(struct inline_asm_stmt *stmt) {
1379 x_fprintf(out, "#APP\n");
1380 /*
1381 * There may be an empty body for statements where only the side
1382 * effect is desired;
1383 * __asm__("" ::: "memory");
1384 */
1385 if (stmt->code != NULL) {
1386 inline_instr_to_gas(out, stmt->code);
1387 }
1388 x_fprintf(out, "#NO_APP\n");
1389 }
1390
1391 static void
emit_unimpl(void)1392 emit_unimpl(void) {
1393 static int n;
1394
1395 x_fprintf(out, "\tpush dword _Unimpl_msg\n");
1396 x_fprintf(out, "\tpush dword %d\n", n++);
1397 x_fprintf(out, "\tcall printf\n");
1398 x_fprintf(out, "\taddl $8, %%esp\n");
1399 x_fprintf(out, "\tpush dword 1\n");
1400 x_fprintf(out, "\tcall exit\n");
1401 }
1402
1403 static void
emit_empty(void)1404 emit_empty(void) {
1405 x_fputc('\n', out);
1406 }
1407
1408 static void
emit_label(const char * name,int is_func)1409 emit_label(const char *name, int is_func) {
1410 if (is_func) {
1411 if (sysflag == OS_OSX) {
1412 /* XXX This @#^%*&#$&$ stuff does not work for asm-renamed symbols */
1413 x_fprintf(out, "_%s:\n", name);
1414 } else {
1415 x_fprintf(out, "%s:\n", name);
1416 }
1417 } else {
1418 x_fprintf(out, ".%s:\n", name);
1419 }
1420 }
1421
1422 static void
emit_call(const char * name)1423 emit_call(const char *name) {
1424 if (sysflag == OS_OSX) {
1425 if (backend->arch == ARCH_X86) {
1426 x_fprintf(out, "\tcall L_%s$stub\n", name);
1427 add_osx_fcall(name, NULL, 0);
1428 } else {
1429 x_fprintf(out, "\tcall %s%s\n",
1430 osx_call_renamed? "": "_", name);
1431 }
1432 return;
1433 }
1434 if (picflag) {
1435 if (backend->arch == ARCH_AMD64) {
1436 x_fprintf(out, "\tcall %s@PLT\n", name);
1437 } else {
1438 x_fprintf(out, "\tcall %s@PLT\n", name);
1439 }
1440 } else {
1441 x_fprintf(out, "\tcall %s\n", name);
1442 }
1443 }
1444
1445 static void
emit_callindir(struct reg * r)1446 emit_callindir(struct reg *r) {
1447 x_fprintf(out, "\tcall *%%%s\n", r->name);
1448 }
1449
1450 static void
emit_func_header(struct function * f)1451 emit_func_header(struct function *f) {
1452 if (sysflag != OS_OSX) {
1453 x_fprintf(out, "\t.type %s, @function\n", f->proto->dtype->name);
1454 }
1455 }
1456
1457 static void
emit_func_intro(struct function * f)1458 emit_func_intro(struct function *f) {
1459 (void) f;
1460 x_fprintf(out, "\tpushl %%ebp\n"); /* XXX */
1461 x_fprintf(out, "\tmov %%esp, %%ebp\n");
1462 }
1463
1464 static void
emit_func_outro(struct function * f)1465 emit_func_outro(struct function *f) {
1466 char *name = f->proto->dtype->name;
1467
1468 /* x_fprintf(out, "\tret\n");*/
1469 /* 02/03/08: Add size for PIC code */
1470 if (sysflag != OS_OSX) {
1471 x_fprintf(out, "\t.size %s, .-%s\n", name, name);
1472 }
1473 }
1474
1475
1476 static void
emit_push(struct function * f,struct icode_instr * ii)1477 emit_push(struct function *f, struct icode_instr *ii) {
1478 struct vreg *vr = ii->src_vreg;
1479 struct reg *r = ii->src_pregs?
1480 (void *)ii->src_pregs[0]: (void *)NULL;
1481
1482 (void) f;
1483
1484 if (ii->src_pregs) {
1485 if (ii->src_vreg->is_multi_reg_obj) {
1486 x_fprintf(out, "\tpushl %%%s\n",
1487 ii->src_pregs[1]->name);
1488 f->total_allocated += 4;
1489 }
1490 x_fprintf(out, "\tpushl %%%s\n", /*ascii_type*/ r->name);
1491 } else if (vr->var_backed) {
1492 struct decl *d = vr->var_backed;
1493
1494 if (vr->parent != NULL) {
1495 /* Structure or union member */
1496 struct decl *d2/* = d*/;
1497 struct vreg *vr2;
1498
1499 vr2 = get_parent_struct(vr);
1500 d2 = vr2->var_backed;
1501 if (vr2->from_ptr) {
1502 /* XXX hmm this is nonsense?!!?? */
1503 x_fprintf(out, "\tpushl [%%%s",
1504 vr2->from_ptr->pregs[0]->name);
1505 if (vr->parent->type->code == TY_STRUCT) {
1506 x_fprintf(out, " + %s.%s",
1507 vr2->from_ptr->type->tstruc->tag,
1508 d2->dtype->name);
1509 }
1510 x_fprintf(out, "]\n");
1511 } else if (d2 && d2->stack_addr != NULL) {
1512 x_fprintf(out, "\tpushl -%ld(%%ebp",
1513 d2->stack_addr->offset);
1514 if (vr->parent->type->code == TY_STRUCT) {
1515 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
1516 x_fprintf(out, " + %lu",
1517 calc_offsets(vr));
1518 }
1519 x_fprintf(out, ")\n");
1520 } else if (d2 != NULL) {
1521 /* Must be static */
1522 x_fprintf(out, "\tpushl [%s",
1523 d2->dtype->name);
1524 if (vr->parent->type->code == TY_STRUCT) {
1525 x_fprintf(out, " + %lu",
1526 calc_offsets(vr));
1527 }
1528 x_fprintf(out, "]\n");
1529 } else {
1530 unimpl();
1531 }
1532 } else {
1533 if (d->stack_addr != NULL) {
1534 /* Stack */
1535 x_fprintf(out, "\tpushl -%ld(%%ebp)\n",
1536 /*ascii_type*/ d->stack_addr->offset);
1537 } else {
1538 /* Static or register variable */
1539 if (d->dtype->storage == TOK_KEY_REGISTER) {
1540 unimpl();
1541 } else {
1542 x_fprintf(out, "\tpushl [%s]\n",
1543 /*ascii_type*/ d->dtype->name);
1544 }
1545 }
1546 }
1547 } else if (vr->from_const) {
1548 struct token *t = vr->from_const;
1549
1550 if (t->type == TOK_STRING_LITERAL) {
1551 struct ty_string *s = t->data;
1552 x_fprintf(out, "\tpushl $._Str%lu\n", s->count);
1553 } else if (IS_INT(t->type) || IS_LONG(t->type)) {
1554 /*
1555 * There are only forms of ``int'' and ``long''
1556 * constants
1557 */
1558 x_fprintf(out, "\tpushl $");
1559 cross_print_value_by_type(out, t->data, t->type, 0);
1560 x_fputc('\n', out);
1561 } else if (IS_LLONG(t->type)) {
1562 unimpl();
1563 } else {
1564 puts("BUG in NASM emit_push()");
1565 exit(EXIT_FAILURE);
1566 }
1567 } else if (vr->from_ptr) {
1568 x_fprintf(out, "\tpushl [%%%s]\n", /*ascii_type,*/
1569 vr->from_ptr->pregs[0]->name);
1570 } else {
1571 unimpl();
1572 }
1573
1574 f->total_allocated += 4;
1575 }
1576
1577 static void
emit_allocstack(struct function * f,size_t nbytes)1578 emit_allocstack(struct function *f, size_t nbytes) {
1579 (void) f;
1580 x_fprintf(out, "\tsubl $%lu, %%esp\n", (unsigned long)nbytes);
1581 }
1582
1583
1584 static void
emit_freestack(struct function * f,size_t * nbytes)1585 emit_freestack(struct function *f, size_t *nbytes) {
1586 if (nbytes == NULL) {
1587 /* Procedure outro */
1588 if (f->total_allocated != 0) {
1589 x_fprintf(out, "\taddl $%lu, %%esp\n",
1590 (unsigned long)f->total_allocated);
1591 }
1592 x_fprintf(out, "\tpop %%ebp\n");
1593 } else {
1594 if (*nbytes != 0) {
1595 x_fprintf(out, "\taddl $%lu, %%esp\n",
1596 (unsigned long)*nbytes);
1597 f->total_allocated -= *nbytes;
1598 }
1599 }
1600 }
1601
1602 static void
emit_adj_allocated(struct function * f,int * nbytes)1603 emit_adj_allocated(struct function *f, int *nbytes) {
1604 f->total_allocated += *nbytes;
1605 }
1606
1607 static int cursect = 0;
1608
1609 static void
emit_setsection(int value)1610 emit_setsection(int value) {
1611 char *p = NULL;
1612
1613 if (cursect == value) {
1614 return;
1615 }
1616 if (sysflag == OS_OSX) {
1617 p = generic_mach_o_section_name(value);
1618 } else {
1619 p = generic_elf_section_name(value);
1620 }
1621
1622 if (p != NULL) {
1623 if (sysflag == OS_OSX) {
1624 x_fprintf(out, ".%s\n", p);
1625 } else {
1626 x_fprintf(out, ".section .%s\n", p);
1627 }
1628 }
1629 cursect = value;
1630 }
1631
1632 static void
emit_alloc(size_t nbytes)1633 emit_alloc(size_t nbytes) {
1634 unimpl();
1635 (void) nbytes;
1636 if (cursect == SECTION_INIT) {
1637 } else if (cursect == SECTION_UNINIT) {
1638 } else if (cursect == SECTION_STACK) {
1639 } else if (cursect == SECTION_TEXT) {
1640 }
1641 }
1642
1643
1644 static void
print_mem_or_reg(struct reg * r,struct vreg * vr)1645 print_mem_or_reg(struct reg *r, struct vreg *vr) {
1646 if (vr->on_var) {
1647 struct decl *d = vr->var_backed;
1648
1649 if (d->stack_addr) {
1650 x_fprintf(out, "-%ld(%%ebp)",
1651 d->stack_addr->offset);
1652 } else {
1653 x_fprintf(out, "%s", d->dtype->name);
1654 }
1655 } else if (r != NULL) {
1656 x_fprintf(out, "%%%s", r->name);
1657 } else if (vr->from_const) {
1658 if (backend->arch == ARCH_AMD64) {
1659 amd64_print_mem_operand_gas(vr, NULL);
1660 } else {
1661 print_mem_operand(vr, NULL);
1662 }
1663 } else {
1664 unimpl();
1665 }
1666 }
1667
1668
1669
1670 static void
emit_inc(struct icode_instr * ii)1671 emit_inc(struct icode_instr *ii) {
1672 x_fprintf(out, "\tinc ");
1673 print_mem_or_reg(ii->src_pregs[0], ii->src_vreg);
1674 x_fputc('\n', out);
1675 }
1676
1677 static void
emit_dec(struct icode_instr * ii)1678 emit_dec(struct icode_instr *ii) {
1679 x_fprintf(out, "\tdec ");
1680 print_mem_or_reg(ii->src_pregs[0], ii->src_vreg);
1681 x_fputc('\n', out);
1682 }
1683
1684 static void
emit_load(struct reg * r,struct vreg * vr)1685 emit_load(struct reg *r, struct vreg *vr) {
1686 char *p;
1687
1688 if (r->type == REG_FPR) {
1689 if (STUPID_X87(r)) {
1690 if (!IS_FLOATING(vr->type->code)) {
1691 #if ! REMOVE_FLOATBUF
1692 p = "fild";
1693 #else
1694 buggypath();
1695 #endif
1696 } else {
1697 p = "fld";
1698 }
1699 x_fprintf(out, "\t%s%c ",
1700 p, size_to_gaspostfix(vr->size, vr->type));
1701 } else {
1702 /* SSE */
1703 if (!IS_FLOATING(vr->type->code)) {
1704 p = "cvtsi2ss";
1705 } else {
1706 if (vr->type->code == TY_FLOAT) {
1707 p = "movss";
1708 } else {
1709 /* Must be double */
1710 p = "movsd";
1711 }
1712 }
1713 x_fprintf(out, "\t%s ", p);
1714 }
1715 } else {
1716 if (vr->stack_addr != NULL) {
1717 p = "mov";
1718 } else if (vr->type
1719 && vr->type->tlist != NULL
1720 && (vr->type->tlist->type == TN_ARRAY_OF
1721 || vr->type->tlist->type == TN_VARARRAY_OF)) {
1722 if (vr->from_const == NULL) {
1723 p = "lea";
1724 } else {
1725 p = "mov";
1726 }
1727 } else {
1728 if (r->size == vr->size
1729 || vr->size == 8) {
1730 /* == 8 for long long, SA for anonymous */
1731 p = "mov";
1732 } else {
1733 if (vr->type == NULL
1734 || vr->type->sign == TOK_KEY_UNSIGNED) {
1735 p = "movzx";
1736 } else {
1737 p = "movsx";
1738 }
1739 }
1740 }
1741 /*_fprintf(out, "\t%s %%%s, ", p, r->name);*/
1742 x_fprintf(out, "\t%s ", p);
1743 }
1744
1745 if (backend->arch == ARCH_AMD64) {
1746 amd64_print_mem_operand_gas(vr, NULL);
1747 } else {
1748 print_mem_operand(vr, NULL);
1749 }
1750 if (r->type != REG_FPR || !STUPID_X87(r)) {
1751 x_fprintf(out, ", %%%s", r->name);
1752 }
1753
1754 x_fputc('\n', out);
1755 }
1756
1757 static void
emit_load_addrlabel(struct reg * r,struct icode_instr * label)1758 emit_load_addrlabel(struct reg *r, struct icode_instr *label) {
1759 x_fprintf(out, "\tlea .%s, %%%s\n", label->dat, r->name);
1760 }
1761
1762 static void
emit_comp_goto(struct reg * r)1763 emit_comp_goto(struct reg *r) {
1764 x_fprintf(out, "\tjmp *%%%s\n", r->name);
1765 }
1766
1767
1768 /*
1769 * Takes vreg source arg - not preg - so that it can be either a preg
1770 * or immediate (where that makes sense!)
1771 */
1772 static void
emit_store(struct vreg * dest,struct vreg * src)1773 emit_store(struct vreg *dest, struct vreg *src) {
1774 char *p = NULL;
1775 int floating = 0;
1776 int post = 0;
1777 static int was_llong;
1778
1779 if (dest->size) {
1780 post = size_to_gaspostfix(dest->size,
1781 dest->type);
1782 }
1783 if (src->pregs[0] && src->pregs[0]->type == REG_FPR) {
1784 if (STUPID_X87(src->pregs[0])) {
1785 if (!IS_FLOATING(dest->type->code)) {
1786 #if ! REMOVE_FLOATBUF
1787 p = "fistp";
1788 #else
1789 buggypath();
1790 #endif
1791 } else {
1792 p = "fstp";
1793 }
1794 floating = 1;
1795 } else {
1796 if (!IS_FLOATING(dest->type->code)) {
1797 unimpl();
1798 } else {
1799 if (dest->type->code == TY_FLOAT) {
1800 p = "movss";
1801 } else {
1802 p = "movsd";
1803 }
1804 }
1805 post = 0;
1806 floating = 0; /* because SSE is non-x87-like */
1807 }
1808 } else {
1809 if (dest->stack_addr != NULL || dest->from_const != NULL) {
1810 p = "mov";
1811 } else {
1812 p = "mov";
1813 }
1814 }
1815
1816 if (post) {
1817 x_fprintf(out, "\t%s%c ", p, post);
1818 } else {
1819 x_fprintf(out, "\t%s ", p);
1820 }
1821 if (floating) {
1822 /* Already done - floating stores only ever come from st0 */
1823 print_mem_operand(dest, NULL);
1824 x_fputc('\n', out);
1825 return;
1826 }
1827 if (src->from_const) {
1828 print_mem_operand(src, NULL);
1829 } else {
1830 /* Must be register */
1831 if (was_llong) {
1832 x_fprintf(out, "%%%s, ", src->pregs[1]->name);
1833 was_llong = 0;
1834 } else {
1835 x_fprintf(out, "%%%s, ", src->pregs[0]->name);
1836 if (src->is_multi_reg_obj) {
1837 was_llong = 1;
1838 }
1839 }
1840 }
1841 print_mem_operand(dest, NULL);
1842 x_fputc('\n', out);
1843 }
1844
1845
1846 static void
emit_neg(struct reg ** dest,struct icode_instr * src)1847 emit_neg(struct reg **dest, struct icode_instr *src) {
1848 (void) src;
1849 if (dest[0]->type == REG_FPR) {
1850 /* fchs only works with TOS! */
1851 x_fprintf(out, "\tfchs\n");
1852 } else {
1853 x_fprintf(out, "\tneg %%%s\n", dest[0]->name);
1854 if (src->src_vreg->is_multi_reg_obj) {
1855 x_fprintf(out, "\tadc $0, %%%s\n", dest[1]->name);
1856 x_fprintf(out, "\tneg %%%s\n", dest[1]->name);
1857 }
1858 }
1859 }
1860
1861
1862 static void
emit_sub(struct reg ** dest,struct icode_instr * src)1863 emit_sub(struct reg **dest, struct icode_instr *src) {
1864 if (dest[0]->type == REG_FPR) {
1865 if (STUPID_X87(dest[0])) {
1866 /*
1867 * 05/27/08: fsubrp instead of fsubp because the order
1868 * was reversed... We used to use fsubp in the nasm
1869 * emitter but that one generated fsubrp instead
1870 * automatically! XXX why?
1871 */
1872 x_fprintf(out, "\tfsubrp ");
1873 } else {
1874 x_fprintf(out, "\tsubs%c ",
1875 src->src_vreg->type->code == TY_FLOAT? 's': 'd');
1876 }
1877 } else {
1878 x_fprintf(out, "\tsub%c ",
1879 size_to_gaspostfix(dest[0]->size,
1880 src->dest_vreg->type));
1881 }
1882 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
1883
1884 x_fprintf(out, ", %%%s", dest[0]->name);
1885 x_fputc('\n', out);
1886 if (src->src_vreg->is_multi_reg_obj
1887 && src->dest_vreg->is_multi_reg_obj) { /* for ptr arit */
1888 /* long long */
1889 x_fprintf(out, "\n\tsbb %%%s, %%%s\n",
1890 src->src_pregs[1]->name, dest[1]->name);
1891 }
1892 }
1893
1894 static void
emit_add(struct reg ** dest,struct icode_instr * src)1895 emit_add(struct reg **dest, struct icode_instr *src) {
1896 if (dest[0]->type == REG_FPR) {
1897 if (STUPID_X87(dest[0])) {
1898 x_fprintf(out, "\tfaddp ");
1899 } else {
1900 x_fprintf(out, "\tadds%c ",
1901 src->src_vreg->type->code == TY_FLOAT? 's': 'd');
1902 }
1903 } else {
1904 x_fprintf(out, "\tadd ");
1905 }
1906 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
1907 x_fprintf(out, ", %%%s", dest[0]->name);
1908 if (src->src_vreg->is_multi_reg_obj
1909 && src->dest_vreg->is_multi_reg_obj) { /* for ptr arit */
1910 /* long long */
1911 x_fprintf(out, "\n\tadc %%%s, %%%s\n",
1912 src->src_pregs[1]->name,
1913 dest[1]->name);
1914 }
1915 x_fputc('\n', out);
1916 }
1917
1918 static void
make_divmul_call(struct icode_instr * src,const char * func,int want_remainder)1919 make_divmul_call(struct icode_instr *src,
1920 const char *func,
1921 int want_remainder) {
1922
1923 int extra_pushed = 4;
1924 int osx_alignment = 0;
1925
1926 if (want_remainder != -1) {
1927 extra_pushed += 4;
1928 }
1929
1930 if (sysflag == OS_OSX) {
1931 if (extra_pushed == 4) {
1932 /*
1933 * 28 bytes passed, 8 for ebp/ret = 36 (need 12
1934 * for 16-byte alignment)
1935 */
1936 osx_alignment = 12;
1937 } else {
1938 /*
1939 * 32 bytes passed, 8 for ebp/ret = 40 (need 8
1940 * for 16-byte alignment)
1941 */
1942 osx_alignment = 8;
1943 }
1944 x_fprintf(out, "\tsubl $%d, %%esp\n",
1945 osx_alignment);
1946 }
1947 x_fprintf(out, "\tsubl $4, %%esp\n");
1948 x_fprintf(out, "\tmovl %%%s, (%%esp)\n", src->dest_pregs[1]->name);
1949 x_fprintf(out, "\tsubl $4, %%esp\n");
1950 x_fprintf(out, "\tmovl %%%s, (%%esp)\n", src->dest_pregs[0]->name);
1951 x_fprintf(out, "\tsubl $4, %%esp\n");
1952 x_fprintf(out, "\tmovl %%%s, (%%esp)\n", src->src_pregs[1]->name);
1953 x_fprintf(out, "\tsubl $4, %%esp\n");
1954 x_fprintf(out, "\tmovl %%%s, (%%esp)\n", src->src_pregs[0]->name);
1955 x_fprintf(out, "\tlea 8(%%esp), %%eax\n");
1956 x_fprintf(out, "\tlea (%%esp), %%ecx\n");
1957
1958 /* Push data size */
1959 x_fprintf(out, "\tpushl $64\n");
1960
1961 if (want_remainder != -1) {
1962 x_fprintf(out, "\tpushl $%d\n", want_remainder);
1963 }
1964
1965 /* Push src address */
1966 x_fprintf(out, "\tpushl %%ecx\n");
1967 /* Push dest address */
1968 x_fprintf(out, "\tpushl %%eax\n");
1969 /* x_fprintf(out, "\tcall %s\n", func);*/
1970 emit_call(func);
1971
1972 /*
1973 * Result is saved in destination stack buffer - let's move it
1974 * to eax:edx
1975 */
1976 x_fprintf(out, "\tmovl %d(%%esp), %%eax\n", 16+extra_pushed);
1977 x_fprintf(out, "\tmovl %d(%%esp), %%edx\n", 20+extra_pushed);
1978 if (sysflag == OS_OSX) {
1979 x_fprintf(out, "\taddl $%d, %%esp\n",
1980 osx_alignment);
1981 }
1982 x_fprintf(out, "\taddl $%d, %%esp\n", 24+extra_pushed);
1983 }
1984
1985 static void
emit_div(struct reg ** dest,struct icode_instr * src,int formod)1986 emit_div(struct reg **dest, struct icode_instr *src, int formod) {
1987 struct type *ty = src->src_vreg->type;
1988
1989 (void) dest;
1990 if (IS_LLONG(ty->code)) {
1991 char *func;
1992
1993 if (ty->code == TY_ULLONG) {
1994 func = "__nwcc_ulldiv";
1995 } else {
1996 func = "__nwcc_lldiv";
1997 }
1998 make_divmul_call(src, func, formod);
1999 return;
2000 } else if (!IS_FLOATING(ty->code)) {
2001 if (ty->sign != TOK_KEY_UNSIGNED) {
2002 /* sign-extend eax to edx:eax */
2003 x_fprintf(out, "\tcltd\n");
2004 } else {
2005 x_fprintf(out, "\txor %%edx, %%edx\n");
2006 }
2007 }
2008
2009 if (IS_FLOATING(ty->code)) {
2010 /*
2011 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
2012 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
2013 * that goddamn fdivp does not work as i expect
2014 * it to with that god awful terrible gas ^%$&@!~!~
2015 * so fxch operands
2016 */
2017 if (STUPID_X87(src->src_pregs[0])) {
2018 x_fprintf(out, "\tfxch %%st(1)\n");
2019 x_fprintf(out, "\tfdivp ");
2020 } else {
2021 x_fprintf(out, "\tdivs%c %%%s, %%%s\n",
2022 ty->code == TY_FLOAT? 's': 'd',
2023 src->src_pregs[0]->name,
2024 dest[0]->name);
2025 return;
2026 }
2027 } else if (ty->sign == TOK_KEY_UNSIGNED) {
2028 x_fprintf(out, "\tdiv ");
2029 } else {
2030 /* signed integer division */
2031 x_fprintf(out, "\tidiv ");
2032 }
2033 if (IS_FLOATING(ty->code)) {
2034 print_mem_or_reg(src->dest_pregs[0], src->dest_vreg);
2035 } else {
2036 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
2037 }
2038 x_fputc('\n', out);
2039 }
2040
2041
2042 static void
emit_mod(struct reg ** dest,struct icode_instr * src)2043 emit_mod(struct reg **dest, struct icode_instr *src) {
2044 emit_div(dest, src, 1);
2045 if (!IS_LLONG(src->dest_vreg->type->code)) {
2046 x_fprintf(out, "\tmov %%edx, %%%s\n", dest[0]->name);
2047 }
2048 }
2049
2050
2051 static void
emit_mul(struct reg ** dest,struct icode_instr * src)2052 emit_mul(struct reg **dest, struct icode_instr *src) {
2053 struct type *ty = src->src_vreg->type;
2054
2055 (void) dest;
2056
2057 if (IS_LLONG(ty->code)) {
2058 char *func;
2059
2060 if (ty->code == TY_ULLONG) {
2061 func = "__nwcc_ullmul";
2062 } else {
2063 func = "__nwcc_llmul";
2064 }
2065 make_divmul_call(src, func, -1);
2066 return;
2067 } else if (IS_FLOATING(ty->code)) {
2068 if (STUPID_X87(dest[0])) {
2069 x_fprintf(out, "\tfmulp ");
2070 } else {
2071 x_fprintf(out, "\tmuls%c ",
2072 ty->code == TY_FLOAT? 's': 'd');
2073 }
2074 } else if (ty->sign == TOK_KEY_UNSIGNED) {
2075 x_fprintf(out, "\tmul ");
2076 } else {
2077 /* signed integer multiplication */
2078 /* XXX should use mul for pointer arithmetic :( */
2079 x_fprintf(out, "\timul ");
2080 }
2081 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
2082 if (IS_FLOATING(ty->code)) {
2083 x_fprintf(out, ", %%%s\n", src->dest_pregs[0]->name);
2084 }
2085 x_fputc('\n', out);
2086 }
2087
2088 static unsigned long shift_idx;
2089
2090 /* XXX sal for signed values!!!!! */
2091 static void
emit_shl(struct reg ** dest,struct icode_instr * src)2092 emit_shl(struct reg **dest, struct icode_instr *src) {
2093 int is_signed = src->dest_vreg->type->sign != TOK_KEY_UNSIGNED;
2094
2095 if (src->dest_vreg->is_multi_reg_obj) {
2096 if (src->src_vreg->from_const) {
2097 /* XXX lazy way */
2098 x_fprintf(out, "\tpushl %%ecx\n");
2099 #if 0
2100 x_fprintf(out, "\tmov $%d, %%ecx\n",
2101 *(int *)src->src_vreg->from_const->
2102 data);
2103 #endif
2104 x_fprintf(out, "\tmov $");
2105 cross_print_value_by_type(out,
2106 src->src_vreg->from_const->data,
2107 TY_INT, 'd');
2108 x_fprintf(out, ", %%ecx\n");
2109
2110 }
2111 x_fprintf(out, "\tshld %%cl, %%%s, %%%s\n",
2112 dest[0]->name, dest[1]->name);
2113 x_fprintf(out, "\t%s %%cl, %%%s\n",
2114 is_signed? "sal": "shl", dest[0]->name);
2115 /* if (!is_signed) {*/
2116 x_fprintf(out, "\tand $32, %%ecx\n");
2117 x_fprintf(out, "\tje .shftdone%lu\n", shift_idx);
2118 x_fprintf(out, "\tmov %%%s, %%%s\n",
2119 dest[0]->name, dest[1]->name);
2120 x_fprintf(out, "\txor %%%s, %%%s\n",
2121 dest[0]->name, dest[0]->name);
2122 x_fprintf(out, ".shftdone%lu:\n", shift_idx++);
2123 /* }*/
2124 if (src->src_vreg->from_const) {
2125 x_fprintf(out, "\tpop %%ecx\n");
2126 }
2127 } else {
2128 if (src->src_vreg->from_const) {
2129 #if 0
2130 x_fprintf(out, "\tshl $%d, %%%s\n",
2131 *(int *)src->src_vreg->from_const->data,
2132 dest[0]->name);
2133 #endif
2134 x_fprintf(out, "\t%s $",
2135 is_signed? "sal": "shl");
2136 cross_print_value_by_type(out,
2137 src->src_vreg->from_const->data,
2138 TY_INT, 'd');
2139 x_fprintf(out, ", %%%s\n", dest[0]->name);
2140 } else {
2141 x_fprintf(out, "\t%s %%cl, %%%s\n",
2142 is_signed? "sal": "shl", dest[0]->name);
2143 }
2144 }
2145 }
2146
2147
2148 /* XXX sar for signed values !!!!!!!! */
2149 static void
emit_shr(struct reg ** dest,struct icode_instr * src)2150 emit_shr(struct reg **dest, struct icode_instr *src) {
2151 int is_signed = src->dest_vreg->type->sign != TOK_KEY_UNSIGNED;
2152
2153 if (src->dest_vreg->is_multi_reg_obj) {
2154 x_fprintf(out, "\tshrdl %%cl, %%%s, %%%s\n",
2155 dest[1]->name, dest[0]->name);
2156 x_fprintf(out, "\t%s %%cl, %%%s\n",
2157 is_signed? "sar": "shr", dest[1]->name);
2158 /* if (!is_signed) {*/
2159 x_fprintf(out, "\tand $32, %%ecx\n");
2160 x_fprintf(out, "\tje .shftdone%lu\n", shift_idx);
2161 x_fprintf(out, "\tmov %%%s, %%%s\n",
2162 dest[1]->name, dest[0]->name);
2163 /*
2164 * 06/21/08: This was always sign-extending! Zero-
2165 * extend for unsigned values
2166 */
2167 if (is_signed) {
2168 x_fprintf(out, "\t%s $31, %%%s\n",
2169 is_signed? "sar": "shr", dest[1]->name);
2170 } else {
2171 x_fprintf(out, "\tmovl $0, %%%s\n",
2172 dest[1]->name);
2173 }
2174 x_fprintf(out, ".shftdone%lu:\n", shift_idx++);
2175 /* }*/
2176 } else {
2177 if (src->src_vreg->from_const) {
2178 #if 0
2179 x_fprintf(out, "\tshr $%d, %%%s\n",
2180 *(int *)src->src_vreg->from_const->data,
2181 dest[0]->name);
2182 #endif
2183 x_fprintf(out, "\t%s $", is_signed? "sar": "shr");
2184 cross_print_value_by_type(out,
2185 src->src_vreg->from_const->data,
2186 TY_INT, 'd');
2187 x_fprintf(out, ", %%%s\n", dest[0]->name);
2188 } else {
2189 x_fprintf(out, "\t%s %%cl, %%%s\n",
2190 is_signed? "sar": "shr",dest[0]->name);
2191 }
2192 }
2193 }
2194
2195 static void
emit_or(struct reg ** dest,struct icode_instr * src)2196 emit_or(struct reg **dest, struct icode_instr *src) {
2197 x_fprintf(out, "\tor ");
2198 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
2199 x_fprintf(out, ", %%%s\n", dest[0]->name);
2200 if (src->src_vreg->is_multi_reg_obj) {
2201 x_fprintf(out, "\tor %%%s, %%%s\n",
2202 src->src_pregs[1]->name, dest[1]->name);
2203 }
2204 }
2205
2206 static void
emit_and(struct reg ** dest,struct icode_instr * src)2207 emit_and(struct reg **dest, struct icode_instr *src) {
2208 x_fprintf(out, "\tand ", dest[0]->name);
2209 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
2210 x_fprintf(out, ", %%%s\n", dest[0]->name);
2211 if (src->src_vreg->is_multi_reg_obj) {
2212 x_fprintf(out, "\tand %%%s, %%%s\n",
2213 src->src_pregs[1]->name, dest[1]->name);
2214 }
2215 }
2216
2217 static void
emit_xor(struct reg ** dest,struct icode_instr * src)2218 emit_xor(struct reg **dest, struct icode_instr *src) {
2219 x_fprintf(out, "\txor ");
2220 if (src->src_vreg == NULL) {
2221 x_fprintf(out, "%%%s, %%%s\n",
2222 dest[0]->name, dest[0]->name);
2223 if (src->src_vreg->is_multi_reg_obj) {
2224 x_fprintf(out, "\txor %%%s, %%%s\n",
2225 dest[1]->name, dest[1]->name);
2226 }
2227 } else {
2228 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
2229 x_fprintf(out, ", %%%s\n", dest[0]->name);
2230 if (src->src_vreg->is_multi_reg_obj) {
2231 x_fprintf(out, "\txor %%%s, %%%s\n",
2232 src->src_pregs[1]->name, dest[1]->name);
2233 }
2234 }
2235 }
2236
2237 static void
emit_not(struct reg ** dest,struct icode_instr * src)2238 emit_not(struct reg **dest, struct icode_instr *src) {
2239 (void) src;
2240 x_fprintf(out, "\tnot %%%s\n", dest[0]->name);
2241 if (src->src_vreg->is_multi_reg_obj) {
2242 x_fprintf(out, "\tnot %%%s\n", dest[1]->name);
2243 }
2244 }
2245
2246 static void
emit_ret(struct icode_instr * ii)2247 emit_ret(struct icode_instr *ii) {
2248 (void) ii;
2249
2250 if (curfunc->proto->dtype->tlist->next == NULL
2251 && (curfunc->proto->dtype->code == TY_STRUCT
2252 || curfunc->proto->dtype->code == TY_UNION)) {
2253 /*
2254 * The hidden pointer used for structure returns
2255 * is cleaned up by the callee. This NONSENSE has
2256 * cost me a long time to track down ...
2257 */
2258 x_fprintf(out, "\tret $4\n");
2259 } else {
2260 x_fprintf(out, "\tret\n"); /* XXX */
2261 }
2262 }
2263
2264 extern struct icode_instr *last_x87_cmp;
2265 extern struct icode_instr *last_sse_cmp;
2266
2267 static void
emit_cmp(struct reg ** dest,struct icode_instr * src)2268 emit_cmp(struct reg **dest, struct icode_instr *src) {
2269 static int was_llong;
2270 int reg_idx = 0;
2271 int need_ffree = 0;
2272
2273 if (dest[0]->type == REG_FPR) {
2274 if (is_x87_trash(src->dest_vreg)) {
2275 last_x87_cmp = src;
2276 } else {
2277 /* Must be SSE */
2278 last_sse_cmp = src;
2279 }
2280 return;
2281 } else {
2282 if (was_llong) {
2283 reg_idx = 0;
2284 was_llong = 0;
2285 } else {
2286 if (src->dest_vreg->is_multi_reg_obj) {
2287 if (!(src->hints
2288 & HINT_INSTR_NEXT_NOT_SECOND_LLONG_WORD)) {
2289 /*
2290 * 06/02/08: Conditional for
2291 * repeated cmps on same dword!
2292 */
2293 was_llong = 1;
2294 }
2295 reg_idx = 1;
2296 } else {
2297 reg_idx = 0;
2298 }
2299 }
2300 fprintf(out, "\tcmp ");
2301 }
2302 if (src->src_pregs == NULL || src->src_vreg == NULL) {
2303 x_fprintf(out, "$0");
2304 } else {
2305 print_mem_or_reg(src->src_pregs[/*0*/reg_idx], src->src_vreg);
2306 }
2307 if (dest[0]->type == REG_FPR) {
2308 x_fprintf(out, ", %%%s", dest[0]->name);
2309 } else {
2310 x_fprintf(out, ", %%%s", dest[reg_idx]->name);
2311 }
2312 x_fputc('\n', out);
2313 if (need_ffree) {
2314 x_fprintf(out, "\tffree %%st\n");
2315 }
2316 }
2317
2318 static void
emit_branch(struct icode_instr * ii)2319 emit_branch(struct icode_instr *ii) {
2320 char *lname;
2321 char *opcode = NULL;
2322 int i;
2323 int is_signed;
2324 static const struct {
2325 int type;
2326 char *for_signed;
2327 char *for_unsigned;
2328 } instructions[] = {
2329 { INSTR_BR_EQUAL, "je", "je" },
2330 { INSTR_BR_SMALLER, "jl", "jb" }, /* less/below */
2331 { INSTR_BR_SMALLEREQ, "jle", "jbe" }, /* less/below or equal */
2332 { INSTR_BR_GREATER, "jg", "ja" }, /* greater/above */
2333 { INSTR_BR_GREATEREQ, "jge", "jae" }, /* greater/above or eq */
2334 { INSTR_BR_NEQUAL, "jne", "jne" },
2335 { INSTR_JUMP, "jmp", "jmp" },
2336 { -1, NULL, NULL }
2337 };
2338
2339 lname = ((struct icode_instr *)ii->dat)->dat;
2340
2341 if (ii->dest_vreg
2342 && is_floating_type(ii->dest_vreg->type)) {
2343 int cmp_with = 0;
2344 int branch_if_equals = 0;
2345 int is_sse = 0;
2346
2347 if (is_x87_trash(ii->dest_vreg)) {
2348 fprintf(out, "\tfucomip %%st(1), %%st(0)\n");
2349 } else {
2350 /*
2351 * Since this is fp but not x87, it must be SSE.
2352 */
2353 is_sse = 1;
2354 if (ii->dest_vreg->type->code == TY_FLOAT) {
2355 x_fprintf(out, "\tucomiss %%%s, %%%s\n",
2356 last_sse_cmp->dest_pregs[0]->name,
2357 last_sse_cmp->src_pregs[0]->name);
2358 } else {
2359 /* double */
2360 x_fprintf(out, "\tucomisd %%%s, %%%s\n",
2361 last_sse_cmp->dest_pregs[0]->name,
2362 last_sse_cmp->src_pregs[0]->name);
2363 }
2364 }
2365
2366 /*
2367 * Now we kludge our way around the x87/SSE way of
2368 * signaling (in-)equality (both set eflags in the
2369 * same way)...
2370 * The flags register has the following meaningful flags:
2371 *
2372 * ZF=0, PF=0, CF=0 means st(0) > st(1)
2373 * ZF=0, PF=0, CF=1 means st(0) < st(1)
2374 * ZF=1, PF=0, CF=0 means st(0) = st(1)
2375 *
2376 * CF = bit 0 (lowest)
2377 * PF = bit 2
2378 * ZF = bit 6
2379 *
2380 * On x86 we can use the lahf instruction to get that
2381 * flag register byte, however this is not available on
2382 * AMD64, so we have to set* and or those flags together.
2383 */
2384 #define FP_EQU_MASK (1 /*CF*/ | (1 << 2) /*PF*/ | (1 << 6) /*ZF*/)
2385 #define ST1_SMALLER (0)
2386 #define ST1_GREATER (1)
2387 #define ST1_EQUAL (1 << 6)
2388 if (backend->arch == ARCH_AMD64) {
2389 x_fprintf(out, "\tpush %%rax\n"); /* save ah/al */
2390 x_fprintf(out, "\tpush %%rbx\n"); /* save bl */
2391
2392 /*
2393 * Now painfully construct flags in ah like
2394 * lahf plus masking does on x86. It is VERY
2395 * important to do the set stuff before or'ing
2396 * because or also sets flags! (sadly I got
2397 * this wrong first, which cost me a good hour
2398 * :-()
2399 */
2400 x_fprintf(out, "\tsetc %%ah\n");
2401 x_fprintf(out, "\tsetp %%al\n");
2402 x_fprintf(out, "\tsetz %%bl\n");
2403 x_fprintf(out, "\tshl $2, %%al\n");
2404 x_fprintf(out, "\tshl $6, %%bl\n");
2405 x_fprintf(out, "\tor %%al, %%ah\n");
2406 x_fprintf(out, "\tor %%bl, %%ah\n");
2407 } else {
2408 x_fprintf(out, "\tpush %%eax\n"); /* save ah */
2409 x_fprintf(out, "\tlahf\n");
2410
2411 /* Mask off unused flags */
2412 x_fprintf(out, "\tand $%d, %%ah\n", FP_EQU_MASK);
2413 }
2414
2415
2416 switch (ii->type) {
2417 case INSTR_BR_EQUAL:
2418 cmp_with = ST1_EQUAL;
2419 branch_if_equals = 1;
2420 break;
2421 case INSTR_BR_SMALLER:
2422 cmp_with = ST1_SMALLER;
2423 branch_if_equals = 1;
2424 break;
2425 case INSTR_BR_SMALLEREQ:
2426 cmp_with = ST1_GREATER;
2427 branch_if_equals = 0;
2428 break;
2429 case INSTR_BR_GREATER:
2430 cmp_with = ST1_GREATER;
2431 branch_if_equals = 1;
2432 break;
2433 case INSTR_BR_GREATEREQ:
2434 cmp_with = ST1_SMALLER;
2435 branch_if_equals = 0;
2436 break;
2437 case INSTR_BR_NEQUAL:
2438 cmp_with = ST1_EQUAL;
2439 branch_if_equals = 0;
2440 break;
2441 default:
2442 unimpl();
2443 }
2444 x_fprintf(out, "\tcmp $%d, %%ah\n", cmp_with);
2445
2446 if (backend->arch == ARCH_AMD64) {
2447 x_fprintf(out, "\tpop %%rbx\n"); /* restore bl */
2448 x_fprintf(out, "\tpop %%rax\n"); /* restore ah/al */
2449 } else {
2450 x_fprintf(out, "\tpop %%eax\n"); /* restore ah */
2451 }
2452
2453 if (!is_sse) {
2454 /* Now free second used fp reg */
2455 x_fprintf(out, "\tffree %%st(0)\n");
2456 }
2457
2458 /* Finally branch! */
2459 x_fprintf(out, "\t%s .%s\n",
2460 branch_if_equals? "je": "jne", lname);
2461
2462 return;
2463 }
2464
2465 if (ii->dest_vreg == NULL) {
2466 /* Signedness doesn't matter */
2467 is_signed = 1;
2468 } else {
2469 /*
2470 * 06/29/08: This was missing the check whether we
2471 * are comparing pointers, and thus need unsigned
2472 * comparison
2473 */
2474 if (ii->dest_vreg->type->sign == TOK_KEY_UNSIGNED
2475 || ii->dest_vreg->type->tlist != NULL) {
2476 is_signed = 0;
2477 } else {
2478 is_signed = 1;
2479 }
2480 }
2481
2482 for (i = 0; instructions[i].type != -1; ++i) {
2483 if (instructions[i].type == ii->type) {
2484 if (is_signed) {
2485 opcode = instructions[i].for_signed;
2486 } else {
2487 opcode = instructions[i].for_unsigned;
2488 }
2489 break;
2490 }
2491 }
2492 if (instructions[i].type == -1) {
2493 printf("BUG: bad branch instruction - %d\n",
2494 ii->type);
2495 abort();
2496 }
2497
2498 /* XXX the near part may not always be necessary */
2499 x_fprintf(out, "\t%s .%s\n", opcode, lname);
2500 }
2501
2502 static void
print_reg_assign(struct reg * dest,struct reg * srcreg,size_t src_size,struct type * src_type)2503 print_reg_assign(
2504 struct reg *dest,
2505 struct reg *srcreg,
2506 size_t src_size,
2507 struct type *src_type) {
2508
2509 if (dest->size == src_size || src_size == 8) {
2510 /* == 8 for long long on x86 */
2511 x_fprintf(out, "\tmov %s, ", dest->name);
2512 } else {
2513 /* dest size > src size */
2514 if (src_type->sign == TOK_KEY_UNSIGNED) {
2515 if (backend->arch == ARCH_AMD64
2516 && dest->size == 8
2517 && src_size == 4) {
2518 if (!isdigit(dest->name[1])) {
2519 /*
2520 * e.g. mov eax, edx zero-extends
2521 * upper 32 bits of rax
2522 */
2523 x_fprintf(out, "mov ");
2524 dest = dest->composed_of[0];
2525 } else {
2526 /* XXX there must be a better way :( */
2527 x_fprintf(out, "\tpush %%rax\n");
2528 x_fprintf(out, "\tmov %%%s, %%eax\n",
2529 srcreg->name);
2530 x_fprintf(out, "\tmov %%rax, %%%s\n",
2531 dest->name);
2532 x_fprintf(out, "\tpop %%rax\n");
2533 return;
2534 }
2535 } else {
2536 x_fprintf(out, "\tmovzx ");
2537 }
2538 } else {
2539 if (backend->arch == ARCH_AMD64
2540 && dest->size == 8
2541 && src_size == 4) {
2542 /* dword -> qword = special case */
2543 x_fprintf(out, "\tmovslq ");
2544 } else {
2545 x_fprintf(out, "\tmovsx ");
2546 }
2547 }
2548 }
2549
2550 x_fprintf(out, "%%%s, %%%s\n", srcreg->name, dest->name);
2551 }
2552
2553
2554 static void
emit_mov(struct copyreg * cr)2555 emit_mov(struct copyreg *cr) {
2556 struct reg *dest = cr->dest_preg;
2557 struct reg *src = cr->src_preg;
2558 struct type *src_type = cr->src_type;
2559
2560 if (src == NULL) {
2561 /* Move null to register (XXX fp?) */
2562 x_fprintf(out, "\tmov $0, %%%s\n",
2563 dest->name);
2564 } else if (dest->type == REG_FPR) {
2565 /* XXX ... */
2566 if (STUPID_X87(dest)) {
2567 emit_x86->fxch(dest, src);
2568 } else {
2569 x_fprintf(out, "\tmovs%c %%%s, %%%s\n",
2570 src_type->code == TY_FLOAT? 's': 'd',
2571 src->name, dest->name);
2572 }
2573 } else if (dest->size == src->size) {
2574 x_fprintf(out, "\tmov %%%s, %%%s\n", src->name, dest->name);
2575 } else if (dest->size > src->size) {
2576 print_reg_assign(dest, src, src->size, src_type);
2577 /*x_fprintf(out, "%s\n", src->name);*/
2578 } else {
2579 /* source larger than dest */
2580 src = get_smaller_reg(src, dest->size);
2581 x_fprintf(out, "\tmov %%%s, %%%s\n", src->name, dest->name);
2582 }
2583 }
2584
2585
2586 static void
emit_setreg(struct reg * dest,int * value)2587 emit_setreg(struct reg *dest, int *value) {
2588 x_fprintf(out, "\tmov $%d, %%%s\n", *(int *)value, dest->name);
2589 }
2590
2591 static void
emit_xchg(struct reg * r1,struct reg * r2)2592 emit_xchg(struct reg *r1, struct reg *r2) {
2593 x_fprintf(out, "\txchg %%%s, %%%s\n", r2->name, r1->name);
2594 }
2595
2596 static void
emit_initialize_pic(struct function * f)2597 emit_initialize_pic(struct function *f) {
2598 char buf[128];
2599 static unsigned long count;
2600
2601 (void) f;
2602 if (sysflag == OS_OSX) {
2603 sprintf(buf, "\"L%011lu$pb\"", count);
2604 f->pic_label = n_xstrdup(buf);
2605 x_fprintf(out, "\tcall _Piclab%lu\n", count);
2606 x_fprintf(out, "%s:\n", buf);
2607 x_fprintf(out, "_Piclab%lu:\n", count);
2608 x_fprintf(out, "\tpopl %%ebx\n");
2609 ++count;
2610 } else {
2611 sprintf(buf, "._Piclab%lu", count++);
2612 x_fprintf(out, "\tcall %s\n", buf);
2613 x_fprintf(out, "%s:\n", buf);
2614 x_fprintf(out, "\tpopl %%ebx\n");
2615 x_fprintf(out, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-%s], %%ebx\n", buf);
2616 }
2617 }
2618
2619 static void
emit_addrof(struct reg * dest,struct vreg * src,struct vreg * structtop)2620 emit_addrof(struct reg *dest, struct vreg *src, struct vreg *structtop) {
2621 struct decl *d;
2622 long offset = 0;
2623 char *sign = NULL;
2624 char *base_pointer_frame;
2625 char *base_pointer_stack;
2626
2627 if (backend->arch == ARCH_AMD64) {
2628 base_pointer_frame = "rbp";
2629 base_pointer_stack = "rsp";
2630 } else {
2631 base_pointer_frame = "ebp";
2632 base_pointer_stack = "esp";
2633 }
2634
2635 if (src == NULL) {
2636 d = curfunc->proto->dtype->tlist->tfunc->lastarg;
2637 } else {
2638 d = src->var_backed;
2639 }
2640
2641 if (structtop != NULL) {
2642 d = structtop->var_backed;
2643 }
2644
2645 if (d != NULL) {
2646 if (d->stack_addr != NULL) {
2647 if (d->stack_addr->is_func_arg) {
2648 sign = "";
2649 } else {
2650 sign = "-";
2651 }
2652 offset = d->stack_addr->offset;
2653 } else if (IS_THREAD(d->dtype->flags)) {
2654 /* 02/02/08: __thread variable */
2655 if (backend->arch == ARCH_AMD64) {
2656 x_fprintf(out, "\tmovq %%fs:0, %%%s\n", dest->name);
2657 x_fprintf(out, "\tleaq %s@TPOFF(%%%s), %%%s\n",
2658 d->dtype->name, dest->name, dest->name);
2659 } else {
2660 /* x86 */
2661 x_fprintf(out, "\tmovl %%gs:0, %%%s\n", dest->name);
2662 x_fprintf(out, "\tleal %s@NTPOFF(%%%s), %%%s\n",
2663 d->dtype->name, dest->name, dest->name);
2664 }
2665 if (src->parent != NULL) {
2666 x_fprintf(out, "\tadd $%ld, %%%s\n",
2667 calc_offsets(src), dest->name);
2668 }
2669 return;
2670 } else if (picflag) {
2671 if (d->dtype->is_func && d->dtype->tlist->type == TN_FUNCTION) {
2672 if (backend->arch == ARCH_AMD64) {
2673 if (sysflag == OS_OSX) {
2674 #if 0
2675 x_fprintf(out, "\tmovq %s%s(%%rip), %%%s\n",
2676 IS_ASM_RENAMED(d->dtype->flags)? "": "_",
2677 d->dtype->name, dest->name);
2678 #endif
2679 x_fprintf(out, "\tmovq %s%s@GOTPCREL(%%rip), %%%s\n",
2680 IS_ASM_RENAMED(d->dtype->flags)? "": "_",
2681 d->dtype->name, dest->name);
2682 } else {
2683 x_fprintf(out, "\tmovq %s@PLT, %%%s\n",
2684 d->dtype->name, dest->name);
2685 }
2686 } else {
2687 /*
2688 * XXX hmmm lea here but mov for data.
2689 * Seems correct though
2690 */
2691 if (sysflag == OS_OSX) {
2692 /*
2693 * XXX We always use the stub entry even for
2694 * local functions, which don't need it. This
2695 * should probably be distinguished
2696 * 02/15/09: WRONG we are forced to distinguish
2697 */
2698 /*if (d->dtype->storage == TOK_KEY_EXTERN) {*/
2699 if (1) { //!d->dtype->is_def) {
2700 if (IS_ASM_RENAMED(d->dtype->flags)) {
2701 osx_call_renamed = 1;
2702 }
2703 add_osx_fcall(d->dtype->name, d, 1);
2704 x_fprintf(out, "\tlea L_%s$non_lazy_ptr-%s(%%ebx), %%%s\n",
2705 d->dtype->name,
2706 curfunc->pic_label,
2707 dest->name);
2708 x_fprintf(out, "\tmov (%%%s), %%%s\n",
2709 dest->name, dest->name);
2710 osx_call_renamed = 0;
2711 } else {
2712 x_fprintf(out, "\tlea _%s-%s(%%ebx), %%%s\n",
2713 d->dtype->name,
2714 curfunc->pic_label,
2715 dest->name);
2716 }
2717 } else {
2718 x_fprintf(out, "\tlea %s@GOT(%%ebx), %%%s\n",
2719 d->dtype->name, dest->name);
2720 }
2721 }
2722 return;
2723 } else if (d->dtype->storage == TOK_KEY_EXTERN
2724 || d->dtype->storage == TOK_KEY_STATIC) {
2725 if (backend->arch == ARCH_AMD64) {
2726 if (sysflag == OS_OSX) {
2727 x_fprintf(out, "\tmovq %s%s@GOTPCREL(%%rip), %%%s\n",
2728 IS_ASM_RENAMED(d->dtype->flags)? "": "_",
2729 d->dtype->name, dest->name);
2730 } else {
2731 x_fprintf(out, "\tmovq %s@GOTPCREL(%%rip), %%%s\n",
2732 d->dtype->name, dest->name);
2733 }
2734 } else {
2735 /* x86 */
2736 if (sysflag == OS_OSX) {
2737 /* x_fprintf(out, "\tlea _%s-%s(%%ebx), %%%s\n",*/
2738 /*
2739 * 02/08/09: Always use a non_lazy_ptr reference
2740 * XXX As with function pointers, we should probably
2741 * distinguish between local symbols and extern ones
2742 * 02/14/09: We HAVE to, in fact! It is apparently
2743 * completely impossible to create a correct indirect
2744 * symbol for local variables :-(
2745 */
2746 if (1) { //d->dtype->storage == TOK_KEY_EXTERN) {
2747 if (IS_ASM_RENAMED(d->dtype->flags)) {
2748 osx_call_renamed = 1;
2749 }
2750 add_osx_fcall(d->dtype->name, d, 1); /* XXX misnomer */
2751 x_fprintf(out, "\tlea L_%s$non_lazy_ptr-%s(%%ebx), %%%s\n",
2752 d->dtype->name,
2753 curfunc->pic_label,
2754 dest->name);
2755 /*
2756 * 02/14/09: Looks like we need another level of
2757 * indirection
2758 */
2759 x_fprintf(out, "\tmov (%%%s), %%%s\n",
2760 dest->name, dest->name);
2761 osx_call_renamed = 0;
2762 } else {
2763 x_fprintf(out, "\tlea _%s-%s(%%ebx), %%%s\n",
2764 d->dtype->name,
2765 curfunc->pic_label,
2766 dest->name);
2767 }
2768 } else {
2769 x_fprintf(out, "\tmov %s@GOT(%%ebx), %%%s\n",
2770 d->dtype->name, dest->name);
2771 }
2772 }
2773 if (src->parent != NULL) {
2774 x_fprintf(out, "\tadd $%ld, %%%s\n",
2775 calc_offsets(src), dest->name);
2776 }
2777 return;
2778 }
2779 }
2780 } else if (picflag && src->from_const) {
2781 /*
2782 * Not variable, but may be a constant that needs a PIC
2783 * relocation too. Most likely a string constant, but may
2784 * also be an FP constant
2785 */
2786 char *name = NULL;
2787 char buf[128];
2788
2789 if (src->from_const->type == TOK_STRING_LITERAL) {
2790 struct ty_string *ts = src->from_const->data;
2791 sprintf(buf, "._Str%lu", ts->count);
2792 name = buf;
2793 } else if (IS_FLOATING(src->from_const->type)) {
2794 struct ty_float *tf = src->from_const->data;
2795 sprintf(buf, "_Float%lu", tf->count); /* XXX hmm need preceding . ? */
2796 name = buf;
2797 }
2798 if (name != NULL) {
2799 if (backend->arch == ARCH_AMD64) {
2800 x_fprintf(out, "\tmovq %s@GOTPCREL(%%rip), %%%s\n",
2801 name, dest->name);
2802 } else {
2803 if (sysflag == OS_OSX) {
2804 x_fprintf(out, "\tlea %s-%s(%%ebx), %%%s\n",
2805 name, curfunc->pic_label, dest->name);
2806 } else {
2807 x_fprintf(out, "\tmov %s@GOT(%%ebx), %%%s\n",
2808 name, dest->name);
2809 }
2810 }
2811 return;
2812 }
2813 }
2814
2815 if (src && src->parent != NULL) {
2816 /* Structure or union type */
2817 long soff = (long)calc_offsets(src); /* XXX */
2818
2819 if (d != NULL) {
2820 if (sign != NULL) {
2821 /* Must be stack address */
2822 if (strcmp(sign, "-") == 0) { /* XXX :( */
2823 if (soff >= offset) {
2824 sign = "";
2825 offset = soff - offset;
2826 } else {
2827 offset -= soff;
2828 }
2829 } else {
2830 offset += soff;
2831 }
2832 }
2833
2834 if (d->stack_addr != NULL) {
2835 /* XXX assumes frame pointer always to be used */
2836 x_fprintf(out, "\tlea %s%ld(%%%s), %%%s",
2837 sign, offset, base_pointer_frame, dest->name);
2838 } else {
2839 /* Static */
2840 /* 08/01/07: Wow this didn't work?!?!? */
2841 x_fprintf(out, "\tlea %s+%ld, %%%s",
2842 d->dtype->name, soff, dest->name);
2843 }
2844 } else if (structtop->from_ptr) {
2845 x_fprintf(out, "\tlea %ld(%%%s), %%%s",
2846 soff,
2847 structtop->from_ptr->pregs[0]->name,
2848 dest->name);
2849 } else {
2850 printf("hm attempt to take address of %s\n",
2851 src->type->name);
2852 unimpl();
2853 }
2854 x_fputc('\n', out);
2855 } else if (src && src->from_ptr) {
2856 x_fprintf(out, "\tmov %%%s, %%%s\n",
2857 src->from_ptr->pregs[0]->name, dest->name);
2858 } else if (src && src->from_const && src->from_const->type == TOK_STRING_LITERAL) {
2859 /* 08/21/08: This was missing */
2860 emit_load(dest, src);
2861 } else if (src && src->stack_addr) {
2862 /*
2863 * 07/26/12: For some reason anonymous stack items hadn't been
2864 * supported yet
2865 */
2866 x_fprintf(out, "\tlea ");
2867 if (backend->arch == ARCH_AMD64) {
2868 amd64_print_mem_operand_gas(src, NULL);
2869 } else {
2870 print_mem_operand(src, NULL);
2871 }
2872 x_fprintf(out, ", %%%s\n", dest->name);
2873 } else {
2874 if (d && d->stack_addr) {
2875 if (src == NULL) {
2876 /* Move past object */
2877 offset += d->stack_addr->nbytes;
2878 }
2879
2880 /* XXX assumes frame pointer always to be used */
2881 x_fprintf(out, "\tlea %s%ld(%%%s), %%%s\n",
2882 sign, offset, base_pointer_frame, dest->name);
2883 } else if (d) {
2884 /*
2885 * Must be static variable - symbol itself is
2886 * address
2887 */
2888 x_fprintf(out, "\tmov $%s, %%%s\n",
2889 d->dtype->name, dest->name);
2890 } else {
2891 printf("BUG: Cannot take address of item!\n");
2892 printf("%p\n", src->stack_addr);
2893 abort();
2894 }
2895 }
2896 }
2897
2898 /* XXX hmm this only works with TOS?! */
2899 static void
emit_fxch(struct reg * r,struct reg * r2)2900 emit_fxch(struct reg *r, struct reg *r2) {
2901 if (r == &x86_fprs[0]) {
2902 x_fprintf(out, "\tfxch %%%s\n", r2->name);
2903 } else {
2904 x_fprintf(out, "\tfxch %%%s\n", r->name);
2905 }
2906 }
2907
2908 static void
emit_ffree(struct reg * r)2909 emit_ffree(struct reg *r) {
2910 x_fprintf(out, "\tffree %%%s\n", r->name);
2911 }
2912
2913
2914 static void
emit_fnstcw(struct vreg * vr)2915 emit_fnstcw(struct vreg *vr) {
2916 if (backend->arch == ARCH_X86) {
2917 x_fprintf(out, "\tfnstcw (%s)\n", vr->type->name);
2918 } else {
2919 x_fprintf(out, "\tfnstcw %s(%%rip)\n", vr->type->name);
2920 }
2921 }
2922
2923 static void
emit_fldcw(struct vreg * vr)2924 emit_fldcw(struct vreg *vr) {
2925 if (backend->arch == ARCH_X86) {
2926 x_fprintf(out, "\tfldcw (%s)\n", vr->type->name);
2927 } else {
2928 x_fprintf(out, "\tfldcw %s(%%rip)\n", vr->type->name);
2929 }
2930 }
2931
2932 static char *
get_symbol_value_representation(const char * symname,int is_func)2933 get_symbol_value_representation(const char *symname, int is_func) {
2934 static char buf[1024];
2935 if (0) { /*picflag) {*/
2936 } else {
2937 sprintf(buf, "$.%s", symname);
2938 }
2939 return buf;
2940 }
2941
2942
2943 /*
2944 * Copy initializer to automatic variable of aggregate type
2945 */
2946 static void
emit_copyinit(struct decl * d)2947 emit_copyinit(struct decl *d) {
2948 if (sysflag == OS_OSX) {
2949 /*
2950 * Ensure 16-byte alignment (we pass 12, and need to
2951 * account for the callee using 8 bytes for ret addr
2952 * and ebp, so 12+12+8 = 32)
2953 */
2954 x_fprintf(out, "\tsubl $12, %%esp\n");
2955 }
2956 x_fprintf(out, "\tpushl $%lu\n",
2957 (unsigned long)backend->get_sizeof_type(d->dtype, NULL) /*d->vreg->size*/);
2958
2959 /*
2960 * 07/26/12: This was missing support for position independence?!!?
2961 * Support it in an ad hoc manner here
2962 */
2963 /*x_fprintf(out, "\tpushl $.%s\n", d->init_name->name);*/ /* XXX */
2964 x_fprintf(out, "\tpushl %s\n",
2965 get_symbol_value_representation(d->init_name->name, 0));
2966 x_fprintf(out, "\tlea -%lu(%%ebp), %%eax\n", d->stack_addr->offset);
2967 x_fprintf(out, "\tpushl %%eax\n");
2968 if (sysflag == OS_OSX) {
2969 add_osx_fcall("memcpy", NULL, 0);
2970 x_fprintf(out, "\tcall L_memcpy$stub\n");
2971 x_fprintf(out, "\taddl $24, %%esp\n");
2972 } else {
2973 x_fprintf(out, "\tcall memcpy\n");
2974 x_fprintf(out, "\taddl $12, %%esp\n");
2975 }
2976 }
2977
2978
2979 /*
2980 * Assign one struct to another (may be any of automatic or static or
2981 * addressed thru pointer)
2982 */
2983 static void
emit_copystruct(struct copystruct * cs)2984 emit_copystruct(struct copystruct *cs) {
2985 struct vreg *stop;
2986 struct reg *tmpreg = NULL;
2987 int i;
2988 static unsigned long lcount;
2989
2990 /* Get temporary register not used by our pointer(s), if any */
2991 if (sysflag != OS_OSX) {
2992 for (i = 0; i < 4; ++i) {
2993 if (i == 1) {
2994 /* Don't use ebx as it's callee-saved */
2995 continue;
2996 }
2997
2998 if (&x86_gprs[i] != cs->dest_from_ptr
2999 && &x86_gprs[i] != cs->src_from_ptr
3000 && &x86_gprs[i] != cs->dest_from_ptr_struct
3001 && &x86_gprs[i] != cs->src_from_ptr_struct) {
3002 tmpreg = &x86_gprs[i];
3003 break;
3004 }
3005 }
3006 } else {
3007 x_fprintf(out, "\tpushl %%eax\n");
3008 x_fprintf(out, "\tpushl %%ecx\n");
3009 x_fprintf(out, "\tpushl %%esi\n");
3010 x_fprintf(out, "\tpushl %%edi\n");
3011 tmpreg = &x86_gprs[0];
3012 }
3013
3014 x_fprintf(out, "\tpushl $%lu\n", (unsigned long)cs->src_vreg->size);
3015 if (cs->src_from_ptr == NULL) {
3016 if (cs->src_vreg->parent) {
3017 stop = get_parent_struct(cs->src_vreg);
3018 } else {
3019 stop = NULL;
3020 }
3021 emit_addrof(tmpreg, cs->src_vreg, stop);
3022 x_fprintf(out, "\tpushl %%%s\n", tmpreg->name);
3023 } else {
3024 if (cs->src_vreg->parent) {
3025 x_fprintf(out, "\tadd $%lu, %%%s\n",
3026 calc_offsets(cs->src_vreg),
3027 /*cs->src_vreg->memberdecl->offset,*/
3028 cs->src_from_ptr->name);
3029 }
3030 x_fprintf(out, "\tpushl %%%s\n", cs->src_from_ptr->name);
3031 }
3032
3033 if (sysflag == OS_OSX) {
3034 x_fprintf(out, "\tmovl 20(%%esp), %%eax\n");
3035 }
3036 if (cs->dest_from_ptr == NULL) {
3037 if (cs->dest_vreg->parent) {
3038 stop = get_parent_struct(cs->dest_vreg);
3039 } else {
3040 stop = NULL;
3041 }
3042 emit_addrof(tmpreg, cs->dest_vreg, stop);
3043 x_fprintf(out, "\tpushl %%%s\n", tmpreg->name);
3044 } else {
3045 if (cs->dest_vreg->parent) {
3046 x_fprintf(out, "\tadd $%lu, %%%s\n",
3047 calc_offsets(cs->dest_vreg),
3048 /*cs->dest_vreg->memberdecl->offset,*/
3049 cs->dest_from_ptr->name);
3050 }
3051 x_fprintf(out, "\tpushl %%%s\n", cs->dest_from_ptr->name);
3052 }
3053 if (sysflag == OS_OSX) {
3054 #if 0
3055 add_osx_fcall("memcpy", NULL, 0);
3056 x_fprintf(out, "\tcall L_memcpy$stub\n");
3057 x_fprintf(out, "\taddl $24, %%esp\n");
3058 #endif
3059 x_fprintf(out, "\tpopl %%edi\n");
3060 x_fprintf(out, "\tpopl %%esi\n");
3061 x_fprintf(out, "\tpopl %%ecx\n");
3062 x_fprintf(out, "\t.copystruct%lu:\n", lcount);
3063 x_fprintf(out, "\tmov (%%esi), %%al\n");
3064 x_fprintf(out, "\tmov %%al, (%%edi)\n");
3065 x_fprintf(out, "\tinc %%edi\n");
3066 x_fprintf(out, "\tinc %%esi\n");
3067 #if 0
3068 /* This loop yields a SEGFAULT on OSX. Give me a BREAK!!!! */
3069 x_fprintf(out, "\tloop .copystruct%lu\n", lcount++);
3070 #endif
3071 x_fprintf(out, "\tdec %%ecx\n");
3072 x_fprintf(out, "\tcmp $0, %%ecx\n");
3073 x_fprintf(out, "\tjne .copystruct%lu\n", lcount++);
3074
3075 x_fprintf(out, "\tpopl %%edi\n");
3076 x_fprintf(out, "\tpopl %%esi\n");
3077 x_fprintf(out, "\tpopl %%ecx\n");
3078 x_fprintf(out, "\tpopl %%eax\n");
3079 } else {
3080 x_fprintf(out, "\tcall memcpy\n");
3081 x_fprintf(out, "\taddl $12, %%esp\n");
3082 }
3083 }
3084
3085 static void
emit_intrinsic_memcpy(struct int_memcpy_data * data)3086 emit_intrinsic_memcpy(struct int_memcpy_data *data) {
3087 struct reg *dest = data->dest_addr;
3088 struct reg *src = data->src_addr;
3089 struct reg *nbytes = data->nbytes;
3090 struct reg *temp = data->temp_reg;
3091 static int labelcount;
3092
3093 if (data->type == BUILTIN_MEMSET && src != temp) {
3094 x_fprintf(out, "\tmov %%%s, %%%s\n", src->name, temp->name);
3095 }
3096 x_fprintf(out, "\tcmp $0, %%%s\n", nbytes->name);
3097 x_fprintf(out, "\tje .Memcpy_done%d\n", labelcount);
3098 x_fprintf(out, ".Memcpy_start%d:\n", labelcount);
3099 if (data->type == BUILTIN_MEMCPY) {
3100 x_fprintf(out, "\tmov (%%%s), %%%s\n", src->name, temp->name);
3101 }
3102 x_fprintf(out, "\tmov %%%s, (%%%s)\n", temp->name, dest->name);
3103 x_fprintf(out, "\tinc %%%s\n", dest->name);
3104 if (data->type == BUILTIN_MEMCPY) {
3105 x_fprintf(out, "\tinc %%%s\n", src->name);
3106 }
3107 x_fprintf(out, "\tdec %%%s\n", nbytes->name);
3108 x_fprintf(out, "\tcmp $0, %%%s\n", nbytes->name);
3109 x_fprintf(out, "\tjne .Memcpy_start%d\n", labelcount);
3110 x_fprintf(out, ".Memcpy_done%d:\n", labelcount);
3111 ++labelcount;
3112 }
3113
3114 static void
emit_zerostack(struct stack_block * sb,size_t nbytes)3115 emit_zerostack(struct stack_block *sb, size_t nbytes) {
3116 if (sysflag == OS_OSX) {
3117 /*
3118 * 16-byte alignment (we pass 12, callee uses
3119 * 8 for ret addr and ebp, so we need 12 to
3120 * get to a multiple of 16)
3121 */
3122 x_fprintf(out, "\tsub $12, %%esp\n");
3123 }
3124 x_fprintf(out, "\tpushl $%lu\n", (unsigned long)nbytes);
3125 x_fprintf(out, "\tpushl $0\n");
3126 x_fprintf(out, "\tleal -%lu(%%ebp), %%ecx\n",
3127 (unsigned long)sb->offset);
3128 x_fprintf(out, "\tpush %%ecx\n");
3129 if (sysflag == OS_OSX) {
3130 add_osx_fcall("memset", NULL, 0);
3131 x_fprintf(out, "\tcall L_memset$stub\n");
3132 x_fprintf(out, "\taddl $24, %%esp\n");
3133 } else {
3134 x_fprintf(out, "\tcall memset\n");
3135 x_fprintf(out, "\taddl $12, %%esp\n");
3136 }
3137 }
3138
3139 static void
emit_alloca(struct allocadata * ad)3140 emit_alloca(struct allocadata *ad) {
3141 if (sysflag == OS_OSX) {
3142 /*
3143 * 16-byte alignment (we pass 4, callee uses
3144 * 8 for ret addr and ebp, so we need 4 to
3145 * get to a multiple of 16)
3146 */
3147 x_fprintf(out, "\tsub $4, %%esp\n");
3148 }
3149 x_fprintf(out, "\tpush %%%s\n", ad->size_reg->name);
3150 if (sysflag == OS_OSX) {
3151 add_osx_fcall("malloc", NULL, 0);
3152 x_fprintf(out, "\tcall L_malloc$stub\n");
3153 x_fprintf(out, "\taddl $8, %%esp\n");
3154 } else {
3155 x_fprintf(out, "\tcall malloc\n");
3156 x_fprintf(out, "\taddl $4, %%esp\n");
3157 }
3158 if (ad->result_reg != &x86_gprs[0]) {
3159 x_fprintf(out, "\tmov %%eax, %%%s\n",
3160 ad->result_reg->name);
3161 }
3162 }
3163
3164 static void
emit_dealloca(struct stack_block * sb,struct reg * r)3165 emit_dealloca(struct stack_block *sb, struct reg *r) {
3166 char *regname = r? r->name: "ecx";
3167
3168 if (sysflag == OS_OSX) {
3169 /*
3170 * 16-byte alignment (we pass 4, callee uses
3171 * 8 for ret addr and ebp, so we need 4 to
3172 * get to a multiple of 16)
3173 */
3174 x_fprintf(out, "\tsub $4, %%esp\n");
3175 }
3176
3177 x_fprintf(out, "\tmov -%lu(%%ebp), %%%s\n",
3178 (unsigned long)sb->offset,
3179 regname);
3180 x_fprintf(out, "\tpush %%%s\n", regname);
3181 if (sysflag == OS_OSX) {
3182 add_osx_fcall("free", NULL, 0);
3183 x_fprintf(out, "\tcall L_free$stub\n");
3184 x_fprintf(out, "\taddl $8, %%esp\n");
3185 } else {
3186 x_fprintf(out, "\tcall free\n");
3187 x_fprintf(out, "\taddl $4, %%esp\n");
3188 }
3189 }
3190
3191 static void
emit_alloc_vla(struct stack_block * sb)3192 emit_alloc_vla(struct stack_block *sb) {
3193 if (sysflag == OS_OSX) {
3194 /*
3195 * 16-byte alignment (we pass 4, callee uses
3196 * 8 for ret addr and ebp, so we need 4 to
3197 * get to a multiple of 16)
3198 */
3199 x_fprintf(out, "\tsub $4, %%esp\n");
3200 }
3201 x_fprintf(out, "\tmov -%lu(%%ebp), %%ecx\n",
3202 (unsigned long)sb->offset - backend->get_ptr_size());
3203 x_fprintf(out, "\tpush %%ecx\n");
3204 if (sysflag == OS_OSX) {
3205 add_osx_fcall("malloc", NULL, 0);
3206 x_fprintf(out, "\tcall L_malloc$stub\n");
3207 x_fprintf(out, "\taddl $8, %%esp\n");
3208 } else {
3209 x_fprintf(out, "\tcall malloc\n");
3210 x_fprintf(out, "\taddl $4, %%esp\n");
3211 }
3212 x_fprintf(out, "\tmov %%eax, -%lu(%%ebp)\n",
3213 (unsigned long)sb->offset);
3214 }
3215
3216 static void
emit_dealloc_vla(struct stack_block * sb,struct reg * r)3217 emit_dealloc_vla(struct stack_block *sb, struct reg *r) {
3218 char *regname = r? r->name: "ecx";
3219
3220 if (sysflag == OS_OSX) {
3221 /*
3222 * 16-byte alignment (we pass 4, callee uses
3223 * 8 for ret addr and ebp, so we need 4 to
3224 * get to a multiple of 16)
3225 */
3226 x_fprintf(out, "\tsub $4, %%esp\n");
3227 }
3228 x_fprintf(out, "\tmov -%lu(%%ebp), %%%s\n",
3229 (unsigned long)sb->offset,
3230 regname);
3231 x_fprintf(out, "\tpush %%%s\n", regname);
3232 if (sysflag == OS_OSX) {
3233 add_osx_fcall("free", NULL, 0);
3234 x_fprintf(out, "\tcall L_free$stub\n");
3235 x_fprintf(out, "\taddl $8, %%esp\n");
3236 } else {
3237 x_fprintf(out, "\tcall free\n");
3238 x_fprintf(out, "\taddl $4, %%esp\n");
3239 }
3240 }
3241
3242 static void
emit_put_vla_size(struct vlasizedata * data)3243 emit_put_vla_size(struct vlasizedata *data) {
3244 x_fprintf(out, "\tmov %%%s, -%lu(%%ebp)\n",
3245 data->size->name,
3246 (unsigned long)data->blockaddr->offset - data->offset);
3247 }
3248
3249 static void
emit_retr_vla_size(struct vlasizedata * data)3250 emit_retr_vla_size(struct vlasizedata *data) {
3251 x_fprintf(out, "\tmov -%lu(%%ebp), %%%s\n",
3252 (unsigned long)data->blockaddr->offset - data->offset,
3253 data->size->name);
3254 }
3255
3256 static void
emit_load_vla(struct reg * r,struct stack_block * sb)3257 emit_load_vla(struct reg *r, struct stack_block *sb) {
3258 x_fprintf(out, "\tmov -%lu(%%ebp), %%%s\n",
3259 (unsigned long)sb->offset, r->name);
3260 }
3261
3262 static void
emit_frame_address(struct builtinframeaddressdata * dat)3263 emit_frame_address(struct builtinframeaddressdata *dat) {
3264 x_fprintf(out, "\tmov %%ebp, %%%s\n", dat->result_reg->name);
3265 }
3266
3267 static void
emit_cdq(void)3268 emit_cdq(void) {
3269 x_fprintf(out, "\tcltd\n");
3270 }
3271
3272 static void
emit_fist(struct fistdata * dat)3273 emit_fist(struct fistdata *dat) {
3274 int size = backend->get_sizeof_type(dat->target_type, NULL);
3275
3276 x_fprintf(out, "\tfistp%c ",
3277 /*dat->vr->size*/ size == 4? 'l': 'q');
3278 if (backend->arch == ARCH_AMD64) {
3279 amd64_print_mem_operand_gas(dat->vr, NULL);
3280 } else {
3281 print_mem_operand(dat->vr, NULL);
3282 print_mem_operand(NULL, NULL); /* 06/12/08: Reset long long flag */
3283 }
3284 x_fputc('\n', out);
3285 }
3286
3287 static void
emit_fild(struct filddata * dat)3288 emit_fild(struct filddata *dat) {
3289 /* s = 16bit, l = 32bit, q = 64bit */
3290 x_fprintf(out, "\tfild%c ",
3291 dat->vr->size == 4? 'l': 'q');
3292 if (backend->arch == ARCH_AMD64) {
3293 amd64_print_mem_operand_gas(dat->vr, NULL);
3294 } else {
3295 print_mem_operand(dat->vr, NULL);
3296 print_mem_operand(NULL, NULL); /* 06/15/08: Reset long long flag */
3297 }
3298 x_fputc('\n', out);
3299 }
3300
3301 static void
emit_x86_ulong_to_float(struct icode_instr * ii)3302 emit_x86_ulong_to_float(struct icode_instr *ii) {
3303 struct amd64_ulong_to_float *data = ii->dat;
3304 static unsigned long count;
3305
3306 x_fprintf(out, "\ttestl %%%s, %%%s\n", data->src_gpr->name, data->src_gpr->name);
3307 x_fprintf(out, "\tjs ._Ulong_float%lu\n", count);
3308 x_fprintf(out, "\tjmp ._Ulong_float%lu\n", count+1);
3309 x_fprintf(out, "._Ulong_float%lu:\n", count);
3310 x_fprintf(out, "\tfadds (_Ulong_float_mask)\n");
3311 x_fprintf(out, "._Ulong_float%lu:\n", count+1);
3312 count += 2;
3313 }
3314
3315 static void
emit_save_ret_addr(struct function * f,struct stack_block * sb)3316 emit_save_ret_addr(struct function *f, struct stack_block *sb) {
3317 (void) f;
3318
3319 x_fprintf(out, "\tmovl 4(%%ebp), %%eax\n");
3320 x_fprintf(out, "\tmovl %%eax, -%lu(%%ebp)\n", sb->offset);
3321 }
3322
3323 static void
emit_check_ret_addr(struct function * f,struct stack_block * saved)3324 emit_check_ret_addr(struct function *f, struct stack_block *saved) {
3325 static unsigned long labval = 0;
3326
3327 (void) f;
3328
3329 x_fprintf(out, "\tmovl -%lu(%%ebp), %%ecx\n", saved->offset);
3330 x_fprintf(out, "\tcmpl 4(%%ebp), %%ecx\n");
3331 x_fprintf(out, "\tje .doret%lu\n", labval);
3332 /* x_fprintf(out, "\tcall __nwcc_stack_corrupt\n");*/
3333 emit_call("__nwcc_stack_corrupt");
3334 x_fprintf(out, ".doret%lu:\n", labval++);
3335 }
3336
3337 #define EXTRA_LLONG(was_llong) \
3338 (was_llong? 4: 0)
3339
3340 static void
do_stack(FILE * out,struct decl * d,int was_llong)3341 do_stack(FILE *out, struct decl *d, int was_llong) {
3342 char *sign;
3343
3344 if (d->stack_addr->is_func_arg) {
3345 sign = "";
3346 if (was_llong) {
3347 was_llong = 4;
3348 }
3349 } else {
3350 sign = "-";
3351 if (was_llong) {
3352 was_llong = -4; /* XXX hmm... */
3353 }
3354 }
3355 x_fprintf(out, "%s%lu(%%ebp",
3356 sign, d->stack_addr->offset+/*EXTRA_LLONG(was_llong)*/was_llong);
3357 }
3358
3359
3360 static void
print_mem_operand(struct vreg * vr,struct token * constant)3361 print_mem_operand(struct vreg *vr, struct token *constant) {
3362 static int was_llong;
3363 int needbracket = 1; /* XXX bogus */
3364
3365 if (vr == NULL && constant == NULL) {
3366 /*
3367 * 06/12/08: Reset long long flag! The problem was
3368 * storing an fp value to a long long buffer, using
3369 * fistpq. This is the single place where we don't
3370 * need two store operations, so we can reset the
3371 * llong flag here
3372 */
3373 was_llong = 0;
3374 return;
3375 }
3376
3377 /*
3378 * 04/11/08: Since some emitter functions are shared between
3379 * x86 and AMD64, print_mem_operand() of x86 may not be used
3380 * because it is 32bit. Caller should use AMD64 version
3381 * instead! It's better to assert instead of fixing the
3382 * issue quietly here, because then function is better
3383 * checked for 64bit cleanliness
3384 */
3385 assert(backend->arch == ARCH_X86);
3386
3387 if (vr && vr->from_const != NULL) {
3388 constant = vr->from_const;
3389 }
3390 if (constant != NULL) {
3391 struct token *t = vr->from_const;
3392
3393 if (!IS_FLOATING(t->type)) {
3394 x_fputc('$', out);
3395 }
3396 if (IS_INT(t->type) || IS_LONG(t->type)) {
3397 cross_print_value_by_type(out, t->data, t->type, 'd');
3398 #if ALLOW_CHAR_SHORT_CONSTANTS
3399 } else if (IS_CHAR(t->type) || IS_SHORT(t->type)) {
3400 cross_print_value_by_type(out, t->data, t->type, 'd');
3401 #endif
3402 } else if (IS_LLONG(t->type)) {
3403 static int was_llong = 0;
3404 void *p;
3405
3406 if (was_llong) {
3407 /* Loading second part of long long */
3408 p = (char *)t->data + 4;
3409 was_llong = 0;
3410 } else {
3411 p = t->data;
3412 was_llong = 1;
3413 }
3414 if (t->type == TY_LLONG) {
3415 cross_print_value_by_type(out,
3416 p, TY_UINT, 'd');
3417 } else {
3418 /* ULLONG */
3419 cross_print_value_by_type(out,
3420 p, TY_UINT, 'd');
3421 }
3422 } else if (t->type == TOK_STRING_LITERAL) {
3423 struct ty_string *ts = t->data;
3424 x_fprintf(out, "._Str%ld",
3425 ts->count);
3426 } else if (t->type == TY_FLOAT
3427 || t->type == TY_DOUBLE
3428 || t->type == TY_LDOUBLE) {
3429 struct ty_float *tf = t->data;
3430
3431 x_fprintf(out, "(_Float%lu)",
3432 tf->count);
3433 } else {
3434 printf("loadimm: Bad data type %d\n", t->type);
3435 abort();
3436 return;
3437 }
3438 } else if (vr->parent != NULL) {
3439 struct vreg *vr2;
3440 struct decl *d2;
3441
3442 vr2 = get_parent_struct(vr);
3443 if ((d2 = vr2->var_backed) != NULL) {
3444 if (d2->stack_addr) {
3445 /* XXX kludgy? */
3446 unsigned long off = calc_offsets(vr);
3447
3448 if (vr2->var_backed->stack_addr->is_func_arg) {
3449 vr2->var_backed->stack_addr->offset +=
3450 /*vr->memberdecl->offset*/off;
3451 } else {
3452 vr2->var_backed->stack_addr->offset -=
3453 /*vr->memberdecl->offset*/off;
3454 }
3455 do_stack(out, vr2->var_backed, was_llong);
3456 if (vr2->var_backed->stack_addr->is_func_arg) {
3457 vr2->var_backed->stack_addr->offset -=
3458 /*vr->memberdecl->offset*/off;
3459 } else {
3460 vr2->var_backed->stack_addr->offset +=
3461 /*vr->memberdecl->offset*/off;
3462 }
3463 } else {
3464 /* static */
3465 x_fprintf(out, "%s+%lu",
3466 d2->dtype->name,
3467 calc_offsets(vr)+EXTRA_LLONG(was_llong));
3468 needbracket = 0;
3469 }
3470 } else if (vr2->from_ptr) {
3471 /* Struct comes from pointer */
3472 x_fprintf(out, "%lu(%%%s",
3473 calc_offsets(vr)+EXTRA_LLONG(was_llong),
3474 vr2->from_ptr->pregs[0]->name);
3475 } else {
3476 printf("BUG: Bad load for %s\n",
3477 vr->type->name? vr->type->name: "structure");
3478 abort();
3479 }
3480 } else if (vr->var_backed) {
3481 struct decl *d = vr->var_backed;
3482
3483 if (d->stack_addr != NULL) {
3484 do_stack(out, d, was_llong);
3485 } else {
3486 if (d->dtype->storage == TOK_KEY_REGISTER) {
3487 unimpl();
3488 } else {
3489 if (d->dtype->tlist != NULL
3490 && d->dtype->tlist->type
3491 == TN_FUNCTION) {
3492 x_fprintf(out, "$%s", d->dtype->name);
3493 } else {
3494 x_fprintf(out, "%s", d->dtype->name);
3495 if (was_llong) {
3496 x_fprintf(out, "+4");
3497 }
3498 }
3499 needbracket = 0;
3500 }
3501 }
3502 } else if (vr->stack_addr) {
3503 /*
3504 * 07/26/12: Honor use_frame_pointer
3505 */
3506 if (vr->stack_addr->use_frame_pointer) {
3507 x_fprintf(out, "-%lu(%%ebp",
3508 vr->stack_addr->offset - EXTRA_LLONG(was_llong));
3509 } else {
3510 x_fprintf(out, "%lu(%%esp",
3511 vr->stack_addr->offset + EXTRA_LLONG(was_llong));
3512 }
3513 } else if (vr->from_ptr) {
3514 if (was_llong) {
3515 x_fputc('4', out);
3516 }
3517 x_fprintf(out, "(%%%s", vr->from_ptr->pregs[0]->name);
3518 } else {
3519 abort();
3520 }
3521 if (constant == NULL) {
3522 if (was_llong) {
3523 /*x_fprintf(out, " + 4 ");*/
3524 was_llong = 0;
3525 } else if (vr->is_multi_reg_obj) {
3526 was_llong = 1;
3527 }
3528 if (needbracket) {
3529 x_fputc(')', out);
3530 }
3531 }
3532 }
3533
3534
3535 void
print_item_gas_x86(FILE * out,void * item,int item_type,int postfix)3536 print_item_gas_x86(FILE *out, void *item, int item_type, int postfix) {
3537 print_asmitem_x86(out, item, item_type, postfix, TO_GAS);
3538 }
3539
3540 struct emitter x86_emit_gas = {
3541 0, /* need_explicit_extern_decls */
3542 init,
3543 emit_strings,
3544 emit_fp_constants,
3545 NULL, /* llong_constants */
3546 emit_support_buffers,
3547 NULL, /* pic_support */
3548 NULL, /* support_decls */
3549 emit_extern_decls,
3550 emit_global_extern_decls,
3551 emit_global_static_decls,
3552 #if 0
3553 emit_global_decls,
3554 emit_static_decls,
3555 #endif
3556 emit_static_init_vars,
3557 emit_static_uninit_vars,
3558 emit_static_init_thread_vars,
3559 emit_static_uninit_thread_vars,
3560 NULL, /* struct_defs */
3561 emit_comment,
3562
3563 emit_dwarf2_line,
3564 emit_dwarf2_files,
3565 emit_inlineasm,
3566 emit_unimpl,
3567 emit_empty,
3568 emit_label,
3569 emit_call,
3570 emit_callindir,
3571 emit_func_header,
3572 emit_func_intro,
3573 emit_func_outro,
3574 NULL, /*emit_define*/
3575 emit_push,
3576 emit_allocstack,
3577 emit_freestack,
3578 emit_adj_allocated,
3579 emit_inc,
3580 emit_dec,
3581 emit_load,
3582 emit_load_addrlabel,
3583 emit_comp_goto,
3584 emit_store,
3585 emit_setsection,
3586 emit_alloc,
3587 emit_neg,
3588 emit_sub,
3589 emit_add,
3590 emit_div,
3591 emit_mod,
3592 emit_mul,
3593 emit_shl,
3594 emit_shr,
3595 emit_or,
3596 NULL, /* emit_preg_or */
3597 emit_and,
3598 emit_xor,
3599 emit_not,
3600 emit_ret,
3601 emit_cmp,
3602 NULL, /* extend_sign */
3603 NULL, /* conv_fp */
3604 NULL, /* from_ldouble */
3605 NULL, /* to_ldouble */
3606 emit_branch,
3607 emit_mov,
3608 emit_setreg,
3609 emit_xchg,
3610 emit_addrof,
3611 emit_initialize_pic,
3612 emit_copyinit,
3613 NULL, /* putstructregs */
3614 emit_copystruct,
3615 emit_intrinsic_memcpy,
3616 emit_zerostack,
3617 emit_alloca,
3618 emit_dealloca,
3619 emit_alloc_vla,
3620 emit_dealloc_vla,
3621 emit_put_vla_size,
3622 emit_retr_vla_size,
3623 emit_load_vla,
3624 emit_frame_address,
3625 emit_struct_inits,
3626 emit_save_ret_addr,
3627 emit_check_ret_addr,
3628 print_mem_operand,
3629 emit_finish_program,
3630 emit_stupidtrace,
3631 emit_finish_stupidtrace
3632 };
3633
3634
3635 struct emitter_x86 x86_emit_x86_gas = {
3636 emit_fxch,
3637 emit_ffree,
3638 emit_fnstcw,
3639 emit_fldcw,
3640 emit_cdq,
3641 emit_fist,
3642 emit_fild,
3643 emit_x86_ulong_to_float
3644 };
3645
3646